From e4305f0c500cc2b8ca8d6ca2fb74fb76bf2cb6ad Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 11 Jun 2012 21:57:14 +0200 Subject: serial/of-serial: Add LPC3220 standard UART compatible string This patch adds a "compatible" string for the new 8250 UART type PORT_LPC3220. This is necessary for initializing LPC32xx UARTs via DT. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/tty/serial/of-serial.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt index b8b27b0aca1..0847fdeee11 100644 --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -9,6 +9,7 @@ Required properties: - "ns16750" - "ns16850" - "nvidia,tegra20-uart" + - "nxp,lpc3220-uart" - "ibm,qpace-nwp-serial" - "serial" if the port type is unknown. - reg : offset and length of the register set for the device. -- cgit v1.2.3-70-g09d2 From 596f93f50e2d1a926bbb6c73aa7ee7fd862b7062 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 11 Jun 2012 22:04:12 +0200 Subject: serial: Add driver for LPC32xx High Speed UARTs This patch adds a driver for the 3 High Speed UARTs of the LPC32xx SoC that support up to 921600bps. These UARTs are different from the 4 "Standard" UARTs of the LPC32xx. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- .../bindings/tty/serial/nxp-lpc32xx-hsuart.txt | 14 + drivers/tty/serial/Kconfig | 19 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/lpc32xx_hs.c | 823 +++++++++++++++++++++ 4 files changed, 857 insertions(+) create mode 100644 Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt create mode 100644 drivers/tty/serial/lpc32xx_hs.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt new file mode 100644 index 00000000000..0d439dfc1aa --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt @@ -0,0 +1,14 @@ +* NXP LPC32xx SoC High Speed UART + +Required properties: +- compatible: Should be "nxp,lpc3220-hsuart" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt + +Example: + + uart1: serial@40014000 { + compatible = "nxp,lpc3220-hsuart"; + reg = <0x40014000 0x1000>; + interrupts = <26 0>; + }; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 070b442c1f8..00207865ec5 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -704,6 +704,25 @@ config SERIAL_PNX8XXX_CONSOLE If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 and you want to use serial console, say Y. Otherwise, say N. +config SERIAL_HS_LPC32XX + tristate "LPC32XX high speed serial port support" + depends on ARCH_LPC32XX && OF + select SERIAL_CORE + help + Support for the LPC32XX high speed serial ports (up to 900kbps). + Those are UARTs completely different from the Standard UARTs on the + LPC32XX SoC. + Choose M or Y here to build this driver. + +config SERIAL_HS_LPC32XX_CONSOLE + bool "Enable LPC32XX high speed UART serial console" + depends on SERIAL_HS_LPC32XX + select SERIAL_CORE_CONSOLE + help + If you would like to be able to use one of the high speed serial + ports on the LPC32XX as the console, you can do so by answering + Y to this option. + config SERIAL_CORE tristate diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 7257c5d898a..8a5df3804e5 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_ZS) += zs.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c new file mode 100644 index 00000000000..ba3af3bf6d4 --- /dev/null +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -0,0 +1,823 @@ +/* + * High Speed Serial Ports on NXP LPC32xx SoC + * + * Authors: Kevin Wells + * Roland Stigge + * + * Copyright (C) 2010 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * High Speed UART register offsets + */ +#define LPC32XX_HSUART_FIFO(x) ((x) + 0x00) +#define LPC32XX_HSUART_LEVEL(x) ((x) + 0x04) +#define LPC32XX_HSUART_IIR(x) ((x) + 0x08) +#define LPC32XX_HSUART_CTRL(x) ((x) + 0x0C) +#define LPC32XX_HSUART_RATE(x) ((x) + 0x10) + +#define LPC32XX_HSU_BREAK_DATA (1 << 10) +#define LPC32XX_HSU_ERROR_DATA (1 << 9) +#define LPC32XX_HSU_RX_EMPTY (1 << 8) + +#define LPC32XX_HSU_TX_LEV(n) (((n) >> 8) & 0xFF) +#define LPC32XX_HSU_RX_LEV(n) ((n) & 0xFF) + +#define LPC32XX_HSU_TX_INT_SET (1 << 6) +#define LPC32XX_HSU_RX_OE_INT (1 << 5) +#define LPC32XX_HSU_BRK_INT (1 << 4) +#define LPC32XX_HSU_FE_INT (1 << 3) +#define LPC32XX_HSU_RX_TIMEOUT_INT (1 << 2) +#define LPC32XX_HSU_RX_TRIG_INT (1 << 1) +#define LPC32XX_HSU_TX_INT (1 << 0) + +#define LPC32XX_HSU_HRTS_INV (1 << 21) +#define LPC32XX_HSU_HRTS_TRIG_8B (0x0 << 19) +#define LPC32XX_HSU_HRTS_TRIG_16B (0x1 << 19) +#define LPC32XX_HSU_HRTS_TRIG_32B (0x2 << 19) +#define LPC32XX_HSU_HRTS_TRIG_48B (0x3 << 19) +#define LPC32XX_HSU_HRTS_EN (1 << 18) +#define LPC32XX_HSU_TMO_DISABLED (0x0 << 16) +#define LPC32XX_HSU_TMO_INACT_4B (0x1 << 16) +#define LPC32XX_HSU_TMO_INACT_8B (0x2 << 16) +#define LPC32XX_HSU_TMO_INACT_16B (0x3 << 16) +#define LPC32XX_HSU_HCTS_INV (1 << 15) +#define LPC32XX_HSU_HCTS_EN (1 << 14) +#define LPC32XX_HSU_OFFSET(n) ((n) << 9) +#define LPC32XX_HSU_BREAK (1 << 8) +#define LPC32XX_HSU_ERR_INT_EN (1 << 7) +#define LPC32XX_HSU_RX_INT_EN (1 << 6) +#define LPC32XX_HSU_TX_INT_EN (1 << 5) +#define LPC32XX_HSU_RX_TL1B (0x0 << 2) +#define LPC32XX_HSU_RX_TL4B (0x1 << 2) +#define LPC32XX_HSU_RX_TL8B (0x2 << 2) +#define LPC32XX_HSU_RX_TL16B (0x3 << 2) +#define LPC32XX_HSU_RX_TL32B (0x4 << 2) +#define LPC32XX_HSU_RX_TL48B (0x5 << 2) +#define LPC32XX_HSU_TX_TLEMPTY (0x0 << 0) +#define LPC32XX_HSU_TX_TL0B (0x0 << 0) +#define LPC32XX_HSU_TX_TL4B (0x1 << 0) +#define LPC32XX_HSU_TX_TL8B (0x2 << 0) +#define LPC32XX_HSU_TX_TL16B (0x3 << 0) + +#define MODNAME "lpc32xx_hsuart" + +struct lpc32xx_hsuart_port { + struct uart_port port; +}; + +#define FIFO_READ_LIMIT 128 +#define MAX_PORTS 3 +#define LPC32XX_TTY_NAME "ttyTX" +static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS]; + +#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE +static void wait_for_xmit_empty(struct uart_port *port) +{ + unsigned int timeout = 10000; + + do { + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL( + port->membase))) == 0) + break; + if (--timeout == 0) + break; + udelay(1); + } while (1); +} + +static void wait_for_xmit_ready(struct uart_port *port) +{ + unsigned int timeout = 10000; + + while (1) { + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL( + port->membase))) < 32) + break; + if (--timeout == 0) + break; + udelay(1); + } +} + +static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmit_ready(port); + writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase)); +} + +static void lpc32xx_hsuart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index]; + unsigned long flags; + int locked = 1; + + touch_nmi_watchdog(); + local_irq_save(flags); + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + + uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); + wait_for_xmit_empty(&up->port); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init lpc32xx_hsuart_console_setup(struct console *co, + char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= MAX_PORTS) + co->index = 0; + + port = &lpc32xx_hs_ports[co->index].port; + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver lpc32xx_hsuart_reg; +static struct console lpc32xx_hsuart_console = { + .name = LPC32XX_TTY_NAME, + .write = lpc32xx_hsuart_console_write, + .device = uart_console_device, + .setup = lpc32xx_hsuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lpc32xx_hsuart_reg, +}; + +static int __init lpc32xx_hsuart_console_init(void) +{ + register_console(&lpc32xx_hsuart_console); + return 0; +} +console_initcall(lpc32xx_hsuart_console_init); + +#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console) +#else +#define LPC32XX_HSUART_CONSOLE NULL +#endif + +static struct uart_driver lpc32xx_hs_reg = { + .owner = THIS_MODULE, + .driver_name = MODNAME, + .dev_name = LPC32XX_TTY_NAME, + .nr = MAX_PORTS, + .cons = LPC32XX_HSUART_CONSOLE, +}; +static int uarts_registered; + +static unsigned int __serial_get_clock_div(unsigned long uartclk, + unsigned long rate) +{ + u32 div, goodrate, hsu_rate, l_hsu_rate, comprate; + u32 rate_diff; + + /* Find the closest divider to get the desired clock rate */ + div = uartclk / rate; + goodrate = hsu_rate = (div / 14) - 1; + if (hsu_rate != 0) + hsu_rate--; + + /* Tweak divider */ + l_hsu_rate = hsu_rate + 3; + rate_diff = 0xFFFFFFFF; + + while (hsu_rate < l_hsu_rate) { + comprate = uartclk / ((hsu_rate + 1) * 14); + if (abs(comprate - rate) < rate_diff) { + goodrate = hsu_rate; + rate_diff = abs(comprate - rate); + } + + hsu_rate++; + } + if (hsu_rate > 0xFF) + hsu_rate = 0xFF; + + return goodrate; +} + +static void __serial_uart_flush(struct uart_port *port) +{ + u32 tmp; + int cnt = 0; + + while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) && + (cnt++ < FIFO_READ_LIMIT)) + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); +} + +static void __serial_lpc32xx_rx(struct uart_port *port) +{ + unsigned int tmp, flag; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + + if (!tty) { + /* Discard data: no tty available */ + while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) & + LPC32XX_HSU_RX_EMPTY)) + ; + + return; + } + + /* Read data from FIFO and push into terminal */ + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + while (!(tmp & LPC32XX_HSU_RX_EMPTY)) { + flag = TTY_NORMAL; + port->icount.rx++; + + if (tmp & LPC32XX_HSU_ERROR_DATA) { + /* Framing error */ + writel(LPC32XX_HSU_FE_INT, + LPC32XX_HSUART_IIR(port->membase)); + port->icount.frame++; + flag = TTY_FRAME; + tty_insert_flip_char(tty, 0, TTY_FRAME); + } + + tty_insert_flip_char(tty, (tmp & 0xFF), flag); + + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + } + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + +static void __serial_lpc32xx_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int tmp; + + if (port->x_char) { + writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase)); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + goto exit_tx; + + /* Transfer data */ + while (LPC32XX_HSU_TX_LEV(readl( + LPC32XX_HSUART_LEVEL(port->membase))) < 64) { + writel((u32) xmit->buf[xmit->tail], + LPC32XX_HSUART_FIFO(port->membase)); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + +exit_tx: + if (uart_circ_empty(xmit)) { + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + } +} + +static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + u32 status; + + spin_lock(&port->lock); + + /* Read UART status and clear latched interrupts */ + status = readl(LPC32XX_HSUART_IIR(port->membase)); + + if (status & LPC32XX_HSU_BRK_INT) { + /* Break received */ + writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase)); + port->icount.brk++; + uart_handle_break(port); + } + + /* Framing error */ + if (status & LPC32XX_HSU_FE_INT) + writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase)); + + if (status & LPC32XX_HSU_RX_OE_INT) { + /* Receive FIFO overrun */ + writel(LPC32XX_HSU_RX_OE_INT, + LPC32XX_HSUART_IIR(port->membase)); + port->icount.overrun++; + if (tty) { + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_schedule_flip(tty); + } + } + + /* Data received? */ + if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) { + __serial_lpc32xx_rx(port); + if (tty) + tty_flip_buffer_push(tty); + } + + /* Transmit data request? */ + if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) { + writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase)); + __serial_lpc32xx_tx(port); + } + + spin_unlock(&port->lock); + tty_kref_put(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port) +{ + unsigned int ret = 0; + + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0) + ret = TIOCSER_TEMT; + + return ret; +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_set_mctrl(struct uart_port *port, + unsigned int mctrl) +{ + /* No signals are supported on HS UARTs */ +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port) +{ + /* No signals are supported on HS UARTs */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_stop_tx(struct uart_port *port) +{ + u32 tmp; + + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_start_tx(struct uart_port *port) +{ + u32 tmp; + + __serial_lpc32xx_tx(port); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp |= LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_stop_rx(struct uart_port *port) +{ + u32 tmp; + + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN); + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT | + LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_enable_ms(struct uart_port *port) +{ + /* Modem status is not supported */ +} + +/* port->lock is not held. */ +static void serial_lpc32xx_break_ctl(struct uart_port *port, + int break_state) +{ + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if (break_state != 0) + tmp |= LPC32XX_HSU_BREAK; + else + tmp &= ~LPC32XX_HSU_BREAK; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */ +static void lpc32xx_loopback_set(resource_size_t mapbase, int state) +{ + int bit; + u32 tmp; + + switch (mapbase) { + case LPC32XX_HS_UART1_BASE: + bit = 0; + break; + case LPC32XX_HS_UART2_BASE: + bit = 1; + break; + case LPC32XX_HS_UART7_BASE: + bit = 6; + break; + default: + WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase); + return; + } + + tmp = readl(LPC32XX_UARTCTL_CLOOP); + if (state) + tmp |= (1 << bit); + else + tmp &= ~(1 << bit); + writel(tmp, LPC32XX_UARTCTL_CLOOP); +} + +/* port->lock is not held. */ +static int serial_lpc32xx_startup(struct uart_port *port) +{ + int retval; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + + __serial_uart_flush(port); + + writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT | + LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT), + LPC32XX_HSUART_IIR(port->membase)); + + writel(0xFF, LPC32XX_HSUART_RATE(port->membase)); + + /* + * Set receiver timeout, HSU offset of 20, no break, no interrupts, + * and default FIFO trigger levels + */ + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ + + spin_unlock_irqrestore(&port->lock, flags); + + retval = request_irq(port->irq, serial_lpc32xx_interrupt, + 0, MODNAME, port); + if (!retval) + writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN), + LPC32XX_HSUART_CTRL(port->membase)); + + return retval; +} + +/* port->lock is not held. */ +static void serial_lpc32xx_shutdown(struct uart_port *port) +{ + u32 tmp; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */ + + spin_unlock_irqrestore(&port->lock, flags); + + free_irq(port->irq, port); +} + +/* port->lock is not held. */ +static void serial_lpc32xx_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, quot; + u32 tmp; + + /* Always 8-bit, no parity, 1 stop bit */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag |= CS8; + + termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS); + + baud = uart_get_baud_rate(port, termios, old, 0, + port->uartclk / 14); + + quot = __serial_get_clock_div(port->uartclk, baud); + + spin_lock_irqsave(&port->lock, flags); + + /* Ignore characters? */ + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if ((termios->c_cflag & CREAD) == 0) + tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN); + else + tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + writel(quot, LPC32XX_HSUART_RATE(port->membase)); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} + +static const char *serial_lpc32xx_type(struct uart_port *port) +{ + return MODNAME; +} + +static void serial_lpc32xx_release_port(struct uart_port *port) +{ + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) { + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, SZ_4K); + } +} + +static int serial_lpc32xx_request_port(struct uart_port *port) +{ + int ret = -ENODEV; + + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) { + ret = 0; + + if (!request_mem_region(port->mapbase, SZ_4K, MODNAME)) + ret = -EBUSY; + else if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, SZ_4K); + if (!port->membase) { + release_mem_region(port->mapbase, SZ_4K); + ret = -ENOMEM; + } + } + } + + return ret; +} + +static void serial_lpc32xx_config_port(struct uart_port *port, int uflags) +{ + int ret; + + ret = serial_lpc32xx_request_port(port); + if (ret < 0) + return; + port->type = PORT_UART00; + port->fifosize = 64; + + __serial_uart_flush(port); + + writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT | + LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT), + LPC32XX_HSUART_IIR(port->membase)); + + writel(0xFF, LPC32XX_HSUART_RATE(port->membase)); + + /* Set receiver timeout, HSU offset of 20, no break, no interrupts, + and default FIFO trigger levels */ + writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B, + LPC32XX_HSUART_CTRL(port->membase)); +} + +static int serial_lpc32xx_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UART00) + ret = -EINVAL; + + return ret; +} + +static struct uart_ops serial_lpc32xx_pops = { + .tx_empty = serial_lpc32xx_tx_empty, + .set_mctrl = serial_lpc32xx_set_mctrl, + .get_mctrl = serial_lpc32xx_get_mctrl, + .stop_tx = serial_lpc32xx_stop_tx, + .start_tx = serial_lpc32xx_start_tx, + .stop_rx = serial_lpc32xx_stop_rx, + .enable_ms = serial_lpc32xx_enable_ms, + .break_ctl = serial_lpc32xx_break_ctl, + .startup = serial_lpc32xx_startup, + .shutdown = serial_lpc32xx_shutdown, + .set_termios = serial_lpc32xx_set_termios, + .type = serial_lpc32xx_type, + .release_port = serial_lpc32xx_release_port, + .request_port = serial_lpc32xx_request_port, + .config_port = serial_lpc32xx_config_port, + .verify_port = serial_lpc32xx_verify_port, +}; + +/* + * Register a set of serial devices attached to a platform device + */ +static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered]; + int ret = 0; + struct resource *res; + + if (uarts_registered >= MAX_PORTS) { + dev_err(&pdev->dev, + "Error: Number of possible ports exceeded (%d)!\n", + uarts_registered + 1); + return -ENXIO; + } + + memset(p, 0, sizeof(*p)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Error getting mem resource for HS UART port %d\n", + uarts_registered); + return -ENXIO; + } + p->port.mapbase = res->start; + p->port.membase = NULL; + + p->port.irq = platform_get_irq(pdev, 0); + if (p->port.irq < 0) { + dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n", + uarts_registered); + return p->port.irq; + } + + p->port.iotype = UPIO_MEM32; + p->port.uartclk = LPC32XX_MAIN_OSC_FREQ; + p->port.regshift = 2; + p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; + p->port.dev = &pdev->dev; + p->port.ops = &serial_lpc32xx_pops; + p->port.line = uarts_registered++; + spin_lock_init(&p->port.lock); + + /* send port to loopback mode by default */ + lpc32xx_loopback_set(p->port.mapbase, 1); + + ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port); + + platform_set_drvdata(pdev, p); + + return ret; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_remove_one_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} + + +#ifdef CONFIG_PM +static int serial_hs_lpc32xx_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_suspend_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} + +static int serial_hs_lpc32xx_resume(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_resume_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} +#else +#define serial_hs_lpc32xx_suspend NULL +#define serial_hs_lpc32xx_resume NULL +#endif + +static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = { + { .compatible = "nxp,lpc3220-hsuart" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids); + +static struct platform_driver serial_hs_lpc32xx_driver = { + .probe = serial_hs_lpc32xx_probe, + .remove = __devexit_p(serial_hs_lpc32xx_remove), + .suspend = serial_hs_lpc32xx_suspend, + .resume = serial_hs_lpc32xx_resume, + .driver = { + .name = MODNAME, + .owner = THIS_MODULE, + .of_match_table = serial_hs_lpc32xx_dt_ids, + }, +}; + +static int __init lpc32xx_hsuart_init(void) +{ + int ret; + + ret = uart_register_driver(&lpc32xx_hs_reg); + if (ret) + return ret; + + ret = platform_driver_register(&serial_hs_lpc32xx_driver); + if (ret) + uart_unregister_driver(&lpc32xx_hs_reg); + + return ret; +} + +static void __exit lpc32xx_hsuart_exit(void) +{ + platform_driver_unregister(&serial_hs_lpc32xx_driver); + uart_unregister_driver(&lpc32xx_hs_reg); +} + +module_init(lpc32xx_hsuart_init); +module_exit(lpc32xx_hsuart_exit); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 63d99c0e89039e1509209d36ee17fc374fd112c9 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 22 May 2012 07:30:48 -0700 Subject: mtd: nand: remove NAND_BBT_SEARCH option This option was never used and isn't currently used. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- Documentation/DocBook/mtdnand.tmpl | 2 -- include/linux/mtd/bbm.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index e0aedb7a782..fe122d6e686 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -1216,8 +1216,6 @@ in this page #define NAND_BBT_LASTBLOCK 0x00000010 /* The bbt is at the given page, else we must scan for the bbt */ #define NAND_BBT_ABSPAGE 0x00000020 -/* The bbt is at the given page, else we must scan for the bbt */ -#define NAND_BBT_SEARCH 0x00000040 /* bbt is stored per chip on multichip devices */ #define NAND_BBT_PERCHIP 0x00000080 /* bbt has a version counter at offset veroffs */ diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 650ef352f04..5d9fcb7645a 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -78,8 +78,6 @@ struct nand_bbt_descr { #define NAND_BBT_LASTBLOCK 0x00000010 /* The bbt is at the given page, else we must scan for the bbt */ #define NAND_BBT_ABSPAGE 0x00000020 -/* The bbt is at the given page, else we must scan for the bbt */ -#define NAND_BBT_SEARCH 0x00000040 /* bbt is stored per chip on multichip devices */ #define NAND_BBT_PERCHIP 0x00000080 /* bbt has a version counter at offset veroffs */ -- cgit v1.2.3-70-g09d2 From 2944a44da09e46b6db2fd2c3334f242b09e05c43 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 7 Jun 2012 12:22:15 +0200 Subject: mtd: add LPC32xx SLC NAND driver This patch adds support for the SLC NAND controller inside the LPC32xx SoC. [dwmw2: 21st century pedantry] Signed-off-by: Roland Stigge Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/lpc32xx-slc.txt | 52 + drivers/mtd/nand/Kconfig | 11 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/lpc32xx_slc.c | 1065 ++++++++++++++++++++ 4 files changed, 1129 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt create mode 100644 drivers/mtd/nand/lpc32xx_slc.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt new file mode 100644 index 00000000000..d94edc0fc55 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt @@ -0,0 +1,52 @@ +NXP LPC32xx SoC NAND SLC controller + +Required properties: +- compatible: "nxp,lpc3220-slc" +- reg: Address and size of the controller +- nand-on-flash-bbt: Use bad block table on flash +- gpios: GPIO specification for NAND write protect + +The following required properties are very controller specific. See the LPC32xx +User Manual: +- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY) +- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY) +(The following values are specified in Hz, to make them independent of actual +clock speed:) +- nxp,wwidth: Write pulse width (W_WIDTH) +- nxp,whold: Write hold time (W_HOLD) +- nxp,wsetup: Write setup time (W_SETUP) +- nxp,rwidth: Read pulse width (R_WIDTH) +- nxp,rhold: Read hold time (R_HOLD) +- nxp,rsetup: Read setup time (R_SETUP) + +Optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + + slc: flash@20020000 { + compatible = "nxp,lpc3220-slc"; + reg = <0x20020000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + nxp,wdr-clks = <14>; + nxp,wwidth = <40000000>; + nxp,whold = <100000000>; + nxp,wsetup = <100000000>; + nxp,rdr-clks = <14>; + nxp,rwidth = <40000000>; + nxp,rhold = <66666666>; + nxp,rsetup = <100000000>; + nand-on-flash-bbt; + gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */ + + mtd0@00000000 { + label = "phy3250-boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + ... + + }; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 31bb7e5b504..b28b57ed51b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -454,6 +454,17 @@ config MTD_NAND_PXA3xx This enables the driver for the NAND flash device found on PXA3xx processors +config MTD_NAND_SLC_LPC32XX + tristate "NXP LPC32xx SLC Controller" + depends on ARCH_LPC32XX + help + Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell + chips) NAND controller. This is the default for the PHYTEC 3250 + reference board which contains a NAND256R3A2CZA6 chip. + + Please check the actual NAND chip connected and its support + by the SLC NAND controller. + config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MACH_ARMCORE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d4b4d8739bd..d29a893608e 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o +obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c new file mode 100644 index 00000000000..1d837b92ac7 --- /dev/null +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -0,0 +1,1065 @@ +/* + * NXP LPC32XX NAND SLC driver + * + * Authors: + * Kevin Wells + * Roland Stigge + * + * Copyright © 2011 NXP Semiconductors + * Copyright © 2012 Roland Stigge + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LPC32XX_MODNAME "lpc32xx-nand" + +/********************************************************************** +* SLC NAND controller register offsets +**********************************************************************/ + +#define SLC_DATA(x) (x + 0x000) +#define SLC_ADDR(x) (x + 0x004) +#define SLC_CMD(x) (x + 0x008) +#define SLC_STOP(x) (x + 0x00C) +#define SLC_CTRL(x) (x + 0x010) +#define SLC_CFG(x) (x + 0x014) +#define SLC_STAT(x) (x + 0x018) +#define SLC_INT_STAT(x) (x + 0x01C) +#define SLC_IEN(x) (x + 0x020) +#define SLC_ISR(x) (x + 0x024) +#define SLC_ICR(x) (x + 0x028) +#define SLC_TAC(x) (x + 0x02C) +#define SLC_TC(x) (x + 0x030) +#define SLC_ECC(x) (x + 0x034) +#define SLC_DMA_DATA(x) (x + 0x038) + +/********************************************************************** +* slc_ctrl register definitions +**********************************************************************/ +#define SLCCTRL_SW_RESET (1 << 2) /* Reset the NAND controller bit */ +#define SLCCTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */ +#define SLCCTRL_DMA_START (1 << 0) /* Start DMA channel bit */ + +/********************************************************************** +* slc_cfg register definitions +**********************************************************************/ +#define SLCCFG_CE_LOW (1 << 5) /* Force CE low bit */ +#define SLCCFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */ +#define SLCCFG_ECC_EN (1 << 3) /* ECC enable bit */ +#define SLCCFG_DMA_BURST (1 << 2) /* DMA burst bit */ +#define SLCCFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */ +#define SLCCFG_WIDTH (1 << 0) /* External device width, 0=8bit */ + +/********************************************************************** +* slc_stat register definitions +**********************************************************************/ +#define SLCSTAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */ +#define SLCSTAT_SLC_FIFO (1 << 1) /* SLC FIFO has data bit */ +#define SLCSTAT_NAND_READY (1 << 0) /* NAND device is ready bit */ + +/********************************************************************** +* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions +**********************************************************************/ +#define SLCSTAT_INT_TC (1 << 1) /* Transfer count bit */ +#define SLCSTAT_INT_RDY_EN (1 << 0) /* Ready interrupt bit */ + +/********************************************************************** +* slc_tac register definitions +**********************************************************************/ +/* Clock setting for RDY write sample wait time in 2*n clocks */ +#define SLCTAC_WDR(n) (((n) & 0xF) << 28) +/* Write pulse width in clock cycles, 1 to 16 clocks */ +#define SLCTAC_WWIDTH(n) (((n) & 0xF) << 24) +/* Write hold time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_WHOLD(n) (((n) & 0xF) << 20) +/* Write setup time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_WSETUP(n) (((n) & 0xF) << 16) +/* Clock setting for RDY read sample wait time in 2*n clocks */ +#define SLCTAC_RDR(n) (((n) & 0xF) << 12) +/* Read pulse width in clock cycles, 1 to 16 clocks */ +#define SLCTAC_RWIDTH(n) (((n) & 0xF) << 8) +/* Read hold time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_RHOLD(n) (((n) & 0xF) << 4) +/* Read setup time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_RSETUP(n) (((n) & 0xF) << 0) + +/********************************************************************** +* slc_ecc register definitions +**********************************************************************/ +/* ECC line party fetch macro */ +#define SLCECC_TO_LINEPAR(n) (((n) >> 6) & 0x7FFF) +#define SLCECC_TO_COLPAR(n) ((n) & 0x3F) + +/* + * DMA requires storage space for the DMA local buffer and the hardware ECC + * storage area. The DMA local buffer is only used if DMA mapping fails + * during runtime. + */ +#define LPC32XX_DMA_DATA_SIZE 4096 +#define LPC32XX_ECC_SAVE_SIZE ((4096 / 256) * 4) + +/* Number of bytes used for ECC stored in NAND per 256 bytes */ +#define LPC32XX_SLC_DEV_ECC_BYTES 3 + +/* + * If the NAND base clock frequency can't be fetched, this frequency will be + * used instead as the base. This rate is used to setup the timing registers + * used for NAND accesses. + */ +#define LPC32XX_DEF_BUS_RATE 133250000 + +/* Milliseconds for DMA FIFO timeout (unlikely anyway) */ +#define LPC32XX_DMA_TIMEOUT 100 + +/* + * NAND ECC Layout for small page NAND devices + * Note: For large and huge page devices, the default layouts are used + */ +static struct nand_ecclayout lpc32xx_nand_oob_16 = { + .eccbytes = 6, + .eccpos = {10, 11, 12, 13, 14, 15}, + .oobfree = { + { .offset = 0, .length = 4 }, + { .offset = 6, .length = 4 }, + }, +}; + +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +/* + * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6 + * Note: Large page devices used the default layout + */ +static struct nand_bbt_descr bbt_smallpage_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 6, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_smallpage_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 6, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/* + * NAND platform configuration structure + */ +struct lpc32xx_nand_cfg_slc { + uint32_t wdr_clks; + uint32_t wwidth; + uint32_t whold; + uint32_t wsetup; + uint32_t rdr_clks; + uint32_t rwidth; + uint32_t rhold; + uint32_t rsetup; + bool use_bbt; + unsigned wp_gpio; + struct mtd_partition *parts; + unsigned num_parts; +}; + +struct lpc32xx_nand_host { + struct nand_chip nand_chip; + struct clk *clk; + struct mtd_info mtd; + void __iomem *io_base; + struct lpc32xx_nand_cfg_slc *ncfg; + + struct completion comp; + struct dma_chan *dma_chan; + uint32_t dma_buf_len; + struct dma_slave_config dma_slave_config; + struct scatterlist sgl; + + /* + * DMA and CPU addresses of ECC work area and data buffer + */ + uint32_t *ecc_buf; + uint8_t *data_buf; + dma_addr_t io_base_dma; +}; + +static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) +{ + uint32_t clkrate, tmp; + + /* Reset SLC controller */ + writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base)); + udelay(1000); + + /* Basic setup */ + writel(0, SLC_CFG(host->io_base)); + writel(0, SLC_IEN(host->io_base)); + writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN), + SLC_ICR(host->io_base)); + + /* Get base clock for SLC block */ + clkrate = clk_get_rate(host->clk); + if (clkrate == 0) + clkrate = LPC32XX_DEF_BUS_RATE; + + /* Compute clock setup values */ + tmp = SLCTAC_WDR(host->ncfg->wdr_clks) | + SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) | + SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) | + SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) | + SLCTAC_RDR(host->ncfg->rdr_clks) | + SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) | + SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) | + SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup)); + writel(tmp, SLC_TAC(host->io_base)); +} + +/* + * Hardware specific access to control lines + */ +static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + uint32_t tmp; + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + /* Does CE state need to be changed? */ + tmp = readl(SLC_CFG(host->io_base)); + if (ctrl & NAND_NCE) + tmp |= SLCCFG_CE_LOW; + else + tmp &= ~SLCCFG_CE_LOW; + writel(tmp, SLC_CFG(host->io_base)); + + if (cmd != NAND_CMD_NONE) { + if (ctrl & NAND_CLE) + writel(cmd, SLC_CMD(host->io_base)); + else + writel(cmd, SLC_ADDR(host->io_base)); + } +} + +/* + * Read the Device Ready pin + */ +static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + int rdy = 0; + + if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0) + rdy = 1; + + return rdy; +} + +/* + * Enable NAND write protect + */ +static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) +{ + gpio_set_value(host->ncfg->wp_gpio, 0); +} + +/* + * Disable NAND write protect + */ +static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) +{ + gpio_set_value(host->ncfg->wp_gpio, 1); +} + +/* + * Prepares SLC for transfers with H/W ECC enabled + */ +static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode) +{ + /* Hardware ECC is enabled automatically in hardware as needed */ +} + +/* + * Calculates the ECC for the data + */ +static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd, + const unsigned char *buf, + unsigned char *code) +{ + /* + * ECC is calculated automatically in hardware during syndrome read + * and write operations, so it doesn't need to be calculated here. + */ + return 0; +} + +/* + * Read a single byte from NAND device + */ +static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + return (uint8_t)readl(SLC_DATA(host->io_base)); +} + +/* + * Simple device read without ECC + */ +static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + /* Direct device read with no ECC */ + while (len-- > 0) + *buf++ = (uint8_t)readl(SLC_DATA(host->io_base)); +} + +/* + * Simple device write without ECC + */ +static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + /* Direct device write with no ECC */ + while (len-- > 0) + writel((uint32_t)*buf++, SLC_DATA(host->io_base)); +} + +/* + * Verify data in buffer to data on device + */ +static int lpc32xx_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + int i; + + /* DATA register must be read as 32 bits or it will fail */ + for (i = 0; i < len; i++) { + if (buf[i] != (uint8_t)readl(SLC_DATA(host->io_base))) + return -EFAULT; + } + + return 0; +} + +/* + * Read the OOB data from the device without ECC using FIFO method + */ +static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +/* + * Write the OOB data to the device without ECC using FIFO method + */ +static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int status; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/* + * Fills in the ECC fields in the OOB buffer with the hardware generated ECC + */ +static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count) +{ + int i; + + for (i = 0; i < (count * 3); i += 3) { + uint32_t ce = ecc[i / 3]; + ce = ~(ce << 2) & 0xFFFFFF; + spare[i + 2] = (uint8_t)(ce & 0xFF); + ce >>= 8; + spare[i + 1] = (uint8_t)(ce & 0xFF); + ce >>= 8; + spare[i] = (uint8_t)(ce & 0xFF); + } +} + +static void lpc32xx_dma_complete_func(void *completion) +{ + complete(completion); +} + +static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma, + void *mem, int len, enum dma_transfer_direction dir) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + struct dma_async_tx_descriptor *desc; + int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + int res; + + host->dma_slave_config.direction = dir; + host->dma_slave_config.src_addr = dma; + host->dma_slave_config.dst_addr = dma; + host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.src_maxburst = 4; + host->dma_slave_config.dst_maxburst = 4; + /* DMA controller does flow control: */ + host->dma_slave_config.device_fc = false; + if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) { + dev_err(mtd->dev.parent, "Failed to setup DMA slave\n"); + return -ENXIO; + } + + sg_init_one(&host->sgl, mem, len); + + res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + if (res != 1) { + dev_err(mtd->dev.parent, "Failed to map sg list\n"); + return -ENXIO; + } + desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir, + flags); + if (!desc) { + dev_err(mtd->dev.parent, "Failed to prepare slave sg\n"); + goto out1; + } + + init_completion(&host->comp); + desc->callback = lpc32xx_dma_complete_func; + desc->callback_param = &host->comp; + + dmaengine_submit(desc); + dma_async_issue_pending(host->dma_chan); + + wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000)); + + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + + return 0; +out1: + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + return -ENXIO; +} + +/* + * DMA read/write transfers with ECC support + */ +static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages, + int read) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + int i, status = 0; + unsigned long timeout; + int res; + enum dma_transfer_direction dir = + read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; + uint8_t *dma_buf; + bool dma_mapped; + + if ((void *)buf <= high_memory) { + dma_buf = buf; + dma_mapped = true; + } else { + dma_buf = host->data_buf; + dma_mapped = false; + if (!read) + memcpy(host->data_buf, buf, mtd->writesize); + } + + if (read) { + writel(readl(SLC_CFG(host->io_base)) | + SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC | + SLCCFG_DMA_BURST, SLC_CFG(host->io_base)); + } else { + writel((readl(SLC_CFG(host->io_base)) | + SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) & + ~SLCCFG_DMA_DIR, + SLC_CFG(host->io_base)); + } + + /* Clear initial ECC */ + writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base)); + + /* Transfer size is data area only */ + writel(mtd->writesize, SLC_TC(host->io_base)); + + /* Start transfer in the NAND controller */ + writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START, + SLC_CTRL(host->io_base)); + + for (i = 0; i < chip->ecc.steps; i++) { + /* Data */ + res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma), + dma_buf + i * chip->ecc.size, + mtd->writesize / chip->ecc.steps, dir); + if (res) + return res; + + /* Always _read_ ECC */ + if (i == chip->ecc.steps - 1) + break; + if (!read) /* ECC availability delayed on write */ + udelay(10); + res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma), + &host->ecc_buf[i], 4, DMA_DEV_TO_MEM); + if (res) + return res; + } + + /* + * According to NXP, the DMA can be finished here, but the NAND + * controller may still have buffered data. After porting to using the + * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty) + * appears to be always true, according to tests. Keeping the check for + * safety reasons for now. + */ + if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) { + dev_warn(mtd->dev.parent, "FIFO not empty!\n"); + timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT); + while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) && + time_before(jiffies, timeout)) + cpu_relax(); + if (!time_before(jiffies, timeout)) { + dev_err(mtd->dev.parent, "FIFO held data too long\n"); + status = -EIO; + } + } + + /* Read last calculated ECC value */ + if (!read) + udelay(10); + host->ecc_buf[chip->ecc.steps - 1] = + readl(SLC_ECC(host->io_base)); + + /* Flush DMA */ + dmaengine_terminate_all(host->dma_chan); + + if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO || + readl(SLC_TC(host->io_base))) { + /* Something is left in the FIFO, something is wrong */ + dev_err(mtd->dev.parent, "DMA FIFO failure\n"); + status = -EIO; + } + + /* Stop DMA & HW ECC */ + writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START, + SLC_CTRL(host->io_base)); + writel(readl(SLC_CFG(host->io_base)) & + ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC | + SLCCFG_DMA_BURST), SLC_CFG(host->io_base)); + + if (!dma_mapped && read) + memcpy(buf, host->data_buf, mtd->writesize); + + return status; +} + +/* + * Read the data and OOB data from the device, use ECC correction with the + * data, disable ECC for the OOB data + */ +static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct lpc32xx_nand_host *host = chip->priv; + int stat, i, status; + uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE]; + + /* Issue read command */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* Read data and oob, calculate ECC */ + status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1); + + /* Get OOB data */ + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Convert to stored ECC format */ + lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps); + + /* Pointer to ECC data retrieved from NAND spare area */ + oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0]; + + for (i = 0; i < chip->ecc.steps; i++) { + stat = chip->ecc.correct(mtd, buf, oobecc, + &tmpecc[i * chip->ecc.bytes]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + buf += chip->ecc.size; + oobecc += chip->ecc.bytes; + } + + return status; +} + +/* + * Read the data and OOB data from the device, no ECC correction with the + * data or OOB data + */ +static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, + int page) +{ + /* Issue read command */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* Raw reads can just use the FIFO interface */ + chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +/* + * Write the data and OOB data to the device, use ECC with the data, + * disable ECC for the OOB data + */ +static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + struct lpc32xx_nand_host *host = chip->priv; + uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0]; + int error; + + /* Write data, calculate ECC on outbound data */ + error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0); + if (error) + return error; + + /* + * The calculated ECC needs some manual work done to it before + * committing it to NAND. Process the calculated ECC and place + * the resultant values directly into the OOB buffer. */ + lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps); + + /* Write ECC data to device */ + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +/* + * Write the data and OOB data to the device, no ECC correction with the + * data or OOB data + */ +static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required) +{ + /* Raw writes can just use the FIFO interface */ + chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param) +{ + struct pl08x_dma_chan *ch = + container_of(chan, struct pl08x_dma_chan, chan); + + /* In LPC32xx's PL080 DMA wiring, the SLC NAND DMA signal is #1 */ + if (ch->cd->min_signal == 1) + return true; + return false; +} + +static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) +{ + struct mtd_info *mtd = &host->mtd; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL); + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } + + return 0; +} + +#ifdef CONFIG_OF +static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) +{ + struct lpc32xx_nand_cfg_slc *pdata; + struct device_node *np = dev->of_node; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return NULL; + } + + of_property_read_u32(np, "nxp,wdr-clks", &pdata->wdr_clks); + of_property_read_u32(np, "nxp,wwidth", &pdata->wwidth); + of_property_read_u32(np, "nxp,whold", &pdata->whold); + of_property_read_u32(np, "nxp,wsetup", &pdata->wsetup); + of_property_read_u32(np, "nxp,rdr-clks", &pdata->rdr_clks); + of_property_read_u32(np, "nxp,rwidth", &pdata->rwidth); + of_property_read_u32(np, "nxp,rhold", &pdata->rhold); + of_property_read_u32(np, "nxp,rsetup", &pdata->rsetup); + + if (!pdata->wdr_clks || !pdata->wwidth || !pdata->whold || + !pdata->wsetup || !pdata->rdr_clks || !pdata->rwidth || + !pdata->rhold || !pdata->rsetup) { + dev_err(dev, "chip parameters not specified correctly\n"); + return NULL; + } + + pdata->use_bbt = of_get_nand_on_flash_bbt(np); + pdata->wp_gpio = of_get_named_gpio_flags(np, "gpios", 0, NULL); + + return pdata; +} +#else +static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + +/* + * Probe for NAND controller + */ +static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *chip; + struct resource *rc; + struct mtd_part_parser_data ppdata = {}; + int res; + + rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (rc == NULL) { + dev_err(&pdev->dev, "No memory resource found for device\n"); + return -EBUSY; + } + + /* Allocate memory for the device structure (and zero it) */ + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) { + dev_err(&pdev->dev, "failed to allocate device structure\n"); + return -ENOMEM; + } + host->io_base_dma = rc->start; + + host->io_base = devm_request_and_ioremap(&pdev->dev, rc); + if (host->io_base == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + return -ENOMEM; + } + + if (pdev->dev.of_node) + host->ncfg = lpc32xx_parse_dt(&pdev->dev); + else + host->ncfg = pdev->dev.platform_data; + if (!host->ncfg) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENOENT; + } + if (gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + dev_err(&pdev->dev, "GPIO not available\n"); + return -EBUSY; + } + lpc32xx_wp_disable(host); + + mtd = &host->mtd; + chip = &host->nand_chip; + chip->priv = host; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; + + /* Get NAND clock */ + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "Clock failure\n"); + res = -ENOENT; + goto err_exit1; + } + clk_enable(host->clk); + + /* Set NAND IO addresses and command/ready functions */ + chip->IO_ADDR_R = SLC_DATA(host->io_base); + chip->IO_ADDR_W = SLC_DATA(host->io_base); + chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; + chip->dev_ready = lpc32xx_nand_device_ready; + chip->chip_delay = 20; /* 20us command delay time */ + + /* Init NAND controller */ + lpc32xx_nand_setup(host); + + platform_set_drvdata(pdev, host); + + /* NAND callbacks for LPC32xx SLC hardware */ + chip->ecc.mode = NAND_ECC_HW_SYNDROME; + chip->read_byte = lpc32xx_nand_read_byte; + chip->read_buf = lpc32xx_nand_read_buf; + chip->write_buf = lpc32xx_nand_write_buf; + chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome; + chip->ecc.read_page = lpc32xx_nand_read_page_syndrome; + chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome; + chip->ecc.write_page = lpc32xx_nand_write_page_syndrome; + chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome; + chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome; + chip->ecc.calculate = lpc32xx_nand_ecc_calculate; + chip->ecc.correct = nand_correct_data; + chip->ecc.strength = 1; + chip->ecc.hwctl = lpc32xx_nand_ecc_enable; + chip->verify_buf = lpc32xx_verify_buf; + + /* bitflip_threshold's default is defined as ecc_strength anyway. + * Unfortunately, it is set only later at add_mtd_device(). Meanwhile + * being 0, it causes bad block table scanning errors in + * nand_scan_tail(), so preparing it here already. */ + mtd->bitflip_threshold = chip->ecc.strength; + + /* + * Allocate a large enough buffer for a single huge page plus + * extra space for the spare area and ECC storage area + */ + host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE; + host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len, + GFP_KERNEL); + if (host->data_buf == NULL) { + dev_err(&pdev->dev, "Error allocating memory\n"); + res = -ENOMEM; + goto err_exit2; + } + + res = lpc32xx_nand_dma_setup(host); + if (res) { + res = -EIO; + goto err_exit2; + } + + /* Find NAND device */ + if (nand_scan_ident(mtd, 1, NULL)) { + res = -ENXIO; + goto err_exit3; + } + + /* OOB and ECC CPU and DMA work areas */ + host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE); + + /* + * Small page FLASH has a unique OOB layout, but large and huge + * page FLASH use the standard layout. Small page FLASH uses a + * custom BBT marker layout. + */ + if (mtd->writesize <= 512) + chip->ecc.layout = &lpc32xx_nand_oob_16; + + /* These sizes remain the same regardless of page size */ + chip->ecc.size = 256; + chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES; + chip->ecc.prepad = chip->ecc.postpad = 0; + + /* Avoid extra scan if using BBT, setup BBT support */ + if (host->ncfg->use_bbt) { + chip->options |= NAND_SKIP_BBTSCAN; + chip->bbt_options |= NAND_BBT_USE_FLASH; + + /* + * Use a custom BBT marker setup for small page FLASH that + * won't interfere with the ECC layout. Large and huge page + * FLASH use the standard layout. + */ + if (mtd->writesize <= 512) { + chip->bbt_td = &bbt_smallpage_main_descr; + chip->bbt_md = &bbt_smallpage_mirror_descr; + } + } + + /* + * Fills out all the uninitialized function pointers with the defaults + */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto err_exit3; + } + + /* Standard layout in FLASH for bad block tables */ + if (host->ncfg->use_bbt) { + if (nand_default_bbt(mtd) < 0) + dev_err(&pdev->dev, + "Error initializing default bad block tables\n"); + } + + mtd->name = "nxp_lpc3220_slc"; + ppdata.of_node = pdev->dev.of_node; + res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts, + host->ncfg->num_parts); + if (!res) + return res; + + nand_release(mtd); + +err_exit3: + dma_release_channel(host->dma_chan); +err_exit2: + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); +err_exit1: + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return res; +} + +/* + * Remove NAND device. + */ +static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +{ + uint32_t tmp; + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + dma_release_channel(host->dma_chan); + + /* Force CE high */ + tmp = readl(SLC_CTRL(host->io_base)); + tmp &= ~SLCCFG_CE_LOW; + writel(tmp, SLC_CTRL(host->io_base)); + + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_nand_resume(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Re-enable NAND clock */ + clk_enable(host->clk); + + /* Fresh init of NAND controller */ + lpc32xx_nand_setup(host); + + /* Disable write protect */ + lpc32xx_wp_disable(host); + + return 0; +} + +static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) +{ + uint32_t tmp; + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Force CE high */ + tmp = readl(SLC_CTRL(host->io_base)); + tmp &= ~SLCCFG_CE_LOW; + writel(tmp, SLC_CTRL(host->io_base)); + + /* Enable write protect for safety */ + lpc32xx_wp_enable(host); + + /* Disable clock */ + clk_disable(host->clk); + + return 0; +} + +#else +#define lpc32xx_nand_resume NULL +#define lpc32xx_nand_suspend NULL +#endif + +#if defined(CONFIG_OF) +static const struct of_device_id lpc32xx_nand_match[] = { + { .compatible = "nxp,lpc3220-slc" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); +#endif + +static struct platform_driver lpc32xx_nand_driver = { + .probe = lpc32xx_nand_probe, + .remove = __devexit_p(lpc32xx_nand_remove), + .resume = lpc32xx_nand_resume, + .suspend = lpc32xx_nand_suspend, + .driver = { + .name = LPC32XX_MODNAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_nand_match), + }, +}; + +module_platform_driver(lpc32xx_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller"); -- cgit v1.2.3-70-g09d2 From a41b51a1f7c15a1b00f30a3ad2d0373ad51b883d Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 29 Jun 2012 17:47:54 +0800 Subject: mtd: at91: add dt parameters for Atmel PMECC Add DT support for PMECC parameters. Signed-off-by: Hong Xu Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/atmel-nand.txt | 40 ++++++++++++++++- drivers/mtd/nand/atmel_nand.c | 52 +++++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index a20069502f5..d555421ea49 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -3,7 +3,9 @@ Atmel NAND flash Required properties: - compatible : "atmel,at91rm9200-nand". - reg : should specify localbus address and size used for the chip, - and if availlable the ECC. + and hardware ECC controller if available. + If the hardware ECC is PMECC, it should contain address and size for + PMECC, PMECC Error Location controller and ROM which has lookup tables. - atmel,nand-addr-offset : offset for the address latch. - atmel,nand-cmd-offset : offset for the command latch. - #address-cells, #size-cells : Must be present if the device has sub-nodes @@ -16,6 +18,15 @@ Optional properties: - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", "soft_bch". +- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware. + Only supported by at91sam9x5 or later sam9 product. +- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC + Controller. Supported values are: 2, 4, 8, 12, 24. +- atmel,pmecc-sector-size : sector size for ECC computation. Supported values + are: 512, 1024. +- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM + for different sector size. First one is for sector size 512, the next is for + sector size 1024. - nand-bus-width : 8 or 16 bus width if not present 8 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false @@ -39,3 +50,30 @@ nand0: nand@40000000,0 { ... }; }; + +/* for PMECC supported chips */ +nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = < 0x40000000 0x10000000 /* bus addr & size */ + 0xffffe000 0x00000600 /* PMECC addr & size */ + 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */ + 0x00100000 0x00100000 /* ROM addr & size */ + >; + atmel,nand-addr-offset = <21>; /* ale */ + atmel,nand-cmd-offset = <22>; /* cle */ + nand-on-flash-bbt; + nand-ecc-mode = "hw"; + atmel,has-pmecc; /* enable PMECC */ + atmel,pmecc-cap = <2>; + atmel,pmecc-sector-size = <512>; + atmel,pmecc-lookup-table-offset = <0x8000 0x10000>; + gpios = <&pioD 5 0 /* rdy */ + &pioD 4 0 /* nce */ + 0 /* cd */ + >; + partition@0 { + ... + }; +}; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 7a41a04beb8..b97ad9f78d3 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -93,6 +93,11 @@ struct atmel_nand_host { struct completion comp; struct dma_chan *dma_chan; + + bool has_pmecc; + u8 pmecc_corr_cap; + u16 pmecc_sector_size; + u32 pmecc_lookup_table_offset; }; static int cpu_has_dma(void) @@ -481,7 +486,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) static int __devinit atmel_of_init_port(struct atmel_nand_host *host, struct device_node *np) { - u32 val; + u32 val, table_offset; + u32 offset[2]; int ecc_mode; struct atmel_nand_data *board = &host->board; enum of_gpio_flags flags; @@ -517,6 +523,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host, board->enable_pin = of_get_gpio(np, 1); board->det_pin = of_get_gpio(np, 2); + host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc"); + + if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc) + return 0; /* Not using PMECC */ + + /* use PMECC, get correction capability, sector size and lookup + * table offset. + */ + if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) { + dev_err(host->dev, "Cannot decide PMECC Capability\n"); + return -EINVAL; + } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) && + (val != 24)) { + dev_err(host->dev, + "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n", + val); + return -EINVAL; + } + host->pmecc_corr_cap = (u8)val; + + if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) { + dev_err(host->dev, "Cannot decide PMECC Sector Size\n"); + return -EINVAL; + } else if ((val != 512) && (val != 1024)) { + dev_err(host->dev, + "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n", + val); + return -EINVAL; + } + host->pmecc_sector_size = (u16)val; + + if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", + offset, 2) != 0) { + dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); + return -EINVAL; + } + table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1]; + + if (!table_offset) { + dev_err(host->dev, "Invalid PMECC lookup table offset\n"); + return -EINVAL; + } + host->pmecc_lookup_table_offset = table_offset; + return 0; } #else -- cgit v1.2.3-70-g09d2 From 70f7cb78ec534301d13af1786b86f13fd96147eb Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sat, 30 Jun 2012 18:50:38 +0200 Subject: mtd: add LPC32xx MLC NAND driver This patch adds a driver for the MLC NAND controller of the LPC32xx SoC. [dwmw2: 21st century pedantry] Signed-off-by: Roland Stigge Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/lpc32xx-mlc.txt | 50 ++ drivers/mtd/nand/Kconfig | 11 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/lpc32xx_mlc.c | 936 +++++++++++++++++++++ 4 files changed, 998 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt create mode 100644 drivers/mtd/nand/lpc32xx_mlc.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt new file mode 100644 index 00000000000..d0a37252eb2 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt @@ -0,0 +1,50 @@ +NXP LPC32xx SoC NAND MLC controller + +Required properties: +- compatible: "nxp,lpc3220-mlc" +- reg: Address and size of the controller +- interrupts: The NAND interrupt specification +- gpios: GPIO specification for NAND write protect + +The following required properties are very controller specific. See the LPC32xx +User Manual 7.5.14 MLC NAND Timing Register (the values here are specified in +Hz, to make them independent of actual clock speed and to provide for good +accuracy:) +- nxp,tcea_delay: TCEA_DELAY +- nxp,busy_delay: BUSY_DELAY +- nxp,nand_ta: NAND_TA +- nxp,rd_high: RD_HIGH +- nxp,rd_low: RD_LOW +- nxp,wr_high: WR_HIGH +- nxp,wr_low: WR_LOW + +Optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + + mlc: flash@200A8000 { + compatible = "nxp,lpc3220-mlc"; + reg = <0x200A8000 0x11000>; + interrupts = <11 0>; + #address-cells = <1>; + #size-cells = <1>; + + nxp,tcea-delay = <333333333>; + nxp,busy-delay = <10000000>; + nxp,nand-ta = <18181818>; + nxp,rd-high = <31250000>; + nxp,rd-low = <45454545>; + nxp,wr-high = <40000000>; + nxp,wr-low = <83333333>; + gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */ + + mtd0@00000000 { + label = "boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + ... + + }; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index de6997832da..adee4681f98 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -425,6 +425,17 @@ config MTD_NAND_SLC_LPC32XX Please check the actual NAND chip connected and its support by the SLC NAND controller. +config MTD_NAND_MLC_LPC32XX + tristate "NXP LPC32xx MLC Controller" + depends on ARCH_LPC32XX + help + Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND + controller. This is the default for the WORK92105 controller + board. + + Please check the actual NAND chip connected and its support + by the MLC NAND controller. + config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MACH_ARMCORE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d29a893608e..ddee81811b4 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o +obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c new file mode 100644 index 00000000000..260b2c24249 --- /dev/null +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -0,0 +1,936 @@ +/* + * Driver for NAND MLC Controller in LPC32xx + * + * Author: Roland Stigge + * + * Copyright © 2011 WORK Microwave GmbH + * Copyright © 2011, 2012 Roland Stigge + * + * 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. + * + * + * NAND Flash Controller Operation: + * - Read: Auto Decode + * - Write: Auto Encode + * - Tested Page Sizes: 2048, 4096 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "lpc32xx_mlc" + +/********************************************************************** +* MLC NAND controller register offsets +**********************************************************************/ + +#define MLC_BUFF(x) (x + 0x00000) +#define MLC_DATA(x) (x + 0x08000) +#define MLC_CMD(x) (x + 0x10000) +#define MLC_ADDR(x) (x + 0x10004) +#define MLC_ECC_ENC_REG(x) (x + 0x10008) +#define MLC_ECC_DEC_REG(x) (x + 0x1000C) +#define MLC_ECC_AUTO_ENC_REG(x) (x + 0x10010) +#define MLC_ECC_AUTO_DEC_REG(x) (x + 0x10014) +#define MLC_RPR(x) (x + 0x10018) +#define MLC_WPR(x) (x + 0x1001C) +#define MLC_RUBP(x) (x + 0x10020) +#define MLC_ROBP(x) (x + 0x10024) +#define MLC_SW_WP_ADD_LOW(x) (x + 0x10028) +#define MLC_SW_WP_ADD_HIG(x) (x + 0x1002C) +#define MLC_ICR(x) (x + 0x10030) +#define MLC_TIME_REG(x) (x + 0x10034) +#define MLC_IRQ_MR(x) (x + 0x10038) +#define MLC_IRQ_SR(x) (x + 0x1003C) +#define MLC_LOCK_PR(x) (x + 0x10044) +#define MLC_ISR(x) (x + 0x10048) +#define MLC_CEH(x) (x + 0x1004C) + +/********************************************************************** +* MLC_CMD bit definitions +**********************************************************************/ +#define MLCCMD_RESET 0xFF + +/********************************************************************** +* MLC_ICR bit definitions +**********************************************************************/ +#define MLCICR_WPROT (1 << 3) +#define MLCICR_LARGEBLOCK (1 << 2) +#define MLCICR_LONGADDR (1 << 1) +#define MLCICR_16BIT (1 << 0) /* unsupported by LPC32x0! */ + +/********************************************************************** +* MLC_TIME_REG bit definitions +**********************************************************************/ +#define MLCTIMEREG_TCEA_DELAY(n) (((n) & 0x03) << 24) +#define MLCTIMEREG_BUSY_DELAY(n) (((n) & 0x1F) << 19) +#define MLCTIMEREG_NAND_TA(n) (((n) & 0x07) << 16) +#define MLCTIMEREG_RD_HIGH(n) (((n) & 0x0F) << 12) +#define MLCTIMEREG_RD_LOW(n) (((n) & 0x0F) << 8) +#define MLCTIMEREG_WR_HIGH(n) (((n) & 0x0F) << 4) +#define MLCTIMEREG_WR_LOW(n) (((n) & 0x0F) << 0) + +/********************************************************************** +* MLC_IRQ_MR and MLC_IRQ_SR bit definitions +**********************************************************************/ +#define MLCIRQ_NAND_READY (1 << 5) +#define MLCIRQ_CONTROLLER_READY (1 << 4) +#define MLCIRQ_DECODE_FAILURE (1 << 3) +#define MLCIRQ_DECODE_ERROR (1 << 2) +#define MLCIRQ_ECC_READY (1 << 1) +#define MLCIRQ_WRPROT_FAULT (1 << 0) + +/********************************************************************** +* MLC_LOCK_PR bit definitions +**********************************************************************/ +#define MLCLOCKPR_MAGIC 0xA25E + +/********************************************************************** +* MLC_ISR bit definitions +**********************************************************************/ +#define MLCISR_DECODER_FAILURE (1 << 6) +#define MLCISR_ERRORS ((1 << 4) | (1 << 5)) +#define MLCISR_ERRORS_DETECTED (1 << 3) +#define MLCISR_ECC_READY (1 << 2) +#define MLCISR_CONTROLLER_READY (1 << 1) +#define MLCISR_NAND_READY (1 << 0) + +/********************************************************************** +* MLC_CEH bit definitions +**********************************************************************/ +#define MLCCEH_NORMAL (1 << 0) + +struct lpc32xx_nand_cfg_mlc { + uint32_t tcea_delay; + uint32_t busy_delay; + uint32_t nand_ta; + uint32_t rd_high; + uint32_t rd_low; + uint32_t wr_high; + uint32_t wr_low; + int wp_gpio; + struct mtd_partition *parts; + unsigned num_parts; +}; + +static struct nand_ecclayout lpc32xx_nand_oob = { + .eccbytes = 40, + .eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, + .oobfree = { + { .offset = 0, + .length = 6, }, + { .offset = 16, + .length = 6, }, + { .offset = 32, + .length = 6, }, + { .offset = 48, + .length = 6, }, + }, +}; + +static struct nand_bbt_descr lpc32xx_nand_bbt = { + .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB | + NAND_BBT_WRITE, + .pages = { 524224, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = { + .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB | + NAND_BBT_WRITE, + .pages = { 524160, 0, 0, 0, 0, 0, 0, 0 }, +}; + +struct lpc32xx_nand_host { + struct nand_chip nand_chip; + struct clk *clk; + struct mtd_info mtd; + void __iomem *io_base; + int irq; + struct lpc32xx_nand_cfg_mlc *ncfg; + struct completion comp_nand; + struct completion comp_controller; + uint32_t llptr; + /* + * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer + */ + dma_addr_t oob_buf_phy; + /* + * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer + */ + uint8_t *oob_buf; + /* Physical address of DMA base address */ + dma_addr_t io_base_phy; + + struct completion comp_dma; + struct dma_chan *dma_chan; + struct dma_slave_config dma_slave_config; + struct scatterlist sgl; + uint8_t *dma_buf; + uint8_t *dummy_buf; + int mlcsubpages; /* number of 512bytes-subpages */ +}; + +/* + * Activate/Deactivate DMA Operation: + * + * Using the PL080 DMA Controller for transferring the 512 byte subpages + * instead of doing readl() / writel() in a loop slows it down significantly. + * Measurements via getnstimeofday() upon 512 byte subpage reads reveal: + * + * - readl() of 128 x 32 bits in a loop: ~20us + * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us + * - DMA read of 512 bytes (32 bit, no bursts): ~100us + * + * This applies to the transfer itself. In the DMA case: only the + * wait_for_completion() (DMA setup _not_ included). + * + * Note that the 512 bytes subpage transfer is done directly from/to a + * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a + * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND + * controller transferring data between its internal buffer to/from the NAND + * chip.) + * + * Therefore, using the PL080 DMA is disabled by default, for now. + * + */ +static int use_dma; + +static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) +{ + uint32_t clkrate, tmp; + + /* Reset MLC controller */ + writel(MLCCMD_RESET, MLC_CMD(host->io_base)); + udelay(1000); + + /* Get base clock for MLC block */ + clkrate = clk_get_rate(host->clk); + if (clkrate == 0) + clkrate = 104000000; + + /* Unlock MLC_ICR + * (among others, will be locked again automatically) */ + writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base)); + + /* Configure MLC Controller: Large Block, 5 Byte Address */ + tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR; + writel(tmp, MLC_ICR(host->io_base)); + + /* Unlock MLC_TIME_REG + * (among others, will be locked again automatically) */ + writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base)); + + /* Compute clock setup values, see LPC and NAND manual */ + tmp = 0; + tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1); + tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1); + tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1); + tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1); + tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low); + tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1); + tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low); + writel(tmp, MLC_TIME_REG(host->io_base)); + + /* Enable IRQ for CONTROLLER_READY and NAND_READY */ + writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY, + MLC_IRQ_MR(host->io_base)); + + /* Normal nCE operation: nCE controlled by controller */ + writel(MLCCEH_NORMAL, MLC_CEH(host->io_base)); +} + +/* + * Hardware specific access to control lines + */ +static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + + if (cmd != NAND_CMD_NONE) { + if (ctrl & NAND_CLE) + writel(cmd, MLC_CMD(host->io_base)); + else + writel(cmd, MLC_ADDR(host->io_base)); + } +} + +/* + * Read Device Ready (NAND device _and_ controller ready) + */ +static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + + if ((readb(MLC_ISR(host->io_base)) & + (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) == + (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) + return 1; + + return 0; +} + +static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host) +{ + uint8_t sr; + + /* Clear interrupt flag by reading status */ + sr = readb(MLC_IRQ_SR(host->io_base)); + if (sr & MLCIRQ_NAND_READY) + complete(&host->comp_nand); + if (sr & MLCIRQ_CONTROLLER_READY) + complete(&host->comp_controller); + + return IRQ_HANDLED; +} + +static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct lpc32xx_nand_host *host = chip->priv; + + if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY) + goto exit; + + wait_for_completion(&host->comp_nand); + + while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) { + /* Seems to be delayed sometimes by controller */ + dev_dbg(&mtd->dev, "Warning: NAND not ready.\n"); + cpu_relax(); + } + +exit: + return NAND_STATUS_READY; +} + +static int lpc32xx_waitfunc_controller(struct mtd_info *mtd, + struct nand_chip *chip) +{ + struct lpc32xx_nand_host *host = chip->priv; + + if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY) + goto exit; + + wait_for_completion(&host->comp_controller); + + while (!(readb(MLC_ISR(host->io_base)) & + MLCISR_CONTROLLER_READY)) { + dev_dbg(&mtd->dev, "Warning: Controller not ready.\n"); + cpu_relax(); + } + +exit: + return NAND_STATUS_READY; +} + +static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +{ + lpc32xx_waitfunc_nand(mtd, chip); + lpc32xx_waitfunc_controller(mtd, chip); + + return NAND_STATUS_READY; +} + +/* + * Enable NAND write protect + */ +static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) +{ + if (gpio_is_valid(host->ncfg->wp_gpio)) + gpio_set_value(host->ncfg->wp_gpio, 0); +} + +/* + * Disable NAND write protect + */ +static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) +{ + if (gpio_is_valid(host->ncfg->wp_gpio)) + gpio_set_value(host->ncfg->wp_gpio, 1); +} + +static void lpc32xx_dma_complete_func(void *completion) +{ + complete(completion); +} + +static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len, + enum dma_transfer_direction dir) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + struct dma_async_tx_descriptor *desc; + int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + int res; + + sg_init_one(&host->sgl, mem, len); + + res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + if (res != 1) { + dev_err(mtd->dev.parent, "Failed to map sg list\n"); + return -ENXIO; + } + desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir, + flags); + if (!desc) { + dev_err(mtd->dev.parent, "Failed to prepare slave sg\n"); + goto out1; + } + + init_completion(&host->comp_dma); + desc->callback = lpc32xx_dma_complete_func; + desc->callback_param = &host->comp_dma; + + dmaengine_submit(desc); + dma_async_issue_pending(host->dma_chan); + + wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000)); + + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + return 0; +out1: + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + return -ENXIO; +} + +static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct lpc32xx_nand_host *host = chip->priv; + int i, j; + uint8_t *oobbuf = chip->oob_poi; + uint32_t mlc_isr; + int res; + uint8_t *dma_buf; + bool dma_mapped; + + if ((void *)buf <= high_memory) { + dma_buf = buf; + dma_mapped = true; + } else { + dma_buf = host->dma_buf; + dma_mapped = false; + } + + /* Writing Command and Address */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* For all sub-pages */ + for (i = 0; i < host->mlcsubpages; i++) { + /* Start Auto Decode Command */ + writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base)); + + /* Wait for Controller Ready */ + lpc32xx_waitfunc_controller(mtd, chip); + + /* Check ECC Error status */ + mlc_isr = readl(MLC_ISR(host->io_base)); + if (mlc_isr & MLCISR_DECODER_FAILURE) { + mtd->ecc_stats.failed++; + dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__); + } else if (mlc_isr & MLCISR_ERRORS_DETECTED) { + mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1; + } + + /* Read 512 + 16 Bytes */ + if (use_dma) { + res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512, + DMA_DEV_TO_MEM); + if (res) + return res; + } else { + for (j = 0; j < (512 >> 2); j++) { + *((uint32_t *)(buf)) = + readl(MLC_BUFF(host->io_base)); + buf += 4; + } + } + for (j = 0; j < (16 >> 2); j++) { + *((uint32_t *)(oobbuf)) = + readl(MLC_BUFF(host->io_base)); + oobbuf += 4; + } + } + + if (use_dma && !dma_mapped) + memcpy(buf, dma_buf, mtd->writesize); + + return 0; +} + +static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + struct lpc32xx_nand_host *host = chip->priv; + const uint8_t *oobbuf = chip->oob_poi; + uint8_t *dma_buf = (uint8_t *)buf; + int res; + int i, j; + + if (use_dma && (void *)buf >= high_memory) { + dma_buf = host->dma_buf; + memcpy(dma_buf, buf, mtd->writesize); + } + + for (i = 0; i < host->mlcsubpages; i++) { + /* Start Encode */ + writeb(0x00, MLC_ECC_ENC_REG(host->io_base)); + + /* Write 512 + 6 Bytes to Buffer */ + if (use_dma) { + res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512, + DMA_MEM_TO_DEV); + if (res) + return res; + } else { + for (j = 0; j < (512 >> 2); j++) { + writel(*((uint32_t *)(buf)), + MLC_BUFF(host->io_base)); + buf += 4; + } + } + writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base)); + oobbuf += 4; + writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base)); + oobbuf += 12; + + /* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */ + writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base)); + + /* Wait for Controller Ready */ + lpc32xx_waitfunc_controller(mtd, chip); + } + return 0; +} + +static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page, + int cached, int raw) +{ + int res; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + lpc32xx_waitfunc(mtd, chip); + + return res; +} + +static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct lpc32xx_nand_host *host = chip->priv; + + /* Read whole page - necessary with MLC controller! */ + lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page); + + return 0; +} + +static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */ + return 0; +} + +/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */ +static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode) +{ + /* Always enabled! */ +} + +static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param) +{ + struct pl08x_dma_chan *ch = + container_of(chan, struct pl08x_dma_chan, chan); + + /* In LPC32xx's PL080 DMA wiring, the MLC NAND DMA signal is #12 */ + if (ch->cd->min_signal == 12) + return true; + return false; +} + +static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host) +{ + struct mtd_info *mtd = &host->mtd; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL); + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } + + /* + * Set direction to a sensible value even if the dmaengine driver + * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x + * driver criticizes it as "alien transfer direction". + */ + host->dma_slave_config.direction = DMA_DEV_TO_MEM; + host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.src_maxburst = 128; + host->dma_slave_config.dst_maxburst = 128; + /* DMA controller does flow control: */ + host->dma_slave_config.device_fc = false; + host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy); + host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy); + if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) { + dev_err(mtd->dev.parent, "Failed to setup DMA slave\n"); + goto out1; + } + + return 0; +out1: + dma_release_channel(host->dma_chan); + return -ENXIO; +} + +#ifdef CONFIG_OF +static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) +{ + struct lpc32xx_nand_cfg_mlc *pdata; + struct device_node *np = dev->of_node; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return NULL; + } + + of_property_read_u32(np, "nxp,tcea-delay", &pdata->tcea_delay); + of_property_read_u32(np, "nxp,busy-delay", &pdata->busy_delay); + of_property_read_u32(np, "nxp,nand-ta", &pdata->nand_ta); + of_property_read_u32(np, "nxp,rd-high", &pdata->rd_high); + of_property_read_u32(np, "nxp,rd-low", &pdata->rd_low); + of_property_read_u32(np, "nxp,wr-high", &pdata->wr_high); + of_property_read_u32(np, "nxp,wr-low", &pdata->wr_low); + + if (!pdata->tcea_delay || !pdata->busy_delay || !pdata->nand_ta || + !pdata->rd_high || !pdata->rd_low || !pdata->wr_high || + !pdata->wr_low) { + dev_err(dev, "chip parameters not specified correctly\n"); + return NULL; + } + + pdata->wp_gpio = of_get_named_gpio(np, "gpios", 0); + + return pdata; +} +#else +static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + +/* + * Probe for NAND controller + */ +static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + struct resource *rc; + int res; + struct mtd_part_parser_data ppdata = {}; + + /* Allocate memory for the device structure (and zero it) */ + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) { + dev_err(&pdev->dev, "failed to allocate device structure.\n"); + return -ENOMEM; + } + + rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (rc == NULL) { + dev_err(&pdev->dev, "No memory resource found for device!\r\n"); + return -ENXIO; + } + + host->io_base = devm_request_and_ioremap(&pdev->dev, rc); + if (host->io_base == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + return -EIO; + } + host->io_base_phy = rc->start; + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + if (pdev->dev.of_node) + host->ncfg = lpc32xx_parse_dt(&pdev->dev); + else + host->ncfg = pdev->dev.platform_data; + if (!host->ncfg) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENOENT; + } + if (host->ncfg->wp_gpio == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(host->ncfg->wp_gpio) && + gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + dev_err(&pdev->dev, "GPIO not available\n"); + return -EBUSY; + } + lpc32xx_wp_disable(host); + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; + + /* Get NAND clock */ + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "Clock initialization failure\n"); + res = -ENOENT; + goto err_exit1; + } + clk_enable(host->clk); + + nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; + nand_chip->dev_ready = lpc32xx_nand_device_ready; + nand_chip->chip_delay = 25; /* us */ + nand_chip->IO_ADDR_R = MLC_DATA(host->io_base); + nand_chip->IO_ADDR_W = MLC_DATA(host->io_base); + + /* Init NAND controller */ + lpc32xx_nand_setup(host); + + platform_set_drvdata(pdev, host); + + /* Initialize function pointers */ + nand_chip->ecc.hwctl = lpc32xx_ecc_enable; + nand_chip->ecc.read_page_raw = lpc32xx_read_page; + nand_chip->ecc.read_page = lpc32xx_read_page; + nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel; + nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel; + nand_chip->ecc.write_oob = lpc32xx_write_oob; + nand_chip->ecc.read_oob = lpc32xx_read_oob; + nand_chip->ecc.strength = 4; + nand_chip->write_page = lpc32xx_write_page; + nand_chip->waitfunc = lpc32xx_waitfunc; + + nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + nand_chip->bbt_td = &lpc32xx_nand_bbt; + nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror; + + /* bitflip_threshold's default is defined as ecc_strength anyway. + * Unfortunately, it is set only later at add_mtd_device(). Meanwhile + * being 0, it causes bad block table scanning errors in + * nand_scan_tail(), so preparing it here. */ + mtd->bitflip_threshold = nand_chip->ecc.strength; + + if (use_dma) { + res = lpc32xx_dma_setup(host); + if (res) { + res = -EIO; + goto err_exit2; + } + } + + /* + * Scan to find existance of the device and + * Get the type of NAND device SMALL block or LARGE block + */ + if (nand_scan_ident(mtd, 1, NULL)) { + res = -ENXIO; + goto err_exit3; + } + + host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); + if (!host->dma_buf) { + dev_err(&pdev->dev, "Error allocating dma_buf memory\n"); + res = -ENOMEM; + goto err_exit3; + } + + host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); + if (!host->dummy_buf) { + dev_err(&pdev->dev, "Error allocating dummy_buf memory\n"); + res = -ENOMEM; + goto err_exit3; + } + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.size = mtd->writesize; + nand_chip->ecc.layout = &lpc32xx_nand_oob; + host->mlcsubpages = mtd->writesize / 512; + + /* initially clear interrupt status */ + readb(MLC_IRQ_SR(host->io_base)); + + init_completion(&host->comp_nand); + init_completion(&host->comp_controller); + + host->irq = platform_get_irq(pdev, 0); + if ((host->irq < 0) || (host->irq >= NR_IRQS)) { + dev_err(&pdev->dev, "failed to get platform irq\n"); + res = -EINVAL; + goto err_exit3; + } + + if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq, + IRQF_TRIGGER_HIGH, DRV_NAME, host)) { + dev_err(&pdev->dev, "Error requesting NAND IRQ\n"); + res = -ENXIO; + goto err_exit3; + } + + /* + * Fills out all the uninitialized function pointers with the defaults + * And scans for a bad block table if appropriate. + */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto err_exit4; + } + + mtd->name = DRV_NAME; + + ppdata.of_node = pdev->dev.of_node; + res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts, + host->ncfg->num_parts); + if (!res) + return res; + + nand_release(mtd); + +err_exit4: + free_irq(host->irq, host); +err_exit3: + if (use_dma) + dma_release_channel(host->dma_chan); +err_exit2: + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); +err_exit1: + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return res; +} + +/* + * Remove NAND device + */ +static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + free_irq(host->irq, host); + if (use_dma) + dma_release_channel(host->dma_chan); + + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); + + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_nand_resume(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Re-enable NAND clock */ + clk_enable(host->clk); + + /* Fresh init of NAND controller */ + lpc32xx_nand_setup(host); + + /* Disable write protect */ + lpc32xx_wp_disable(host); + + return 0; +} + +static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Enable write protect for safety */ + lpc32xx_wp_enable(host); + + /* Disable clock */ + clk_disable(host->clk); + return 0; +} + +#else +#define lpc32xx_nand_resume NULL +#define lpc32xx_nand_suspend NULL +#endif + +#if defined(CONFIG_OF) +static const struct of_device_id lpc32xx_nand_match[] = { + { .compatible = "nxp,lpc3220-mlc" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); +#endif + +static struct platform_driver lpc32xx_nand_driver = { + .probe = lpc32xx_nand_probe, + .remove = __devexit_p(lpc32xx_nand_remove), + .resume = lpc32xx_nand_resume, + .suspend = lpc32xx_nand_suspend, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_nand_match), + }, +}; + +module_platform_driver(lpc32xx_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller"); -- cgit v1.2.3-70-g09d2 From c50c69402ac24641da38c146796c199387b97f8d Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Tue, 3 Jul 2012 16:24:32 +0800 Subject: mtd: gpmi: add on-flash BBT support for gpmi nand add the on flash bbt support for gpmi nand driver. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- Documentation/devicetree/bindings/mtd/gpmi-nand.txt | 4 ++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 3 +++ 2 files changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt index 1a5bbd346d2..3fb3f901536 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt @@ -12,6 +12,10 @@ Required properties: - interrupt-names : The interrupt names "gpmi-dma", "bch"; - fsl,gpmi-dma-channel : Should contain the dma channel it uses. +Optional properties: + - nand-on-flash-bbt: boolean to enable on flash bbt option if not + present false + The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d6fa8f4779c..5d9796acc49 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "gpmi-nand.h" /* add our owner bbt descriptor */ @@ -1502,6 +1503,8 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) chip->ecc.size = 1; chip->ecc.strength = 8; chip->ecc.layout = &gpmi_hw_ecclayout; + if (of_get_nand_on_flash_bbt(this->dev->of_node)) + chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ this->bch_geometry.payload_size = 1024; -- cgit v1.2.3-70-g09d2 From fde8be29239bf4a4118d918df1b2b8ef7266b1a2 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 17 Jul 2012 17:08:31 +0100 Subject: tty: of_serial: add no-loopback-test property The loopback test mode is not implemented in all NS16550 compatible UARTs. The 8250 driver uses the UPF_SKIP_TEST flag to indicate this, however it is not possible to set this flag via device-tree. Add a new 'no-loopback-test' property, and modify the of_serial driver to set the UPF_SKIP_TEST flag if the property is present. Signed-off-by: Gabor Juhos Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/tty/serial/of-serial.txt | 2 ++ drivers/tty/serial/of_serial.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt index 0847fdeee11..ba385f2e0dd 100644 --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -25,6 +25,8 @@ Optional properties: accesses to the UART (e.g. TI davinci). - used-by-rtas : set to indicate that the port is in use by the OpenFirmware RTAS and should not be registered. +- no-loopback-test: set to indicate that the port does not implements loopback + test mode Example: diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index ffc7879e85a..df443b908ca 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -105,6 +105,10 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, port->uartclk = clk; port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; + + if (of_find_property(np, "no-loopback-test", NULL)) + port->flags |= UPF_SKIP_TEST; + port->dev = &ofdev->dev; if (type == PORT_TEGRA) -- cgit v1.2.3-70-g09d2 From c2794437091a4fda72c4a4f3567dd728dcc0c3c9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Feb 2012 18:10:58 -0600 Subject: ARM: Add fixed PCI i/o mapping This adds a fixed virtual mapping for PCI i/o addresses. The mapping is located at the last 2MB of vmalloc region (0xfee00000-0xff000000). 2MB is used to align with PMD size, but IO_SPACE_LIMIT is 1MB. The space is reserved after .map_io and can be mapped at any time later with pci_ioremap_io. Platforms which need early i/o mapping (e.g. for vga console) can call pci_map_io_early in their .map_io function. This has changed completely from the 1st implementation which only supported creating the static mapping at .map_io. Signed-off-by: Rob Herring Cc: Russell King Acked-by: Nicolas Pitre --- Documentation/arm/memory.txt | 3 +++ arch/arm/include/asm/io.h | 8 ++++++ arch/arm/include/asm/mach/map.h | 8 ++++++ arch/arm/include/asm/mach/pci.h | 10 ++++++++ arch/arm/kernel/bios32.c | 13 ++++++++++ arch/arm/mm/ioremap.c | 14 +++++++++++ arch/arm/mm/mmu.c | 54 ++++++++++++++++++++++++++++++++--------- 7 files changed, 99 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index 208a2d465b9..4bfb9ffbdbc 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -51,6 +51,9 @@ ffc00000 ffefffff DMA memory mapping region. Memory returned ff000000 ffbfffff Reserved for future expansion of DMA mapping region. +fee00000 feffffff Mapping of PCI I/O space. This is a static + mapping within the vmalloc space. + VMALLOC_START VMALLOC_END-1 vmalloc() / ioremap() space. Memory returned by vmalloc/ioremap will be dynamically placed in this region. diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 815c669fec0..8f4db67533e 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -113,11 +113,19 @@ static inline void __iomem *__typesafe_io(unsigned long addr) #define __iowmb() do { } while (0) #endif +/* PCI fixed i/o mapping */ +#define PCI_IO_VIRT_BASE 0xfee00000 + +extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr); + /* * Now, pick up the machine-defined IO definitions */ #ifdef CONFIG_NEED_MACH_IO_H #include +#elif defined(CONFIG_PCI) +#define IO_SPACE_LIMIT ((resource_size_t)0xfffff) +#define __io(a) __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT)) #else #define __io(a) __typesafe_io((a) & IO_SPACE_LIMIT) #endif diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index a6efcdd6fd2..195ac2f9d3d 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -9,6 +9,9 @@ * * Page table mapping constructs and function prototypes */ +#ifndef __ASM_MACH_MAP_H +#define __ASM_MACH_MAP_H + #include struct map_desc { @@ -34,6 +37,8 @@ struct map_desc { #ifdef CONFIG_MMU extern void iotable_init(struct map_desc *, int); +extern void vm_reserve_area_early(unsigned long addr, unsigned long size, + void *caller); struct mem_type; extern const struct mem_type *get_mem_type(unsigned int type); @@ -44,4 +49,7 @@ extern int ioremap_page(unsigned long virt, unsigned long phys, const struct mem_type *mtype); #else #define iotable_init(map,num) do { } while (0) +#define vm_reserve_area_early(a,s,c) do { } while (0) +#endif + #endif diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 26c511fddf8..df818876fa3 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h @@ -11,6 +11,7 @@ #ifndef __ASM_MACH_PCI_H #define __ASM_MACH_PCI_H + struct pci_sys_data; struct pci_ops; struct pci_bus; @@ -54,6 +55,15 @@ struct pci_sys_data { */ void pci_common_init(struct hw_pci *); +/* + * Setup early fixed I/O mapping. + */ +#if defined(CONFIG_PCI) +extern void pci_map_io_early(unsigned long pfn); +#else +static inline void pci_map_io_early(unsigned long pfn) {} +#endif + /* * PCI controllers */ diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 25552508c3f..c3165f0fef6 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -13,6 +13,7 @@ #include #include +#include #include static int debug_pci; @@ -627,3 +628,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, return 0; } + +void __init pci_map_io_early(unsigned long pfn) +{ + struct map_desc pci_io_desc = { + .virtual = PCI_IO_VIRT_BASE, + .type = MT_DEVICE, + .length = SZ_64K, + }; + + pci_io_desc.pfn = pfn; + iotable_init(&pci_io_desc, 1); +} diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 4f55f5062ab..8727802f866 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -36,6 +36,7 @@ #include #include +#include #include "mm.h" int ioremap_page(unsigned long virt, unsigned long phys, @@ -383,3 +384,16 @@ void __arm_iounmap(volatile void __iomem *io_addr) arch_iounmap(io_addr); } EXPORT_SYMBOL(__arm_iounmap); + +#ifdef CONFIG_PCI +int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr) +{ + BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT); + + return ioremap_page_range(PCI_IO_VIRT_BASE + offset, + PCI_IO_VIRT_BASE + offset + SZ_64K, + phys_addr, + __pgprot(get_mem_type(MT_DEVICE)->prot_pte)); +} +EXPORT_SYMBOL_GPL(pci_ioremap_io); +#endif diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index cf4528d5177..714a7fd99ca 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -31,6 +31,7 @@ #include #include +#include #include "mm.h" @@ -216,7 +217,7 @@ static struct mem_type mem_types[] = { .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB, .domain = DOMAIN_IO, - }, + }, [MT_DEVICE_WC] = { /* ioremap_wc */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC, .prot_l1 = PMD_TYPE_TABLE, @@ -783,14 +784,27 @@ void __init iotable_init(struct map_desc *io_desc, int nr) create_mapping(md); vm->addr = (void *)(md->virtual & PAGE_MASK); vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); - vm->phys_addr = __pfn_to_phys(md->pfn); - vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; + vm->phys_addr = __pfn_to_phys(md->pfn); + vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; vm->flags |= VM_ARM_MTYPE(md->type); vm->caller = iotable_init; vm_area_add_early(vm++); } } +void __init vm_reserve_area_early(unsigned long addr, unsigned long size, + void *caller) +{ + struct vm_struct *vm; + + vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm)); + vm->addr = (void *)addr; + vm->size = size; + vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; + vm->caller = caller; + vm_area_add_early(vm); +} + #ifndef CONFIG_ARM_LPAE /* @@ -808,14 +822,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr) static void __init pmd_empty_section_gap(unsigned long addr) { - struct vm_struct *vm; - - vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm)); - vm->addr = (void *)addr; - vm->size = SECTION_SIZE; - vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; - vm->caller = pmd_empty_section_gap; - vm_area_add_early(vm); + vm_reserve_area_early(addr, SECTION_SIZE, pmd_empty_section_gap); } static void __init fill_pmd_gaps(void) @@ -864,6 +871,28 @@ static void __init fill_pmd_gaps(void) #define fill_pmd_gaps() do { } while (0) #endif +#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H) +static void __init pci_reserve_io(void) +{ + struct vm_struct *vm; + unsigned long addr; + + /* we're still single threaded hence no lock needed here */ + for (vm = vmlist; vm; vm = vm->next) { + if (!(vm->flags & VM_ARM_STATIC_MAPPING)) + continue; + addr = (unsigned long)vm->addr; + addr &= ~(SZ_2M - 1); + if (addr == PCI_IO_VIRT_BASE) + return; + + } + vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io); +} +#else +#define pci_reserve_io() do { } while (0) +#endif + static void * __initdata vmalloc_min = (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET); @@ -1147,6 +1176,9 @@ static void __init devicemaps_init(struct machine_desc *mdesc) mdesc->map_io(); fill_pmd_gaps(); + /* Reserve fixed i/o space in VMALLOC region */ + pci_reserve_io(); + /* * Finally flush the caches and tlb to ensure that we're in a * consistent state wrt the writebuffer. This also ensures that -- cgit v1.2.3-70-g09d2 From 5ef75e710b4950439f953c4897e4a871c2f9dc8f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 25 Jul 2012 16:09:11 +0300 Subject: ASoC: omap-abe-twl6040: Add device tree support When the board boots with device tree the driver will receive the name of the card, DAPM routing map, phandle for the audio components described in the dts file, mclk speed, and the possibility of detecting the jack detection. The card will be set up based on this information. Since the routing is provided via DT we can mark the card fully routed so core can take care of disconnecting the unused pins. Signed-off-by: Peter Ujfalusi Reviwed-by: Mark Brown Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/omap-abe-twl6040.txt | 91 +++++++++++++ sound/soc/omap/omap-abe-twl6040.c | 145 ++++++++++++++++----- 2 files changed, 206 insertions(+), 30 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt new file mode 100644 index 00000000000..65dec876cb2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt @@ -0,0 +1,91 @@ +* Texas Instruments OMAP4+ and twl6040 based audio setups + +Required properties: +- compatible: "ti,abe-twl6040" +- ti,model: Name of the sound card ( for example "SDP4430") +- ti,mclk-freq: MCLK frequency for HPPLL operation +- ti,mcpdm: phandle for the McPDM node +- ti,twl6040: phandle for the twl6040 core node +- ti,audio-routing: List of connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + +Optional properties: +- ti,dmic: phandle for the OMAP dmic node if the machine have it connected +- ti,jack_detection: Need to be set to <1> if the board capable to detect jack + insertion, removal. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Earphone Spk + * Ext Spk + * Line Out + * Vibrator + * Headset Mic + * Main Handset Mic + * Sub Handset Mic + * Line In + * Digital Mic + +twl6040 pins: + * HSOL + * HSOR + * EP + * HFL + * HFR + * AUXL + * AUXR + * VIBRAL + * VIBRAR + * HSMIC + * MAINMIC + * SUBMIC + * AFML + * AFMR + + * Headset Mic Bias + * Main Mic Bias + * Digital Mic1 Bias + * Digital Mic2 Bias + +Digital mic pins: + * DMic + +Example: + +sound { + compatible = "ti,abe-twl6040"; + ti,model = "SDP4430"; + + ti,jack-detection = <1>; + ti,mclk-freq = <38400000>; + + ti,mcpdm = <&mcpdm>; + ti,dmic = <&dmic>; + + ti,twl6040 = <&twl6040>; + + /* Audio routing */ + ti,audio-routing = + "Headset Stereophone", "HSOL", + "Headset Stereophone", "HSOR", + "Earphone Spk", "EP", + "Ext Spk", "HFL", + "Ext Spk", "HFR", + "Line Out", "AUXL", + "Line Out", "AUXR", + "Vibrator", "VIBRAL", + "Vibrator", "VIBRAR", + "HSMIC", "Headset Mic", + "Headset Mic", "Headset Mic Bias", + "MAINMIC", "Main Handset Mic", + "Main Handset Mic", "Main Mic Bias", + "SUBMIC", "Sub Handset Mic", + "Sub Handset Mic", "Main Mic Bias", + "AFML", "Line In", + "AFMR", "Line In", + "DMic", "Digital Mic", + "Digital Mic", "Digital Mic1 Bias"; +}; diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 9d93793d307..be525dfe9fa 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,8 @@ struct abe_twl6040 { int jack_detection; /* board can detect jack events */ int mclk_freq; /* MCLK frequency speed for twl6040 */ + + struct platform_device *dmic_codec_dev; }; static int omap_abe_hw_params(struct snd_pcm_substream *substream, @@ -185,17 +188,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) int hs_trim; int ret = 0; - /* Disable not connected paths if not used */ - twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); - twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); - twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); - twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); - twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); - twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); - /* * Configure McPDM offset cancellation based on the HSOTRIM value from * twl6040. @@ -216,6 +208,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); } + /* + * NULL pdata means we booted with DT. In this case the routing is + * provided and the card is fully routed, no need to mark pins. + */ + if (!pdata) + return ret; + + /* Disable not connected paths if not used */ + twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); + twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); + twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); + twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); + return ret; } @@ -270,52 +280,116 @@ static struct snd_soc_card omap_abe_card = { static __devinit int omap_abe_probe(struct platform_device *pdev) { struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); + struct device_node *node = pdev->dev.of_node; struct snd_soc_card *card = &omap_abe_card; struct abe_twl6040 *priv; int num_links = 0; - int ret; + int ret = 0; card->dev = &pdev->dev; - if (!pdata) { - dev_err(&pdev->dev, "Missing pdata\n"); - return -ENODEV; - } - priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - if (pdata->card_name) { - card->name = pdata->card_name; + priv->dmic_codec_dev = ERR_PTR(-EINVAL); + + if (node) { + struct device_node *dai_node; + + if (snd_soc_of_parse_card_name(card, "ti,model")) { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + ret = snd_soc_of_parse_audio_routing(card, + "ti,audio-routing"); + if (ret) { + dev_err(&pdev->dev, + "Error while parsing DAPM routing\n"); + return ret; + } + + dai_node = of_parse_phandle(node, "ti,mcpdm", 0); + if (!dai_node) { + dev_err(&pdev->dev, "McPDM node is not provided\n"); + return -EINVAL; + } + abe_twl6040_dai_links[0].cpu_dai_name = NULL; + abe_twl6040_dai_links[0].cpu_of_node = dai_node; + + dai_node = of_parse_phandle(node, "ti,dmic", 0); + if (dai_node) { + num_links = 2; + abe_twl6040_dai_links[1].cpu_dai_name = NULL; + abe_twl6040_dai_links[1].cpu_of_node = dai_node; + + priv->dmic_codec_dev = platform_device_register_simple( + "dmic-codec", -1, NULL, 0); + if (IS_ERR(priv->dmic_codec_dev)) { + dev_err(&pdev->dev, + "Can't instantiate dmic-codec\n"); + return PTR_ERR(priv->dmic_codec_dev); + } + } else { + num_links = 1; + } + + of_property_read_u32(node, "ti,jack-detection", + &priv->jack_detection); + of_property_read_u32(node, "ti,mclk-freq", + &priv->mclk_freq); + if (!priv->mclk_freq) { + dev_err(&pdev->dev, "MCLK frequency not provided\n"); + ret = -EINVAL; + goto err_unregister; + } + + omap_abe_card.fully_routed = 1; + } else if (pdata) { + if (pdata->card_name) { + card->name = pdata->card_name; + } else { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + if (pdata->has_dmic) + num_links = 2; + else + num_links = 1; + + priv->jack_detection = pdata->jack_detection; + priv->mclk_freq = pdata->mclk_freq; } else { - dev_err(&pdev->dev, "Card name is not provided\n"); + dev_err(&pdev->dev, "Missing pdata\n"); return -ENODEV; } - priv->jack_detection = pdata->jack_detection; - priv->mclk_freq = pdata->mclk_freq; - if (!priv->mclk_freq) { dev_err(&pdev->dev, "MCLK frequency missing\n"); - return -ENODEV; + ret = -ENODEV; + goto err_unregister; } - if (pdata->has_dmic) - num_links = 2; - else - num_links = 1; - card->dai_link = abe_twl6040_dai_links; card->num_links = num_links; snd_soc_card_set_drvdata(card, priv); ret = snd_soc_register_card(card); - if (ret) + if (ret) { dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + goto err_unregister; + } + + return 0; + +err_unregister: + if (!IS_ERR(priv->dmic_codec_dev)) + platform_device_unregister(priv->dmic_codec_dev); return ret; } @@ -323,17 +397,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) static int __devexit omap_abe_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); snd_soc_unregister_card(card); + if (!IS_ERR(priv->dmic_codec_dev)) + platform_device_unregister(priv->dmic_codec_dev); + return 0; } +static const struct of_device_id omap_abe_of_match[] = { + {.compatible = "ti,abe-twl6040", }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_abe_of_match); + static struct platform_driver omap_abe_driver = { .driver = { .name = "omap-abe-twl6040", .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, + .of_match_table = omap_abe_of_match, }, .probe = omap_abe_probe, .remove = __devexit_p(omap_abe_remove), -- cgit v1.2.3-70-g09d2 From 85d07e4d625d6511934799f7df93e9111ac2c88b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 25 Jul 2012 15:28:34 +0200 Subject: ASoC: add DT bindings for cs4270 Signed-off-by: Daniel Mack Acked-by: Timur Tabi Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cs4270.txt | 16 ++++++++++++++++ sound/soc/codecs/cs4270.c | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs4270.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt new file mode 100644 index 00000000000..7f0bfd84d3f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4270.txt @@ -0,0 +1,16 @@ +CS4270 audio CODEC + +The driver for this device currently only supports I2C. + +Required properties: + + - compatible : "cirrus,cs4270" + + - reg : the I2C address of the device for I2C + +Example: + +codec: cs4270@48 { + compatible = "cirrus,cs4270"; + reg = <0x48>; +}; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 047917f0b8a..4b71b01ecbc 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * The codec isn't really big-endian or little-endian, since the I2S @@ -639,6 +640,15 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { .reg_cache_default = cs4270_default_reg_cache, }; +/* + * cs4270_of_match - the device tree bindings + */ +static const struct of_device_id cs4270_of_match[] = { + { .compatible = "cirrus,cs4270", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs4270_of_match); + /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object @@ -718,6 +728,7 @@ static struct i2c_driver cs4270_i2c_driver = { .driver = { .name = "cs4270", .owner = THIS_MODULE, + .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, .probe = cs4270_i2c_probe, -- cgit v1.2.3-70-g09d2 From 02286190f3ec86f03025a60c4d3f747ff1047248 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 25 Jul 2012 15:28:35 +0200 Subject: ASoC: Add reset-gpio DT property to cs4270 driver In the process of moving over from static board files to the device tree, reset pins of peripheral reset pins should be handled by their corresponding drivers. Add a reset-gpio DT property to the cs4270 driver, and de-assert it before probing the chip. The logic could be augmented some day to re-assert it when codec is put to suspend. Signed-off-by: Daniel Mack Acked-by: Timur Tabi Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cs4270.txt | 5 +++++ sound/soc/codecs/cs4270.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt index 7f0bfd84d3f..6b222f9b8ef 100644 --- a/Documentation/devicetree/bindings/sound/cs4270.txt +++ b/Documentation/devicetree/bindings/sound/cs4270.txt @@ -8,6 +8,11 @@ Required properties: - reg : the I2C address of the device for I2C +Optional properties: + + - reset-gpio : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + Example: codec: cs4270@48 { diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 4b71b01ecbc..fd11bb646d4 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * The codec isn't really big-endian or little-endian, since the I2S @@ -660,9 +661,25 @@ MODULE_DEVICE_TABLE(of, cs4270_of_match); static int cs4270_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device_node *np = i2c_client->dev.of_node; struct cs4270_private *cs4270; int ret; + /* See if we have a way to bring the codec out of reset */ + if (np) { + enum of_gpio_flags flags; + int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); + + if (gpio_is_valid(gpio)) { + ret = devm_gpio_request_one(&i2c_client->dev, gpio, + flags & OF_GPIO_ACTIVE_LOW ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + "cs4270 reset"); + if (ret < 0) + return ret; + } + } + /* Verify that we have a CS4270 */ ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); -- cgit v1.2.3-70-g09d2 From 2eb32b0a6f9d73fafc6b2c00ac0b705de13ae143 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Mon, 30 Jul 2012 10:17:14 +0000 Subject: drivers: net: ethernet: cpsw: Add device tree support to CPSW This patch adds device tree support for cpsw driver Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/cpsw.txt | 104 +++++++++++++++ drivers/net/ethernet/ti/cpsw.c | 174 ++++++++++++++++++++++++- 2 files changed, 272 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/cpsw.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt new file mode 100644 index 00000000000..acca48c4246 --- /dev/null +++ b/Documentation/devicetree/bindings/net/cpsw.txt @@ -0,0 +1,104 @@ +TI SoC Ethernet Switch Controller Device Tree Bindings +------------------------------------------------------ + +Required properties: +- compatible : Should be "ti,cpsw" +- reg : physical base address and size of the cpsw + registers map +- interrupts : property with a value describing the interrupt + number +- interrupt-parent : The parent interrupt controller +- cpdma_channels : Specifies number of channels in CPDMA +- host_port_no : Specifies host port shift +- cpdma_reg_ofs : Specifies CPDMA submodule register offset +- ale_reg_ofs : Specifies ALE submodule register offset +- ale_entries : Specifies No of entries ALE can hold +- host_port_reg_ofs : Specifies host port register offset +- hw_stats_reg_ofs : Specifies hardware statistics register offset +- bd_ram_ofs : Specifies internal desciptor RAM offset +- bd_ram_size : Specifies internal descriptor RAM size +- rx_descs : Specifies number of Rx descriptors +- mac_control : Specifies Default MAC control register content + for the specific platform +- slaves : Specifies number for slaves +- slave_reg_ofs : Specifies slave register offset +- sliver_reg_ofs : Specifies slave sliver register offset +- phy_id : Specifies slave phy id +- mac-address : Specifies slave MAC address + +Optional properties: +- ti,hwmods : Must be "cpgmac0" +- no_bd_ram : Must be 0 or 1 + +Note: "ti,hwmods" field is used to fetch the base address and irq +resources from TI, omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples: + + mac: ethernet@4A100000 { + compatible = "ti,cpsw"; + reg = <0x4A100000 0x1000>; + interrupts = <55 0x4>; + interrupt-parent = <&intc>; + cpdma_channels = 8; + host_port_no = 0; + cpdma_reg_ofs = 0x800; + ale_reg_ofs = 0xd00; + ale_entries = 1024; + host_port_reg_ofs = 0x108; + hw_stats_reg_ofs = 0x900; + bd_ram_ofs = 0x2000; + bd_ram_size = 0x2000; + no_bd_ram = 0; + rx_descs = 64; + mac_control = 0x20; + slaves = 2; + slave@0 { + slave_reg_ofs = 0x208; + sliver_reg_ofs = 0xd80; + phy_id = "davinci_mdio-0:00" + mac-address = [00 04 9F 01 1B B8]; + }; + slave@1 { + slave_reg_ofs = 0x208; + sliver_reg_ofs = 0xd80; + phy_id = "davinci_mdio-0:01" + mac-address = [00 04 9F 01 1B B9]; + }; + }; + +(or) + + mac: ethernet@4A100000 { + compatible = "ti,cpsw"; + ti,hwmods = "cpgmac0"; + cpdma_channels = 8; + host_port_no = 0; + cpdma_reg_ofs = 0x800; + ale_reg_ofs = 0xd00; + ale_entries = 1024; + host_port_reg_ofs = 0x108; + hw_stats_reg_ofs = 0x900; + bd_ram_ofs = 0x2000; + bd_ram_size = 0x2000; + no_bd_ram = 0; + rx_descs = 64; + mac_control = 0x20; + slaves = 2; + slave@0 { + slave_reg_ofs = 0x208; + sliver_reg_ofs = 0xd80; + phy_id = "davinci_mdio-0:00" + mac-address = [00 04 9F 01 1B B8]; + }; + slave@1 { + slave_reg_ofs = 0x208; + sliver_reg_ofs = 0xd80; + phy_id = "davinci_mdio-0:01" + mac-address = [00 04 9F 01 1B B9]; + }; + + }; diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 1e5d85b06e7..0cbc0e59252 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include @@ -709,6 +712,158 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) slave->sliver = regs + data->sliver_reg_ofs; } +static int cpsw_probe_dt(struct cpsw_platform_data *data, + struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct device_node *slave_node; + int i = 0, ret; + u32 prop; + + if (!node) + return -EINVAL; + + if (of_property_read_u32(node, "slaves", &prop)) { + pr_err("Missing slaves property in the DT.\n"); + return -EINVAL; + } + data->slaves = prop; + + data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) * + data->slaves, GFP_KERNEL); + if (!data->slave_data) { + pr_err("Could not allocate slave memory.\n"); + return -EINVAL; + } + + data->no_bd_ram = of_property_read_bool(node, "no_bd_ram"); + + if (of_property_read_u32(node, "cpdma_channels", &prop)) { + pr_err("Missing cpdma_channels property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->channels = prop; + + if (of_property_read_u32(node, "host_port_no", &prop)) { + pr_err("Missing host_port_no property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->host_port_num = prop; + + if (of_property_read_u32(node, "cpdma_reg_ofs", &prop)) { + pr_err("Missing cpdma_reg_ofs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->cpdma_reg_ofs = prop; + + if (of_property_read_u32(node, "cpdma_sram_ofs", &prop)) { + pr_err("Missing cpdma_sram_ofs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->cpdma_sram_ofs = prop; + + if (of_property_read_u32(node, "ale_reg_ofs", &prop)) { + pr_err("Missing ale_reg_ofs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->ale_reg_ofs = prop; + + if (of_property_read_u32(node, "ale_entries", &prop)) { + pr_err("Missing ale_entries property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->ale_entries = prop; + + if (of_property_read_u32(node, "host_port_reg_ofs", &prop)) { + pr_err("Missing host_port_reg_ofs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->host_port_reg_ofs = prop; + + if (of_property_read_u32(node, "hw_stats_reg_ofs", &prop)) { + pr_err("Missing hw_stats_reg_ofs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->hw_stats_reg_ofs = prop; + + if (of_property_read_u32(node, "bd_ram_ofs", &prop)) { + pr_err("Missing bd_ram_ofs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->bd_ram_ofs = prop; + + if (of_property_read_u32(node, "bd_ram_size", &prop)) { + pr_err("Missing bd_ram_size property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->bd_ram_size = prop; + + if (of_property_read_u32(node, "rx_descs", &prop)) { + pr_err("Missing rx_descs property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->rx_descs = prop; + + if (of_property_read_u32(node, "mac_control", &prop)) { + pr_err("Missing mac_control property in the DT.\n"); + ret = -EINVAL; + goto error_ret; + } + data->mac_control = prop; + + for_each_child_of_node(node, slave_node) { + struct cpsw_slave_data *slave_data = data->slave_data + i; + const char *phy_id = NULL; + const void *mac_addr = NULL; + + if (of_property_read_string(slave_node, "phy_id", &phy_id)) { + pr_err("Missing slave[%d] phy_id property\n", i); + ret = -EINVAL; + goto error_ret; + } + slave_data->phy_id = phy_id; + + if (of_property_read_u32(slave_node, "slave_reg_ofs", &prop)) { + pr_err("Missing slave[%d] slave_reg_ofs property\n", i); + ret = -EINVAL; + goto error_ret; + } + slave_data->slave_reg_ofs = prop; + + if (of_property_read_u32(slave_node, "sliver_reg_ofs", + &prop)) { + pr_err("Missing slave[%d] sliver_reg_ofs property\n", + i); + ret = -EINVAL; + goto error_ret; + } + slave_data->sliver_reg_ofs = prop; + + mac_addr = of_get_mac_address(slave_node); + if (mac_addr) + memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); + + i++; + } + + return 0; + +error_ret: + kfree(data->slave_data); + return ret; +} + static int __devinit cpsw_probe(struct platform_device *pdev) { struct cpsw_platform_data *data = pdev->dev.platform_data; @@ -720,11 +875,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev) struct resource *res; int ret = 0, i, k = 0; - if (!data) { - pr_err("platform data missing\n"); - return -ENODEV; - } - ndev = alloc_etherdev(sizeof(struct cpsw_priv)); if (!ndev) { pr_err("error allocating net_device\n"); @@ -734,13 +884,19 @@ static int __devinit cpsw_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); priv = netdev_priv(ndev); spin_lock_init(&priv->lock); - priv->data = *data; priv->pdev = pdev; priv->ndev = ndev; priv->dev = &ndev->dev; priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); priv->rx_packet_max = max(rx_packet_max, 128); + if (cpsw_probe_dt(&priv->data, pdev)) { + pr_err("cpsw: platform data missing\n"); + ret = -ENODEV; + goto clean_ndev_ret; + } + data = &priv->data; + if (is_valid_ether_addr(data->slave_data[0].mac_addr)) { memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN); pr_info("Detected MACID = %pM", priv->mac_addr); @@ -996,11 +1152,17 @@ static const struct dev_pm_ops cpsw_pm_ops = { .resume = cpsw_resume, }; +static const struct of_device_id cpsw_of_mtable[] = { + { .compatible = "ti,cpsw", }, + { /* sentinel */ }, +}; + static struct platform_driver cpsw_driver = { .driver = { .name = "cpsw", .owner = THIS_MODULE, .pm = &cpsw_pm_ops, + .of_match_table = of_match_ptr(cpsw_of_mtable), }, .probe = cpsw_probe, .remove = __devexit_p(cpsw_remove), -- cgit v1.2.3-70-g09d2 From ec03e6a89e5168c92581a769681207c29ad2030f Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Mon, 6 Aug 2012 05:05:57 +0000 Subject: drivers: net: ethernet: davince_mdio: device tree implementation device tree implementation for davinci mdio driver Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- .../devicetree/bindings/net/davinci-mdio.txt | 33 +++++++++++++++++ drivers/net/ethernet/ti/davinci_mdio.c | 41 +++++++++++++++++++--- 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/davinci-mdio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt new file mode 100644 index 00000000000..72efaaf764f --- /dev/null +++ b/Documentation/devicetree/bindings/net/davinci-mdio.txt @@ -0,0 +1,33 @@ +TI SoC Davinci MDIO Controller Device Tree Bindings +--------------------------------------------------- + +Required properties: +- compatible : Should be "ti,davinci_mdio" +- reg : physical base address and size of the davinci mdio + registers map +- bus_freq : Mdio Bus frequency + +Optional properties: +- ti,hwmods : Must be "davinci_mdio" + +Note: "ti,hwmods" field is used to fetch the base address and irq +resources from TI, omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples: + + mdio: davinci_mdio@4A101000 { + compatible = "ti,cpsw"; + reg = <0x4A101000 0x1000>; + bus_freq = <1000000>; + }; + +(or) + + mdio: davinci_mdio@4A101000 { + compatible = "ti,cpsw"; + ti,hwmods = "davinci_mdio"; + bus_freq = <1000000>; + }; diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index cd7ee204e94..573f3be5f42 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include /* * This timeout definition is a worst-case ultra defensive measure against @@ -289,6 +291,25 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id, return 0; } +static int davinci_mdio_probe_dt(struct mdio_platform_data *data, + struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + u32 prop; + + if (!node) + return -EINVAL; + + if (of_property_read_u32(node, "bus_freq", &prop)) { + pr_err("Missing bus_freq property in the DT.\n"); + return -EINVAL; + } + data->bus_freq = prop; + + return 0; +} + + static int __devinit davinci_mdio_probe(struct platform_device *pdev) { struct mdio_platform_data *pdata = pdev->dev.platform_data; @@ -304,8 +325,6 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev) return -ENOMEM; } - data->pdata = pdata ? (*pdata) : default_pdata; - data->bus = mdiobus_alloc(); if (!data->bus) { dev_err(dev, "failed to alloc mii bus\n"); @@ -313,14 +332,22 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev) goto bail_out; } + if (dev->of_node) { + if (davinci_mdio_probe_dt(&data->pdata, pdev)) + data->pdata = default_pdata; + snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); + } else { + data->pdata = pdata ? (*pdata) : default_pdata; + snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); + } + data->bus->name = dev_name(dev); data->bus->read = davinci_mdio_read, data->bus->write = davinci_mdio_write, data->bus->reset = davinci_mdio_reset, data->bus->parent = dev; data->bus->priv = data; - snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x", - pdev->name, pdev->id); pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); @@ -454,11 +481,17 @@ static const struct dev_pm_ops davinci_mdio_pm_ops = { .resume = davinci_mdio_resume, }; +static const struct of_device_id davinci_mdio_of_mtable[] = { + { .compatible = "ti,davinci_mdio", }, + { /* sentinel */ }, +}; + static struct platform_driver davinci_mdio_driver = { .driver = { .name = "davinci_mdio", .owner = THIS_MODULE, .pm = &davinci_mdio_pm_ops, + .of_match_table = of_match_ptr(davinci_mdio_of_mtable), }, .probe = davinci_mdio_probe, .remove = __devexit_p(davinci_mdio_remove), -- cgit v1.2.3-70-g09d2 From e07b94f1352723994d8b588ac5ed8af91bcc9fb6 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Mon, 6 Aug 2012 05:05:58 +0000 Subject: documentation: dt: bindings: cpsw: fixing the examples for directly using it in dts file Fixing the cpsw device tree example to make it simpler to copy pastable to dts file and use it directly. Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/cpsw.txt | 101 +++++++++++++------------ 1 file changed, 53 insertions(+), 48 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt index acca48c4246..dcaabe9fe86 100644 --- a/Documentation/devicetree/bindings/net/cpsw.txt +++ b/Documentation/devicetree/bindings/net/cpsw.txt @@ -11,6 +11,7 @@ Required properties: - cpdma_channels : Specifies number of channels in CPDMA - host_port_no : Specifies host port shift - cpdma_reg_ofs : Specifies CPDMA submodule register offset +- cpdma_sram_ofs : Specifies CPDMA SRAM offset - ale_reg_ofs : Specifies ALE submodule register offset - ale_entries : Specifies No of entries ALE can hold - host_port_reg_ofs : Specifies host port register offset @@ -43,62 +44,66 @@ Examples: reg = <0x4A100000 0x1000>; interrupts = <55 0x4>; interrupt-parent = <&intc>; - cpdma_channels = 8; - host_port_no = 0; - cpdma_reg_ofs = 0x800; - ale_reg_ofs = 0xd00; - ale_entries = 1024; - host_port_reg_ofs = 0x108; - hw_stats_reg_ofs = 0x900; - bd_ram_ofs = 0x2000; - bd_ram_size = 0x2000; - no_bd_ram = 0; - rx_descs = 64; - mac_control = 0x20; - slaves = 2; - slave@0 { - slave_reg_ofs = 0x208; - sliver_reg_ofs = 0xd80; - phy_id = "davinci_mdio-0:00" - mac-address = [00 04 9F 01 1B B8]; + cpdma_channels = <8>; + host_port_no = <0>; + cpdma_reg_ofs = <0x800>; + cpdma_sram_ofs = <0xa00>; + ale_reg_ofs = <0xd00>; + ale_entries = <1024>; + host_port_reg_ofs = <0x108>; + hw_stats_reg_ofs = <0x900>; + bd_ram_ofs = <0x2000>; + bd_ram_size = <0x2000>; + no_bd_ram = <0>; + rx_descs = <64>; + mac_control = <0x20>; + slaves = <2>; + cpsw_emac0: slave@0 { + slave_reg_ofs = <0x208>; + sliver_reg_ofs = <0xd80>; + phy_id = "davinci_mdio.16:00"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; }; - slave@1 { - slave_reg_ofs = 0x208; - sliver_reg_ofs = 0xd80; - phy_id = "davinci_mdio-0:01" - mac-address = [00 04 9F 01 1B B9]; + cpsw_emac1: slave@1 { + slave_reg_ofs = <0x308>; + sliver_reg_ofs = <0xdc0>; + phy_id = "davinci_mdio.16:01"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; }; }; (or) - mac: ethernet@4A100000 { compatible = "ti,cpsw"; ti,hwmods = "cpgmac0"; - cpdma_channels = 8; - host_port_no = 0; - cpdma_reg_ofs = 0x800; - ale_reg_ofs = 0xd00; - ale_entries = 1024; - host_port_reg_ofs = 0x108; - hw_stats_reg_ofs = 0x900; - bd_ram_ofs = 0x2000; - bd_ram_size = 0x2000; - no_bd_ram = 0; - rx_descs = 64; - mac_control = 0x20; - slaves = 2; - slave@0 { - slave_reg_ofs = 0x208; - sliver_reg_ofs = 0xd80; - phy_id = "davinci_mdio-0:00" - mac-address = [00 04 9F 01 1B B8]; + cpdma_channels = <8>; + host_port_no = <0>; + cpdma_reg_ofs = <0x800>; + cpdma_sram_ofs = <0xa00>; + ale_reg_ofs = <0xd00>; + ale_entries = <1024>; + host_port_reg_ofs = <0x108>; + hw_stats_reg_ofs = <0x900>; + bd_ram_ofs = <0x2000>; + bd_ram_size = <0x2000>; + no_bd_ram = <0>; + rx_descs = <64>; + mac_control = <0x20>; + slaves = <2>; + cpsw_emac0: slave@0 { + slave_reg_ofs = <0x208>; + sliver_reg_ofs = <0xd80>; + phy_id = "davinci_mdio.16:00"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; }; - slave@1 { - slave_reg_ofs = 0x208; - sliver_reg_ofs = 0xd80; - phy_id = "davinci_mdio-0:01" - mac-address = [00 04 9F 01 1B B9]; + cpsw_emac1: slave@1 { + slave_reg_ofs = <0x308>; + sliver_reg_ofs = <0xdc0>; + phy_id = "davinci_mdio.16:01"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; }; - }; -- cgit v1.2.3-70-g09d2 From c43cdfbc4cebdf1a7992432615bf5155b51b8cc0 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Tue, 18 Sep 2012 09:57:47 +0000 Subject: docs: Xen ARM DT bindings Add a doc to describe the Xen ARM device tree bindings Changes in v5: - add a comment about the size of the grant table memory region; - add a comment about the required presence of a GIC node; - specify that the described properties are part of a top-level "hypervisor" node; - specify #address-cells and #size-cells for the example. Changes in v4: - "xen,xen" should be last as it is less specific; - update reg property using 2 address-cells and 2 size-cells. Signed-off-by: Stefano Stabellini Acked-by: Rob Herring CC: devicetree-discuss@lists.ozlabs.org CC: David Vrabel CC: Rob Herring CC: Dave Martin --- Documentation/devicetree/bindings/arm/xen.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/xen.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/xen.txt b/Documentation/devicetree/bindings/arm/xen.txt new file mode 100644 index 00000000000..0f7b9c2109f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/xen.txt @@ -0,0 +1,25 @@ +* Xen hypervisor device tree bindings + +Xen ARM virtual platforms shall have a top-level "hypervisor" node with +the following properties: + +- compatible: + compatible = "xen,xen-", "xen,xen"; + where is the version of the Xen ABI of the platform. + +- reg: specifies the base physical address and size of a region in + memory where the grant table should be mapped to, using an + HYPERVISOR_memory_op hypercall. The memory region is large enough to map + the whole grant table (it is larger or equal to gnttab_max_grant_frames()). + +- interrupts: the interrupt used by Xen to inject event notifications. + A GIC node is also required. + + +Example (assuming #address-cells = <2> and #size-cells = <2>): + +hypervisor { + compatible = "xen,xen-4.3", "xen,xen"; + reg = <0 0xb0000000 0 0x20000>; + interrupts = <1 15 0xf08>; +}; -- cgit v1.2.3-70-g09d2 From 1139b4516f3927ae835ed3b0a9c69a0dfaf4cdd4 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Jul 2012 09:29:12 +0200 Subject: USB: ohci-pxa27x: add DT bindings Add DT bindings to the ohci-pxa27x driver and some documentation. Successfully tested on a PXA3xx board. Signed-off-by: Daniel Mack Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/pxa-usb.txt | 31 +++++++++++ drivers/usb/host/ohci-pxa27x.c | 68 +++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/pxa-usb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt new file mode 100644 index 00000000000..79729a948d5 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/pxa-usb.txt @@ -0,0 +1,31 @@ +PXA USB controllers + +OHCI + +Required properties: + - compatible: Should be "marvell,pxa-ohci" for USB controllers + used in host mode. + +Optional properties: + - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3" + If present, enables the appropriate USB port of the controller. + - "marvell,port-mode" selects the mode of the ports: + 1 = PMM_NPS_MODE + 2 = PMM_GLOBAL_MODE + 3 = PMM_PERPORT_MODE + - "marvell,power-sense-low" - power sense pin is low-active. + - "marvell,power-control-low" - power control pin is low-active. + - "marvell,no-oc-protection" - disable over-current protection. + - "marvell,oc-mode-perport" - enable per-port over-current protection. + - "marvell,power_on_delay" Power On to Power Good time - in ms. + +Example: + + usb0: ohci@4c000000 { + compatible = "marvell,pxa-ohci", "usb-ohci"; + reg = <0x4c000000 0x100000>; + interrupts = <18>; + marvell,enable-port1; + marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */ + }; + diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index e1a3cc6d28d..77f4402aca0 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -272,6 +274,67 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) clk_disable_unprepare(ohci->clk); } +#ifdef CONFIG_OF +static const struct of_device_id pxa_ohci_dt_ids[] = { + { .compatible = "marvell,pxa-ohci" }, + { } +}; + +MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids); + +static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32); + +static int __devinit ohci_pxa_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct pxaohci_platform_data *pdata; + u32 tmp; + + if (!np) + return 0; + + /* Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pxa_ohci_dma_mask; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "marvell,enable-port1", NULL)) + pdata->flags |= ENABLE_PORT1; + if (of_get_property(np, "marvell,enable-port2", NULL)) + pdata->flags |= ENABLE_PORT2; + if (of_get_property(np, "marvell,enable-port3", NULL)) + pdata->flags |= ENABLE_PORT3; + if (of_get_property(np, "marvell,port-sense-low", NULL)) + pdata->flags |= POWER_SENSE_LOW; + if (of_get_property(np, "marvell,power-control-low", NULL)) + pdata->flags |= POWER_CONTROL_LOW; + if (of_get_property(np, "marvell,no-oc-protection", NULL)) + pdata->flags |= NO_OC_PROTECTION; + if (of_get_property(np, "marvell,oc-mode-perport", NULL)) + pdata->flags |= OC_MODE_PERPORT; + if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp)) + pdata->power_on_delay = tmp; + if (!of_property_read_u32(np, "marvell,port-mode", &tmp)) + pdata->port_mode = tmp; + if (!of_property_read_u32(np, "marvell,power-budget", &tmp)) + pdata->power_budget = tmp; + + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static int __devinit ohci_pxa_of_init(struct platform_device *pdev) +{ + return 0; +} +#endif /*-------------------------------------------------------------------------*/ @@ -297,6 +360,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device struct resource *r; struct clk *usb_clk; + retval = ohci_pxa_of_init(pdev); + if (retval) + return retval; + inf = pdev->dev.platform_data; if (!inf) @@ -544,6 +611,7 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { .driver = { .name = "pxa27x-ohci", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pxa_ohci_dt_ids), #ifdef CONFIG_PM .pm = &ohci_hcd_pxa27x_pm_ops, #endif -- cgit v1.2.3-70-g09d2 From 4d9e4088e074e674bc7a9fef4381e0910323c649 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 3 Aug 2012 16:30:36 +0800 Subject: usb: add decriptor of persist fail for some morph usb devices Some morph devices will morph after being reset and cause persist to fail. This patch is to add descriptor about this in the Document/usb/persist.txt Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/persist.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt index 074b159b77c..35d70eda9ad 100644 --- a/Documentation/usb/persist.txt +++ b/Documentation/usb/persist.txt @@ -155,6 +155,9 @@ If the kernel gets fooled in this way, it's almost certain to cause data corruption and to crash your system. You'll have no one to blame but yourself. +For those devices with avoid_reset_quirk attribute being set, persist +maybe fail because they may morph after reset. + YOU HAVE BEEN WARNED! USE AT YOUR OWN RISK! That having been said, most of the time there shouldn't be any trouble -- cgit v1.2.3-70-g09d2 From 9ee99783d7571d7e1ca8540e82b21f51b69595f4 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 17 Jul 2012 16:20:13 +0200 Subject: arm: add documentation describing Marvell families of SoC As stated in the introduction of the document, the families of ARM SoCs at Marvell are very complicated, and it is difficult for newcomers to understand the organization of this SoC family and how it relates to the Linux kernel support for those hardware platforms. This document is only at RFC stage for now, it requires reviews and comments from the Marvell maintainers, the PXA maintainers and the MMP maintainers. For correctness of course, but also to add any other information that would be useful. For example, one of the thing that wasn't clear how to detail in the documentation is how the SoCs relate to each other in terms of hardware IP blocks. For example, most of the Kirkwood/Dove/Armada 370-XP/etc. hardware IPs (I2C, SPI, USB, SATA, etc.) are identical, while the PXA and MMP families are completely separate. Signed-off-by: Thomas Petazzoni Cc: Andrew Lunn Cc: Jason Cooper Cc: Gregory Clement Cc: Eric Miao Cc: Russell King Cc: Haojian Zhuang Cc: Nicolas Pitre Cc: Arnd Bergmann Cc: Olof Johansson Cc: Lior Amsalem Cc: Maen Suleiman Cc: Tawfik Bayouk Cc: Shadi Ammouri Cc: Eran Ben-Avi Acked-by: Arnd Bergmann --- Changes from v3: * Add Arnd Bergmann Acked-by. Changes from v2: * Mention the plat- directory that each SoC family is using. * Take into account Eric Miao's comments on the PXA/MMP families: add PXA21x/PXA25x/PXA26x to the list, mention which processors are AP+CP or AP only. Clarify the comments on which SoCs were designed by Intel, which ones were designed by Marvell after the acquisition of the XScale family. * Mention long-term plans regarding the support of those SoC families. Changes from v1: * Added publicly available datasheet for the 88F5182 pointed by Andrew Lunn. * Added publicly available datasheet for the 88F5281 found with Google searches * Mentionned the Feroceon core name where appropriate, and Sheeva where appropriate * Fixed the core names for PXA930, PXA935 and PXA955 after comments from Arnd Bergmann. Wikipedia is mistakenly suggesting that PXA93x are Sheeva-based, and there isn't much information available on the web about the 955. --- Documentation/arm/Marvell/README | 232 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 Documentation/arm/Marvell/README (limited to 'Documentation') diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README new file mode 100644 index 00000000000..8f08a86e03b --- /dev/null +++ b/Documentation/arm/Marvell/README @@ -0,0 +1,232 @@ +ARM Marvell SoCs +================ + +This document lists all the ARM Marvell SoCs that are currently +supported in mainline by the Linux kernel. As the Marvell families of +SoCs are large and complex, it is hard to understand where the support +for a particular SoC is available in the Linux kernel. This document +tries to help in understanding where those SoCs are supported, and to +match them with their corresponding public datasheet, when available. + +Orion family +------------ + + Flavors: + 88F5082 + 88F5181 + 88F5181L + 88F5182 + Datasheet : http://www.embeddedarm.com/documentation/third-party/MV88F5182-datasheet.pdf + Programmer's User Guide : http://www.embeddedarm.com/documentation/third-party/MV88F5182-opensource-manual.pdf + User Manual : http://www.embeddedarm.com/documentation/third-party/MV88F5182-usermanual.pdf + 88F5281 + Datasheet : http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf + 88F6183 + Core: Feroceon ARMv5 compatible + Linux kernel mach directory: arch/arm/mach-orion5x + Linux kernel plat directory: arch/arm/plat-orion + +Kirkwood family +--------------- + + Flavors: + 88F6282 a.k.a Armada 300 + Product Brief : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf + 88F6283 a.k.a Armada 310 + Product Brief : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf + 88F6190 + Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf + Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf + Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + 88F6192 + Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf + Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf + Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + 88F6182 + 88F6180 + Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf + Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf + Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + 88F6281 + Product Brief : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf + Hardware Spec : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf + Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + Homepage: http://www.marvell.com/embedded-processors/kirkwood/ + Core: Feroceon ARMv5 compatible + Linux kernel mach directory: arch/arm/mach-kirkwood + Linux kernel plat directory: arch/arm/plat-orion + +Discovery family +---------------- + + Flavors: + MV78100 + Product Brief : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf + Hardware Spec : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf + Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf + MV78200 + Product Brief : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf + Hardware Spec : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf + Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf + MV76100 + Not supported by the Linux kernel. + + Core: Feroceon ARMv5 compatible + + Linux kernel mach directory: arch/arm/mach-mv78xx0 + Linux kernel plat directory: arch/arm/plat-orion + +EBU Armada family +----------------- + + Armada 370 Flavors: + 88F6710 + 88F6707 + 88F6W11 + + Armada XP Flavors: + MV78230 + MV78260 + MV78460 + + Product Brief: http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf + No public datasheet available. + + Core: Sheeva ARMv7 compatible + + Linux kernel mach directory: arch/arm/mach-mvebu + Linux kernel plat directory: none + +Avanta family +------------- + + Flavors: + 88F6510 + 88F6530P + 88F6550 + 88F6560 + Homepage : http://www.marvell.com/broadband/ + Product Brief: http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf + No public datasheet available. + + Core: ARMv5 compatible + + Linux kernel mach directory: no code in mainline yet, planned for the future + Linux kernel plat directory: no code in mainline yet, planned for the future + +Dove family (application processor) +----------------------------------- + + Flavors: + 88AP510 a.k.a Armada 510 + Product Brief : http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf + Hardware Spec : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf + Functional Spec : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf + Homepage: http://www.marvell.com/application-processors/armada-500/ + Core: ARMv7 compatible + Directory: arch/arm/mach-dove + +PXA 2xx/3xx/93x/95x family +-------------------------- + + Flavors: + PXA21x, PXA25x, PXA26x + Application processor only + Core: ARMv5 XScale core + PXA270, PXA271, PXA272 + Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf + Design guide : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf + Developers manual : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf + Specification : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf + Specification update : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf + Application processor only + Core: ARMv5 XScale core + PXA300, PXA310, PXA320 + PXA 300 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf + PXA 310 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf + PXA 320 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf + Design guide : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf + Developers manual : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip + Specifications : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf + Specification Update : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip + Reference Manual : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf + Application processor only + Core: ARMv5 XScale core + PXA930, PXA935 + Application processor with Communication processor + Core: ARMv5 XScale core + PXA955 + Application processor with Communication processor + Core: ARMv7 compatible Sheeva PJ4 core + + Comments: + + * This line of SoCs originates from the XScale family developed by + Intel and acquired by Marvell in ~2006. The PXA21x, PXA25x, + PXA26x, PXA27x, PXA3xx and PXA93x were developed by Intel, while + the later PXA95x were developed by Marvell. + + * Due to their XScale origin, these SoCs have virtually nothing in + common with the other (Kirkwood, Dove, etc.) families of Marvell + SoCs, except with the MMP/MMP2 family of SoCs. + + Linux kernel mach directory: arch/arm/mach-pxa + Linux kernel plat directory: arch/arm/plat-pxa + +MMP/MMP2 family (communication processor) +----------------------------------------- + + Flavors: + PXA168, a.k.a Armada 168 + Homepage : http://www.marvell.com/application-processors/armada-100/armada-168.jsp + Product brief : http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf + Hardware manual : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf + Software manual : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf + Specification update : http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf + Boot ROM manual : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf + App node package : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf + Application processor only + Core: ARMv5 compatible Marvell PJ1 (Mohawk) + PXA910 + Homepage : http://www.marvell.com/communication-processors/pxa910/ + Product Brief : http://www.marvell.com/communication-processors/pxa910/assets/Marvell_PXA910_Platform-001_PB_final.pdf + Application processor with Communication processor + Core: ARMv5 compatible Marvell PJ1 (Mohawk) + MMP2, a.k.a Armada 610 + Product Brief : http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf + Application processor only + Core: ARMv7 compatible Sheeva PJ4 core + + Comments: + + * This line of SoCs originates from the XScale family developed by + Intel and acquired by Marvell in ~2006. All the processors of + this MMP/MMP2 family were developed by Marvell. + + * Due to their XScale origin, these SoCs have virtually nothing in + common with the other (Kirkwood, Dove, etc.) families of Marvell + SoCs, except with the PXA family of SoCs listed above. + + Linux kernel mach directory: arch/arm/mach-mmp + Linux kernel plat directory: arch/arm/plat-pxa + +Long-term plans +--------------- + + * Unify the mach-dove/, mach-mv78xx0/, mach-orion5x/ and + mach-kirkwood/ into the mach-mvebu/ to support all SoCs from the + Marvell EBU (Engineering Business Unit) in a single mach- + directory. The plat-orion/ would therefore disappear. + + * Unify the mach-mmp/ and mach-pxa/ into the same mach-pxa + directory. The plat-pxa/ would therefore disappear. + +Credits +------- + + Maen Suleiman + Lior Amsalem + Thomas Petazzoni + Andrew Lunn + Nicolas Pitre + Eric Miao -- cgit v1.2.3-70-g09d2 From 7a44e3763d7ac90524961212ef0033c32403c3eb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 04:40:57 -0300 Subject: [media] Remove documentation chunk of non-existent V4L2_CID_AUTO_FOCUS_AREA Remove documentation chunk of non-existent V4L2_CID_AUTO_FOCUS_AREA control. It fixes following build error: Error: no ID for constraint linkend: v4l2-auto-focus-area. Signed-off-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 4 ---- 1 file changed, 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index faa0fd14666..843ec47ea6b 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2614,10 +2614,6 @@ ioctls. Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION; and &VIDIOC-SUBDEV-S-SELECTION; ioctls. - - - V4L2_CID_AUTO_FOCUS_AREA control. - Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl. -- cgit v1.2.3-70-g09d2 From 571d19c39714bdea4fbffd6e03f9ff5646ac571b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 06:04:43 -0300 Subject: [media] DocBook: various version/copyright year updates - update 2011 to 2012 for copyrights - update V4L2 spec version to 3.6 - update the intro to also refer to part four: the Media Controller - fix an incorrect revision section - fix an incorrect 3.6 kernel changes section Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbapi.xml | 2 +- Documentation/DocBook/media/v4l/compat.xml | 12 ------------ Documentation/DocBook/media/v4l/v4l2.xml | 14 +++++++------- Documentation/DocBook/media_api.tmpl | 9 +++++---- 4 files changed, 13 insertions(+), 24 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml index 2ab6ddcfc4e..d36f8f93c4f 100644 --- a/Documentation/DocBook/media/dvb/dvbapi.xml +++ b/Documentation/DocBook/media/dvb/dvbapi.xml @@ -28,7 +28,7 @@ Convergence GmbH - 2009-2011 + 2009-2012 Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 843ec47ea6b..98e8d088b3a 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2468,21 +2468,9 @@ that used it. It was originally scheduled for removal in 2.6.35. reserved2 and removed V4L2_BUF_FLAG_INPUT. - - - -
- V4L2 in Linux 3.6 - Added V4L2_CAP_VIDEO_M2M and V4L2_CAP_VIDEO_M2M_MPLANE capabilities. - -
- -
- V4L2 in Linux 3.6 - Added support for frequency band enumerations: &VIDIOC-ENUM-FREQ-BANDS;. diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index eee6908c749..0292ed10688 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -145,9 +145,12 @@ applications. --> hv Added VIDIOC_ENUM_FREQ_BANDS. + + + 3.5 2012-05-07 - sa, sn + sa, sn, hv Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev selections API. Improved the description of V4L2_CID_COLORFX control, added V4L2_CID_COLORFX_CBCR control. @@ -158,11 +161,8 @@ applications. --> V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START, V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS and V4L2_CID_AUTO_FOCUS_RANGE. - - 2012-05-01 - hv - Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and - VIDIOC_DV_TIMINGS_CAP. + Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and + VIDIOC_DV_TIMINGS_CAP. @@ -472,7 +472,7 @@ and discussions on the V4L mailing list. Video for Linux Two API Specification - Revision 3.5 + Revision 3.6 &sub-common; diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index 4e8e8985cc1..f2413acfe24 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -29,7 +29,7 @@ LINUX MEDIA INFRASTRUCTURE API - 2009-2011 + 2009-2012 LinuxTV Developers @@ -53,7 +53,7 @@ Foundation. A copy of the license is included in the chapter entitled video and radio straming devices, including video cameras, analog and digital TV receiver cards, AM/FM receiver cards, streaming capture devices. - It is divided into three parts. + It is divided into four parts. The first part covers radio, capture, cameras and analog TV devices. The second part covers the @@ -62,7 +62,8 @@ Foundation. A copy of the license is included in the chapter entitled in fact it covers several different video standards including DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated to documment support also for DVB-S2, ISDB-T and ISDB-S. - The third part covers Remote Controller API + The third part covers the Remote Controller API. + The fourth part covers the Media Controller API. For additional information and for the latest development code, see: http://linuxtv.org. For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: Linux Media Mailing List (LMML).. @@ -87,7 +88,7 @@ Foundation. A copy of the license is included in the chapter entitled - 2009-2011 + 2009-2012 Mauro Carvalho Chehab -- cgit v1.2.3-70-g09d2 From 510f0a0ff0a422e0de35d3614261d9e1a4883aaa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 06:41:43 -0300 Subject: [media] DocBook: fix incorrect or missing links Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbproperty.xml | 24 +++++++++++++++++------- Documentation/DocBook/media/dvb/frontend.xml | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index e633c097a8d..bb4777a2cd9 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -567,28 +567,33 @@ typedef enum fe_delivery_system { <constant>DTV_ATSCMH_RS_FRAME_MODE</constant> RS frame mode. Possible values are: +
typedef enum atscmh_rs_frame_mode { ATSCMH_RSFRAME_PRI_ONLY = 0, ATSCMH_RSFRAME_PRI_SEC = 1, } atscmh_rs_frame_mode_t; +
<constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant> RS frame ensemble. Possible values are: +
typedef enum atscmh_rs_frame_ensemble { ATSCMH_RSFRAME_ENS_PRI = 0, ATSCMH_RSFRAME_ENS_SEC = 1, } atscmh_rs_frame_ensemble_t; +
<constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant> RS code mode (primary). Possible values are: +
typedef enum atscmh_rs_code_mode { ATSCMH_RSCODE_211_187 = 0, @@ -596,6 +601,7 @@ typedef enum atscmh_rs_code_mode { ATSCMH_RSCODE_235_187 = 2, } atscmh_rs_code_mode_t; +
<constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant> @@ -613,23 +619,27 @@ typedef enum atscmh_rs_code_mode { <constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant> Series Concatenated Convolutional Code Block Mode. Possible values are: +
typedef enum atscmh_sccc_block_mode { ATSCMH_SCCC_BLK_SEP = 0, ATSCMH_SCCC_BLK_COMB = 1, } atscmh_sccc_block_mode_t; +
<constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant> Series Concatenated Convolutional Code Rate. Possible values are: +
typedef enum atscmh_sccc_code_mode { ATSCMH_SCCC_CODE_HLF = 0, ATSCMH_SCCC_CODE_QTR = 1, } atscmh_sccc_code_mode_t; +
<constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant> @@ -784,7 +794,7 @@ typedef enum fe_hierarchy { many data types via a single multiplex. The API will soon support this at which point this section will be expanded.
-
+
<constant>DTV_ENUM_DELSYS</constant> A Multi standard frontend needs to advertise the delivery systems provided. Applications need to enumerate the provided delivery systems, before using @@ -925,13 +935,13 @@ typedef enum fe_hierarchy { DTV_ATSCMH_PRC DTV_ATSCMH_RS_FRAME_MODE DTV_ATSCMH_RS_FRAME_ENSEMBLE - DTV_ATSCMH_CODE_MODE_PRI - DTV_ATSCMH_CODE_MODE_SEC + DTV_ATSCMH_RS_CODE_MODE_PRI + DTV_ATSCMH_RS_CODE_MODE_SEC DTV_ATSCMH_SCCC_BLOCK_MODE - DTV_ATSCMH_SCCC_CODE_MODE_A - DTV_ATSCMH_SCCC_CODE_MODE_B - DTV_ATSCMH_SCCC_CODE_MODE_C - DTV_ATSCMH_SCCC_CODE_MODE_D + DTV_ATSCMH_SCCC_CODE_MODE_A + DTV_ATSCMH_SCCC_CODE_MODE_B + DTV_ATSCMH_SCCC_CODE_MODE_C + DTV_ATSCMH_SCCC_CODE_MODE_D
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml index aeaed59d0f1..81082fb84b1 100644 --- a/Documentation/DocBook/media/dvb/frontend.xml +++ b/Documentation/DocBook/media/dvb/frontend.xml @@ -66,7 +66,7 @@ supported via the new FE_GET_PROPERTY/FE_GET The usage of this field is deprecated, as it doesn't report all supported standards, and will provide an incomplete information for frontends that support multiple delivery systems. -Please use DTV_ENUM_DELSYS instead. +Please use DTV_ENUM_DELSYS instead.
-- cgit v1.2.3-70-g09d2 From a9d134f208570aee9ea8d4a2065ac21d37773385 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 05:46:16 -0300 Subject: [media] DocBook: add missing AUDIO_* ioctls Add the missing AUDIO_* ioctls and document the V4L2 replacements for the various DVB AUDIO ioctls that were (ab)used by V4L2. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/audio.xml | 113 +++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml index d6438623720..a7ea56c71a2 100644 --- a/Documentation/DocBook/media/dvb/audio.xml +++ b/Documentation/DocBook/media/dvb/audio.xml @@ -1,12 +1,16 @@ DVB Audio Device The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It can be accessed through /dev/dvb/adapter0/audio0. Data types and and -ioctl definitions can be accessed by including linux/dvb/video.h in your +ioctl definitions can be accessed by including linux/dvb/audio.h in your application. Please note that some DVB cards don’t have their own MPEG decoder, which results in the omission of the audio and video device. + +These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use +of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls +have been created to replace that functionality.
Audio Data Types @@ -558,6 +562,8 @@ role="subsection">AUDIO_SELECT_SOURCE role="subsection">AUDIO_SET_MUTE DESCRIPTION +This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2 +&VIDIOC-DECODER-CMD; with the V4L2_DEC_CMD_START_MUTE_AUDIO flag instead. This ioctl call asks the audio device to mute the stream that is currently being @@ -730,6 +736,8 @@ role="subsection">AUDIO_SET_BYPASS_MODE role="subsection">AUDIO_CHANNEL_SELECT DESCRIPTION +This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2 +V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK control instead. This ioctl call asks the Audio Device to select the requested channel if possible. @@ -772,6 +780,109 @@ role="subsection">AUDIO_CHANNEL_SELECT &return-value-dvb; +
AUDIO_BILINGUAL_CHANNEL_SELECT +DESCRIPTION + +This ioctl is obsolete. Do not use in new drivers. It has been replaced by +the V4L2 V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK control +for MPEG decoders controlled through V4L2. + +This ioctl call asks the Audio Device to select the requested channel for bilingual streams if possible. + + +SYNOPSIS + + +int ioctl(int fd, int request = + AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this + command. + + +audio_channel_select_t +ch + +Select the output format of the audio (mono left/right, + stereo). + + + +&return-value-dvb; + +
AUDIO_GET_PTS +DESCRIPTION + +This ioctl is obsolete. Do not use in new drivers. If you need this functionality, +then please contact the linux-media mailing list (&v4l-ml;). + +This ioctl call asks the Audio Device to return the current PTS timestamp. + + +SYNOPSIS + + +int ioctl(int fd, int request = + AUDIO_GET_PTS, __u64 *pts); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals AUDIO_GET_PTS for this + command. + + +__u64 *pts + + +Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1. + + +The PTS should belong to the currently played +frame if possible, but may also be a value close to it +like the PTS of the last decoded frame or the last PTS +extracted by the PES parser. + + +&return-value-dvb; +
AUDIO_GET_STATUS DESCRIPTION -- cgit v1.2.3-70-g09d2 From 8465efbb9a488628209d91ec7dbc436d89b13485 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 07:27:12 -0300 Subject: [media] DocBook: add missing DVB video ioctls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/video.xml | 333 +++++++++++++++++++++++++++++- 1 file changed, 322 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml index 25fb823226b..3ea1ca7e785 100644 --- a/Documentation/DocBook/media/dvb/video.xml +++ b/Documentation/DocBook/media/dvb/video.xml @@ -15,6 +15,10 @@ the audio and video device as well as the video4linux device. The ioctls that deal with SPUs (sub picture units) and navigation packets are only supported on some MPEG decoders made for DVD playback. + +These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use +of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls +have been created to replace that functionality.
Video Data Types @@ -55,7 +59,7 @@ typedef enum {
-video stream source +video_stream_source_t The video stream source is set through the VIDEO_SELECT_SOURCE call and can take the following values, depending on whether we are replaying from an internal (demuxer) or external (user write) source. @@ -76,7 +80,7 @@ call.
-video play state +video_play_state_t The following values can be returned by the VIDEO_GET_STATUS call representing the state of video playback. @@ -90,9 +94,9 @@ typedef enum {
+struct video_command The structure must be zeroed before use by the application This ensures it can be extended safely in the future. -struct video-command struct video_command { __u32 cmd; @@ -121,7 +125,7 @@ struct video_command {
-struct video_size-t +video_size_t typedef struct { int w; @@ -217,7 +221,7 @@ bits set according to the hardwares capabilities.
-video system +video_system_t A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The following system types can be set: @@ -263,7 +267,7 @@ call expects the following format for that information:
-video SPU +struct video_spu Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the following format: @@ -277,12 +281,12 @@ following format:
-video SPU palette +struct video_spu_palette The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE: typedef - struct video_spu_palette{ + struct video_spu_palette { int length; uint8_t ⋆palette; } video_spu_palette_t; @@ -290,13 +294,13 @@ following format:
-video NAVI pack +struct video_navi_pack In order to get the navigational data the following structure has to be passed to the ioctl VIDEO_GET_NAVI: typedef - struct video_navi_pack{ + struct video_navi_pack { int length; /⋆ 0 ... 1024 ⋆/ uint8_t data[1024]; } video_navi_pack_t; @@ -305,7 +309,7 @@ VIDEO_GET_NAVI:
-video attributes +video_attributes_t The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES: @@ -541,6 +545,8 @@ VIDEO_GET_NAVI: role="subsection">VIDEO_STOP DESCRIPTION +This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2 +&VIDIOC-DECODER-CMD; instead. This ioctl call asks the Video Device to stop playing the current stream. @@ -598,6 +604,8 @@ role="subsection">VIDEO_STOP role="subsection">VIDEO_PLAY DESCRIPTION +This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2 +&VIDIOC-DECODER-CMD; instead. This ioctl call asks the Video Device to start playing a video stream from the @@ -634,6 +642,8 @@ role="subsection">VIDEO_PLAY role="subsection">VIDEO_FREEZE DESCRIPTION +This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2 +&VIDIOC-DECODER-CMD; instead. This ioctl call suspends the live video stream being played. Decoding @@ -674,6 +684,8 @@ role="subsection">VIDEO_FREEZE role="subsection">VIDEO_CONTINUE DESCRIPTION +This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2 +&VIDIOC-DECODER-CMD; instead. This ioctl call restarts decoding and playing processes of the video stream @@ -710,6 +722,9 @@ role="subsection">VIDEO_CONTINUE role="subsection">VIDEO_SELECT_SOURCE DESCRIPTION +This ioctl is for DVB devices only. This ioctl was also supported by the +V4L2 ivtv driver, but that has been replaced by the ivtv-specific +IVTV_IOC_PASSTHROUGH_MODE ioctl. This ioctl call informs the video device which source shall be used for the input @@ -845,10 +860,160 @@ role="subsection">VIDEO_GET_STATUS &return-value-dvb; +
VIDEO_GET_FRAME_COUNT +DESCRIPTION + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this +ioctl has been replaced by the V4L2_CID_MPEG_VIDEO_DEC_FRAME control. + +This ioctl call asks the Video Device to return the number of displayed frames +since the decoder was started. + + +SYNOPSIS + + +int ioctl(int fd, int request = + VIDEO_GET_FRAME_COUNT, __u64 *pts); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals VIDEO_GET_FRAME_COUNT for this + command. + + +__u64 *pts + + +Returns the number of frames displayed since the decoder was started. + + + +&return-value-dvb; + +
VIDEO_GET_PTS +DESCRIPTION + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this +ioctl has been replaced by the V4L2_CID_MPEG_VIDEO_DEC_PTS control. + +This ioctl call asks the Video Device to return the current PTS timestamp. + + +SYNOPSIS + + +int ioctl(int fd, int request = + VIDEO_GET_PTS, __u64 *pts); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals VIDEO_GET_PTS for this + command. + + +__u64 *pts + + +Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1. + + +The PTS should belong to the currently played +frame if possible, but may also be a value close to it +like the PTS of the last decoded frame or the last PTS +extracted by the PES parser. + + +&return-value-dvb; + +
VIDEO_GET_FRAME_RATE +DESCRIPTION + + +This ioctl call asks the Video Device to return the current framerate. + + +SYNOPSIS + + +int ioctl(int fd, int request = + VIDEO_GET_FRAME_RATE, unsigned int *rate); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals VIDEO_GET_FRAME_RATE for this + command. + + +unsigned int *rate + + +Returns the framerate in number of frames per 1000 seconds. + + + +&return-value-dvb; +
VIDEO_GET_EVENT DESCRIPTION +This ioctl is for DVB devices only. To get events from a V4L2 decoder use the V4L2 +&VIDIOC-DQEVENT; ioctl instead. This ioctl call returns an event of type video_event if available. If an event is @@ -914,6 +1079,152 @@ role="subsection">VIDEO_GET_EVENT +
VIDEO_COMMAND +DESCRIPTION + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this +ioctl has been replaced by the &VIDIOC-DECODER-CMD; ioctl. + +This ioctl commands the decoder. The video_command struct +is a subset of the v4l2_decoder_cmd struct, so refer to the +&VIDIOC-DECODER-CMD; documentation for more information. + + +SYNOPSIS + + +int ioctl(int fd, int request = + VIDEO_COMMAND, struct video_command *cmd); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals VIDEO_COMMAND for this + command. + + +struct video_command *cmd + + +Commands the decoder. + + + +&return-value-dvb; + +
VIDEO_TRY_COMMAND +DESCRIPTION + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this +ioctl has been replaced by the &VIDIOC-TRY-DECODER-CMD; ioctl. + +This ioctl tries a decoder command. The video_command struct +is a subset of the v4l2_decoder_cmd struct, so refer to the +&VIDIOC-TRY-DECODER-CMD; documentation for more information. + + +SYNOPSIS + + +int ioctl(int fd, int request = + VIDEO_TRY_COMMAND, struct video_command *cmd); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals VIDEO_TRY_COMMAND for this + command. + + +struct video_command *cmd + + +Try a decoder command. + + + +&return-value-dvb; + +
VIDEO_GET_SIZE +DESCRIPTION + + +This ioctl returns the size and aspect ratio. + + +SYNOPSIS + + +int ioctl(int fd, int request = + VIDEO_GET_SIZE, video_size_t *size); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals VIDEO_GET_SIZE for this + command. + + +video_size_t *size + + +Returns the size and aspect ratio. + + + +&return-value-dvb; +
VIDEO_SET_DISPLAY_FORMAT DESCRIPTION -- cgit v1.2.3-70-g09d2 From 3612378c5167004b3538d42dc16a184893ff6fbb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 07:42:08 -0300 Subject: [media] DocBook: add stubs for the undocumented DVB net ioctls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/net.xml | 127 ++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml index 67d37e5ce59..a193e86941b 100644 --- a/Documentation/DocBook/media/dvb/net.xml +++ b/Documentation/DocBook/media/dvb/net.xml @@ -26,4 +26,131 @@ struct dvb_net_if { DVB net Function Calls To be written… + +
NET_ADD_IF +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = NET_ADD_IF, + struct dvb_net_if *if); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals NET_ADD_IF for this command. + + +struct dvb_net_if *if + + +Undocumented. + + +&return-value-dvb; +
+ +
NET_REMOVE_IF +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = NET_REMOVE_IF); + + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals NET_REMOVE_IF for this command. + + +&return-value-dvb; +
+ +
NET_GET_IF +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = NET_GET_IF, + struct dvb_net_if *if); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals NET_GET_IF for this command. + + +struct dvb_net_if *if + + +Undocumented. + + +&return-value-dvb; +
-- cgit v1.2.3-70-g09d2 From 6406e311c61997b8e19aff6ac2c7179d10aed472 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 07:50:39 -0300 Subject: [media] DocBook: add stubs for missing DVB DMX ioctls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/demux.xml | 230 +++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml index 37c17908aa4..86de89cfbd6 100644 --- a/Documentation/DocBook/media/dvb/demux.xml +++ b/Documentation/DocBook/media/dvb/demux.xml @@ -899,4 +899,232 @@ typedef enum { Invalid stc number. -
+
+ +
DMX_GET_PES_PIDS +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = DMX_GET_PES_PIDS, + __u16[5]); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals DMX_GET_PES_PIDS for this command. + + +__u16[5] + + +Undocumented. + + +&return-value-dvb; +
+ +
DMX_GET_CAPS +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = DMX_GET_CAPS, + dmx_caps_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals DMX_GET_CAPS for this command. + + +dmx_caps_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
DMX_SET_SOURCE +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = DMX_SET_SOURCE, + dmx_source_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals DMX_SET_SOURCE for this command. + + +dmx_source_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
DMX_ADD_PID +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = DMX_ADD_PID, + __u16 *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals DMX_ADD_PID for this command. + + +__u16 * + + +Undocumented. + + +&return-value-dvb; +
+ +
DMX_REMOVE_PID +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = DMX_REMOVE_PID, + __u16 *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals DMX_REMOVE_PID for this command. + + +__u16 * + + +Undocumented. + + +&return-value-dvb; +
+ + + -- cgit v1.2.3-70-g09d2 From fdeae29005aae41837e70c395c8290a8297ca677 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2012 07:59:50 -0300 Subject: [media] DocBook: add stubs for missing DVB CA ioctls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/ca.xml | 353 +++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml index 5c4adb44b1c..85eaf4fe293 100644 --- a/Documentation/DocBook/media/dvb/ca.xml +++ b/Documentation/DocBook/media/dvb/ca.xml @@ -226,4 +226,357 @@ typedef struct ca_pid { + +
CA_RESET +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_RESET); + + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_RESET for this command. + + +&return-value-dvb; +
+ +
CA_GET_CAP +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_GET_CAP, + ca_caps_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_GET_CAP for this command. + + +ca_caps_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
CA_GET_SLOT_INFO +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_GET_SLOT_INFO, + ca_slot_info_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_GET_SLOT_INFO for this command. + + +ca_slot_info_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
CA_GET_DESCR_INFO +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_GET_DESCR_INFO, + ca_descr_info_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_GET_DESCR_INFO for this command. + + +ca_descr_info_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
CA_GET_MSG +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_GET_MSG, + ca_msg_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_GET_MSG for this command. + + +ca_msg_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
CA_SEND_MSG +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_SEND_MSG, + ca_msg_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_SEND_MSG for this command. + + +ca_msg_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
CA_SET_DESCR +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_SET_DESCR, + ca_descr_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_SET_DESCR for this command. + + +ca_descr_t * + + +Undocumented. + + +&return-value-dvb; +
+ +
CA_SET_PID +DESCRIPTION + + +This ioctl is undocumented. Documentation is welcome. + + +SYNOPSIS + + +int ioctl(fd, int request = CA_SET_PID, + ca_pid_t *); + + +PARAMETERS + + +int fd + +File descriptor returned by a previous call to open(). + + +int request + +Equals CA_SET_PID for this command. + + +ca_pid_t * + + +Undocumented. + + +&return-value-dvb; +
+ -- cgit v1.2.3-70-g09d2 From 224b6642f5e82a1b21f6b552c799fa02e527d542 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 12 Aug 2012 22:33:21 -0300 Subject: [media] add DTMB support for DVB API Cc: Patrick Boettcher Cc: Andreas Oberritter Cc: Mauro Carvalho Chehab Acked-by: Patrick Boettcher Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbproperty.xml | 40 ++++++++++++++++++++++++- drivers/media/dvb/dvb-core/dvb_frontend.c | 14 +++++++-- drivers/media/dvb/dvb-core/dvb_frontend.h | 2 ++ drivers/media/dvb/frontends/atbm8830.c | 2 +- drivers/media/dvb/frontends/lgs8gl5.c | 2 +- drivers/media/dvb/frontends/lgs8gxx.c | 2 +- include/linux/dvb/frontend.h | 21 +++++++++++-- include/linux/dvb/version.h | 2 +- 8 files changed, 74 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index bb4777a2cd9..5aea35e66af 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -194,6 +194,7 @@ get/set up to 64 properties. The actual meaning of each property is described on APSK_16, APSK_32, DQPSK, + QAM_4_NR, } fe_modulation_t; @@ -265,6 +266,7 @@ typedef enum fe_code_rate { FEC_AUTO, FEC_3_5, FEC_9_10, + FEC_2_5, } fe_code_rate_t; which correspond to error correction rates of 1/2, 2/3, etc., @@ -351,7 +353,7 @@ typedef enum fe_delivery_system { SYS_ISDBC, SYS_ATSC, SYS_ATSCMH, - SYS_DMBTH, + SYS_DTMB, SYS_CMMB, SYS_DAB, SYS_DVBT2, @@ -735,6 +737,9 @@ typedef enum fe_guard_interval { GUARD_INTERVAL_1_128, GUARD_INTERVAL_19_128, GUARD_INTERVAL_19_256, + GUARD_INTERVAL_PN420, + GUARD_INTERVAL_PN595, + GUARD_INTERVAL_PN945, } fe_guard_interval_t; @@ -743,6 +748,7 @@ typedef enum fe_guard_interval { try to find the correct guard interval (if capable) and will use TMCC to fill in the missing parameters. 2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present + 3) DTMB specifies PN420, PN595 and PN945.
<constant>DTV_TRANSMISSION_MODE</constant> @@ -759,6 +765,8 @@ typedef enum fe_transmit_mode { TRANSMISSION_MODE_1K, TRANSMISSION_MODE_16K, TRANSMISSION_MODE_32K, + TRANSMISSION_MODE_C1, + TRANSMISSION_MODE_C3780, } fe_transmit_mode_t; Notes: @@ -770,6 +778,7 @@ typedef enum fe_transmit_mode { use TMCC to fill in the missing parameters. 3) DVB-T specifies 2K and 8K as valid sizes. 4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K. + 5) DTMB specifies C1 and C3780.
<constant>DTV_HIERARCHY</constant> @@ -806,6 +815,17 @@ typedef enum fe_hierarchy { FE_GET_INFO. In the case of a legacy frontend, the result is just the same as with FE_GET_INFO, but in a more structured format
+
+ <constant>DTV_INTERLEAVING</constant> + Interleaving mode + +enum fe_interleaving { + INTERLEAVING_NONE, + INTERLEAVING_240, + INTERLEAVING_720, +}; + +
Properties used on terrestrial delivery systems @@ -944,6 +964,24 @@ typedef enum fe_hierarchy { DTV_ATSCMH_SCCC_CODE_MODE_D
+
+ DTMB delivery system + The following parameters are valid for DTMB: + + DTV_API_VERSION + DTV_DELIVERY_SYSTEM + DTV_TUNE + DTV_CLEAR + DTV_FREQUENCY + DTV_MODULATION + DTV_BANDWIDTH_HZ + DTV_INVERSION + DTV_INNER_FEC + DTV_GUARD_INTERVAL + DTV_TRANSMISSION_MODE + DTV_INTERLEAVING + +
Properties used on cable delivery systems diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 746dfd86aea..3a0f2454719 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -179,7 +179,7 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system) case SYS_DVBT: case SYS_DVBT2: case SYS_ISDBT: - case SYS_DMBTH: + case SYS_DTMB: return DVBV3_OFDM; case SYS_ATSC: case SYS_ATSCMH: @@ -997,6 +997,7 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_CODE_RATE_LP, 1, 0), _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0), _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0), + _DTV_CMD(DTV_INTERLEAVING, 1, 0), _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0), _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0), @@ -1028,6 +1029,7 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), _DTV_CMD(DTV_HIERARCHY, 0, 0), + _DTV_CMD(DTV_INTERLEAVING, 0, 0), _DTV_CMD(DTV_ENUM_DELSYS, 0, 0), @@ -1326,6 +1328,9 @@ static int dtv_property_process_get(struct dvb_frontend *fe, case DTV_HIERARCHY: tvp->u.data = c->hierarchy; break; + case DTV_INTERLEAVING: + tvp->u.data = c->interleaving; + break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: @@ -1593,7 +1598,7 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) * The DVBv3 or DVBv5 call is requesting a different system. So, * emulation is needed. * - * Emulate newer delivery systems like ISDBT, DVBT and DMBTH + * Emulate newer delivery systems like ISDBT, DVBT and DTMB * for older DVBv5 applications. The emulation will try to use * the auto mode for most things, and will assume that the desired * delivery system is the last one at the ops.delsys[] array @@ -1715,6 +1720,9 @@ static int dtv_property_process_set(struct dvb_frontend *fe, case DTV_HIERARCHY: c->hierarchy = tvp->u.data; break; + case DTV_INTERLEAVING: + c->interleaving = tvp->u.data; + break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: @@ -2012,7 +2020,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe) case SYS_DVBT: case SYS_DVBT2: case SYS_ISDBT: - case SYS_DMBTH: + case SYS_DTMB: fepriv->min_delay = HZ / 20; fepriv->step_size = fe->ops.info.frequency_stepsize * 2; fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 7c64c09103a..de410cc94fb 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -354,6 +354,8 @@ struct dtv_frontend_properties { fe_delivery_system_t delivery_system; + enum fe_interleaving interleaving; + /* ISDB-T specifics */ u8 isdbt_partial_reception; u8 isdbt_sb_mode; diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c index a2261ea2cf8..4e11dc4b133 100644 --- a/drivers/media/dvb/frontends/atbm8830.c +++ b/drivers/media/dvb/frontends/atbm8830.c @@ -428,7 +428,7 @@ static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } static struct dvb_frontend_ops atbm8830_ops = { - .delsys = { SYS_DMBTH }, + .delsys = { SYS_DTMB }, .info = { .name = "AltoBeam ATBM8830/8831 DMB-TH", .frequency_min = 474000000, diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c index 2cec8041a10..416cce3fefc 100644 --- a/drivers/media/dvb/frontends/lgs8gl5.c +++ b/drivers/media/dvb/frontends/lgs8gl5.c @@ -412,7 +412,7 @@ EXPORT_SYMBOL(lgs8gl5_attach); static struct dvb_frontend_ops lgs8gl5_ops = { - .delsys = { SYS_DMBTH }, + .delsys = { SYS_DTMB }, .info = { .name = "Legend Silicon LGS-8GL5 DMB-TH", .frequency_min = 474000000, diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index c2ea2749ebe..3c92f36ea5c 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -995,7 +995,7 @@ static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } static struct dvb_frontend_ops lgs8gxx_ops = { - .delsys = { SYS_DMBTH }, + .delsys = { SYS_DTMB }, .info = { .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH", .frequency_min = 474000000, diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index f50d4058c5f..2dd5823b59b 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -152,6 +152,7 @@ typedef enum fe_code_rate { FEC_AUTO, FEC_3_5, FEC_9_10, + FEC_2_5, } fe_code_rate_t; @@ -169,6 +170,7 @@ typedef enum fe_modulation { APSK_16, APSK_32, DQPSK, + QAM_4_NR, } fe_modulation_t; typedef enum fe_transmit_mode { @@ -179,6 +181,8 @@ typedef enum fe_transmit_mode { TRANSMISSION_MODE_1K, TRANSMISSION_MODE_16K, TRANSMISSION_MODE_32K, + TRANSMISSION_MODE_C1, + TRANSMISSION_MODE_C3780, } fe_transmit_mode_t; #if defined(__DVB_CORE__) || !defined (__KERNEL__) @@ -202,6 +206,9 @@ typedef enum fe_guard_interval { GUARD_INTERVAL_1_128, GUARD_INTERVAL_19_128, GUARD_INTERVAL_19_256, + GUARD_INTERVAL_PN420, + GUARD_INTERVAL_PN595, + GUARD_INTERVAL_PN945, } fe_guard_interval_t; @@ -213,6 +220,11 @@ typedef enum fe_hierarchy { HIERARCHY_AUTO } fe_hierarchy_t; +enum fe_interleaving { + INTERLEAVING_NONE, + INTERLEAVING_240, + INTERLEAVING_720, +}; #if defined(__DVB_CORE__) || !defined (__KERNEL__) struct dvb_qpsk_parameters { @@ -337,7 +349,9 @@ struct dvb_frontend_event { #define DTV_ATSCMH_SCCC_CODE_MODE_C 58 #define DTV_ATSCMH_SCCC_CODE_MODE_D 59 -#define DTV_MAX_COMMAND DTV_ATSCMH_SCCC_CODE_MODE_D +#define DTV_INTERLEAVING 60 + +#define DTV_MAX_COMMAND DTV_INTERLEAVING typedef enum fe_pilot { PILOT_ON, @@ -366,7 +380,7 @@ typedef enum fe_delivery_system { SYS_ISDBC, SYS_ATSC, SYS_ATSCMH, - SYS_DMBTH, + SYS_DTMB, SYS_CMMB, SYS_DAB, SYS_DVBT2, @@ -374,8 +388,9 @@ typedef enum fe_delivery_system { SYS_DVBC_ANNEX_C, } fe_delivery_system_t; - +/* backward compatibility */ #define SYS_DVBC_ANNEX_AC SYS_DVBC_ANNEX_A +#define SYS_DMBTH SYS_DTMB /* DMB-TH is legacy name, use DTMB instead */ /* ATSC-MH */ diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 43d9e8d462d..70c2c7edcc7 100644 --- a/include/linux/dvb/version.h +++ b/include/linux/dvb/version.h @@ -24,6 +24,6 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 6 +#define DVB_API_VERSION_MINOR 7 #endif /*_DVBVERSION_H_*/ -- cgit v1.2.3-70-g09d2 From 8746adda9eec9da9a2c5c2944740163628bd1d68 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 12 Aug 2012 22:33:22 -0300 Subject: [media] DVB API: add INTERLEAVING_AUTO After thinking twice, I ended up adding own value for AUTO interleaving instead of using NONE. API minor number is not needed to increase as that patch should be the same Kernel as interleaving parameter is initially added. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/dvbproperty.xml | 1 + include/linux/dvb/frontend.h | 1 + 2 files changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 5aea35e66af..eddfe6f9a75 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -821,6 +821,7 @@ typedef enum fe_hierarchy { enum fe_interleaving { INTERLEAVING_NONE, + INTERLEAVING_AUTO, INTERLEAVING_240, INTERLEAVING_720, }; diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index 2dd5823b59b..c92b4d64e01 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -222,6 +222,7 @@ typedef enum fe_hierarchy { enum fe_interleaving { INTERLEAVING_NONE, + INTERLEAVING_AUTO, INTERLEAVING_240, INTERLEAVING_720, }; -- cgit v1.2.3-70-g09d2 From 0d27bbfe81cb087748dc1511683bd3e7335a7da5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 13 Aug 2012 17:03:12 -0300 Subject: [media] frontend.h, Docbook: Improve status documentation No functional changes. It just improves the description of the frontend status, using Documentation/kernel-doc-nano-HOWTO.txt for the status enumeration, and a table inside the DocBook. Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/frontend.xml | 48 +++++++++++++++++++++------- include/linux/dvb/frontend.h | 29 +++++++++++------ 2 files changed, 57 insertions(+), 20 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml index 81082fb84b1..1ab2e1af81f 100644 --- a/Documentation/DocBook/media/dvb/frontend.xml +++ b/Documentation/DocBook/media/dvb/frontend.xml @@ -207,18 +207,44 @@ spec. Several functions of the frontend device use the fe_status data type defined by - typedef enum fe_status { - FE_HAS_SIGNAL = 0x01, /⋆ found something above the noise level ⋆/ - FE_HAS_CARRIER = 0x02, /⋆ found a DVB signal ⋆/ - FE_HAS_VITERBI = 0x04, /⋆ FEC is stable ⋆/ - FE_HAS_SYNC = 0x08, /⋆ found sync bytes ⋆/ - FE_HAS_LOCK = 0x10, /⋆ everything's working... ⋆/ - FE_TIMEDOUT = 0x20, /⋆ no lock within the last ~2 seconds ⋆/ - FE_REINIT = 0x40 /⋆ frontend was reinitialized, ⋆/ - } fe_status_t; /⋆ application is recommned to reset ⋆/ +typedef enum fe_status { + FE_HAS_SIGNAL = 0x01, + FE_HAS_CARRIER = 0x02, + FE_HAS_VITERBI = 0x04, + FE_HAS_SYNC = 0x08, + FE_HAS_LOCK = 0x10, + FE_TIMEDOUT = 0x20, + FE_REINIT = 0x40, +} fe_status_t; -to indicate the current state and/or state changes of the frontend hardware. - +to indicate the current state and/or state changes of the frontend hardware: + + + + +FE_HAS_SIGNAL +The frontend has found something above the noise level + +FE_HAS_CARRIER +The frontend has found a DVB signal + +FE_HAS_VITERBI +The frontend FEC code is stable + +FE_HAS_SYNC +Syncronization bytes was found + +FE_HAS_LOCK +The DVB were locked and everything is working + +FE_TIMEDOUT +no lock within the last about 2 seconds + +FE_REINIT +The frontend was reinitialized, application is +recommended to reset DiSEqC, tone and parameters + +
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index c92b4d64e01..bb51edfc72a 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -121,16 +121,27 @@ typedef enum fe_sec_mini_cmd { } fe_sec_mini_cmd_t; +/** + * enum fe_status - enumerates the possible frontend status + * @FE_HAS_SIGNAL: found something above the noise level + * @FE_HAS_CARRIER: found a DVB signal + * @FE_HAS_VITERBI: FEC is stable + * @FE_HAS_SYNC: found sync bytes + * @FE_HAS_LOCK: everything's working + * @FE_TIMEDOUT: no lock within the last ~2 seconds + * @FE_REINIT: frontend was reinitialized, application is recommended + * to reset DiSEqC, tone and parameters + */ + typedef enum fe_status { - FE_HAS_SIGNAL = 0x01, /* found something above the noise level */ - FE_HAS_CARRIER = 0x02, /* found a DVB signal */ - FE_HAS_VITERBI = 0x04, /* FEC is stable */ - FE_HAS_SYNC = 0x08, /* found sync bytes */ - FE_HAS_LOCK = 0x10, /* everything's working... */ - FE_TIMEDOUT = 0x20, /* no lock within the last ~2 seconds */ - FE_REINIT = 0x40 /* frontend was reinitialized, */ -} fe_status_t; /* application is recommended to reset */ - /* DiSEqC, tone and parameters */ + FE_HAS_SIGNAL = 0x01, + FE_HAS_CARRIER = 0x02, + FE_HAS_VITERBI = 0x04, + FE_HAS_SYNC = 0x08, + FE_HAS_LOCK = 0x10, + FE_TIMEDOUT = 0x20, + FE_REINIT = 0x40, +} fe_status_t; typedef enum fe_spectral_inversion { INVERSION_OFF, -- cgit v1.2.3-70-g09d2 From fc16123937ccfc2f2bbe98a5e41c4f6d26a22b24 Mon Sep 17 00:00:00 2001 From: Raghavendra K T Date: Tue, 7 Aug 2012 13:09:59 +0530 Subject: KVM: Add documentation on hypercalls Thanks Alex for KVM_HC_FEATURES inputs and Jan for VAPIC_POLL_IRQ, and Peter (HPA) for suggesting hypercall ABI addition. Signed-off-by: Raghavendra K T Signed-off-by: Marcelo Tosatti --- Documentation/virtual/kvm/hypercalls.txt | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/virtual/kvm/hypercalls.txt (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt new file mode 100644 index 00000000000..ea113b5d87a --- /dev/null +++ b/Documentation/virtual/kvm/hypercalls.txt @@ -0,0 +1,66 @@ +Linux KVM Hypercall: +=================== +X86: + KVM Hypercalls have a three-byte sequence of either the vmcall or the vmmcall + instruction. The hypervisor can replace it with instructions that are + guaranteed to be supported. + + Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively. + The hypercall number should be placed in rax and the return value will be + placed in rax. No other registers will be clobbered unless explicitly stated + by the particular hypercall. + +S390: + R2-R7 are used for parameters 1-6. In addition, R1 is used for hypercall + number. The return value is written to R2. + + S390 uses diagnose instruction as hypercall (0x500) along with hypercall + number in R1. + + PowerPC: + It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers. + Return value is placed in R3. + + KVM hypercalls uses 4 byte opcode, that are patched with 'hypercall-instructions' + property inside the device tree's /hypervisor node. + For more information refer to Documentation/virtual/kvm/ppc-pv.txt + +KVM Hypercalls Documentation +=========================== +The template for each hypercall is: +1. Hypercall name. +2. Architecture(s) +3. Status (deprecated, obsolete, active) +4. Purpose + +1. KVM_HC_VAPIC_POLL_IRQ +------------------------ +Architecture: x86 +Status: active +Purpose: Trigger guest exit so that the host can check for pending +interrupts on reentry. + +2. KVM_HC_MMU_OP +------------------------ +Architecture: x86 +Status: deprecated. +Purpose: Support MMU operations such as writing to PTE, +flushing TLB, release PT. + +3. KVM_HC_FEATURES +------------------------ +Architecture: PPC +Status: active +Purpose: Expose hypercall availability to the guest. On x86 platforms, cpuid +used to enumerate which hypercalls are available. On PPC, either device tree +based lookup ( which is also what EPAPR dictates) OR KVM specific enumeration +mechanism (which is this hypercall) can be used. + +4. KVM_HC_PPC_MAP_MAGIC_PAGE +------------------------ +Architecture: PPC +Status: active +Purpose: To enable communication between the hypervisor and guest there is a +shared page that contains parts of supervisor visible register state. +The guest can map this shared page to access its supervisor register through +memory using this hypercall. -- cgit v1.2.3-70-g09d2 From 6024f1a4dd066d54213cc17f821e19e3062298ca Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 7 Aug 2012 13:10:26 +0530 Subject: KVM: Add ppc hypercall documentation Signed-off-by: Alexander Graf Signed-off-by: Raghavendra K T Signed-off-by: Marcelo Tosatti --- Documentation/virtual/kvm/ppc-pv.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt index 4911cf95c67..4cd076febb0 100644 --- a/Documentation/virtual/kvm/ppc-pv.txt +++ b/Documentation/virtual/kvm/ppc-pv.txt @@ -174,3 +174,25 @@ following: That way we can inject an arbitrary amount of code as replacement for a single instruction. This allows us to check for pending interrupts when setting EE=1 for example. + +Hypercall ABIs in KVM on PowerPC +================================= +1) KVM hypercalls (ePAPR) + +These are ePAPR compliant hypercall implementation (mentioned above). Even +generic hypercalls are implemented here, like the ePAPR idle hcall. These are +available on all targets. + +2) PAPR hypercalls + +PAPR hypercalls are needed to run server PowerPC PAPR guests (-M pseries in QEMU). +These are the same hypercalls that pHyp, the POWER hypervisor implements. Some of +them are handled in the kernel, some are handled in user space. This is only +available on book3s_64. + +3) OSI hypercalls + +Mac-on-Linux is another user of KVM on PowerPC, which has its own hypercall (long +before KVM). This is supported to maintain compatibility. All these hypercalls get +forwarded to user space. This is only useful on book3s_32, but can be used with +book3s_64 as well. -- cgit v1.2.3-70-g09d2 From 251658e5185e69bd8563737e94d877fed788bfb5 Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 26 Jul 2012 07:20:36 -0300 Subject: [media] Schedule removal of i.MX25 support in mx2_camera.c Support for i.MX25 in mx2_camera.c has been broken for a year. Furthermore, i.MX25 video capture HW doesn't have much in common with i.MX27. A separate driver would be desirable. Signed-off-by: Javier Martin Signed-off-by: Mauro Carvalho Chehab --- Documentation/feature-removal-schedule.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index afaff312bf4..a52924ef128 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -6,6 +6,15 @@ be removed from this file. The suggested deprecation period is 3 releases. --------------------------- +What: support for i.mx25 in mx2_camera.c +When: v3.8 +Why: it's been broken for a year. Furthermore, i.MX25 video capture + HW doesn't have much in common with i.MX27. A separate driver + will be needed for it. +Who: Javier Martin + +--------------------------- + What: ddebug_query="query" boot cmdline param When: v3.8 Why: obsoleted by dyndbg="query" and module.dyndbg="query" -- cgit v1.2.3-70-g09d2 From 786baecfe78f8e25547c628b48a60fc8e5636056 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Jun 2012 16:35:56 -0300 Subject: [media] dvb-usb: move it to drivers/media/usb/dvb-usb As media/dvb will be removed, move it to a proper place. Signed-off-by: Mauro Carvalho Chehab --- Documentation/dvb/README.dvb-usb | 2 +- drivers/media/Kconfig | 1 + drivers/media/Makefile | 2 +- drivers/media/dvb/Kconfig | 8 - drivers/media/dvb/Makefile | 5 - drivers/media/dvb/dvb-usb-v2/Kconfig | 146 - drivers/media/dvb/dvb-usb-v2/Makefile | 48 - drivers/media/dvb/dvb-usb-v2/af9015.c | 1434 ------ drivers/media/dvb/dvb-usb-v2/af9015.h | 170 - drivers/media/dvb/dvb-usb-v2/af9035.c | 1086 ----- drivers/media/dvb/dvb-usb-v2/af9035.h | 111 - drivers/media/dvb/dvb-usb-v2/anysee.c | 1324 ------ drivers/media/dvb/dvb-usb-v2/anysee.h | 356 -- drivers/media/dvb/dvb-usb-v2/au6610.c | 206 - drivers/media/dvb/dvb-usb-v2/au6610.h | 32 - drivers/media/dvb/dvb-usb-v2/az6007.c | 919 ---- drivers/media/dvb/dvb-usb-v2/ce6230.c | 287 -- drivers/media/dvb/dvb-usb-v2/ce6230.h | 61 - drivers/media/dvb/dvb-usb-v2/cypress_firmware.c | 125 - drivers/media/dvb/dvb-usb-v2/cypress_firmware.h | 31 - drivers/media/dvb/dvb-usb-v2/dvb_usb.h | 389 -- drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h | 35 - drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c | 997 ----- drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c | 77 - drivers/media/dvb/dvb-usb-v2/ec168.c | 376 -- drivers/media/dvb/dvb-usb-v2/ec168.h | 63 - drivers/media/dvb/dvb-usb-v2/gl861.c | 175 - drivers/media/dvb/dvb-usb-v2/gl861.h | 12 - drivers/media/dvb/dvb-usb-v2/it913x.c | 799 ---- drivers/media/dvb/dvb-usb-v2/lmedm04.c | 1369 ------ drivers/media/dvb/dvb-usb-v2/lmedm04.h | 175 - drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c | 612 --- drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h | 55 - drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c | 763 ---- drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h | 56 - drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c | 850 ---- drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h | 35 - drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c | 343 -- drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h | 53 - drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h | 179 - drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c | 527 --- drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h | 89 - drivers/media/dvb/dvb-usb-v2/mxl111sf.c | 1431 ------ drivers/media/dvb/dvb-usb-v2/mxl111sf.h | 160 - drivers/media/dvb/dvb-usb-v2/rtl28xxu.c | 1259 ------ drivers/media/dvb/dvb-usb-v2/rtl28xxu.h | 254 -- drivers/media/dvb/dvb-usb-v2/usb_urb.c | 357 -- drivers/media/dvb/dvb-usb/Kconfig | 313 -- drivers/media/dvb/dvb-usb/Makefile | 82 - drivers/media/dvb/dvb-usb/a800.c | 191 - drivers/media/dvb/dvb-usb/af9005-fe.c | 1487 ------- drivers/media/dvb/dvb-usb/af9005-remote.c | 157 - drivers/media/dvb/dvb-usb/af9005-script.h | 203 - drivers/media/dvb/dvb-usb/af9005.c | 1117 ----- drivers/media/dvb/dvb-usb/af9005.h | 3496 --------------- drivers/media/dvb/dvb-usb/az6027.c | 1182 ----- drivers/media/dvb/dvb-usb/az6027.h | 14 - drivers/media/dvb/dvb-usb/cinergyT2-core.c | 254 -- drivers/media/dvb/dvb-usb/cinergyT2-fe.c | 356 -- drivers/media/dvb/dvb-usb/cinergyT2.h | 95 - drivers/media/dvb/dvb-usb/cxusb.c | 2043 --------- drivers/media/dvb/dvb-usb/cxusb.h | 35 - drivers/media/dvb/dvb-usb/dib0700.h | 75 - drivers/media/dvb/dvb-usb/dib0700_core.c | 845 ---- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4813 --------------------- drivers/media/dvb/dvb-usb/dib07x0.h | 21 - drivers/media/dvb/dvb-usb/dibusb-common.c | 479 -- drivers/media/dvb/dvb-usb/dibusb-mb.c | 471 -- drivers/media/dvb/dvb-usb/dibusb-mc.c | 149 - drivers/media/dvb/dvb-usb/dibusb.h | 131 - drivers/media/dvb/dvb-usb/digitv.c | 354 -- drivers/media/dvb/dvb-usb/digitv.h | 66 - drivers/media/dvb/dvb-usb/dtt200u-fe.c | 210 - drivers/media/dvb/dvb-usb/dtt200u.c | 368 -- drivers/media/dvb/dvb-usb/dtt200u.h | 57 - drivers/media/dvb/dvb-usb/dtv5100.c | 224 - drivers/media/dvb/dvb-usb/dtv5100.h | 51 - drivers/media/dvb/dvb-usb/dvb-usb-common.h | 52 - drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 288 -- drivers/media/dvb/dvb-usb/dvb-usb-firmware.c | 146 - drivers/media/dvb/dvb-usb/dvb-usb-i2c.c | 43 - drivers/media/dvb/dvb-usb/dvb-usb-init.c | 304 -- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 391 -- drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 121 - drivers/media/dvb/dvb-usb/dvb-usb.h | 483 --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 403 -- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 117 - drivers/media/dvb/dvb-usb/dw2102.c | 1951 --------- drivers/media/dvb/dvb-usb/dw2102.h | 9 - drivers/media/dvb/dvb-usb/friio-fe.c | 473 -- drivers/media/dvb/dvb-usb/friio.c | 522 --- drivers/media/dvb/dvb-usb/friio.h | 99 - drivers/media/dvb/dvb-usb/gp8psk-fe.c | 369 -- drivers/media/dvb/dvb-usb/gp8psk.c | 328 -- drivers/media/dvb/dvb-usb/gp8psk.h | 100 - drivers/media/dvb/dvb-usb/m920x.c | 1099 ----- drivers/media/dvb/dvb-usb/m920x.h | 77 - drivers/media/dvb/dvb-usb/nova-t-usb2.c | 233 - drivers/media/dvb/dvb-usb/opera1.c | 583 --- drivers/media/dvb/dvb-usb/pctv452e.c | 1063 ----- drivers/media/dvb/dvb-usb/technisat-usb2.c | 789 ---- drivers/media/dvb/dvb-usb/ttusb2.c | 820 ---- drivers/media/dvb/dvb-usb/ttusb2.h | 70 - drivers/media/dvb/dvb-usb/umt-010.c | 151 - drivers/media/dvb/dvb-usb/usb-urb.c | 254 -- drivers/media/dvb/dvb-usb/vp702x-fe.c | 379 -- drivers/media/dvb/dvb-usb/vp702x.c | 444 -- drivers/media/dvb/dvb-usb/vp702x.h | 113 - drivers/media/dvb/dvb-usb/vp7045-fe.c | 190 - drivers/media/dvb/dvb-usb/vp7045.c | 302 -- drivers/media/dvb/dvb-usb/vp7045.h | 70 - drivers/media/dvb/siano/Kconfig | 34 - drivers/media/dvb/siano/Makefile | 11 - drivers/media/dvb/siano/sms-cards.c | 311 -- drivers/media/dvb/siano/sms-cards.h | 123 - drivers/media/dvb/siano/smscoreapi.c | 1637 ------- drivers/media/dvb/siano/smscoreapi.h | 775 ---- drivers/media/dvb/siano/smsdvb.c | 1078 ----- drivers/media/dvb/siano/smsendian.c | 103 - drivers/media/dvb/siano/smsendian.h | 32 - drivers/media/dvb/siano/smsir.c | 114 - drivers/media/dvb/siano/smsir.h | 55 - drivers/media/dvb/siano/smssdio.c | 365 -- drivers/media/dvb/siano/smsusb.c | 568 --- drivers/media/dvb/ttusb-budget/Kconfig | 18 - drivers/media/dvb/ttusb-budget/Makefile | 3 - drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 1816 -------- drivers/media/dvb/ttusb-dec/Kconfig | 21 - drivers/media/dvb/ttusb-dec/Makefile | 3 - drivers/media/dvb/ttusb-dec/ttusb_dec.c | 1764 -------- drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 298 -- drivers/media/dvb/ttusb-dec/ttusbdecfe.h | 38 - drivers/media/usb/Kconfig | 18 + drivers/media/usb/Makefile | 6 + drivers/media/usb/dvb-usb-v2/Kconfig | 146 + drivers/media/usb/dvb-usb-v2/Makefile | 48 + drivers/media/usb/dvb-usb-v2/af9015.c | 1434 ++++++ drivers/media/usb/dvb-usb-v2/af9015.h | 170 + drivers/media/usb/dvb-usb-v2/af9035.c | 1086 +++++ drivers/media/usb/dvb-usb-v2/af9035.h | 111 + drivers/media/usb/dvb-usb-v2/anysee.c | 1324 ++++++ drivers/media/usb/dvb-usb-v2/anysee.h | 356 ++ drivers/media/usb/dvb-usb-v2/au6610.c | 206 + drivers/media/usb/dvb-usb-v2/au6610.h | 32 + drivers/media/usb/dvb-usb-v2/az6007.c | 919 ++++ drivers/media/usb/dvb-usb-v2/ce6230.c | 287 ++ drivers/media/usb/dvb-usb-v2/ce6230.h | 61 + drivers/media/usb/dvb-usb-v2/cypress_firmware.c | 125 + drivers/media/usb/dvb-usb-v2/cypress_firmware.h | 31 + drivers/media/usb/dvb-usb-v2/dvb_usb.h | 389 ++ drivers/media/usb/dvb-usb-v2/dvb_usb_common.h | 35 + drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 997 +++++ drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c | 77 + drivers/media/usb/dvb-usb-v2/ec168.c | 376 ++ drivers/media/usb/dvb-usb-v2/ec168.h | 63 + drivers/media/usb/dvb-usb-v2/gl861.c | 175 + drivers/media/usb/dvb-usb-v2/gl861.h | 12 + drivers/media/usb/dvb-usb-v2/it913x.c | 799 ++++ drivers/media/usb/dvb-usb-v2/lmedm04.c | 1369 ++++++ drivers/media/usb/dvb-usb-v2/lmedm04.h | 175 + drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c | 612 +++ drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h | 55 + drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c | 763 ++++ drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h | 56 + drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c | 850 ++++ drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h | 35 + drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c | 343 ++ drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h | 53 + drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h | 179 + drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c | 527 +++ drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h | 89 + drivers/media/usb/dvb-usb-v2/mxl111sf.c | 1431 ++++++ drivers/media/usb/dvb-usb-v2/mxl111sf.h | 160 + drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 1259 ++++++ drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 254 ++ drivers/media/usb/dvb-usb-v2/usb_urb.c | 357 ++ drivers/media/usb/dvb-usb/Kconfig | 313 ++ drivers/media/usb/dvb-usb/Makefile | 82 + drivers/media/usb/dvb-usb/a800.c | 191 + drivers/media/usb/dvb-usb/af9005-fe.c | 1487 +++++++ drivers/media/usb/dvb-usb/af9005-remote.c | 157 + drivers/media/usb/dvb-usb/af9005-script.h | 203 + drivers/media/usb/dvb-usb/af9005.c | 1117 +++++ drivers/media/usb/dvb-usb/af9005.h | 3496 +++++++++++++++ drivers/media/usb/dvb-usb/az6027.c | 1182 +++++ drivers/media/usb/dvb-usb/az6027.h | 14 + drivers/media/usb/dvb-usb/cinergyT2-core.c | 254 ++ drivers/media/usb/dvb-usb/cinergyT2-fe.c | 356 ++ drivers/media/usb/dvb-usb/cinergyT2.h | 95 + drivers/media/usb/dvb-usb/cxusb.c | 2043 +++++++++ drivers/media/usb/dvb-usb/cxusb.h | 35 + drivers/media/usb/dvb-usb/dib0700.h | 75 + drivers/media/usb/dvb-usb/dib0700_core.c | 845 ++++ drivers/media/usb/dvb-usb/dib0700_devices.c | 4813 +++++++++++++++++++++ drivers/media/usb/dvb-usb/dib07x0.h | 21 + drivers/media/usb/dvb-usb/dibusb-common.c | 479 ++ drivers/media/usb/dvb-usb/dibusb-mb.c | 471 ++ drivers/media/usb/dvb-usb/dibusb-mc.c | 149 + drivers/media/usb/dvb-usb/dibusb.h | 131 + drivers/media/usb/dvb-usb/digitv.c | 354 ++ drivers/media/usb/dvb-usb/digitv.h | 66 + drivers/media/usb/dvb-usb/dtt200u-fe.c | 210 + drivers/media/usb/dvb-usb/dtt200u.c | 368 ++ drivers/media/usb/dvb-usb/dtt200u.h | 57 + drivers/media/usb/dvb-usb/dtv5100.c | 224 + drivers/media/usb/dvb-usb/dtv5100.h | 51 + drivers/media/usb/dvb-usb/dvb-usb-common.h | 52 + drivers/media/usb/dvb-usb/dvb-usb-dvb.c | 288 ++ drivers/media/usb/dvb-usb/dvb-usb-firmware.c | 146 + drivers/media/usb/dvb-usb/dvb-usb-i2c.c | 43 + drivers/media/usb/dvb-usb/dvb-usb-init.c | 304 ++ drivers/media/usb/dvb-usb/dvb-usb-remote.c | 391 ++ drivers/media/usb/dvb-usb/dvb-usb-urb.c | 121 + drivers/media/usb/dvb-usb/dvb-usb.h | 483 +++ drivers/media/usb/dvb-usb/dvb_usb_dvb.c | 403 ++ drivers/media/usb/dvb-usb/dvb_usb_remote.c | 117 + drivers/media/usb/dvb-usb/dw2102.c | 1951 +++++++++ drivers/media/usb/dvb-usb/dw2102.h | 9 + drivers/media/usb/dvb-usb/friio-fe.c | 473 ++ drivers/media/usb/dvb-usb/friio.c | 522 +++ drivers/media/usb/dvb-usb/friio.h | 99 + drivers/media/usb/dvb-usb/gp8psk-fe.c | 369 ++ drivers/media/usb/dvb-usb/gp8psk.c | 328 ++ drivers/media/usb/dvb-usb/gp8psk.h | 100 + drivers/media/usb/dvb-usb/m920x.c | 1099 +++++ drivers/media/usb/dvb-usb/m920x.h | 77 + drivers/media/usb/dvb-usb/nova-t-usb2.c | 233 + drivers/media/usb/dvb-usb/opera1.c | 583 +++ drivers/media/usb/dvb-usb/pctv452e.c | 1063 +++++ drivers/media/usb/dvb-usb/technisat-usb2.c | 789 ++++ drivers/media/usb/dvb-usb/ttusb2.c | 820 ++++ drivers/media/usb/dvb-usb/ttusb2.h | 70 + drivers/media/usb/dvb-usb/umt-010.c | 151 + drivers/media/usb/dvb-usb/usb-urb.c | 254 ++ drivers/media/usb/dvb-usb/vp702x-fe.c | 379 ++ drivers/media/usb/dvb-usb/vp702x.c | 444 ++ drivers/media/usb/dvb-usb/vp702x.h | 113 + drivers/media/usb/dvb-usb/vp7045-fe.c | 190 + drivers/media/usb/dvb-usb/vp7045.c | 302 ++ drivers/media/usb/dvb-usb/vp7045.h | 70 + drivers/media/usb/siano/Kconfig | 34 + drivers/media/usb/siano/Makefile | 11 + drivers/media/usb/siano/sms-cards.c | 311 ++ drivers/media/usb/siano/sms-cards.h | 123 + drivers/media/usb/siano/smscoreapi.c | 1637 +++++++ drivers/media/usb/siano/smscoreapi.h | 775 ++++ drivers/media/usb/siano/smsdvb.c | 1078 +++++ drivers/media/usb/siano/smsendian.c | 103 + drivers/media/usb/siano/smsendian.h | 32 + drivers/media/usb/siano/smsir.c | 114 + drivers/media/usb/siano/smsir.h | 55 + drivers/media/usb/siano/smssdio.c | 365 ++ drivers/media/usb/siano/smsusb.c | 568 +++ drivers/media/usb/ttusb-budget/Kconfig | 18 + drivers/media/usb/ttusb-budget/Makefile | 3 + drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c | 1816 ++++++++ drivers/media/usb/ttusb-dec/Kconfig | 21 + drivers/media/usb/ttusb-dec/Makefile | 3 + drivers/media/usb/ttusb-dec/ttusb_dec.c | 1764 ++++++++ drivers/media/usb/ttusb-dec/ttusbdecfe.c | 298 ++ drivers/media/usb/ttusb-dec/ttusbdecfe.h | 38 + drivers/media/video/cx231xx/Makefile | 2 +- drivers/staging/media/go7007/Makefile | 2 +- 263 files changed, 59197 insertions(+), 59185 deletions(-) delete mode 100644 drivers/media/dvb/dvb-usb-v2/Kconfig delete mode 100644 drivers/media/dvb/dvb-usb-v2/Makefile delete mode 100644 drivers/media/dvb/dvb-usb-v2/af9015.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/af9015.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/af9035.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/af9035.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/anysee.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/anysee.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/au6610.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/au6610.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/az6007.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/ce6230.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/ce6230.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/cypress_firmware.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/cypress_firmware.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/dvb_usb.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/ec168.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/ec168.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/gl861.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/gl861.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/it913x.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/lmedm04.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/lmedm04.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/mxl111sf.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/rtl28xxu.c delete mode 100644 drivers/media/dvb/dvb-usb-v2/rtl28xxu.h delete mode 100644 drivers/media/dvb/dvb-usb-v2/usb_urb.c delete mode 100644 drivers/media/dvb/dvb-usb/Kconfig delete mode 100644 drivers/media/dvb/dvb-usb/Makefile delete mode 100644 drivers/media/dvb/dvb-usb/a800.c delete mode 100644 drivers/media/dvb/dvb-usb/af9005-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/af9005-remote.c delete mode 100644 drivers/media/dvb/dvb-usb/af9005-script.h delete mode 100644 drivers/media/dvb/dvb-usb/af9005.c delete mode 100644 drivers/media/dvb/dvb-usb/af9005.h delete mode 100644 drivers/media/dvb/dvb-usb/az6027.c delete mode 100644 drivers/media/dvb/dvb-usb/az6027.h delete mode 100644 drivers/media/dvb/dvb-usb/cinergyT2-core.c delete mode 100644 drivers/media/dvb/dvb-usb/cinergyT2-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/cinergyT2.h delete mode 100644 drivers/media/dvb/dvb-usb/cxusb.c delete mode 100644 drivers/media/dvb/dvb-usb/cxusb.h delete mode 100644 drivers/media/dvb/dvb-usb/dib0700.h delete mode 100644 drivers/media/dvb/dvb-usb/dib0700_core.c delete mode 100644 drivers/media/dvb/dvb-usb/dib0700_devices.c delete mode 100644 drivers/media/dvb/dvb-usb/dib07x0.h delete mode 100644 drivers/media/dvb/dvb-usb/dibusb-common.c delete mode 100644 drivers/media/dvb/dvb-usb/dibusb-mb.c delete mode 100644 drivers/media/dvb/dvb-usb/dibusb-mc.c delete mode 100644 drivers/media/dvb/dvb-usb/dibusb.h delete mode 100644 drivers/media/dvb/dvb-usb/digitv.c delete mode 100644 drivers/media/dvb/dvb-usb/digitv.h delete mode 100644 drivers/media/dvb/dvb-usb/dtt200u-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/dtt200u.c delete mode 100644 drivers/media/dvb/dvb-usb/dtt200u.h delete mode 100644 drivers/media/dvb/dvb-usb/dtv5100.c delete mode 100644 drivers/media/dvb/dvb-usb/dtv5100.h delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-common.h delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-dvb.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-firmware.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-i2c.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-init.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-remote.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-urb.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb-usb.h delete mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_dvb.c delete mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_remote.c delete mode 100644 drivers/media/dvb/dvb-usb/dw2102.c delete mode 100644 drivers/media/dvb/dvb-usb/dw2102.h delete mode 100644 drivers/media/dvb/dvb-usb/friio-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/friio.c delete mode 100644 drivers/media/dvb/dvb-usb/friio.h delete mode 100644 drivers/media/dvb/dvb-usb/gp8psk-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/gp8psk.c delete mode 100644 drivers/media/dvb/dvb-usb/gp8psk.h delete mode 100644 drivers/media/dvb/dvb-usb/m920x.c delete mode 100644 drivers/media/dvb/dvb-usb/m920x.h delete mode 100644 drivers/media/dvb/dvb-usb/nova-t-usb2.c delete mode 100644 drivers/media/dvb/dvb-usb/opera1.c delete mode 100644 drivers/media/dvb/dvb-usb/pctv452e.c delete mode 100644 drivers/media/dvb/dvb-usb/technisat-usb2.c delete mode 100644 drivers/media/dvb/dvb-usb/ttusb2.c delete mode 100644 drivers/media/dvb/dvb-usb/ttusb2.h delete mode 100644 drivers/media/dvb/dvb-usb/umt-010.c delete mode 100644 drivers/media/dvb/dvb-usb/usb-urb.c delete mode 100644 drivers/media/dvb/dvb-usb/vp702x-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/vp702x.c delete mode 100644 drivers/media/dvb/dvb-usb/vp702x.h delete mode 100644 drivers/media/dvb/dvb-usb/vp7045-fe.c delete mode 100644 drivers/media/dvb/dvb-usb/vp7045.c delete mode 100644 drivers/media/dvb/dvb-usb/vp7045.h delete mode 100644 drivers/media/dvb/siano/Kconfig delete mode 100644 drivers/media/dvb/siano/Makefile delete mode 100644 drivers/media/dvb/siano/sms-cards.c delete mode 100644 drivers/media/dvb/siano/sms-cards.h delete mode 100644 drivers/media/dvb/siano/smscoreapi.c delete mode 100644 drivers/media/dvb/siano/smscoreapi.h delete mode 100644 drivers/media/dvb/siano/smsdvb.c delete mode 100644 drivers/media/dvb/siano/smsendian.c delete mode 100644 drivers/media/dvb/siano/smsendian.h delete mode 100644 drivers/media/dvb/siano/smsir.c delete mode 100644 drivers/media/dvb/siano/smsir.h delete mode 100644 drivers/media/dvb/siano/smssdio.c delete mode 100644 drivers/media/dvb/siano/smsusb.c delete mode 100644 drivers/media/dvb/ttusb-budget/Kconfig delete mode 100644 drivers/media/dvb/ttusb-budget/Makefile delete mode 100644 drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c delete mode 100644 drivers/media/dvb/ttusb-dec/Kconfig delete mode 100644 drivers/media/dvb/ttusb-dec/Makefile delete mode 100644 drivers/media/dvb/ttusb-dec/ttusb_dec.c delete mode 100644 drivers/media/dvb/ttusb-dec/ttusbdecfe.c delete mode 100644 drivers/media/dvb/ttusb-dec/ttusbdecfe.h create mode 100644 drivers/media/usb/Kconfig create mode 100644 drivers/media/usb/Makefile create mode 100644 drivers/media/usb/dvb-usb-v2/Kconfig create mode 100644 drivers/media/usb/dvb-usb-v2/Makefile create mode 100644 drivers/media/usb/dvb-usb-v2/af9015.c create mode 100644 drivers/media/usb/dvb-usb-v2/af9015.h create mode 100644 drivers/media/usb/dvb-usb-v2/af9035.c create mode 100644 drivers/media/usb/dvb-usb-v2/af9035.h create mode 100644 drivers/media/usb/dvb-usb-v2/anysee.c create mode 100644 drivers/media/usb/dvb-usb-v2/anysee.h create mode 100644 drivers/media/usb/dvb-usb-v2/au6610.c create mode 100644 drivers/media/usb/dvb-usb-v2/au6610.h create mode 100644 drivers/media/usb/dvb-usb-v2/az6007.c create mode 100644 drivers/media/usb/dvb-usb-v2/ce6230.c create mode 100644 drivers/media/usb/dvb-usb-v2/ce6230.h create mode 100644 drivers/media/usb/dvb-usb-v2/cypress_firmware.c create mode 100644 drivers/media/usb/dvb-usb-v2/cypress_firmware.h create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb.h create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb_common.h create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c create mode 100644 drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c create mode 100644 drivers/media/usb/dvb-usb-v2/ec168.c create mode 100644 drivers/media/usb/dvb-usb-v2/ec168.h create mode 100644 drivers/media/usb/dvb-usb-v2/gl861.c create mode 100644 drivers/media/usb/dvb-usb-v2/gl861.h create mode 100644 drivers/media/usb/dvb-usb-v2/it913x.c create mode 100644 drivers/media/usb/dvb-usb-v2/lmedm04.c create mode 100644 drivers/media/usb/dvb-usb-v2/lmedm04.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf.c create mode 100644 drivers/media/usb/dvb-usb-v2/mxl111sf.h create mode 100644 drivers/media/usb/dvb-usb-v2/rtl28xxu.c create mode 100644 drivers/media/usb/dvb-usb-v2/rtl28xxu.h create mode 100644 drivers/media/usb/dvb-usb-v2/usb_urb.c create mode 100644 drivers/media/usb/dvb-usb/Kconfig create mode 100644 drivers/media/usb/dvb-usb/Makefile create mode 100644 drivers/media/usb/dvb-usb/a800.c create mode 100644 drivers/media/usb/dvb-usb/af9005-fe.c create mode 100644 drivers/media/usb/dvb-usb/af9005-remote.c create mode 100644 drivers/media/usb/dvb-usb/af9005-script.h create mode 100644 drivers/media/usb/dvb-usb/af9005.c create mode 100644 drivers/media/usb/dvb-usb/af9005.h create mode 100644 drivers/media/usb/dvb-usb/az6027.c create mode 100644 drivers/media/usb/dvb-usb/az6027.h create mode 100644 drivers/media/usb/dvb-usb/cinergyT2-core.c create mode 100644 drivers/media/usb/dvb-usb/cinergyT2-fe.c create mode 100644 drivers/media/usb/dvb-usb/cinergyT2.h create mode 100644 drivers/media/usb/dvb-usb/cxusb.c create mode 100644 drivers/media/usb/dvb-usb/cxusb.h create mode 100644 drivers/media/usb/dvb-usb/dib0700.h create mode 100644 drivers/media/usb/dvb-usb/dib0700_core.c create mode 100644 drivers/media/usb/dvb-usb/dib0700_devices.c create mode 100644 drivers/media/usb/dvb-usb/dib07x0.h create mode 100644 drivers/media/usb/dvb-usb/dibusb-common.c create mode 100644 drivers/media/usb/dvb-usb/dibusb-mb.c create mode 100644 drivers/media/usb/dvb-usb/dibusb-mc.c create mode 100644 drivers/media/usb/dvb-usb/dibusb.h create mode 100644 drivers/media/usb/dvb-usb/digitv.c create mode 100644 drivers/media/usb/dvb-usb/digitv.h create mode 100644 drivers/media/usb/dvb-usb/dtt200u-fe.c create mode 100644 drivers/media/usb/dvb-usb/dtt200u.c create mode 100644 drivers/media/usb/dvb-usb/dtt200u.h create mode 100644 drivers/media/usb/dvb-usb/dtv5100.c create mode 100644 drivers/media/usb/dvb-usb/dtv5100.h create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-common.h create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-dvb.c create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-firmware.c create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-i2c.c create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-init.c create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-remote.c create mode 100644 drivers/media/usb/dvb-usb/dvb-usb-urb.c create mode 100644 drivers/media/usb/dvb-usb/dvb-usb.h create mode 100644 drivers/media/usb/dvb-usb/dvb_usb_dvb.c create mode 100644 drivers/media/usb/dvb-usb/dvb_usb_remote.c create mode 100644 drivers/media/usb/dvb-usb/dw2102.c create mode 100644 drivers/media/usb/dvb-usb/dw2102.h create mode 100644 drivers/media/usb/dvb-usb/friio-fe.c create mode 100644 drivers/media/usb/dvb-usb/friio.c create mode 100644 drivers/media/usb/dvb-usb/friio.h create mode 100644 drivers/media/usb/dvb-usb/gp8psk-fe.c create mode 100644 drivers/media/usb/dvb-usb/gp8psk.c create mode 100644 drivers/media/usb/dvb-usb/gp8psk.h create mode 100644 drivers/media/usb/dvb-usb/m920x.c create mode 100644 drivers/media/usb/dvb-usb/m920x.h create mode 100644 drivers/media/usb/dvb-usb/nova-t-usb2.c create mode 100644 drivers/media/usb/dvb-usb/opera1.c create mode 100644 drivers/media/usb/dvb-usb/pctv452e.c create mode 100644 drivers/media/usb/dvb-usb/technisat-usb2.c create mode 100644 drivers/media/usb/dvb-usb/ttusb2.c create mode 100644 drivers/media/usb/dvb-usb/ttusb2.h create mode 100644 drivers/media/usb/dvb-usb/umt-010.c create mode 100644 drivers/media/usb/dvb-usb/usb-urb.c create mode 100644 drivers/media/usb/dvb-usb/vp702x-fe.c create mode 100644 drivers/media/usb/dvb-usb/vp702x.c create mode 100644 drivers/media/usb/dvb-usb/vp702x.h create mode 100644 drivers/media/usb/dvb-usb/vp7045-fe.c create mode 100644 drivers/media/usb/dvb-usb/vp7045.c create mode 100644 drivers/media/usb/dvb-usb/vp7045.h create mode 100644 drivers/media/usb/siano/Kconfig create mode 100644 drivers/media/usb/siano/Makefile create mode 100644 drivers/media/usb/siano/sms-cards.c create mode 100644 drivers/media/usb/siano/sms-cards.h create mode 100644 drivers/media/usb/siano/smscoreapi.c create mode 100644 drivers/media/usb/siano/smscoreapi.h create mode 100644 drivers/media/usb/siano/smsdvb.c create mode 100644 drivers/media/usb/siano/smsendian.c create mode 100644 drivers/media/usb/siano/smsendian.h create mode 100644 drivers/media/usb/siano/smsir.c create mode 100644 drivers/media/usb/siano/smsir.h create mode 100644 drivers/media/usb/siano/smssdio.c create mode 100644 drivers/media/usb/siano/smsusb.c create mode 100644 drivers/media/usb/ttusb-budget/Kconfig create mode 100644 drivers/media/usb/ttusb-budget/Makefile create mode 100644 drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c create mode 100644 drivers/media/usb/ttusb-dec/Kconfig create mode 100644 drivers/media/usb/ttusb-dec/Makefile create mode 100644 drivers/media/usb/ttusb-dec/ttusb_dec.c create mode 100644 drivers/media/usb/ttusb-dec/ttusbdecfe.c create mode 100644 drivers/media/usb/ttusb-dec/ttusbdecfe.h (limited to 'Documentation') diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb index c4d963a67d6..8eb92264ee0 100644 --- a/Documentation/dvb/README.dvb-usb +++ b/Documentation/dvb/README.dvb-usb @@ -30,7 +30,7 @@ with the device via the bus. The connection between the DVB-API-functionality is done via callbacks, assigned in a static device-description (struct dvb_usb_device) each device-driver has to have. -For an example have a look in drivers/media/dvb/dvb-usb/vp7045*. +For an example have a look in drivers/media/usb/dvb-usb/vp7045*. Objective is to migrate all the usb-devices (dibusb, cinergyT2, maybe the ttusb; flexcop-usb already benefits from the generic flexcop-device) to use diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index b7d2802e6a3..26da8b8721d 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -163,6 +163,7 @@ source "drivers/media/radio/Kconfig" source "drivers/media/dvb-core/Kconfig" source "drivers/media/dvb/Kconfig" +source "drivers/media/usb/Kconfig" comment "Supported FireWire (IEEE 1394) Adapters" depends on DVB_CORE && FIREWIRE diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 37e448cafb7..46a8dc3337b 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -11,5 +11,5 @@ endif obj-y += v4l2-core/ common/ rc/ video/ obj-$(CONFIG_VIDEO_DEV) += radio/ -obj-$(CONFIG_DVB_CORE) += dvb-core/ dvb/ dvb-frontends/ +obj-$(CONFIG_DVB_CORE) += dvb-core/ dvb/ dvb-frontends/ usb/ obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index b4665460c74..e2565a45de9 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -15,14 +15,6 @@ comment "Supported SAA7146 based PCI Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/ttpci/Kconfig" -comment "Supported USB Adapters" - depends on DVB_CORE && USB && I2C -source "drivers/media/dvb/dvb-usb/Kconfig" -source "drivers/media/dvb/dvb-usb-v2/Kconfig" -source "drivers/media/dvb/ttusb-budget/Kconfig" -source "drivers/media/dvb/ttusb-dec/Kconfig" -source "drivers/media/dvb/siano/Kconfig" - comment "Supported FlexCopII (B2C2) Adapters" depends on DVB_CORE && (PCI || USB) && I2C source "drivers/media/dvb/b2c2/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index fc248268cb5..c5fa43a275a 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -3,14 +3,9 @@ # obj-y := ttpci/ \ - ttusb-dec/ \ - ttusb-budget/ \ b2c2/ \ bt8xx/ \ - dvb-usb/ \ - dvb-usb-v2/ \ pluto2/ \ - siano/ \ dm1105/ \ pt1/ \ mantis/ \ diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig deleted file mode 100644 index 276374fbaf4..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/Kconfig +++ /dev/null @@ -1,146 +0,0 @@ -config DVB_USB_V2 - tristate "Support for various USB DVB devices v2" - depends on DVB_CORE && USB && I2C && RC_CORE - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_CYPRESS_FIRMWARE - tristate "Cypress firmware helper routines" - depends on DVB_USB_V2 - -config DVB_USB_AF9015 - tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9013 - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver - -config DVB_USB_AF9035 - tristate "Afatech AF9035 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9033 - select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9035 based DVB USB receiver. - -config DVB_USB_ANYSEE - tristate "Anysee DVB-T/C USB2.0 support" - depends on DVB_USB_V2 - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_ISL6423 if !DVB_FE_CUSTOMISE - select DVB_CXD2820R if !DVB_FE_CUSTOMISE - help - Say Y here to support the Anysee E30, Anysee E30 Plus or - Anysee E30 C Plus DVB USB2.0 receiver. - -config DVB_USB_AU6610 - tristate "Alcor Micro AU6610 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. - -config DVB_USB_AZ6007 - tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" - depends on DVB_USB_V2 - select DVB_USB_CYPRESS_FIRMWARE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE - help - Say Y here to support the AZ6007 receivers like Terratec H7. - -config DVB_USB_CE6230 - tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 - 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_EC168 - tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_EC100 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. - -config DVB_USB_GL861 - tristate "Genesys Logic GL861 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 - receiver with USB ID 0db0:5581. - -config DVB_USB_IT913X - tristate "ITE IT913X DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_IT913X_FE - help - Say Y here to support the ITE IT913X DVB-T USB2.0 - -config DVB_USB_LME2510 - tristate "LME DM04/QQBOX DVB-S USB2.0 support" - depends on DVB_USB_V2 - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_IX2505V if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_M88RS2000 if !DVB_FE_CUSTOMISE - help - Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 - -config DVB_USB_MXL111SF - tristate "MxL111SF DTV USB2.0 support" - depends on DVB_USB_V2 - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_LG2160 if !DVB_FE_CUSTOMISE - select VIDEO_TVEEPROM - help - Say Y here to support the MxL111SF USB2.0 DTV receiver. - -config DVB_USB_RTL28XXU - tristate "Realtek RTL28xxU DVB USB support" - depends on DVB_USB_V2 && EXPERIMENTAL - select DVB_RTL2830 - select DVB_RTL2832 - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Realtek RTL28xxU DVB USB receiver. - diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile deleted file mode 100644 index 24248b3acd4..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o -obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o - -dvb_usb_cypress_firmware-objs = cypress_firmware.o -obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o - -dvb-usb-af9015-objs = af9015.o -obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o - -dvb-usb-af9035-objs = af9035.o -obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o - -dvb-usb-anysee-objs = anysee.o -obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o - -dvb-usb-au6610-objs = au6610.o -obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o - -dvb-usb-az6007-objs = az6007.o -obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o - -dvb-usb-ce6230-objs = ce6230.o -obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o - -dvb-usb-ec168-objs = ec168.o -obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o - -dvb-usb-it913x-objs = it913x.o -obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o - -dvb-usb-lmedm04-objs = lmedm04.o -obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o - -dvb-usb-gl861-objs = gl861.o -obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o - -dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o -obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o - -dvb-usb-rtl28xxu-objs = rtl28xxu.o -obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o - -ccflags-y += -I$(srctree)/drivers/media/dvb-core -ccflags-y += -I$(srctree)/drivers/media/dvb-frontends -ccflags-y += -I$(srctree)/drivers/media/common/tuners - diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.c b/drivers/media/dvb/dvb-usb-v2/af9015.c deleted file mode 100644 index e77429b37a7..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/af9015.c +++ /dev/null @@ -1,1434 +0,0 @@ -/* - * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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 "af9015.h" - -static int dvb_usb_af9015_debug; -module_param_named(debug, dvb_usb_af9015_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -static int dvb_usb_af9015_remote; -module_param_named(remote, dvb_usb_af9015_remote, int, 0644); -MODULE_PARM_DESC(remote, "select remote"); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) -{ -#define BUF_LEN 63 -#define REQ_HDR_LEN 8 /* send header size */ -#define ACK_HDR_LEN 2 /* rece header size */ - struct af9015_state *state = d_to_priv(d); - int ret, wlen, rlen; - u8 buf[BUF_LEN]; - u8 write = 1; - - buf[0] = req->cmd; - buf[1] = state->seq++; - buf[2] = req->i2c_addr; - buf[3] = req->addr >> 8; - buf[4] = req->addr & 0xff; - buf[5] = req->mbox; - buf[6] = req->addr_len; - buf[7] = req->data_len; - - switch (req->cmd) { - case GET_CONFIG: - case READ_MEMORY: - case RECONNECT_USB: - write = 0; - break; - case READ_I2C: - write = 0; - buf[2] |= 0x01; /* set I2C direction */ - case WRITE_I2C: - buf[0] = READ_WRITE_I2C; - break; - case WRITE_MEMORY: - if (((req->addr & 0xff00) == 0xff00) || - ((req->addr & 0xff00) == 0xae00)) - buf[0] = WRITE_VIRTUAL_MEMORY; - case WRITE_VIRTUAL_MEMORY: - case COPY_FIRMWARE: - case DOWNLOAD_FIRMWARE: - case BOOT: - break; - default: - err("unknown command:%d", req->cmd); - ret = -1; - goto error; - } - - /* buffer overflow check */ - if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || - (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { - err("too much data; cmd:%d len:%d", req->cmd, req->data_len); - ret = -EINVAL; - goto error; - } - - /* write receives seq + status = 2 bytes - read receives seq + status + data = 2 + N bytes */ - wlen = REQ_HDR_LEN; - rlen = ACK_HDR_LEN; - if (write) { - wlen += req->data_len; - memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); - } else { - rlen += req->data_len; - } - - /* no ack for these packets */ - if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) - rlen = 0; - - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); - if (ret) - goto error; - - /* check status */ - if (rlen && buf[1]) { - err("command failed:%d", buf[1]); - ret = -1; - goto error; - } - - /* read request, copy returned data to return buf */ - if (!write) - memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); -error: - return ret; -} - -static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, - u8 len) -{ - struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) -{ - struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - -static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) -{ - return af9015_read_regs(d, addr, val, 1); -} - -static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 val) -{ - struct af9015_state *state = d_to_priv(d); - struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) - req.addr_len = 3; - - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 *val) -{ - struct af9015_state *state = d_to_priv(d); - struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) - req.addr_len = 3; - - return af9015_ctrl_msg(d, &req); -} - -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) -{ - int ret; - u8 val, mask = 0x01; - - ret = af9015_read_reg(d, addr, &val); - if (ret) - return ret; - - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - -static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct af9015_state *state = d_to_priv(d); - int ret = 0, i = 0; - u16 addr; - u8 uninitialized_var(mbox), addr_len; - struct req_t req; - -/* -The bus lock is needed because there is two tuners both using same I2C-address. -Due to that the only way to select correct tuner is use demodulator I2C-gate. - -................................................ -. AF9015 includes integrated AF9013 demodulator. -. ____________ ____________ . ____________ -.| uC | | demod | . | tuner | -.|------------| |------------| . |------------| -.| AF9015 | | AF9013/5 | . | MXL5003 | -.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | -.| | | | addr 0x38 | . | addr 0xc6 | -.|____________| | |____________| . |____________| -.................|.............................. - | ____________ ____________ - | | demod | | tuner | - | |------------| |------------| - | | AF9013 | | MXL5003 | - +----I2C-------|-----/ -----|-------I2C-------| | - | addr 0x3a | | addr 0xc6 | - |____________| |____________| -*/ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (msg[i].addr == state->af9013_config[0].i2c_addr || - msg[i].addr == state->af9013_config[1].i2c_addr) { - addr = msg[i].buf[0] << 8; - addr += msg[i].buf[1]; - mbox = msg[i].buf[2]; - addr_len = 3; - } else { - addr = msg[i].buf[0]; - addr_len = 1; - /* mbox is don't care in that case */ - } - - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 3 || msg[i+1].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) - req.cmd = READ_MEMORY; - else - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 2; - } else if (msg[i].flags & I2C_M_RD) { - if (msg[i].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) { - ret = -EINVAL; - goto error; - } - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i].len; - req.data = &msg[i].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 1; - } else { - if (msg[i].len > 21) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) - req.cmd = WRITE_MEMORY; - else - req.cmd = WRITE_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i].len-addr_len; - req.data = &msg[i].buf[addr_len]; - ret = af9015_ctrl_msg(d, &req); - i += 1; - } - if (ret) - goto error; - - } - ret = i; - -error: - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 af9015_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9015_i2c_algo = { - .master_xfer = af9015_i2c_xfer, - .functionality = af9015_i2c_func, -}; - -static int af9015_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 reply; - struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; - - ret = af9015_ctrl_msg(d, &req); - if (ret) - return ret; - - deb_info("%s: reply:%02x\n", __func__, reply); - if (reply == 0x02) - ret = WARM; - else - ret = COLD; - - return ret; -} - -static int af9015_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - struct af9015_state *state = d_to_priv(d); - int i, len, remaining, ret; - struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; - - deb_info("%s:\n", __func__); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; - - state->firmware_size = fw->size; - state->firmware_checksum = checksum; - - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 55 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.data_len = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; - - ret = af9015_ctrl_msg(d, &req); - if (ret) { - err("firmware download failed:%d", ret); - goto error; - } - } - - /* firmware loaded, request boot */ - req.cmd = BOOT; - req.data_len = 0; - ret = af9015_ctrl_msg(d, &req); - if (ret) { - err("firmware boot failed:%d", ret); - goto error; - } - -error: - return ret; -} - -/* hash (and dump) eeprom */ -static int af9015_eeprom_hash(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - static const unsigned int eeprom_size = 256; - unsigned int reg; - u8 val, *eeprom; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - eeprom = kmalloc(eeprom_size, GFP_KERNEL); - if (eeprom == NULL) - return -ENOMEM; - - for (reg = 0; reg < eeprom_size; reg++) { - req.addr = reg; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto free; - - eeprom[reg] = val; - } - - if (dvb_usb_af9015_debug & 0x01) - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, - eeprom_size); - - BUG_ON(eeprom_size % 4); - - state->eeprom_sum = 0; - for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { - state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; - state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); - } - - deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum); - - ret = 0; -free: - kfree(eeprom); - return ret; -} - -static int af9015_read_config(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u8 val, i, offset = 0; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - deb_info("%s:\n", __func__); - - /* IR remote controller */ - req.addr = AF9015_EEPROM_IR_MODE; - /* first message will timeout often due to possible hw bug */ - for (i = 0; i < 4; i++) { - ret = af9015_ctrl_msg(d, &req); - if (!ret) - break; - } - if (ret) - goto error; - - ret = af9015_eeprom_hash(d); - if (ret) - goto error; - - deb_info("%s: IR mode=%d\n", __func__, val); - state->ir_mode = val; - - /* TS mode - one or two receivers */ - req.addr = AF9015_EEPROM_TS_MODE; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->dual_mode = val; - deb_info("%s: TS mode=%d\n", __func__, state->dual_mode); - - /* disable 2nd adapter because we don't have PID-filters */ - if (d->udev->speed == USB_SPEED_FULL) - state->dual_mode = 0; - - if (state->dual_mode) { - /* read 2nd demodulator I2C address */ - req.addr = AF9015_EEPROM_DEMOD2_I2C; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->af9013_config[1].i2c_addr = val; - } - - for (i = 0; i < state->dual_mode + 1; i++) { - if (i == 1) - offset = AF9015_EEPROM_OFFSET; - /* xtal */ - req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - switch (val) { - case 0: - state->af9013_config[i].clock = 28800000; - break; - case 1: - state->af9013_config[i].clock = 20480000; - break; - case 2: - state->af9013_config[i].clock = 28000000; - break; - case 3: - state->af9013_config[i].clock = 25000000; - break; - }; - deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, - val, state->af9013_config[i].clock); - - /* IF frequency */ - req.addr = AF9015_EEPROM_IF1H + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->af9013_config[i].if_frequency = val << 8; - - req.addr = AF9015_EEPROM_IF1L + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->af9013_config[i].if_frequency += val; - state->af9013_config[i].if_frequency *= 1000; - deb_info("%s: [%d] IF frequency=%d\n", __func__, i, - state->af9013_config[i].if_frequency); - - /* MT2060 IF1 */ - req.addr = AF9015_EEPROM_MT2060_IF1H + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - state->mt2060_if1[i] = val << 8; - req.addr = AF9015_EEPROM_MT2060_IF1L + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - state->mt2060_if1[i] += val; - deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, - state->mt2060_if1[i]); - - /* tuner */ - req.addr = AF9015_EEPROM_TUNER_ID1 + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - switch (val) { - case AF9013_TUNER_ENV77H11D5: - case AF9013_TUNER_MT2060: - case AF9013_TUNER_QT1010: - case AF9013_TUNER_UNKNOWN: - case AF9013_TUNER_MT2060_2: - case AF9013_TUNER_TDA18271: - case AF9013_TUNER_QT1010A: - case AF9013_TUNER_TDA18218: - state->af9013_config[i].spec_inv = 1; - break; - case AF9013_TUNER_MXL5003D: - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - case AF9013_TUNER_MXL5007T: - state->af9013_config[i].spec_inv = 0; - break; - case AF9013_TUNER_MC44S803: - state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; - state->af9013_config[i].spec_inv = 1; - break; - default: - warn("tuner id=%d not supported, please report!", val); - return -ENODEV; - }; - - state->af9013_config[i].tuner = val; - deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); - } - -error: - if (ret) - err("eeprom read failed=%d", ret); - - /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM - content :-( Override some wrong values here. Ditto for the - AVerTV Red HD+ (A850T) device. */ - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && - ((le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850) || - (le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850T))) { - deb_info("%s: AverMedia A850: overriding config\n", __func__); - /* disable dual mode */ - state->dual_mode = 0; - - /* set correct IF */ - state->af9013_config[0].if_frequency = 4570000; - } - - return ret; -} - -static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) -{ - deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id); - - if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL) - stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; - - return 0; -} - -static int af9015_get_adapter_count(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - return state->dual_mode + 1; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_set_frontend(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->set_frontend[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->read_status[fe_to_adap(fe)->id](fe, status); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_init(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->init[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_sleep(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->sleep[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override tuner callbacks for resource locking */ -static int af9015_tuner_init(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->tuner_init[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override tuner callbacks for resource locking */ -static int af9015_tuner_sleep(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -static int af9015_copy_firmware(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u8 fw_params[4]; - u8 val, i; - struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), - fw_params }; - deb_info("%s:\n", __func__); - - fw_params[0] = state->firmware_size >> 8; - fw_params[1] = state->firmware_size & 0xff; - fw_params[2] = state->firmware_checksum >> 8; - fw_params[3] = state->firmware_checksum & 0xff; - - /* wait 2nd demodulator ready */ - msleep(100); - - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0x98be, &val); - if (ret) - goto error; - else - deb_info("%s: firmware status:%02x\n", __func__, val); - - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; - - /* set I2C master clock to fast (to speed up firmware copy) */ - ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ - if (ret) - goto error; - - msleep(50); - - /* copy firmware */ - ret = af9015_ctrl_msg(d, &req); - if (ret) - err("firmware copy cmd failed:%d", ret); - deb_info("%s: firmware copy done\n", __func__); - - /* set I2C master clock back to normal */ - ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ - if (ret) - goto error; - - /* request boot firmware */ - ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0xe205, 1); - deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); - if (ret) - goto error; - - for (i = 0; i < 15; i++) { - msleep(100); - - /* check firmware status */ - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0x98be, &val); - deb_info("%s: firmware status cmd status:%d fw status:%02x\n", - __func__, ret, val); - if (ret) - goto error; - - if (val == 0x0c || val == 0x04) /* success or fail */ - break; - } - - if (val == 0x04) { - err("firmware did not run"); - ret = -1; - } else if (val != 0x0c) { - err("firmware boot timeout"); - ret = -1; - } - -error: -exit: - return ret; -} - -static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct af9015_state *state = adap_to_priv(adap); - - if (adap->id == 0) { - state->af9013_config[0].ts_mode = AF9013_TS_USB; - memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; - state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; - } else if (adap->id == 1) { - state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; - memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; - state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; - - /* copy firmware to 2nd demodulator */ - if (state->dual_mode) { - ret = af9015_copy_firmware(adap_to_d(adap)); - if (ret) { - err("firmware copy to 2nd frontend " \ - "failed, will disable it"); - state->dual_mode = 0; - return -ENODEV; - } - } else { - return -ENODEV; - } - } - - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9013_attach, - &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); - - /* - * AF9015 firmware does not like if it gets interrupted by I2C adapter - * request on some critical phases. During normal operation I2C adapter - * is used only 2nd demodulator and tuner on dual tuner devices. - * Override demodulator callbacks and use mutex for limit access to - * those "critical" paths to keep AF9015 happy. - */ - if (adap->fe[0]) { - state->set_frontend[adap->id] = - adap->fe[0]->ops.set_frontend; - adap->fe[0]->ops.set_frontend = - af9015_af9013_set_frontend; - - state->read_status[adap->id] = - adap->fe[0]->ops.read_status; - adap->fe[0]->ops.read_status = - af9015_af9013_read_status; - - state->init[adap->id] = adap->fe[0]->ops.init; - adap->fe[0]->ops.init = af9015_af9013_init; - - state->sleep[adap->id] = adap->fe[0]->ops.sleep; - adap->fe[0]->ops.sleep = af9015_af9013_sleep; - } - - return adap->fe[0] == NULL ? -ENODEV : 0; -} - -static struct mt2060_config af9015_mt2060_config = { - .i2c_address = 0xc0, - .clock_out = 0, -}; - -static struct qt1010_config af9015_qt1010_config = { - .i2c_address = 0xc4, -}; - -static struct tda18271_config af9015_tda18271_config = { - .gate = TDA18271_GATE_DIGITAL, - .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, -}; - -static struct mxl5005s_config af9015_mxl5003_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct mxl5005s_config af9015_mxl5005_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct mc44s803_config af9015_mc44s803_config = { - .i2c_address = 0xc0, - .dig_out = 1, -}; - -static struct tda18218_config af9015_tda18218_config = { - .i2c_address = 0xc0, - .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ -}; - -static struct mxl5007t_config af9015_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_24_MHZ, - .if_freq_hz = MxL_IF_4_57_MHZ, -}; - -static int af9015_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct af9015_state *state = adap_to_priv(adap); - int ret; - deb_info("%s:\n", __func__); - - switch (state->af9013_config[adap->id].tuner) { - case AF9013_TUNER_MT2060: - case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, - state->mt2060_if1[adap->id]) - == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_QT1010: - case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_qt1010_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, - &adap_to_d(adap)->i2c_adap, - &af9015_tda18271_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_tda18218_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mxl5003_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mxl5005_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, - &adap_to_d(adap)->i2c_adap, - DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mc44s803_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_UNKNOWN: - default: - ret = -ENODEV; - err("Unknown tuner id:%d", - state->af9013_config[adap->id].tuner); - } - - if (adap->fe[0]->ops.tuner_ops.init) { - state->tuner_init[adap->id] = - adap->fe[0]->ops.tuner_ops.init; - adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; - } - - if (adap->fe[0]->ops.tuner_ops.sleep) { - state->tuner_sleep[adap->id] = - adap->fe[0]->ops.tuner_ops.sleep; - adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; - } - - return ret; -} - -static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); - - if (onoff) - ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0); - else - ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0); - - return ret; -} - -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - int ret; - u8 idx; - - deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", - __func__, index, pid, onoff); - - ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff)); - if (ret) - goto error; - - ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx); - -error: - return ret; -} - -static int af9015_init_endpoint(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u16 frame_size; - u8 packet_size; - deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); - - if (d->udev->speed == USB_SPEED_FULL) { - frame_size = TS_USB11_FRAME_SIZE/4; - packet_size = TS_USB11_MAX_PACKET_SIZE/4; - } else { - frame_size = TS_USB20_FRAME_SIZE/4; - packet_size = TS_USB20_MAX_PACKET_SIZE/4; - } - - ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ - if (ret) - goto error; - } - ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ - if (ret) - goto error; - } - /* EP4 xfer length */ - ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); - if (ret) - goto error; - /* EP5 xfer length */ - ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ - if (ret) - goto error; - } - - /* enable / disable mp2if2 */ - if (state->dual_mode) - ret = af9015_set_reg_bit(d, 0xd50b, 0); - else - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - -error: - if (ret) - err("endpoint init failed:%d", ret); - return ret; -} - -static int af9015_init(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - deb_info("%s:\n", __func__); - - mutex_init(&state->fe_mutex); - - /* init RC canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - ret = af9015_init_endpoint(d); - if (ret) - goto error; - -error: - return ret; -} - -struct af9015_rc_setup { - unsigned int id; - char *rc_codes; -}; - -static char *af9015_rc_setup_match(unsigned int id, - const struct af9015_rc_setup *table) -{ - for (; table->rc_codes; table++) - if (table->id == id) - return table->rc_codes; - return NULL; -} - -static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { - { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, - { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, - { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, - { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, - { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, - { } -}; - -static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { - { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, - { 0xa3703d00, RC_MAP_ALINK_DTU_M }, - { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ - { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ - { } -}; - -static int af9015_rc_query(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u8 buf[17]; - - deb_info("%s:\n", __func__); - - /* read registers needed to detect remote controller code */ - ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); - if (ret) - goto error; - - /* If any of these are non-zero, assume invalid data */ - if (buf[1] || buf[2] || buf[3]) - return ret; - - /* Check for repeat of previous code */ - if ((state->rc_repeat != buf[6] || buf[0]) && - !memcmp(&buf[12], state->rc_last, 4)) { - deb_rc("%s: key repeated\n", __func__); - rc_keydown(d->rc_dev, state->rc_keycode, 0); - state->rc_repeat = buf[6]; - return ret; - } - - /* Only process key if canary killed */ - if (buf[16] != 0xff && buf[0] != 0x01) { - deb_rc("%s: key pressed %*ph\n", __func__, 4, buf + 12); - - /* Reset the canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - /* Remember this key */ - memcpy(state->rc_last, &buf[12], 4); - if (buf[14] == (u8) ~buf[15]) { - if (buf[12] == (u8) ~buf[13]) { - /* NEC */ - state->rc_keycode = buf[12] << 8 | buf[14]; - } else { - /* NEC extended*/ - state->rc_keycode = buf[12] << 16 | - buf[13] << 8 | buf[14]; - } - } else { - /* 32 bit NEC */ - state->rc_keycode = buf[12] << 24 | buf[13] << 16 | - buf[14] << 8 | buf[15]; - } - rc_keydown(d->rc_dev, state->rc_keycode, 0); - } else { - deb_rc("%s: no key press\n", __func__); - /* Invalidate last keypress */ - /* Not really needed, but helps with debug */ - state->rc_last[2] = state->rc_last[3]; - } - - state->rc_repeat = buf[6]; - state->rc_failed = false; - -error: - if (ret) { - err("%s: failed:%d", __func__, ret); - - /* allow random errors as dvb-usb will stop polling on error */ - if (!state->rc_failed) - ret = 0; - - state->rc_failed = true; - } - - return ret; -} - -static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - struct af9015_state *state = d_to_priv(d); - u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); - - if (state->ir_mode == AF9015_IR_MODE_DISABLED) - return 0; - - /* try to load remote based module param */ - if (!rc->map_name) - rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, - af9015_rc_setup_modparam); - - /* try to load remote based eeprom hash */ - if (!rc->map_name) - rc->map_name = af9015_rc_setup_match(state->eeprom_sum, - af9015_rc_setup_hashes); - - /* try to load remote based USB iManufacturer string */ - if (!rc->map_name && vid == USB_VID_AFATECH) { - /* Check USB manufacturer and product strings and try - to determine correct remote in case of chip vendor - reference IDs are used. - DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ - char manufacturer[10]; - memset(manufacturer, 0, sizeof(manufacturer)); - usb_string(d->udev, d->udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); - if (!strcmp("MSI", manufacturer)) { - /* iManufacturer 1 MSI - iProduct 2 MSI K-VOX */ - rc->map_name = af9015_rc_setup_match( - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - af9015_rc_setup_modparam); - } - } - - /* load empty to enable rc */ - if (!rc->map_name) - rc->map_name = RC_MAP_EMPTY; - - rc->allowed_protos = RC_TYPE_NEC; - rc->query = af9015_rc_query; - rc->interval = 500; - - return 0; -} - -/* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ -static struct dvb_usb_device_properties af9015_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct af9015_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9015_identify_state, - .firmware = "dvb-usb-af9015.fw", - .download_firmware = af9015_download_firmware, - - .i2c_algo = &af9015_i2c_algo, - .read_config = af9015_read_config, - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .init = af9015_init, - .get_rc_config = af9015_get_rc_config, - .get_stream_config = af9015_get_stream_config, - - .get_adapter_count = af9015_get_adapter_count, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), - }, - }, -}; - -static const struct usb_device_id af9015_id_table[] = { - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, - &af9015_props, "Afatech AF9015 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, - &af9015_props, "Afatech AF9015 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, - &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) }, - { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, - &af9015_props, "Pinnacle PCTV 71e", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, - &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, - &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) }, - { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, - &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, - &af9015_props, "TerraTec Cinergy T USB XE", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, - &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, - &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) }, - { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, - &af9015_props, "Xtensions XD-380", NULL) }, - { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, - &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, - &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) }, - { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, - &af9015_props, "Telestar Starstick 2", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, - &af9015_props, "AVerMedia A309", NULL) }, - { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, - &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, - &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, - &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, - &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, - &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, - &af9015_props, "KWorld Digial MC-810", NULL) }, - { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, - &af9015_props, "Genius TVGo DVB-T03", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, - &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, - &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, - &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, - &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) }, - { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, - &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, - &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, - &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, - &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, - &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, - &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, - &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, - &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) }, - { } -}; -MODULE_DEVICE_TABLE(usb, af9015_id_table); - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver af9015_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = af9015_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(af9015_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Afatech AF9015 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.h b/drivers/media/dvb/dvb-usb-v2/af9015.h deleted file mode 100644 index c6b304d962a..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/af9015.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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 AF9015_H -#define AF9015_H - -#include -#include "dvb_usb.h" -#include "af9013.h" -#include "dvb-pll.h" -#include "mt2060.h" -#include "qt1010.h" -#include "tda18271.h" -#include "mxl5005s.h" -#include "mc44s803.h" -#include "tda18218.h" -#include "mxl5007t.h" - -#define DVB_USB_LOG_PREFIX "af9015" - -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" -#endif - -#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) - -#undef err -#define err(format, arg...) \ - printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) \ - printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. - We use smaller - about 1/4 from the original, 5 and 87. */ -#define TS_PACKET_SIZE 188 - -#define TS_USB20_PACKET_COUNT 87 -#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) - -#define TS_USB11_PACKET_COUNT 5 -#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) - -#define TS_USB20_MAX_PACKET_SIZE 512 -#define TS_USB11_MAX_PACKET_SIZE 64 - -#define AF9015_I2C_EEPROM 0xa0 -#define AF9015_I2C_DEMOD 0x38 -#define AF9015_USB_TIMEOUT 2000 - -/* EEPROM locations */ -#define AF9015_EEPROM_IR_MODE 0x18 -#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 -#define AF9015_EEPROM_TS_MODE 0x31 -#define AF9015_EEPROM_DEMOD2_I2C 0x32 - -#define AF9015_EEPROM_SAW_BW1 0x35 -#define AF9015_EEPROM_XTAL_TYPE1 0x36 -#define AF9015_EEPROM_SPEC_INV1 0x37 -#define AF9015_EEPROM_IF1L 0x38 -#define AF9015_EEPROM_IF1H 0x39 -#define AF9015_EEPROM_MT2060_IF1L 0x3a -#define AF9015_EEPROM_MT2060_IF1H 0x3b -#define AF9015_EEPROM_TUNER_ID1 0x3c - -#define AF9015_EEPROM_SAW_BW2 0x45 -#define AF9015_EEPROM_XTAL_TYPE2 0x46 -#define AF9015_EEPROM_SPEC_INV2 0x47 -#define AF9015_EEPROM_IF2L 0x48 -#define AF9015_EEPROM_IF2H 0x49 -#define AF9015_EEPROM_MT2060_IF2L 0x4a -#define AF9015_EEPROM_MT2060_IF2H 0x4b -#define AF9015_EEPROM_TUNER_ID2 0x4c - -#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) - -struct req_t { - u8 cmd; /* [0] */ - /* seq */ /* [1] */ - u8 i2c_addr; /* [2] */ - u16 addr; /* [3|4] */ - u8 mbox; /* [5] */ - u8 addr_len; /* [6] */ - u8 data_len; /* [7] */ - u8 *data; -}; - -enum af9015_cmd { - GET_CONFIG = 0x10, - DOWNLOAD_FIRMWARE = 0x11, - BOOT = 0x13, - READ_MEMORY = 0x20, - WRITE_MEMORY = 0x21, - READ_WRITE_I2C = 0x22, - COPY_FIRMWARE = 0x23, - RECONNECT_USB = 0x5a, - WRITE_VIRTUAL_MEMORY = 0x26, - GET_IR_CODE = 0x27, - READ_I2C, - WRITE_I2C, -}; - -enum af9015_ir_mode { - AF9015_IR_MODE_DISABLED = 0, - AF9015_IR_MODE_HID, - AF9015_IR_MODE_RLC, - AF9015_IR_MODE_RC6, - AF9015_IR_MODE_POLLING, /* just guess */ -}; - -struct af9015_state { - u8 ir_mode; - u8 rc_repeat; - u32 rc_keycode; - u8 rc_last[4]; - bool rc_failed; - u8 dual_mode; - u8 seq; /* packet sequence number */ - u16 mt2060_if1[2]; - u16 firmware_size; - u16 firmware_checksum; - u32 eeprom_sum; - struct af9013_config af9013_config[2]; - - /* for demod callback override */ - int (*set_frontend[2]) (struct dvb_frontend *fe); - int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); - int (*init[2]) (struct dvb_frontend *fe); - int (*sleep[2]) (struct dvb_frontend *fe); - int (*tuner_init[2]) (struct dvb_frontend *fe); - int (*tuner_sleep[2]) (struct dvb_frontend *fe); - struct mutex fe_mutex; -}; - -enum af9015_remote { - AF9015_REMOTE_NONE = 0, -/* 1 */ AF9015_REMOTE_A_LINK_DTU_M, - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - AF9015_REMOTE_MYGICTV_U718, - AF9015_REMOTE_DIGITTRADE_DVB_T, -/* 5 */ AF9015_REMOTE_AVERMEDIA_KS, -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/af9035.c b/drivers/media/dvb/dvb-usb-v2/af9035.c deleted file mode 100644 index bb90b877d07..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/af9035.c +++ /dev/null @@ -1,1086 +0,0 @@ -/* - * Afatech AF9035 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "af9035.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static u16 af9035_checksum(const u8 *buf, size_t len) -{ - size_t i; - u16 checksum = 0; - - for (i = 1; i < len; i++) { - if (i % 2) - checksum += buf[i] << 8; - else - checksum += buf[i]; - } - checksum = ~checksum; - - return checksum; -} - -static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) -{ -#define BUF_LEN 64 -#define REQ_HDR_LEN 4 /* send header size */ -#define ACK_HDR_LEN 3 /* rece header size */ -#define CHECKSUM_LEN 2 -#define USB_TIMEOUT 2000 - struct state *state = d_to_priv(d); - int ret, wlen, rlen; - u8 buf[BUF_LEN]; - u16 checksum, tmp_checksum; - - /* buffer overflow check */ - if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || - req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { - pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, - req->wlen, req->rlen); - return -EINVAL; - } - - buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; - buf[1] = req->mbox; - buf[2] = req->cmd; - buf[3] = state->seq++; - memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen); - - wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN; - rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; - - /* calc and add checksum */ - checksum = af9035_checksum(buf, buf[0] - 1); - buf[buf[0] - 1] = (checksum >> 8); - buf[buf[0] - 0] = (checksum & 0xff); - - /* no ack for these packets */ - if (req->cmd == CMD_FW_DL) - rlen = 0; - - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); - if (ret) - goto err; - - /* no ack for those packets */ - if (req->cmd == CMD_FW_DL) - goto exit; - - /* verify checksum */ - checksum = af9035_checksum(buf, rlen - 2); - tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1]; - if (tmp_checksum != checksum) { - pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n", - KBUILD_MODNAME, req->cmd, tmp_checksum, - checksum); - ret = -EIO; - goto err; - } - - /* check status */ - if (buf[2]) { - pr_debug("%s: command=%02x failed fw error=%d\n", __func__, - req->cmd, buf[2]); - ret = -EIO; - goto err; - } - - /* read request, copy returned data to return buf */ - if (req->rlen) - memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); - -exit: - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -/* write multiple registers */ -static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) -{ - u8 wbuf[6 + len]; - u8 mbox = (reg >> 16) & 0xff; - struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; - - wbuf[0] = len; - wbuf[1] = 2; - wbuf[2] = 0; - wbuf[3] = 0; - wbuf[4] = (reg >> 8) & 0xff; - wbuf[5] = (reg >> 0) & 0xff; - memcpy(&wbuf[6], val, len); - - return af9035_ctrl_msg(d, &req); -} - -/* read multiple registers */ -static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) -{ - u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; - u8 mbox = (reg >> 16) & 0xff; - struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; - - return af9035_ctrl_msg(d, &req); -} - -/* write single register */ -static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) -{ - return af9035_wr_regs(d, reg, &val, 1); -} - -/* read single register */ -static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) -{ - return af9035_rd_regs(d, reg, val, 1); -} - -/* write single register with mask */ -static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, - u8 mask) -{ - int ret; - u8 tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = af9035_rd_regs(d, reg, &tmp, 1); - if (ret) - return ret; - - val &= mask; - tmp &= ~mask; - val |= tmp; - } - - return af9035_wr_regs(d, reg, &val, 1); -} - -static int af9035_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct state *state = d_to_priv(d); - int ret; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - /* - * I2C sub header is 5 bytes long. Meaning of those bytes are: - * 0: data len - * 1: I2C addr << 1 - * 2: reg addr len - * byte 3 and 4 can be used as reg addr - * 3: reg addr MSB - * used when reg addr len is set to 2 - * 4: reg addr LSB - * used when reg addr len is set to 1 or 2 - * - * For the simplify we do not use register addr at all. - * NOTE: As a firmware knows tuner type there is very small possibility - * there could be some tuner I2C hacks done by firmware and this may - * lead problems if firmware expects those bytes are used. - */ - if (num == 2 && !(msg[0].flags & I2C_M_RD) && - (msg[1].flags & I2C_M_RD)) { - if (msg[0].len > 40 || msg[1].len > 40) { - /* TODO: correct limits > 40 */ - ret = -EOPNOTSUPP; - } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { - /* integrated demod */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; - ret = af9035_rd_regs(d, reg, &msg[1].buf[0], - msg[1].len); - } else { - /* I2C */ - u8 buf[5 + msg[0].len]; - struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), - buf, msg[1].len, msg[1].buf }; - buf[0] = msg[1].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ - memcpy(&buf[5], msg[0].buf, msg[0].len); - ret = af9035_ctrl_msg(d, &req); - } - } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { - if (msg[0].len > 40) { - /* TODO: correct limits > 40 */ - ret = -EOPNOTSUPP; - } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { - /* integrated demod */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; - ret = af9035_wr_regs(d, reg, &msg[0].buf[3], - msg[0].len - 3); - } else { - /* I2C */ - u8 buf[5 + msg[0].len]; - struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, - 0, NULL }; - buf[0] = msg[0].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ - memcpy(&buf[5], msg[0].buf, msg[0].len); - ret = af9035_ctrl_msg(d, &req); - } - } else { - /* - * We support only two kind of I2C transactions: - * 1) 1 x read + 1 x write - * 2) 1 x write - */ - ret = -EOPNOTSUPP; - } - - mutex_unlock(&d->i2c_mutex); - - if (ret < 0) - return ret; - else - return num; -} - -static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9035_i2c_algo = { - .master_xfer = af9035_i2c_master_xfer, - .functionality = af9035_i2c_functionality, -}; - -static int af9035_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 wbuf[1] = { 1 }; - u8 rbuf[4]; - struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, - sizeof(rbuf), rbuf }; - - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - pr_debug("%s: reply=%*ph\n", __func__, 4, rbuf); - if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) - ret = WARM; - else - ret = COLD; - - return ret; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret, i, j, len; - u8 wbuf[1]; - u8 rbuf[4]; - struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; - struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; - u8 hdr_core; - u16 hdr_addr, hdr_data_len, hdr_checksum; - #define MAX_DATA 58 - #define HDR_SIZE 7 - - /* - * Thanks to Daniel Glöckner about that info! - * - * byte 0: MCS 51 core - * There are two inside the AF9035 (1=Link and 2=OFDM) with separate - * address spaces - * byte 1-2: Big endian destination address - * byte 3-4: Big endian number of data bytes following the header - * byte 5-6: Big endian header checksum, apparently ignored by the chip - * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) - */ - - for (i = fw->size; i > HDR_SIZE;) { - hdr_core = fw->data[fw->size - i + 0]; - hdr_addr = fw->data[fw->size - i + 1] << 8; - hdr_addr |= fw->data[fw->size - i + 2] << 0; - hdr_data_len = fw->data[fw->size - i + 3] << 8; - hdr_data_len |= fw->data[fw->size - i + 4] << 0; - hdr_checksum = fw->data[fw->size - i + 5] << 8; - hdr_checksum |= fw->data[fw->size - i + 6] << 0; - - pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", - __func__, hdr_core, hdr_addr, hdr_data_len, - hdr_checksum); - - if (((hdr_core != 1) && (hdr_core != 2)) || - (hdr_data_len > i)) { - pr_debug("%s: bad firmware\n", __func__); - break; - } - - /* download begin packet */ - req.cmd = CMD_FW_DL_BEGIN; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* download firmware packet(s) */ - for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { - len = j; - if (len > MAX_DATA) - len = MAX_DATA; - req_fw_dl.wlen = len; - req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + - HDR_SIZE + hdr_data_len - j]; - ret = af9035_ctrl_msg(d, &req_fw_dl); - if (ret < 0) - goto err; - } - - /* download end packet */ - req.cmd = CMD_FW_DL_END; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - i -= hdr_data_len + HDR_SIZE; - - pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); - } - - /* firmware loaded, request boot */ - req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* ensure firmware starts */ - wbuf[0] = 1; - ret = af9035_ctrl_msg(d, &req_fw_ver); - if (ret < 0) - goto err; - - if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - pr_err("%s: firmware did not run\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, - rbuf[0], rbuf[1], rbuf[2], rbuf[3]); - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_download_firmware_it9135(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret, i, i_prev; - u8 wbuf[1]; - u8 rbuf[4]; - struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; - #define HDR_SIZE 7 - - /* - * There seems to be following firmware header. Meaning of bytes 0-3 - * is unknown. - * - * 0: 3 - * 1: 0, 1 - * 2: 0 - * 3: 1, 2, 3 - * 4: addr MSB - * 5: addr LSB - * 6: count of data bytes ? - */ - - for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { - if (i == fw->size || - (fw->data[i + 0] == 0x03 && - (fw->data[i + 1] == 0x00 || - fw->data[i + 1] == 0x01) && - fw->data[i + 2] == 0x00)) { - req_fw_dl.wlen = i - i_prev; - req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; - i_prev = i; - ret = af9035_ctrl_msg(d, &req_fw_dl); - if (ret < 0) - goto err; - - pr_debug("%s: data uploaded=%d\n", __func__, i); - } - } - - /* firmware loaded, request boot */ - req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* ensure firmware starts */ - wbuf[0] = 1; - ret = af9035_ctrl_msg(d, &req_fw_ver); - if (ret < 0) - goto err; - - if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - pr_err("%s: firmware did not run\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, - rbuf[0], rbuf[1], rbuf[2], rbuf[3]); - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_read_config(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i, eeprom_shift = 0; - u8 tmp; - u16 tmp16; - - /* check if there is dual tuners */ - ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); - if (ret < 0) - goto err; - - state->dual_mode = tmp; - pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode); - - for (i = 0; i < state->dual_mode + 1; i++) { - /* tuner */ - ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); - if (ret < 0) - goto err; - - state->af9033_config[i].tuner = tmp; - pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); - - switch (tmp) { - case AF9033_TUNER_TUA9001: - case AF9033_TUNER_FC0011: - case AF9033_TUNER_MXL5007T: - case AF9033_TUNER_TDA18218: - state->af9033_config[i].spec_inv = 1; - break; - default: - pr_info("%s: tuner ID=%02x not supported, please " \ - "report!", KBUILD_MODNAME, tmp); - }; - - /* tuner IF frequency */ - ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); - if (ret < 0) - goto err; - - tmp16 = tmp; - - ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); - if (ret < 0) - goto err; - - tmp16 |= tmp << 8; - - pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); - - eeprom_shift = 0x10; /* shift for the 2nd tuner params */ - } - - /* get demod clock */ - ret = af9035_rd_reg(d, 0x00d800, &tmp); - if (ret < 0) - goto err; - - tmp = (tmp >> 0) & 0x0f; - - for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) - state->af9033_config[i].clock = clock_lut[tmp]; - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_read_config_it9135(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i; - u8 tmp; - - state->dual_mode = false; - - /* get demod clock */ - ret = af9035_rd_reg(d, 0x00d800, &tmp); - if (ret < 0) - goto err; - - tmp = (tmp >> 0) & 0x0f; - - for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) - state->af9033_config[i].clock = clock_lut_it9135[tmp]; - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, - int cmd, int arg) -{ - int ret; - - switch (cmd) { - case FC0011_FE_CALLBACK_POWER: - /* Tuner enable */ - ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); - if (ret < 0) - goto err; - - /* LED */ - ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); - if (ret < 0) - goto err; - - usleep_range(10000, 50000); - break; - case FC0011_FE_CALLBACK_RESET: - ret = af9035_wr_reg(d, 0xd8e9, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0xd8e8, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0xd8e7, 1); - if (ret < 0) - goto err; - - usleep_range(10000, 20000); - - ret = af9035_wr_reg(d, 0xd8e7, 0); - if (ret < 0) - goto err; - - usleep_range(10000, 20000); - break; - default: - ret = -EINVAL; - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) -{ - struct state *state = d_to_priv(d); - - switch (state->af9033_config[0].tuner) { - case AF9033_TUNER_FC0011: - return af9035_fc0011_tuner_callback(d, cmd, arg); - default: - break; - } - - return -ENODEV; -} - -static int af9035_frontend_callback(void *adapter_priv, int component, - int cmd, int arg) -{ - struct i2c_adapter *adap = adapter_priv; - struct dvb_usb_device *d = i2c_get_adapdata(adap); - - switch (component) { - case DVB_FRONTEND_COMPONENT_TUNER: - return af9035_tuner_callback(d, cmd, arg); - default: - break; - } - - return -EINVAL; -} - -static int af9035_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - - if (!state->af9033_config[adap->id].tuner) { - /* unsupported tuner */ - ret = -ENODEV; - goto err; - } - - if (adap->id == 0) { - state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; - state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; - - ret = af9035_wr_reg(d, 0x00417f, - state->af9033_config[1].i2c_addr); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x00d81a, - state->dual_mode); - if (ret < 0) - goto err; - } - - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9033_attach, - &state->af9033_config[adap->id], &d->i2c_adap); - if (adap->fe[0] == NULL) { - ret = -ENODEV; - goto err; - } - - /* disable I2C-gate */ - adap->fe[0]->ops.i2c_gate_ctrl = NULL; - adap->fe[0]->callback = af9035_frontend_callback; - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static struct tua9001_config af9035_tua9001_config = { - .i2c_addr = 0x60, -}; - -static const struct fc0011_config af9035_fc0011_config = { - .i2c_address = 0x60, -}; - -static struct mxl5007t_config af9035_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_24_MHZ, - .if_freq_hz = MxL_IF_4_57_MHZ, - .invert_if = 0, - .loop_thru_enable = 0, - .clk_out_enable = 0, - .clk_out_amp = MxL_CLKOUT_AMP_0_94V, -}; - -static struct tda18218_config af9035_tda18218_config = { - .i2c_address = 0x60, - .i2c_wr_max = 21, -}; - -static int af9035_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - struct dvb_frontend *fe; - - switch (state->af9033_config[adap->id].tuner) { - case AF9033_TUNER_TUA9001: - /* AF9035 gpiot3 = TUA9001 RESETN - AF9035 gpiot2 = TUA9001 RXEN */ - - /* configure gpiot2 and gpiot2 as output */ - ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01); - if (ret < 0) - goto err; - - /* reset tuner */ - ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01); - if (ret < 0) - goto err; - - usleep_range(2000, 20000); - - ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01); - if (ret < 0) - goto err; - - /* activate tuner RX */ - /* TODO: use callback for TUA9001 RXEN */ - ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01); - if (ret < 0) - goto err; - - /* attach tuner */ - fe = dvb_attach(tua9001_attach, adap->fe[0], - &d->i2c_adap, &af9035_tua9001_config); - break; - case AF9033_TUNER_FC0011: - fe = dvb_attach(fc0011_attach, adap->fe[0], - &d->i2c_adap, &af9035_fc0011_config); - break; - case AF9033_TUNER_MXL5007T: - ret = af9035_wr_reg(d, 0x00d8e0, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8e1, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8df, 0); - if (ret < 0) - goto err; - - msleep(30); - - ret = af9035_wr_reg(d, 0x00d8df, 1); - if (ret < 0) - goto err; - - msleep(300); - - ret = af9035_wr_reg(d, 0x00d8c0, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8c1, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8bf, 0); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8b4, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8b5, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8b3, 1); - if (ret < 0) - goto err; - - /* attach tuner */ - fe = dvb_attach(mxl5007t_attach, adap->fe[0], - &d->i2c_adap, 0x60, &af9035_mxl5007t_config); - break; - case AF9033_TUNER_TDA18218: - /* attach tuner */ - fe = dvb_attach(tda18218_attach, adap->fe[0], - &d->i2c_adap, &af9035_tda18218_config); - break; - default: - fe = NULL; - } - - if (fe == NULL) { - ret = -ENODEV; - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_init(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i; - u16 frame_size = 87 * 188 / 4; - u8 packet_size = 512 / 4; - struct reg_val_mask tab[] = { - { 0x80f99d, 0x01, 0x01 }, - { 0x80f9a4, 0x01, 0x01 }, - { 0x00dd11, 0x00, 0x20 }, - { 0x00dd11, 0x00, 0x40 }, - { 0x00dd13, 0x00, 0x20 }, - { 0x00dd13, 0x00, 0x40 }, - { 0x00dd11, 0x20, 0x20 }, - { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, - { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, - { 0x00dd0c, packet_size, 0xff}, - { 0x00dd11, state->dual_mode << 6, 0x40 }, - { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, - { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, - { 0x00dd0d, packet_size, 0xff }, - { 0x80f9a3, 0x00, 0x01 }, - { 0x80f9cd, 0x00, 0x01 }, - { 0x80f99d, 0x00, 0x01 }, - { 0x80f9a4, 0x00, 0x01 }, - }; - - pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", - __func__, d->udev->speed, frame_size, packet_size); - - /* init endpoints */ - for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, - tab[i].mask); - if (ret < 0) - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_rc_query(struct dvb_usb_device *d) -{ - unsigned int key; - unsigned char b[4]; - int ret; - struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; - - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - if ((b[2] + b[3]) == 0xff) { - if ((b[0] + b[1]) == 0xff) { - /* NEC */ - key = b[0] << 8 | b[2]; - } else { - /* ext. NEC */ - key = b[0] << 16 | b[1] << 8 | b[2]; - } - } else { - key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; - } - - rc_keydown(d->rc_dev, key, 0); - -err: - /* ignore errors */ - return 0; -} - -static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - int ret; - u8 tmp; - - ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); - if (ret < 0) - goto err; - - pr_debug("%s: ir_mode=%02x\n", __func__, tmp); - - /* don't activate rc if in HID mode or if not available */ - if (tmp == 5) { - ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); - if (ret < 0) - goto err; - - pr_debug("%s: ir_type=%02x\n", __func__, tmp); - - switch (tmp) { - case 0: /* NEC */ - default: - rc->allowed_protos = RC_TYPE_NEC; - break; - case 1: /* RC6 */ - rc->allowed_protos = RC_TYPE_RC6; - break; - } - - rc->query = af9035_rc_query; - rc->interval = 500; - - /* load empty to enable rc */ - if (!rc->map_name) - rc->map_name = RC_MAP_EMPTY; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -/* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ -static const struct dvb_usb_device_properties af9035_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9035_identify_state, - .firmware = "dvb-usb-af9035-02.fw", - .download_firmware = af9035_download_firmware, - - .i2c_algo = &af9035_i2c_algo, - .read_config = af9035_read_config, - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .init = af9035_init, - .get_rc_config = af9035_get_rc_config, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), - }, - }, -}; - -static const struct dvb_usb_device_properties it9135_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9035_identify_state, - .firmware = "dvb-usb-it9135-01.fw", - .download_firmware = af9035_download_firmware_it9135, - - .i2c_algo = &af9035_i2c_algo, - .read_config = af9035_read_config_it9135, - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .init = af9035_init, - .get_rc_config = af9035_get_rc_config, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), - }, - }, -}; - -static const struct usb_device_id af9035_id_table[] = { - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK, - &af9035_props, "TerraTec Cinergy T Stick", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835, - &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835, - &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867, - &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867, - &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR, - &af9035_props, "AVerMedia Twinstar (A825)", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, af9035_id_table); - -static struct usb_driver af9035_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = af9035_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(af9035_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Afatech AF9035 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/af9035.h b/drivers/media/dvb/dvb-usb-v2/af9035.h deleted file mode 100644 index 59ff69ede0f..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/af9035.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Afatech AF9035 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef AF9035_H -#define AF9035_H - -#include "dvb_usb.h" -#include "af9033.h" -#include "tua9001.h" -#include "fc0011.h" -#include "mxl5007t.h" -#include "tda18218.h" - -struct reg_val { - u32 reg; - u8 val; -}; - -struct reg_val_mask { - u32 reg; - u8 val; - u8 mask; -}; - -struct usb_req { - u8 cmd; - u8 mbox; - u8 wlen; - u8 *wbuf; - u8 rlen; - u8 *rbuf; -}; - -struct state { - u8 seq; /* packet sequence number */ - bool dual_mode; - - struct af9033_config af9033_config[2]; -}; - -u32 clock_lut[] = { - 20480000, /* FPGA */ - 16384000, /* 16.38 MHz */ - 20480000, /* 20.48 MHz */ - 36000000, /* 36.00 MHz */ - 30000000, /* 30.00 MHz */ - 26000000, /* 26.00 MHz */ - 28000000, /* 28.00 MHz */ - 32000000, /* 32.00 MHz */ - 34000000, /* 34.00 MHz */ - 24000000, /* 24.00 MHz */ - 22000000, /* 22.00 MHz */ - 12000000, /* 12.00 MHz */ -}; - -u32 clock_lut_it9135[] = { - 12000000, /* 12.00 MHz */ - 20480000, /* 20.48 MHz */ - 36000000, /* 36.00 MHz */ - 30000000, /* 30.00 MHz */ - 26000000, /* 26.00 MHz */ - 28000000, /* 28.00 MHz */ - 32000000, /* 32.00 MHz */ - 34000000, /* 34.00 MHz */ - 24000000, /* 24.00 MHz */ - 22000000, /* 22.00 MHz */ -}; - -/* EEPROM locations */ -#define EEPROM_IR_MODE 0x430d -#define EEPROM_DUAL_MODE 0x4326 -#define EEPROM_IR_TYPE 0x4329 -#define EEPROM_1_IFFREQ_L 0x432d -#define EEPROM_1_IFFREQ_H 0x432e -#define EEPROM_1_TUNER_ID 0x4331 -#define EEPROM_2_IFFREQ_L 0x433d -#define EEPROM_2_IFFREQ_H 0x433e -#define EEPROM_2_TUNER_ID 0x4341 - -/* USB commands */ -#define CMD_MEM_RD 0x00 -#define CMD_MEM_WR 0x01 -#define CMD_I2C_RD 0x02 -#define CMD_I2C_WR 0x03 -#define CMD_IR_GET 0x18 -#define CMD_FW_DL 0x21 -#define CMD_FW_QUERYINFO 0x22 -#define CMD_FW_BOOT 0x23 -#define CMD_FW_DL_BEGIN 0x24 -#define CMD_FW_DL_END 0x25 -#define CMD_FW_SCATTER_WR 0x29 - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/anysee.c b/drivers/media/dvb/dvb-usb-v2/anysee.c deleted file mode 100644 index fb3829a73d2..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/anysee.c +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * 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. - * - * TODO: - * - add smart card reader support for Conditional Access (CA) - * - * Card reader in Anysee is nothing more than ISO 7816 card reader. - * There is no hardware CAM in any Anysee device sold. - * In my understanding it should be implemented by making own module - * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This - * module registers serial interface that can be used to communicate - * with any ISO 7816 smart card. - * - * Any help according to implement serial smart card reader support - * is highly welcome! - */ - -#include "anysee.h" -#include "dvb-pll.h" -#include "tda1002x.h" -#include "mt352.h" -#include "mt352_priv.h" -#include "zl10353.h" -#include "tda18212.h" -#include "cx24116.h" -#include "stv0900.h" -#include "stv6110.h" -#include "isl6423.h" -#include "cxd2820r.h" - -/* debug */ -static int dvb_usb_anysee_debug; -module_param_named(debug, dvb_usb_anysee_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static DEFINE_MUTEX(anysee_usb_mutex); - -static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, - u8 *rbuf, u8 rlen) -{ - struct anysee_state *state = d_to_priv(d); - int act_len, ret, i; - u8 buf[64]; - - memcpy(&buf[0], sbuf, slen); - buf[60] = state->seq++; - - mutex_lock(&anysee_usb_mutex); - - deb_xfer(">>> "); - debug_dump(buf, slen, deb_xfer); - - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf)); - if (ret) - goto error_unlock; - - /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 - * (EPIPE, Broken pipe). Function supports currently msleep() as a - * parameter but I would not like to use it, since according to - * Documentation/timers/timers-howto.txt it should not be used such - * short, under < 20ms, sleeps. Repeating failed message would be - * better choice as not to add unwanted delays... - * Fixing that correctly is one of those or both; - * 1) use repeat if possible - * 2) add suitable delay - */ - - /* get answer, retry few times if error returned */ - for (i = 0; i < 3; i++) { - /* receive 2nd answer */ - ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf), - &act_len, 2000); - - if (ret) { - deb_info("%s: recv bulk message failed: %d", - __func__, ret); - } else { - deb_xfer("<<< "); - debug_dump(buf, rlen, deb_xfer); - - if (buf[63] != 0x4f) - deb_info("%s: cmd failed\n", __func__); - - break; - } - } - - if (ret) { - /* all retries failed, it is fatal */ - err("%s: recv bulk message failed: %d", __func__, ret); - goto error_unlock; - } - - /* read request, copy returned data to return buf */ - if (rbuf && rlen) - memcpy(rbuf, buf, rlen); - -error_unlock: - mutex_unlock(&anysee_usb_mutex); - - return ret; -} - -static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) -{ - u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; - int ret; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); - deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); - return ret; -} - -static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) -{ - u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; - deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -/* write single register with mask */ -static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, - u8 mask) -{ - int ret; - u8 tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = anysee_read_reg(d, reg, &tmp); - if (ret) - return ret; - - val &= mask; - tmp &= ~mask; - val |= tmp; - } - - return anysee_write_reg(d, reg, val); -} - -/* read single register with mask */ -static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, - u8 mask) -{ - int ret, i; - u8 tmp; - - ret = anysee_read_reg(d, reg, &tmp); - if (ret) - return ret; - - tmp &= mask; - - /* find position of the first bit */ - for (i = 0; i < 8; i++) { - if ((mask >> i) & 0x01) - break; - } - *val = tmp >> i; - - return 0; -} - -static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) -{ - u8 buf[] = {CMD_GET_HW_INFO}; - return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); -} - -static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; - deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0); -} - -static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) -{ - u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; - deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) -{ - u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; - deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -/* I2C */ -static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, inc, i = 0; - u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */ - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 2 || msg[i+1].len > 60) { - ret = -EOPNOTSUPP; - break; - } - buf[0] = CMD_I2C_READ; - buf[1] = (msg[i].addr << 1) | 0x01; - buf[2] = msg[i].buf[0]; - buf[3] = msg[i].buf[1]; - buf[4] = msg[i].len-1; - buf[5] = msg[i+1].len; - ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf, - msg[i+1].len); - inc = 2; - } else { - if (msg[i].len > 48) { - ret = -EOPNOTSUPP; - break; - } - buf[0] = CMD_I2C_WRITE; - buf[1] = (msg[i].addr << 1); - buf[2] = msg[i].len; - buf[3] = 0x01; - memcpy(&buf[4], msg[i].buf, msg[i].len); - ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0); - inc = 1; - } - if (ret) - break; - - i += inc; - } - - mutex_unlock(&d->i2c_mutex); - - return ret ? ret : i; -} - -static u32 anysee_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm anysee_i2c_algo = { - .master_xfer = anysee_master_xfer, - .functionality = anysee_i2c_func, -}; - -static int anysee_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset[] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -/* Callbacks for DVB USB */ -static struct tda10023_config anysee_tda10023_config = { - .demod_address = (0x1a >> 1), - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, - .deltaf = 0xfeeb, -}; - -static struct mt352_config anysee_mt352_config = { - .demod_address = (0x1e >> 1), - .demod_init = anysee_mt352_demod_init, -}; - -static struct zl10353_config anysee_zl10353_config = { - .demod_address = (0x1e >> 1), - .parallel_ts = 1, -}; - -static struct zl10353_config anysee_zl10353_tda18212_config2 = { - .demod_address = (0x1e >> 1), - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, - .no_tuner = 1, - .if2 = 41500, -}; - -static struct zl10353_config anysee_zl10353_tda18212_config = { - .demod_address = (0x18 >> 1), - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, - .no_tuner = 1, - .if2 = 41500, -}; - -static struct tda10023_config anysee_tda10023_tda18212_config = { - .demod_address = (0x1a >> 1), - .xtal = 16000000, - .pll_m = 12, - .pll_p = 3, - .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, - .deltaf = 0xba02, -}; - -static struct tda18212_config anysee_tda18212_config = { - .i2c_address = (0xc0 >> 1), - .if_dvbt_6 = 4150, - .if_dvbt_7 = 4150, - .if_dvbt_8 = 4150, - .if_dvbc = 5000, -}; - -static struct tda18212_config anysee_tda18212_config2 = { - .i2c_address = 0x60 /* (0xc0 >> 1) */, - .if_dvbt_6 = 3550, - .if_dvbt_7 = 3700, - .if_dvbt_8 = 4150, - .if_dvbt2_6 = 3250, - .if_dvbt2_7 = 4000, - .if_dvbt2_8 = 4000, - .if_dvbc = 5000, -}; - -static struct cx24116_config anysee_cx24116_config = { - .demod_address = (0xaa >> 1), - .mpg_clk_pos_pol = 0x00, - .i2c_wr_max = 48, -}; - -static struct stv0900_config anysee_stv0900_config = { - .demod_address = (0xd0 >> 1), - .demod_mode = 0, - .xtal = 8000000, - .clkmode = 3, - .diseqc_mode = 2, - .tun1_maddress = 0, - .tun1_adc = 1, /* 1 Vpp */ - .path1_mode = 3, -}; - -static struct stv6110_config anysee_stv6110_config = { - .i2c_address = (0xc0 >> 1), - .mclk = 16000000, - .clk_div = 1, -}; - -static struct isl6423_config anysee_isl6423_config = { - .current_max = SEC_CURRENT_800m, - .curlim = SEC_CURRENT_LIM_OFF, - .mod_extern = 1, - .addr = (0x10 >> 1), -}; - -static struct cxd2820r_config anysee_cxd2820r_config = { - .i2c_address = 0x6d, /* (0xda >> 1) */ - .ts_mode = 0x38, -}; - -/* - * New USB device strings: Mfr=1, Product=2, SerialNumber=0 - * Manufacturer: AMT.CO.KR - * - * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=???????? - * PCB: ? - * parts: DNOS404ZH102A(MT352, DTT7579(?)) - * - * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)" - * PCB: PCB 507T (rev1.61) - * parts: DNOS404ZH103A(ZL10353, DTT7579(?)) - * OEA=0a OEB=00 OEC=00 OED=ff OEE=00 - * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00 - * - * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee" - * PCB: 507CD (rev1.1) - * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01 - * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe - * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01 - * IOD[0] ZL10353 1=enabled - * IOA[7] TS 0=enabled - * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not) - * - * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)" - * PCB: 507DC (rev0.2) - * parts: TDA10023, DTOS403IH102B TM, CST56I01 - * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe - * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01 - * IOD[0] TDA10023 1=enabled - * - * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)" - * PCB: 507SI (rev2.1) - * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe - * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01 - * IOD[0] CX24116 1=enabled - * - * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" - * PCB: 507FA (rev0.4) - * parts: TDA10023, DTOS403IH102B TM, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff - * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 - * IOD[5] TDA10023 1=enabled - * IOE[0] tuner 1=enabled - * - * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" - * PCB: 507FA (rev1.1) - * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff - * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 - * DVB-C: - * IOD[5] TDA10023 1=enabled - * IOE[0] tuner 1=enabled - * DVB-T: - * IOD[0] ZL10353 1=enabled - * IOE[0] tuner 0=enabled - * tuner is behind ZL10353 I2C-gate - * - * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" - * PCB: 508TC (rev0.6) - * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[4] TDA18212 1=enabled - * DVB-C: - * IOD[6] ZL10353 0=disabled - * IOD[5] TDA10023 1=enabled - * IOE[0] IF 1=enabled - * DVB-T: - * IOD[5] TDA10023 0=disabled - * IOD[6] ZL10353 1=enabled - * IOE[0] IF 0=enabled - * - * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)" - * PCB: 508S2 (rev0.7) - * parts: DNBU10512IST(STV0903, STV6110), ISL6423 - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[5] STV0903 1=enabled - * - * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" - * PCB: 508T2C (rev0.3) - * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[5] CXD2820R 1=enabled - * - * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" - * PCB: 508PTC (rev0.5) - * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[4] TDA18212 1=enabled - * DVB-C: - * IOD[6] ZL10353 0=disabled - * IOD[5] TDA10023 1=enabled - * IOE[0] IF 1=enabled - * DVB-T: - * IOD[5] TDA10023 0=disabled - * IOD[6] ZL10353 1=enabled - * IOE[0] IF 0=enabled - * - * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" - * PCB: 508PS2 (rev0.4) - * parts: DNBU10512IST(STV0903, STV6110), ISL6423 - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[5] STV0903 1=enabled - */ - -static int anysee_read_config(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - int ret; - u8 hw_info[3]; - - /* - * Check which hardware we have. - * We must do this call two times to get reliable values (hw/fw bug). - */ - ret = anysee_get_hw_info(d, hw_info); - if (ret) - goto error; - - ret = anysee_get_hw_info(d, hw_info); - if (ret) - goto error; - - /* Meaning of these info bytes are guessed. */ - info("firmware version:%d.%d hardware id:%d", - hw_info[1], hw_info[2], hw_info[0]); - - state->hw = hw_info[0]; -error: - return ret; -} - -/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ -static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - /* enable / disable tuner access on IOE[4] */ - return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10); -} - -static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct anysee_state *state = fe_to_priv(fe); - struct dvb_usb_device *d = fe_to_d(fe); - int ret; - - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - /* no frontend sleep control */ - if (onoff == 0) - return 0; - - switch (state->hw) { - case ANYSEE_HW_507FA: /* 15 */ - /* E30 Combo Plus */ - /* E30 C Plus */ - - if (fe->id == 0) { - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-C tuner on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); - if (ret) - goto error; - } else { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* enable DVB-T tuner on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); - if (ret) - goto error; - } - - break; - case ANYSEE_HW_508TC: /* 18 */ - case ANYSEE_HW_508PTC: /* 21 */ - /* E7 TC */ - /* E7 PTC */ - - if (fe->id == 0) { - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); - if (ret) - goto error; - } else { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); - if (ret) - goto error; - - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); - if (ret) - goto error; - } - - break; - default: - ret = 0; - } - -error: - return ret; -} - -static int anysee_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct anysee_state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - u8 tmp; - struct i2c_msg msg[2] = { - { - .addr = anysee_tda18212_config.i2c_address, - .flags = 0, - .len = 1, - .buf = "\x00", - }, { - .addr = anysee_tda18212_config.i2c_address, - .flags = I2C_M_RD, - .len = 1, - .buf = &tmp, - } - }; - - switch (state->hw) { - case ANYSEE_HW_507T: /* 2 */ - /* E30 */ - - /* attach demod */ - adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, - &d->i2c_adap); - if (adap->fe[0]) - break; - - /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &d->i2c_adap); - - break; - case ANYSEE_HW_507CD: /* 6 */ - /* E30 Plus */ - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &d->i2c_adap); - - break; - case ANYSEE_HW_507DC: /* 10 */ - /* E30 C Plus */ - - /* enable DVB-C demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, &d->i2c_adap, 0x48); - - break; - case ANYSEE_HW_507SI: /* 11 */ - /* E30 S2 Plus */ - - /* enable DVB-S/S2 demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, - &d->i2c_adap); - - break; - case ANYSEE_HW_507FA: /* 15 */ - /* E30 Combo Plus */ - /* E30 C Plus */ - - /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10); - if (ret) - goto error; - - /* probe TDA18212 */ - tmp = 0; - ret = i2c_transfer(&d->i2c_adap, msg, 2); - if (ret == 2 && tmp == 0xc7) - deb_info("%s: TDA18212 found\n", __func__); - else - tmp = 0; - - /* disable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10); - if (ret) - goto error; - - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - if (tmp == 0xc7) { - /* TDA18212 config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &d->i2c_adap, 0x48); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[0]) - adap->fe[0]->ops.i2c_gate_ctrl = - anysee_i2c_gate_ctrl; - } else { - /* PLL config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, - &d->i2c_adap, 0x48); - } - - /* break out if first frontend attaching fails */ - if (!adap->fe[0]) - break; - - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* attach demod */ - if (tmp == 0xc7) { - /* TDA18212 config */ - adap->fe[1] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config2, - &d->i2c_adap); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[1]) - adap->fe[1]->ops.i2c_gate_ctrl = - anysee_i2c_gate_ctrl; - } else { - /* PLL config */ - adap->fe[1] = dvb_attach(zl10353_attach, - &anysee_zl10353_config, - &d->i2c_adap); - } - - break; - case ANYSEE_HW_508TC: /* 18 */ - case ANYSEE_HW_508PTC: /* 21 */ - /* E7 TC */ - /* E7 PTC */ - - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &d->i2c_adap, 0x48); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[0]) - adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; - - /* break out if first frontend attaching fails */ - if (!adap->fe[0]) - break; - - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); - if (ret) - goto error; - - /* attach demod */ - adap->fe[1] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config, - &d->i2c_adap); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[1]) - adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; - - state->has_ci = true; - - break; - case ANYSEE_HW_508S2: /* 19 */ - case ANYSEE_HW_508PS2: /* 22 */ - /* E7 S2 */ - /* E7 PS2 */ - - /* enable DVB-S/S2 demod on IOE[5] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(stv0900_attach, - &anysee_stv0900_config, &d->i2c_adap, 0); - - state->has_ci = true; - - break; - case ANYSEE_HW_508T2C: /* 20 */ - /* E7 T2C */ - - /* enable DVB-T/T2/C demod on IOE[5] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(cxd2820r_attach, - &anysee_cxd2820r_config, &d->i2c_adap); - - state->has_ci = true; - - break; - } - - if (!adap->fe[0]) { - /* we have no frontend :-( */ - ret = -ENODEV; - err("Unsupported Anysee version. " \ - "Please report the ."); - } -error: - return ret; -} - -static int anysee_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct anysee_state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - struct dvb_frontend *fe; - int ret; - deb_info("%s: adap=%d\n", __func__, adap->id); - - switch (state->hw) { - case ANYSEE_HW_507T: /* 2 */ - /* E30 */ - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, - DVB_PLL_THOMSON_DTT7579); - - break; - case ANYSEE_HW_507CD: /* 6 */ - /* E30 Plus */ - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), - &d->i2c_adap, DVB_PLL_THOMSON_DTT7579); - - break; - case ANYSEE_HW_507DC: /* 10 */ - /* E30 C Plus */ - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); - - break; - case ANYSEE_HW_507SI: /* 11 */ - /* E30 S2 Plus */ - - /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap, - &anysee_isl6423_config); - - break; - case ANYSEE_HW_507FA: /* 15 */ - /* E30 Combo Plus */ - /* E30 C Plus */ - - /* Try first attach TDA18212 silicon tuner on IOE[4], if that - * fails attach old simple PLL. */ - - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config); - - if (fe && adap->fe[1]) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(tda18212_attach, adap->fe[1], - &d->i2c_adap, &anysee_tda18212_config); - break; - } else if (fe) { - break; - } - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); - - if (fe && adap->fe[1]) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], - (0xc0 >> 1), &d->i2c_adap, - DVB_PLL_SAMSUNG_DTOS403IH102A); - } - - break; - case ANYSEE_HW_508TC: /* 18 */ - case ANYSEE_HW_508PTC: /* 21 */ - /* E7 TC */ - /* E7 PTC */ - - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config); - - if (fe) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(tda18212_attach, adap->fe[1], - &d->i2c_adap, &anysee_tda18212_config); - } - - break; - case ANYSEE_HW_508S2: /* 19 */ - case ANYSEE_HW_508PS2: /* 22 */ - /* E7 S2 */ - /* E7 PS2 */ - - /* attach tuner */ - fe = dvb_attach(stv6110_attach, adap->fe[0], - &anysee_stv6110_config, &d->i2c_adap); - - if (fe) { - /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], - &d->i2c_adap, &anysee_isl6423_config); - } - - break; - - case ANYSEE_HW_508T2C: /* 20 */ - /* E7 T2C */ - - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config2); - - break; - default: - fe = NULL; - } - - if (fe) - ret = 0; - else - ret = -ENODEV; - - return ret; -} - -static int anysee_rc_query(struct dvb_usb_device *d) -{ - u8 buf[] = {CMD_GET_IR_CODE}; - u8 ircode[2]; - int ret; - - /* Remote controller is basic NEC using address byte 0x08. - Anysee device RC query returns only two bytes, status and code, - address byte is dropped. Also it does not return any value for - NEC RCs having address byte other than 0x08. Due to that, we - cannot use that device as standard NEC receiver. - It could be possible make hack which reads whole code directly - from device memory... */ - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode)); - if (ret) - return ret; - - if (ircode[0]) { - deb_rc("%s: key pressed %02x\n", __func__, ircode[1]); - rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0); - } - - return 0; -} - -static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - rc->allowed_protos = RC_TYPE_NEC; - rc->query = anysee_rc_query; - rc->interval = 250; /* windows driver uses 500ms */ - - return 0; -} - -static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, - int addr) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; - u8 val; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); - if (ret) - return ret; - - return val; -} - -static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, - int addr, u8 val) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, - u8 addr) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; - u8 val; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); - if (ret) - return ret; - - return val; -} - -static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, - u8 addr, u8 val) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) -{ - struct dvb_usb_device *d = ci->data; - int ret; - struct anysee_state *state = d_to_priv(d); - - state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); - - ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); - if (ret) - return ret; - - msleep(300); - - ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) -{ - struct dvb_usb_device *d = ci->data; - int ret; - - ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); - if (ret) - return ret; - - msleep(30); - - ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) -{ - struct dvb_usb_device *d = ci->data; - int ret; - - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, - int open) -{ - struct dvb_usb_device *d = ci->data; - struct anysee_state *state = d_to_priv(d); - int ret; - u8 tmp; - - ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); - if (ret) - return ret; - - if (tmp == 0) { - ret = DVB_CA_EN50221_POLL_CAM_PRESENT; - if (time_after(jiffies, state->ci_cam_ready)) - ret |= DVB_CA_EN50221_POLL_CAM_READY; - } - - return ret; -} - -static int anysee_ci_init(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - int ret; - - state->ci.owner = THIS_MODULE; - state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; - state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; - state->ci.read_cam_control = anysee_ci_read_cam_control; - state->ci.write_cam_control = anysee_ci_write_cam_control; - state->ci.slot_reset = anysee_ci_slot_reset; - state->ci.slot_shutdown = anysee_ci_slot_shutdown; - state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; - state->ci.poll_slot_status = anysee_ci_poll_slot_status; - state->ci.data = d; - - ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); - if (ret) - return ret; - - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07); - if (ret) - return ret; - - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07); - if (ret) - return ret; - - ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); - if (ret) - return ret; - - return 0; -} - -static void anysee_ci_release(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - - /* detach CI */ - if (state->has_ci) - dvb_ca_en50221_release(&state->ci); - - return; -} - -static int anysee_init(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - int ret; - - /* There is one interface with two alternate settings. - Alternate setting 0 is for bulk transfer. - Alternate setting 1 is for isochronous transfer. - We use bulk transfer (alternate setting 0). */ - ret = usb_set_interface(d->udev, 0, 0); - if (ret) - return ret; - - /* LED light */ - ret = anysee_led_ctrl(d, 0x01, 0x03); - if (ret) - return ret; - - /* enable IR */ - ret = anysee_ir_ctrl(d, 1); - if (ret) - return ret; - - /* attach CI */ - if (state->has_ci) { - ret = anysee_ci_init(d); - if (ret) { - state->has_ci = false; - return ret; - } - } - - return 0; -} - -static void anysee_exit(struct dvb_usb_device *d) -{ - return anysee_ci_release(d); -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties anysee_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct anysee_state), - - .generic_bulk_ctrl_endpoint = 0x01, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &anysee_i2c_algo, - .read_config = anysee_read_config, - .frontend_attach = anysee_frontend_attach, - .tuner_attach = anysee_tuner_attach, - .init = anysee_init, - .get_rc_config = anysee_get_rc_config, - .frontend_ctrl = anysee_frontend_ctrl, - .streaming_ctrl = anysee_streaming_ctrl, - .exit = anysee_exit, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512), - } - } -}; - -static const struct usb_device_id anysee_id_table[] = { - { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE, - &anysee_props, "Anysee", RC_MAP_ANYSEE) }, - { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE, - &anysee_props, "Anysee", RC_MAP_ANYSEE) }, - { } -}; -MODULE_DEVICE_TABLE(usb, anysee_id_table); - -static struct usb_driver anysee_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = anysee_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(anysee_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/anysee.h b/drivers/media/dvb/dvb-usb-v2/anysee.h deleted file mode 100644 index dc40dcf7c32..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/anysee.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * 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. - * - * TODO: - * - add smart card reader support for Conditional Access (CA) - * - * Card reader in Anysee is nothing more than ISO 7816 card reader. - * There is no hardware CAM in any Anysee device sold. - * In my understanding it should be implemented by making own module - * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This - * module registers serial interface that can be used to communicate - * with any ISO 7816 smart card. - * - * Any help according to implement serial smart card reader support - * is highly welcome! - */ - -#ifndef _DVB_USB_ANYSEE_H_ -#define _DVB_USB_ANYSEE_H_ - -#define DVB_USB_LOG_PREFIX "anysee" -#include "dvb_usb.h" -#include "dvb_ca_en50221.h" - -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define debug_dump(b, l, func) -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" -#endif - -#define debug_dump(b, l, func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) - -#undef err -#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -enum cmd { - CMD_I2C_READ = 0x33, - CMD_I2C_WRITE = 0x31, - CMD_REG_READ = 0xb0, - CMD_REG_WRITE = 0xb1, - CMD_STREAMING_CTRL = 0x12, - CMD_LED_AND_IR_CTRL = 0x16, - CMD_GET_IR_CODE = 0x41, - CMD_GET_HW_INFO = 0x19, - CMD_SMARTCARD = 0x34, - CMD_CI = 0x37, -}; - -struct anysee_state { - u8 hw; /* PCB ID */ - u8 seq; - u8 fe_id:1; /* frondend ID */ - u8 has_ci:1; - struct dvb_ca_en50221 ci; - unsigned long ci_cam_ready; /* jiffies */ -}; - -#define ANYSEE_HW_507T 2 /* E30 */ -#define ANYSEE_HW_507CD 6 /* E30 Plus */ -#define ANYSEE_HW_507DC 10 /* E30 C Plus */ -#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ -#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ -#define ANYSEE_HW_508TC 18 /* E7 TC */ -#define ANYSEE_HW_508S2 19 /* E7 S2 */ -#define ANYSEE_HW_508T2C 20 /* E7 T2C */ -#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ -#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ - -#define REG_IOA 0x80 /* Port A (bit addressable) */ -#define REG_IOB 0x90 /* Port B (bit addressable) */ -#define REG_IOC 0xa0 /* Port C (bit addressable) */ -#define REG_IOD 0xb0 /* Port D (bit addressable) */ -#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */ -#define REG_OEA 0xb2 /* Port A Output Enable */ -#define REG_OEB 0xb3 /* Port B Output Enable */ -#define REG_OEC 0xb4 /* Port C Output Enable */ -#define REG_OED 0xb5 /* Port D Output Enable */ -#define REG_OEE 0xb6 /* Port E Output Enable */ - -#endif - -/*************************************************************************** - * USB API description (reverse engineered) - *************************************************************************** - -Transaction flow: -================= -BULK[00001] >>> REQUEST PACKET 64 bytes -BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) -BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) - -General reply packet(s) are always used if not own reply defined. - -============================================================================ -| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) -============================================================================ -| 00 | reply data (if any) from previous transaction -| | Just same reply packet as returned during previous transaction. -| | Needed only if reply is missed in previous transaction. -| | Just skip normally. ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) -============================================================================ -| 00 | reply data (if any) ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | I2C WRITE REQUEST PACKET -============================================================================ -| 00 | 0x31 I2C write command ----------------------------------------------------------------------------- -| 01 | i2c address ----------------------------------------------------------------------------- -| 02 | data length -| | 0x02 (for typical I2C reg / val pair) ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04- | data ----------------------------------------------------------------------------- -| -59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | I2C READ REQUEST PACKET -============================================================================ -| 00 | 0x33 I2C read command ----------------------------------------------------------------------------- -| 01 | i2c address + 1 ----------------------------------------------------------------------------- -| 02 | register ----------------------------------------------------------------------------- -| 03 | 0x00 ----------------------------------------------------------------------------- -| 04 | 0x00 ----------------------------------------------------------------------------- -| 05 | data length ----------------------------------------------------------------------------- -| 06-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET -============================================================================ -| 00 | 0xb1 register write command ----------------------------------------------------------------------------- -| 01-02 | register ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04 | value ----------------------------------------------------------------------------- -| 05-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET -============================================================================ -| 00 | 0xb0 register read command ----------------------------------------------------------------------------- -| 01-02 | register ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | LED CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x16 LED and IR control command ----------------------------------------------------------------------------- -| 01 | 0x01 (LED) ----------------------------------------------------------------------------- -| 03 | 0x00 blink -| | 0x01 lights continuously ----------------------------------------------------------------------------- -| 04 | blink interval -| | 0x00 fastest (looks like LED lights continuously) -| | 0xff slowest ----------------------------------------------------------------------------- -| 05-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | IR CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x16 LED and IR control command ----------------------------------------------------------------------------- -| 01 | 0x02 (IR) ----------------------------------------------------------------------------- -| 03 | 0x00 IR disabled -| | 0x01 IR enabled ----------------------------------------------------------------------------- -| 04-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | STREAMING CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x12 streaming control command ----------------------------------------------------------------------------- -| 01 | 0x00 streaming disabled -| | 0x01 streaming enabled ----------------------------------------------------------------------------- -| 02 | 0x00 ----------------------------------------------------------------------------- -| 03-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | REMOTE CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x41 remote control command ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | REMOTE CONTROL REPLY PACKET -============================================================================ -| 00 | 0x00 code not received -| | 0x01 code received ----------------------------------------------------------------------------- -| 01 | remote control code ----------------------------------------------------------------------------- -| 02-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GET HARDWARE INFO REQUEST PACKET -============================================================================ -| 00 | 0x19 get hardware info command ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GET HARDWARE INFO REPLY PACKET -============================================================================ -| 00 | hardware id ----------------------------------------------------------------------------- -| 01-02 | firmware version ----------------------------------------------------------------------------- -| 03-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | SMART CARD READER PACKET -============================================================================ -| 00 | 0x34 smart card reader command ----------------------------------------------------------------------------- -| xx | ----------------------------------------------------------------------------- -| xx-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -*/ diff --git a/drivers/media/dvb/dvb-usb-v2/au6610.c b/drivers/media/dvb/dvb-usb-v2/au6610.c deleted file mode 100644 index 05f2a862814..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/au6610.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. - * - * Copyright (C) 2006 Antti Palosaari - * - * 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 "au6610.h" -#include "zl10353.h" -#include "qt1010.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - int ret; - u16 index; - u8 *usb_buf; - - /* - * allocate enough for all known requests, - * read returns 5 and write 6 bytes - */ - usb_buf = kmalloc(6, GFP_KERNEL); - if (!usb_buf) - return -ENOMEM; - - switch (wlen) { - case 1: - index = wbuf[0] << 8; - break; - case 2: - index = wbuf[0] << 8; - index += wbuf[1]; - break; - default: - pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen); - ret = -EINVAL; - goto error; - } - - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, - USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, - usb_buf, 6, AU6610_USB_TIMEOUT); - if (ret < 0) - goto error; - - switch (operation) { - case AU6610_REQ_I2C_READ: - case AU6610_REQ_USB_READ: - /* requested value is always 5th byte in buffer */ - rbuf[0] = usb_buf[4]; - } -error: - kfree(usb_buf); - return ret; -} - -static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 request; - u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ - - if (wo) { - request = AU6610_REQ_I2C_WRITE; - } else { /* rw */ - request = AU6610_REQ_I2C_READ; - } - - return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); -} - - -/* I2C */ -static int au6610_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 (au6610_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 (au6610_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 au6610_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm au6610_i2c_algo = { - .master_xfer = au6610_i2c_xfer, - .functionality = au6610_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config au6610_zl10353_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -ENODEV; - - return 0; -} - -static struct qt1010_config au6610_qt1010_config = { - .i2c_address = 0x62 -}; - -static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &au6610_qt1010_config) == NULL ? -ENODEV : 0; -} - -static int au6610_init(struct dvb_usb_device *d) -{ - /* TODO: this functionality belongs likely to the streaming control */ - /* bInterfaceNumber 0, bAlternateSetting 5 */ - return usb_set_interface(d->udev, 0, 5); -} - -static struct dvb_usb_device_properties au6610_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - - .i2c_algo = &au6610_i2c_algo, - .frontend_attach = au6610_zl10353_frontend_attach, - .tuner_attach = au6610_qt1010_tuner_attach, - .init = au6610_init, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1), - }, - }, -}; - -static const struct usb_device_id au6610_id_table[] = { - { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110, - &au6610_props, "Sigmatek DVB-110", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, au6610_id_table); - -static struct usb_driver au6610_driver = { - .name = KBUILD_MODNAME, - .id_table = au6610_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(au6610_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/au6610.h b/drivers/media/dvb/dvb-usb-v2/au6610.h deleted file mode 100644 index ea337bfc00b..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/au6610.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. - * - * Copyright (C) 2006 Antti Palosaari - * - * 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 AU6610_H -#define AU6610_H -#include "dvb_usb.h" - -#define AU6610_REQ_I2C_WRITE 0x14 -#define AU6610_REQ_I2C_READ 0x13 -#define AU6610_REQ_USB_WRITE 0x16 -#define AU6610_REQ_USB_READ 0x15 - -#define AU6610_USB_TIMEOUT 1000 - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c deleted file mode 100644 index 54f1221d930..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones - * - * Copyright (c) Henry Wang - * - * This driver was made publicly available by Terratec, at: - * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz - * The original driver's license is GPL, as declared with MODULE_LICENSE() - * - * Copyright (c) 2010-2012 Mauro Carvalho Chehab - * Driver modified by in order to work with upstream drxk driver, and - * tons of bugs got fixed, and converted to use dvb-usb-v2. - * - * 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 under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "drxk.h" -#include "mt2063.h" -#include "dvb_ca_en50221.h" -#include "dvb_usb.h" -#include "cypress_firmware.h" - -#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw" - -static int az6007_xfer_debug; -module_param_named(xfer_debug, az6007_xfer_debug, int, 0644); -MODULE_PARM_DESC(xfer_debug, "Enable xfer debug"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/ - -#define FX2_OED 0xb5 -#define AZ6007_READ_DATA 0xb7 -#define AZ6007_I2C_RD 0xb9 -#define AZ6007_POWER 0xbc -#define AZ6007_I2C_WR 0xbd -#define FX2_SCON1 0xc0 -#define AZ6007_TS_THROUGH 0xc7 -#define AZ6007_READ_IR 0xb4 - -struct az6007_device_state { - struct mutex mutex; - struct mutex ca_mutex; - struct dvb_ca_en50221 ca; - unsigned warm:1; - int (*gate_ctrl) (struct dvb_frontend *, int); - unsigned char data[4096]; -}; - -static struct drxk_config terratec_h7_drxk = { - .adr = 0x29, - .parallel_ts = true, - .dynamic_clk = true, - .single_master = true, - .enable_merr_cfg = true, - .no_i2c_bridge = false, - .chunk_size = 64, - .mpeg_out_clk_strength = 0x02, - .qam_demod_parameter_count = 2, - .microcode_name = "dvb-usb-terratec-h7-drxk.fw", -}; - -static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct az6007_device_state *st = fe_to_priv(fe); - struct dvb_usb_adapter *adap = fe->sec_priv; - int status = 0; - - pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable"); - - if (!adap || !st) - return -EINVAL; - - if (enable) - status = st->gate_ctrl(fe, 1); - else - status = st->gate_ctrl(fe, 0); - - return status; -} - -static struct mt2063_config az6007_mt2063_config = { - .tuner_address = 0x60, - .refclock = 36125000, -}; - -static int __az6007_read(struct usb_device *udev, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value, index, b, blen, 5000); - if (ret < 0) { - pr_warn("usb read operation failed. (%d)\n", ret); - return -EIO; - } - - if (az6007_xfer_debug) { - printk(KERN_DEBUG "az6007: IN req: %02x, value: %04x, index: %04x\n", - req, value, index); - print_hex_dump_bytes("az6007: payload: ", - DUMP_PREFIX_NONE, b, blen); - } - - return ret; -} - -static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - struct az6007_device_state *st = d->priv; - int ret; - - if (mutex_lock_interruptible(&st->mutex) < 0) - return -EAGAIN; - - ret = __az6007_read(d->udev, req, value, index, b, blen); - - mutex_unlock(&st->mutex); - - return ret; -} - -static int __az6007_write(struct usb_device *udev, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - - if (az6007_xfer_debug) { - printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n", - req, value, index); - print_hex_dump_bytes("az6007: payload: ", - DUMP_PREFIX_NONE, b, blen); - } - - if (blen > 64) { - pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", - blen); - return -EOPNOTSUPP; - } - - ret = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value, index, b, blen, 5000); - if (ret != blen) { - pr_err("usb write operation failed. (%d)\n", ret); - return -EIO; - } - - return 0; -} - -static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - struct az6007_device_state *st = d->priv; - int ret; - - if (mutex_lock_interruptible(&st->mutex) < 0) - return -EAGAIN; - - ret = __az6007_write(d->udev, req, value, index, b, blen); - - mutex_unlock(&st->mutex); - - return ret; -} - -static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_device *d = fe_to_d(fe); - - pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable"); - - return az6007_write(d, 0xbc, onoff, 0, NULL, 0); -} - -/* remote control stuff (does not work with my box) */ -static int az6007_rc_query(struct dvb_usb_device *d) -{ - struct az6007_device_state *st = d_to_priv(d); - unsigned code = 0; - - az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); - - if (st->data[1] == 0x44) - return 0; - - if ((st->data[1] ^ st->data[2]) == 0xff) - code = st->data[1]; - else - code = st->data[1] << 8 | st->data[2]; - - if ((st->data[3] ^ st->data[4]) == 0xff) - code = code << 8 | st->data[3]; - else - code = code << 16 | st->data[3] << 8 | st->data[4]; - - rc_keydown(d->rc_dev, code, st->data[5]); - - return 0; -} - -static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, - int address) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - if (slot != 0) - return -EINVAL; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - mutex_lock(&state->ca_mutex); - - req = 0xC1; - value = address; - index = 0; - blen = 1; - - ret = az6007_read(d, req, value, index, b, blen); - if (ret < 0) { - pr_warn("usb in operation failed. (%d)\n", ret); - ret = -EINVAL; - } else { - ret = b[0]; - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - -static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, - int address, - u8 value) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - - int ret; - u8 req; - u16 value1; - u16 index; - int blen; - - pr_debug("%s(), slot %d\n", __func__, slot); - if (slot != 0) - return -EINVAL; - - mutex_lock(&state->ca_mutex); - req = 0xC2; - value1 = address; - index = value; - blen = 0; - - ret = az6007_write(d, req, value1, index, NULL, blen); - if (ret != 0) - pr_warn("usb out operation failed. (%d)\n", ret); - - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - if (slot != 0) - return -EINVAL; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - mutex_lock(&state->ca_mutex); - - req = 0xC3; - value = address; - index = 0; - blen = 2; - - ret = az6007_read(d, req, value, index, b, blen); - if (ret < 0) { - pr_warn("usb in operation failed. (%d)\n", ret); - ret = -EINVAL; - } else { - if (b[0] == 0) - pr_warn("Read CI IO error\n"); - - ret = b[1]; - pr_debug("read cam data = %x from 0x%x\n", b[1], value); - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - -static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address, - u8 value) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - - int ret; - u8 req; - u16 value1; - u16 index; - int blen; - - if (slot != 0) - return -EINVAL; - - mutex_lock(&state->ca_mutex); - req = 0xC4; - value1 = address; - index = value; - blen = 0; - - ret = az6007_write(d, req, value1, index, NULL, blen); - if (ret != 0) { - pr_warn("usb out operation failed. (%d)\n", ret); - goto failed; - } - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - req = 0xC8; - value = 0; - index = 0; - blen = 1; - - ret = az6007_read(d, req, value, index, b, blen); - if (ret < 0) { - pr_warn("usb in operation failed. (%d)\n", ret); - ret = -EIO; - } else{ - ret = b[0]; - } - kfree(b); - return ret; -} - -static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - - int ret, i; - u8 req; - u16 value; - u16 index; - int blen; - - mutex_lock(&state->ca_mutex); - - req = 0xC6; - value = 1; - index = 0; - blen = 0; - - ret = az6007_write(d, req, value, index, NULL, blen); - if (ret != 0) { - pr_warn("usb out operation failed. (%d)\n", ret); - goto failed; - } - - msleep(500); - req = 0xC6; - value = 0; - index = 0; - blen = 0; - - ret = az6007_write(d, req, value, index, NULL, blen); - if (ret != 0) { - pr_warn("usb out operation failed. (%d)\n", ret); - goto failed; - } - - for (i = 0; i < 15; i++) { - msleep(100); - - if (CI_CamReady(ca, slot)) { - pr_debug("CAM Ready\n"); - break; - } - } - msleep(5000); - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - return 0; -} - -static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - pr_debug("%s()\n", __func__); - mutex_lock(&state->ca_mutex); - req = 0xC7; - value = 1; - index = 0; - blen = 0; - - ret = az6007_write(d, req, value, index, NULL, blen); - if (ret != 0) { - pr_warn("usb out operation failed. (%d)\n", ret); - goto failed; - } - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = d_to_priv(d); - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - mutex_lock(&state->ca_mutex); - - req = 0xC5; - value = 0; - index = 0; - blen = 1; - - ret = az6007_read(d, req, value, index, b, blen); - if (ret < 0) { - pr_warn("usb in operation failed. (%d)\n", ret); - ret = -EIO; - } else - ret = 0; - - if (!ret && b[0] == 1) { - ret = DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - - -static void az6007_ci_uninit(struct dvb_usb_device *d) -{ - struct az6007_device_state *state; - - pr_debug("%s()\n", __func__); - - if (NULL == d) - return; - - state = d_to_priv(d); - if (NULL == state) - return; - - if (NULL == state->ca.data) - return; - - dvb_ca_en50221_release(&state->ca); - - memset(&state->ca, 0, sizeof(state->ca)); -} - - -static int az6007_ci_init(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct az6007_device_state *state = adap_to_priv(adap); - int ret; - - pr_debug("%s()\n", __func__); - - mutex_init(&state->ca_mutex); - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; - state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; - state->ca.read_cam_control = az6007_ci_read_cam_control; - state->ca.write_cam_control = az6007_ci_write_cam_control; - state->ca.slot_reset = az6007_ci_slot_reset; - state->ca.slot_shutdown = az6007_ci_slot_shutdown; - state->ca.slot_ts_enable = az6007_ci_slot_ts_enable; - state->ca.poll_slot_status = az6007_ci_poll_slot_status; - state->ca.data = d; - - ret = dvb_ca_en50221_init(&adap->dvb_adap, - &state->ca, - 0, /* flags */ - 1);/* n_slots */ - if (ret != 0) { - pr_err("Cannot initialize CI: Error %d.\n", ret); - memset(&state->ca, 0, sizeof(state->ca)); - return ret; - } - - pr_debug("CI initialized.\n"); - - return 0; -} - -static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6]) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct az6007_device_state *st = adap_to_priv(adap); - int ret; - - ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); - memcpy(mac, st->data, 6); - - if (ret > 0) - pr_debug("%s: mac is %pM\n", __func__, mac); - - return ret; -} - -static int az6007_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct az6007_device_state *st = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - - pr_debug("attaching demod drxk\n"); - - adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk, - &d->i2c_adap); - if (!adap->fe[0]) - return -EINVAL; - - adap->fe[0]->sec_priv = adap; - st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl; - adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; - - az6007_ci_init(adap); - - return 0; -} - -static int az6007_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - - pr_debug("attaching tuner mt2063\n"); - - /* Attach mt2063 to DVB-C frontend */ - if (adap->fe[0]->ops.i2c_gate_ctrl) - adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1); - if (!dvb_attach(mt2063_attach, adap->fe[0], - &az6007_mt2063_config, - &d->i2c_adap)) - return -EINVAL; - - if (adap->fe[0]->ops.i2c_gate_ctrl) - adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0); - - return 0; -} - -static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - struct az6007_device_state *state = d_to_priv(d); - int ret; - - pr_debug("%s()\n", __func__); - - if (!state->warm) { - mutex_init(&state->mutex); - - ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0); - if (ret < 0) - return ret; - msleep(60); - ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); - if (ret < 0) - return ret; - msleep(100); - ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0); - if (ret < 0) - return ret; - msleep(20); - ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); - if (ret < 0) - return ret; - - msleep(400); - ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0); - if (ret < 0) - return ret; - msleep(150); - ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0); - if (ret < 0) - return ret; - msleep(430); - ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); - if (ret < 0) - return ret; - - state->warm = true; - - return 0; - } - - if (!onoff) - return 0; - - az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); - az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0); - - return 0; -} - -/* I2C */ -static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct az6007_device_state *st = d_to_priv(d); - int i, j, len; - int ret = 0; - u16 index; - u16 value; - int length; - u8 req, addr; - - if (mutex_lock_interruptible(&st->mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - addr = msgs[i].addr << 1; - if (((i + 1) < num) - && (msgs[i].len == 1) - && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD) - && (msgs[i + 1].flags & I2C_M_RD) - && (msgs[i].addr == msgs[i + 1].addr)) { - /* - * A write + read xfer for the same address, where - * the first xfer has just 1 byte length. - * Need to join both into one operation - */ - if (az6007_xfer_debug) - printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n", - addr, msgs[i].len, msgs[i + 1].len); - req = AZ6007_I2C_RD; - index = msgs[i].buf[0]; - value = addr | (1 << 8); - length = 6 + msgs[i + 1].len; - len = msgs[i + 1].len; - ret = __az6007_read(d->udev, req, value, index, - st->data, length); - if (ret >= len) { - for (j = 0; j < len; j++) - msgs[i + 1].buf[j] = st->data[j + 5]; - } else - ret = -EIO; - i++; - } else if (!(msgs[i].flags & I2C_M_RD)) { - /* write bytes */ - if (az6007_xfer_debug) - printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n", - addr, msgs[i].len); - req = AZ6007_I2C_WR; - index = msgs[i].buf[0]; - value = addr | (1 << 8); - length = msgs[i].len - 1; - len = msgs[i].len - 1; - for (j = 0; j < len; j++) - st->data[j] = msgs[i].buf[j + 1]; - ret = __az6007_write(d->udev, req, value, index, - st->data, length); - } else { - /* read bytes */ - if (az6007_xfer_debug) - printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n", - addr, msgs[i].len); - req = AZ6007_I2C_RD; - index = msgs[i].buf[0]; - value = addr; - length = msgs[i].len + 6; - len = msgs[i].len; - ret = __az6007_read(d->udev, req, value, index, - st->data, length); - for (j = 0; j < len; j++) - msgs[i].buf[j] = st->data[j + 5]; - } - if (ret < 0) - goto err; - } -err: - mutex_unlock(&st->mutex); - - if (ret < 0) { - pr_info("%s ERROR: %i\n", __func__, ret); - return ret; - } - return num; -} - -static u32 az6007_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm az6007_i2c_algo = { - .master_xfer = az6007_i2c_xfer, - .functionality = az6007_i2c_func, -}; - -static int az6007_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 *mac; - - pr_debug("Identifying az6007 state\n"); - - mac = kmalloc(6, GFP_ATOMIC); - if (!mac) - return -ENOMEM; - - /* Try to read the mac address */ - ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6); - if (ret == 6) - ret = WARM; - else - ret = COLD; - - kfree(mac); - - if (ret == COLD) { - __az6007_write(d->udev, 0x09, 1, 0, NULL, 0); - __az6007_write(d->udev, 0x00, 0, 0, NULL, 0); - __az6007_write(d->udev, 0x00, 0, 0, NULL, 0); - } - - pr_debug("Device is on %s state\n", - ret == WARM ? "warm" : "cold"); - return ret; -} - -static void az6007_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - az6007_ci_uninit(d); - dvb_usbv2_disconnect(intf); -} - -static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - pr_debug("Getting az6007 Remote Control properties\n"); - - rc->allowed_protos = RC_TYPE_NEC; - rc->query = az6007_rc_query; - rc->interval = 400; - - return 0; -} - -static int az6007_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - pr_debug("Loading az6007 firmware\n"); - - return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2); -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties az6007_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .firmware = AZ6007_FIRMWARE, - - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct az6007_device_state), - .i2c_algo = &az6007_i2c_algo, - .tuner_attach = az6007_tuner_attach, - .frontend_attach = az6007_frontend_attach, - .streaming_ctrl = az6007_streaming_ctrl, - .get_rc_config = az6007_get_rc_config, - .read_mac_address = az6007_read_mac_addr, - .download_firmware = az6007_download_firmware, - .identify_state = az6007_identify_state, - .power_ctrl = az6007_power_ctrl, - .num_adapters = 1, - .adapter = { - { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), } - } -}; - -static struct usb_device_id az6007_usb_table[] = { - {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, - &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, - {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7, - &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, - {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2, - &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, - {0}, -}; - -MODULE_DEVICE_TABLE(usb, az6007_usb_table); - -static int az6007_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - - az6007_ci_uninit(d); - return dvb_usbv2_suspend(intf, msg); -} - -static int az6007_resume(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - struct dvb_usb_adapter *adap = &d->adapter[0]; - - az6007_ci_init(adap); - return dvb_usbv2_resume(intf); -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver az6007_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = az6007_usb_table, - .probe = dvb_usbv2_probe, - .disconnect = az6007_usb_disconnect, - .no_dynamic_id = 1, - .soft_unbind = 1, - /* - * FIXME: need to implement reset_resume, likely with - * dvb-usb-v2 core support - */ - .suspend = az6007_suspend, - .resume = az6007_resume, -}; - -module_usb_driver(az6007_usb_driver); - -MODULE_AUTHOR("Henry Wang "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); -MODULE_VERSION("2.0"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(AZ6007_FIRMWARE); diff --git a/drivers/media/dvb/dvb-usb-v2/ce6230.c b/drivers/media/dvb/dvb-usb-v2/ce6230.c deleted file mode 100644 index 84ff4a96ca4..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/ce6230.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Intel CE6230 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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 "ce6230.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) -{ - int ret; - unsigned int pipe; - u8 request; - u8 requesttype; - u16 value; - u16 index; - u8 *buf; - - request = req->cmd; - value = req->value; - index = req->index; - - switch (req->cmd) { - case I2C_READ: - case DEMOD_READ: - case REG_READ: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - break; - case I2C_WRITE: - case DEMOD_WRITE: - case REG_WRITE: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - break; - default: - pr_debug("%s: unknown command=%02x\n", __func__, req->cmd); - ret = -EINVAL; - goto error; - } - - buf = kmalloc(req->data_len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto error; - } - - if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { - /* write */ - memcpy(buf, req->data, req->data_len); - pipe = usb_sndctrlpipe(d->udev, 0); - } else { - /* read */ - pipe = usb_rcvctrlpipe(d->udev, 0); - } - - msleep(1); /* avoid I2C errors */ - - ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, - buf, req->data_len, CE6230_USB_TIMEOUT); - - ce6230_debug_dump(request, requesttype, value, index, buf, - req->data_len); - - if (ret < 0) - pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME, - ret); - else - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->data_len); - - kfree(buf); -error: - return ret; -} - -/* I2C */ -static struct zl10353_config ce6230_zl10353_config; - -static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, i = 0; - struct usb_req req; - - if (num > 2) - return -EOPNOTSUPP; - - memset(&req, 0, sizeof(req)); - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == - ce6230_zl10353_config.demod_address) { - req.cmd = DEMOD_READ; - req.value = msg[i].addr >> 1; - req.index = msg[i].buf[0]; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = ce6230_ctrl_msg(d, &req); - } else { - pr_err("%s: I2C read not implemented\n", - KBUILD_MODNAME); - ret = -EOPNOTSUPP; - } - i += 2; - } else { - if (msg[i].addr == - ce6230_zl10353_config.demod_address) { - req.cmd = DEMOD_WRITE; - req.value = msg[i].addr >> 1; - req.index = msg[i].buf[0]; - req.data_len = msg[i].len-1; - req.data = &msg[i].buf[1]; - ret = ce6230_ctrl_msg(d, &req); - } else { - req.cmd = I2C_WRITE; - req.value = 0x2000 + (msg[i].addr >> 1); - req.index = 0x0000; - req.data_len = msg[i].len; - req.data = &msg[i].buf[0]; - ret = ce6230_ctrl_msg(d, &req); - } - i += 1; - } - if (ret) - break; - } - - mutex_unlock(&d->i2c_mutex); - return ret ? ret : i; -} - -static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ce6230_i2c_algorithm = { - .master_xfer = ce6230_i2c_master_xfer, - .functionality = ce6230_i2c_functionality, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config ce6230_zl10353_config = { - .demod_address = 0x1e, - .adc_clock = 450000, - .if2 = 45700, - .no_tuner = 1, - .parallel_ts = 1, - .clock_ctl_1 = 0x34, - .pll_0 = 0x0e, -}; - -static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) -{ - pr_debug("%s:\n", __func__); - - adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -ENODEV; - - return 0; -} - -static struct mxl5005s_config ce6230_mxl5003s_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - int ret; - - pr_debug("%s:\n", __func__); - - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; - return ret; -} - -static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - - pr_debug("%s: onoff=%d\n", __func__, onoff); - - /* InterfaceNumber 1 / AlternateSetting 0 idle - InterfaceNumber 1 / AlternateSetting 1 streaming */ - ret = usb_set_interface(d->udev, 1, onoff); - if (ret) - pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME, - ret); - - return ret; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ce6230_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .bInterfaceNumber = 1, - - .i2c_algo = &ce6230_i2c_algorithm, - .power_ctrl = ce6230_power_ctrl, - .frontend_attach = ce6230_zl10353_frontend_attach, - .tuner_attach = ce6230_mxl5003s_tuner_attach, - - .num_adapters = 1, - .adapter = { - { - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (16 * 512), - } - } - }, - } - }, -}; - -static const struct usb_device_id ce6230_id_table[] = { - { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, - &ce6230_props, "Intel CE9500 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, - &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, ce6230_id_table); - -static struct usb_driver ce6230_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = ce6230_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(ce6230_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Intel CE6230 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/ce6230.h b/drivers/media/dvb/dvb-usb-v2/ce6230.h deleted file mode 100644 index 42d754494a3..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/ce6230.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Intel CE6230 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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 CE6230_H -#define CE6230_H - -#include "dvb_usb.h" -#include "zl10353.h" -#include "mxl5005s.h" - -#define ce6230_debug_dump(r, t, v, i, b, l) { \ - char *direction; \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - direction = ">>>"; \ - else \ - direction = "<<<"; \ - pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \ - __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ - l & 0xff, l >> 8, direction, l); \ -} - -#define CE6230_USB_TIMEOUT 1000 - -struct usb_req { - u8 cmd; /* [1] */ - u16 value; /* [2|3] */ - u16 index; /* [4|5] */ - u16 data_len; /* [6|7] */ - u8 *data; -}; - -enum ce6230_cmd { - CONFIG_READ = 0xd0, /* rd 0 (unclear) */ - UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */ - I2C_READ = 0xd9, /* rd 9 (unclear) */ - I2C_WRITE = 0xca, /* wr a */ - DEMOD_READ = 0xdb, /* rd b */ - DEMOD_WRITE = 0xcc, /* wr c */ - REG_READ = 0xde, /* rd e */ - REG_WRITE = 0xcf, /* wr f */ -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c deleted file mode 100644 index 9f7c970c642..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c +++ /dev/null @@ -1,125 +0,0 @@ -/* cypress_firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - */ - -#include "dvb_usb.h" -#include "cypress_firmware.h" - -struct usb_cypress_controller { - u8 id; - const char *name; /* name of the usb controller */ - u16 cs_reg; /* needs to be restarted, - * when the firmware has been downloaded */ -}; - -static const struct usb_cypress_controller cypress[] = { - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, -}; - -/* - * load a firmware packet to the device - */ -static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, - u8 len) -{ - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); -} - -int usbv2_cypress_load_firmware(struct usb_device *udev, - const struct firmware *fw, int type) -{ - struct hexline hx; - u8 reset; - int ret, pos = 0; - - /* stop the CPU */ - reset = 1; - ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1); - if (ret != 1) - pr_err("%s: could not stop the USB controller CPU", - KBUILD_MODNAME); - - while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { - pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n", - __func__, hx.addr, hx.len, hx.chk); - - ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); - if (ret != hx.len) { - pr_err("%s: error while transferring firmware " \ - "(transferred size=%d, block size=%d)", - KBUILD_MODNAME, ret, hx.len); - ret = -EINVAL; - break; - } - } - if (ret < 0) { - pr_err("%s: firmware download failed at %d with %d", - KBUILD_MODNAME, pos, ret); - return ret; - } - - if (ret == 0) { - /* restart the CPU */ - reset = 0; - if (ret || usb_cypress_writemem( - udev, cypress[type].cs_reg, &reset, 1) != 1) { - pr_err("%s: could not restart the USB controller CPU", - KBUILD_MODNAME); - ret = -EINVAL; - } - } else - ret = -EIO; - - return ret; -} -EXPORT_SYMBOL(usbv2_cypress_load_firmware); - -int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos) -{ - u8 *b = (u8 *) &fw->data[*pos]; - int data_offs = 4; - - if (*pos >= fw->size) - return 0; - - memset(hx, 0, sizeof(struct hexline)); - - hx->len = b[0]; - - if ((*pos + hx->len + 4) >= fw->size) - return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); - hx->type = b[3]; - - if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data - * field */ - hx->addr |= (b[4] << 24) | (b[5] << 16); - /* - hx->len -= 2; - data_offs += 2; - */ - } - memcpy(hx->data, &b[data_offs], hx->len); - hx->chk = b[hx->len + data_offs]; - - *pos += hx->len + 5; - - return *pos; -} -EXPORT_SYMBOL(dvb_usbv2_get_hexline); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Cypress firmware download"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h deleted file mode 100644 index 80085fd4132..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h +++ /dev/null @@ -1,31 +0,0 @@ -/* cypress_firmware.h is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - */ - -#ifndef CYPRESS_FIRMWARE_H -#define CYPRESS_FIRMWARE_H - -#define CYPRESS_AN2135 0 -#define CYPRESS_AN2235 1 -#define CYPRESS_FX2 2 - -/* commonly used firmware download types and function */ -struct hexline { - u8 len; - u32 addr; - u8 type; - u8 data[255]; - u8 chk; -}; -extern int usbv2_cypress_load_firmware(struct usb_device *, - const struct firmware *, int); -extern int dvb_usbv2_get_hexline(const struct firmware *, - struct hexline *, int *); - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h deleted file mode 100644 index 79b3b8b6750..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb.h +++ /dev/null @@ -1,389 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef DVB_USB_H -#define DVB_USB_H - -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "dmxdev.h" -#include "dvb-usb-ids.h" - -/* - * device file: /dev/dvb/adapter[0-1]/frontend[0-2] - * - * |-- device - * | |-- adapter0 - * | | |-- frontend0 - * | | |-- frontend1 - * | | `-- frontend2 - * | `-- adapter1 - * | |-- frontend0 - * | |-- frontend1 - * | `-- frontend2 - * - * - * Commonly used variable names: - * d = pointer to device (struct dvb_usb_device *) - * adap = pointer to adapter (struct dvb_usb_adapter *) - * fe = pointer to frontend (struct dvb_frontend *) - * - * Use macros defined in that file to resolve needed pointers. - */ - -/* helper macros for every DVB USB driver use */ -#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \ - adapter[adap->id])) -#define adap_to_priv(adap) (adap_to_d(adap)->priv) -#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv)) -#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe))) -#define fe_to_priv(fe) (fe_to_d(fe)->priv) -#define d_to_priv(d) (d->priv) - -#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \ - .type = USB_BULK, \ - .count = count_, \ - .endpoint = endpoint_, \ - .u = { \ - .bulk = { \ - .buffersize = size_, \ - } \ - } \ -} - -#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \ - .type = USB_ISOC, \ - .count = count_, \ - .endpoint = endpoint_, \ - .u = { \ - .isoc = { \ - .framesperurb = frames_, \ - .framesize = size_,\ - .interval = interval_, \ - } \ - } \ -} - -#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \ - .props = (props_), \ - .name = (name_), \ - .rc_map = (rc), \ - }) - -struct dvb_usb_device; -struct dvb_usb_adapter; - -/** - * structure for carrying all needed data from the device driver to the general - * dvb usb routines - * @name: device name - * @rc_map: name of rc codes table - * @props: structure containing all device properties - */ -struct dvb_usb_driver_info { - const char *name; - const char *rc_map; - const struct dvb_usb_device_properties *props; -}; - -/** - * structure for remote controller configuration - * @map_name: name of rc codes table - * @allowed_protos: protocol(s) supported by the driver - * @change_protocol: callback to change protocol - * @query: called to query an event from the device - * @interval: time in ms between two queries - * @driver_type: used to point if a device supports raw mode - * @bulk_mode: device supports bulk mode for rc (disable polling mode) - */ -struct dvb_usb_rc { - const char *map_name; - u64 allowed_protos; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); - int (*query) (struct dvb_usb_device *d); - unsigned int interval; - const enum rc_driver_type driver_type; - bool bulk_mode; -}; - -/** - * usb streaming configration for adapter - * @type: urb type - * @count: count of used urbs - * @endpoint: stream usb endpoint number - */ -struct usb_data_stream_properties { -#define USB_BULK 1 -#define USB_ISOC 2 - u8 type; - u8 count; - u8 endpoint; - - union { - struct { - unsigned int buffersize; /* per URB */ - } bulk; - struct { - int framesperurb; - int framesize; - int interval; - } isoc; - } u; -}; - -/** - * properties of dvb usb device adapter - * @caps: adapter capabilities - * @pid_filter_count: pid count of adapter pid-filter - * @pid_filter_ctrl: called to enable/disable pid-filter - * @pid_filter: called to set/unset pid for filtering - * @stream: adapter usb stream configuration - */ -#define MAX_NO_OF_FE_PER_ADAP 3 -struct dvb_usb_adapter_properties { -#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 -#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 -#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 - u8 caps; - - u8 pid_filter_count; - int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - - struct usb_data_stream_properties stream; -}; - -/** - * struct dvb_usb_device_properties - properties of a dvb-usb-device - * @driver_name: name of the owning driver module - * @owner: owner of the dvb_adapter - * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro - * @bInterfaceNumber: usb interface number driver binds - * @size_of_priv: bytes allocated for the driver private data - * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent - * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for - * receive - * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message - * @identify_state: called to determine the firmware state (cold or warm) and - * return possible firmware file name to be loaded - * @firmware: name of the firmware file to be loaded - * @download_firmware: called to download the firmware - * @i2c_algo: i2c_algorithm if the device has i2c-adapter - * @num_adapters: dvb usb device adapter count - * @get_adapter_count: called to resolve adapter count - * @adapter: array of all adapter properties of device - * @power_ctrl: called to enable/disable power of the device - * @read_config: called to resolve device configuration - * @read_mac_address: called to resolve adapter mac-address - * @frontend_attach: called to attach the possible frontends - * @tuner_attach: called to attach the possible tuners - * @frontend_ctrl: called to power on/off active frontend - * @streaming_ctrl: called to start/stop the usb streaming of adapter - * @init: called after adapters are created in order to finalize device - * configuration - * @exit: called when driver is unloaded - * @get_rc_config: called to resolve used remote controller configuration - * @get_stream_config: called to resolve input and output stream configuration - * of the adapter just before streaming is started. input stream is transport - * stream from the demodulator and output stream is usb stream to host. - */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 -struct dvb_usb_device_properties { - const char *driver_name; - struct module *owner; - short *adapter_nr; - - u8 bInterfaceNumber; - unsigned int size_of_priv; - u8 generic_bulk_ctrl_endpoint; - u8 generic_bulk_ctrl_endpoint_response; - unsigned int generic_bulk_ctrl_delay; - -#define WARM 0 -#define COLD 1 - int (*identify_state) (struct dvb_usb_device *, const char **); - const char *firmware; -#define RECONNECTS_USB 1 - int (*download_firmware) (struct dvb_usb_device *, - const struct firmware *); - - struct i2c_algorithm *i2c_algo; - - unsigned int num_adapters; - int (*get_adapter_count) (struct dvb_usb_device *); - struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - int (*power_ctrl) (struct dvb_usb_device *, int); - int (*read_config) (struct dvb_usb_device *d); - int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); - int (*frontend_attach) (struct dvb_usb_adapter *); - int (*tuner_attach) (struct dvb_usb_adapter *); - int (*frontend_ctrl) (struct dvb_frontend *, int); - int (*streaming_ctrl) (struct dvb_frontend *, int); - int (*init) (struct dvb_usb_device *); - void (*exit) (struct dvb_usb_device *); - int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); -#define DVB_USB_FE_TS_TYPE_188 0 -#define DVB_USB_FE_TS_TYPE_204 1 -#define DVB_USB_FE_TS_TYPE_RAW 2 - int (*get_stream_config) (struct dvb_frontend *, u8 *, - struct usb_data_stream_properties *); -}; - -/** - * generic object of an usb stream - * @buf_num: number of buffer allocated - * @buf_size: size of each buffer in buf_list - * @buf_list: array containing all allocate buffers for streaming - * @dma_addr: list of dma_addr_t for each buffer in buf_list - * - * @urbs_initialized: number of URBs initialized - * @urbs_submitted: number of URBs submitted - */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 -struct usb_data_stream { - struct usb_device *udev; - struct usb_data_stream_properties props; - -#define USB_STATE_INIT 0x00 -#define USB_STATE_URB_BUF 0x01 - u8 state; - - void (*complete) (struct usb_data_stream *, u8 *, size_t); - - struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; - int buf_num; - unsigned long buf_size; - u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; - dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; - - int urbs_initialized; - int urbs_submitted; - - void *user_priv; -}; - -/** - * dvb adapter object on dvb usb device - * @props: pointer to adapter properties - * @stream: adapter the usb data stream - * @id: index of this adapter (starting with 0) - * @ts_type: transport stream, input stream, type - * @pid_filtering: is hardware pid_filtering used or not - * @feed_count: current feed count - * @max_feed_count: maimum feed count device can handle - * @dvb_adap: adapter dvb_adapter - * @dmxdev: adapter dmxdev - * @demux: adapter software demuxer - * @dvb_net: adapter dvb_net interfaces - * @sync_mutex: mutex used to sync control and streaming of the adapter - * @fe: adapter frontends - * @fe_init: rerouted frontend-init function - * @fe_sleep: rerouted frontend-sleep function - */ -struct dvb_usb_adapter { - const struct dvb_usb_adapter_properties *props; - struct usb_data_stream stream; - u8 id; - u8 ts_type; - bool pid_filtering; - u8 feed_count; - u8 max_feed_count; - s8 active_fe; - - /* dvb */ - struct dvb_adapter dvb_adap; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct mutex sync_mutex; - - struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; - int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); - int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); -}; - -/** - * dvb usb device object - * @props: device properties - * @name: device name - * @rc_map: name of rc codes table - * @udev: pointer to the device's struct usb_device - * @intf: pointer to the device's usb interface - * @rc: remote controller configuration - * @probe_work: work to defer .probe() - * @powered: indicated whether the device is power or not - * @usb_mutex: mutex for usb control messages - * @i2c_mutex: mutex for i2c-transfers - * @i2c_adap: device's i2c-adapter - * @rc_dev: rc device for the remote control - * @rc_query_work: work for polling remote - * @priv: private data of the actual driver (allocate by dvb usb, size defined - * in size_of_priv of dvb_usb_properties). - */ -struct dvb_usb_device { - const struct dvb_usb_device_properties *props; - const char *name; - const char *rc_map; - - struct usb_device *udev; - struct usb_interface *intf; - struct dvb_usb_rc rc; - struct work_struct probe_work; - pid_t work_pid; - int powered; - - /* locking */ - struct mutex usb_mutex; - - /* i2c */ - struct mutex i2c_mutex; - struct i2c_adapter i2c_adap; - - struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - - /* remote control */ - struct rc_dev *rc_dev; - char rc_phys[64]; - struct delayed_work rc_query_work; - - void *priv; -}; - -extern int dvb_usbv2_probe(struct usb_interface *, - const struct usb_device_id *); -extern void dvb_usbv2_disconnect(struct usb_interface *); -extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t); -extern int dvb_usbv2_resume(struct usb_interface *); - -/* the generic read/write method for device control */ -extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16); -extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h deleted file mode 100644 index 45f07090d43..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef DVB_USB_COMMON_H -#define DVB_USB_COMMON_H - -#include "dvb_usb.h" - -/* commonly used methods */ -extern int usb_urb_initv2(struct usb_data_stream *stream, - const struct usb_data_stream_properties *props); -extern int usb_urb_exitv2(struct usb_data_stream *stream); -extern int usb_urb_submitv2(struct usb_data_stream *stream, - struct usb_data_stream_properties *props); -extern int usb_urb_killv2(struct usb_data_stream *stream); - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c deleted file mode 100644 index a72f9c7de68..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c +++ /dev/null @@ -1,997 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "dvb_usb_common.h" - -int dvb_usbv2_disable_rc_polling; -module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); -MODULE_PARM_DESC(disable_rc_polling, - "disable remote control polling (default: 0)"); -static int dvb_usb_force_pid_filter_usage; -module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, - int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \ - "PID filter, if any (default: 0)"); - -static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) -{ - int ret; - const struct firmware *fw; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (!d->props->download_firmware) { - ret = -EINVAL; - goto err; - } - - ret = request_firmware(&fw, name, &d->udev->dev); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: Did not find the firmware file "\ - "'%s'. Please see linux/Documentation/dvb/ " \ - "for more details on firmware-problems. " \ - "Status %d\n", KBUILD_MODNAME, name, ret); - goto err; - } - - dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, name); - - ret = d->props->download_firmware(d, fw); - release_firmware(fw); - if (ret < 0) - goto err; - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) -{ - int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (!d->props->i2c_algo) - return 0; - - strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props->i2c_algo; - d->i2c_adap.dev.parent = &d->udev->dev; - i2c_set_adapdata(&d->i2c_adap, d); - - ret = i2c_add_adapter(&d->i2c_adap); - if (ret < 0) { - d->i2c_adap.algo = NULL; - dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n", - KBUILD_MODNAME, ret); - goto err; - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) -{ - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (d->i2c_adap.algo) - i2c_del_adapter(&d->i2c_adap); - - return 0; -} - -static void dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = container_of(work, - struct dvb_usb_device, rc_query_work.work); - int ret; - - /* - * When the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init. - */ - if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) - return; - - ret = d->rc.query(d); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n", - KBUILD_MODNAME, ret); - return; /* stop polling */ - } - - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); -} - -static int dvb_usbv2_remote_init(struct dvb_usb_device *d) -{ - int ret; - struct rc_dev *dev; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) - return 0; - - d->rc.map_name = d->rc_map; - ret = d->props->get_rc_config(d, &d->rc); - if (ret < 0) - goto err; - - /* disable rc when there is no keymap defined */ - if (!d->rc.map_name) - return 0; - - dev = rc_allocate_device(); - if (!dev) { - ret = -ENOMEM; - goto err; - } - - dev->dev.parent = &d->udev->dev; - dev->input_name = d->name; - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - dev->input_phys = d->rc_phys; - usb_to_input_id(d->udev, &dev->input_id); - /* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props->driver_name; - dev->map_name = d->rc.map_name; - dev->driver_type = d->rc.driver_type; - dev->allowed_protos = d->rc.allowed_protos; - dev->change_protocol = d->rc.change_protocol; - dev->priv = d; - - ret = rc_register_device(dev); - if (ret < 0) { - rc_free_device(dev); - goto err; - } - - d->rc_dev = dev; - - /* start polling if needed */ - if (d->rc.query && !d->rc.bulk_mode) { - /* initialize a work queue for handling polling */ - INIT_DELAYED_WORK(&d->rc_query_work, - dvb_usb_read_remote_control); - dev_info(&d->udev->dev, "%s: schedule remote query interval " \ - "to %d msecs\n", KBUILD_MODNAME, - d->rc.interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) -{ - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (d->rc_dev) { - cancel_delayed_work_sync(&d->rc_query_work); - rc_unregister_device(d->rc_dev); - d->rc_dev = NULL; - } - - return 0; -} - -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter(&adap->demux, buf, len); -} - -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter_204(&adap->demux, buf, len); -} - -static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter_raw(&adap->demux, buf, len); -} - -int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) -{ - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - adap->stream.udev = adap_to_d(adap)->udev; - adap->stream.user_priv = adap; - adap->stream.complete = dvb_usb_data_complete; - - return usb_urb_initv2(&adap->stream, &adap->props->stream); -} - -int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) -{ - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - return usb_urb_exitv2(&adap->stream); -} - -static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, - int count) -{ - struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \ - "setting pid [%s]: %04x (%04d) at index %d '%s'\n", - __func__, adap->id, adap->active_fe, dvbdmxfeed->type, - adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, - dvbdmxfeed->pid, dvbdmxfeed->index, - (count == 1) ? "on" : "off"); - - if (adap->active_fe == -1) - return -EINVAL; - - adap->feed_count += count; - - /* stop feeding if it is last pid */ - if (adap->feed_count == 0) { - dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); - usb_urb_killv2(&adap->stream); - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl( - adap->fe[adap->active_fe], 0); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); - goto err_mutex_unlock; - } - } - mutex_unlock(&adap->sync_mutex); - } - - /* activate the pid on the device pid filter */ - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props->pid_filter) - ret = adap->props->pid_filter(adap, dvbdmxfeed->index, - dvbdmxfeed->pid, (count == 1) ? 1 : 0); - if (ret < 0) - dev_err(&d->udev->dev, "%s: pid_filter() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); - - /* start feeding if it is first pid */ - if (adap->feed_count == 1 && count == 1) { - struct usb_data_stream_properties stream_props; - mutex_lock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); - - /* resolve input and output streaming paramters */ - if (d->props->get_stream_config) { - memcpy(&stream_props, &adap->props->stream, - sizeof(struct usb_data_stream_properties)); - ret = d->props->get_stream_config( - adap->fe[adap->active_fe], - &adap->ts_type, &stream_props); - if (ret < 0) - goto err_mutex_unlock; - } else { - stream_props = adap->props->stream; - } - - switch (adap->ts_type) { - case DVB_USB_FE_TS_TYPE_204: - adap->stream.complete = dvb_usb_data_complete_204; - break; - case DVB_USB_FE_TS_TYPE_RAW: - adap->stream.complete = dvb_usb_data_complete_raw; - break; - case DVB_USB_FE_TS_TYPE_188: - default: - adap->stream.complete = dvb_usb_data_complete; - break; - } - - usb_urb_submitv2(&adap->stream, &stream_props); - - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props->caps & - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props->pid_filter_ctrl) { - ret = adap->props->pid_filter_ctrl(adap, - adap->pid_filtering); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: " \ - "pid_filter_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_mutex_unlock; - } - } - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl( - adap->fe[adap->active_fe], 1); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); - goto err_mutex_unlock; - } - } - } - - return 0; -err_mutex_unlock: - mutex_unlock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, 1); -} - -static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, -1); -} - -int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); - - ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, - &d->udev->dev, d->props->adapter_nr); - if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n", - __func__, ret); - goto err_dvb_register_adapter; - } - - adap->dvb_adap.priv = adap; - - if (d->props->read_mac_address) { - ret = d->props->read_mac_address(adap, - adap->dvb_adap.proposed_mac); - if (ret < 0) - goto err_dvb_dmx_init; - - dev_info(&d->udev->dev, "%s: MAC address: %pM\n", - KBUILD_MODNAME, adap->dvb_adap.proposed_mac); - } - - adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - adap->demux.priv = adap; - adap->demux.filternum = 0; - adap->demux.filternum = adap->max_feed_count; - adap->demux.feednum = adap->demux.filternum; - adap->demux.start_feed = dvb_usb_start_feed; - adap->demux.stop_feed = dvb_usb_stop_feed; - adap->demux.write_to_decoder = NULL; - ret = dvb_dmx_init(&adap->demux); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_dvb_dmx_init; - } - - adap->dmxdev.filternum = adap->demux.filternum; - adap->dmxdev.demux = &adap->demux.dmx; - adap->dmxdev.capabilities = 0; - ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_dvb_dmxdev_init; - } - - ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_dvb_net_init; - } - - mutex_init(&adap->sync_mutex); - - return 0; -err_dvb_net_init: - dvb_dmxdev_release(&adap->dmxdev); -err_dvb_dmxdev_init: - dvb_dmx_release(&adap->demux); -err_dvb_dmx_init: - dvb_unregister_adapter(&adap->dvb_adap); -err_dvb_register_adapter: - adap->dvb_adap.priv = NULL; - return ret; -} - -int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) -{ - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - if (adap->dvb_adap.priv) { - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - } - - return 0; -} - -int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - - if (onoff) - d->powered++; - else - d->powered--; - - if (d->powered == 0 || (onoff && d->powered == 1)) { - /* when switching from 1 to 0 or from 0 to 1 */ - dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff); - if (d->props->power_ctrl) { - ret = d->props->power_ctrl(d, onoff); - if (ret < 0) - goto err; - } - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_fe_init(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap_to_d(adap); - mutex_lock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, - fe->id); - - ret = dvb_usbv2_device_power_ctrl(d, 1); - if (ret < 0) - goto err; - - if (d->props->frontend_ctrl) { - ret = d->props->frontend_ctrl(fe, 1); - if (ret < 0) - goto err; - } - - if (adap->fe_init[fe->id]) { - ret = adap->fe_init[fe->id](fe); - if (ret < 0) - goto err; - } - - adap->active_fe = fe->id; - mutex_unlock(&adap->sync_mutex); - - return 0; -err: - mutex_unlock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_fe_sleep(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap_to_d(adap); - mutex_lock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, - fe->id); - - if (adap->fe_sleep[fe->id]) { - ret = adap->fe_sleep[fe->id](fe); - if (ret < 0) - goto err; - } - - if (d->props->frontend_ctrl) { - ret = d->props->frontend_ctrl(fe, 0); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_device_power_ctrl(d, 0); - if (ret < 0) - goto err; - - adap->active_fe = -1; - mutex_unlock(&adap->sync_mutex); - - return 0; -err: - mutex_unlock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) -{ - int ret, i, count_registered = 0; - struct dvb_usb_device *d = adap_to_d(adap); - dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); - - memset(adap->fe, 0, sizeof(adap->fe)); - adap->active_fe = -1; - - if (d->props->frontend_attach) { - ret = d->props->frontend_attach(adap); - if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: frontend_attach() " \ - "failed=%d\n", __func__, ret); - goto err_dvb_frontend_detach; - } - } else { - dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n", - __func__); - ret = 0; - goto err; - } - - for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { - adap->fe[i]->id = i; - /* re-assign sleep and wakeup functions */ - adap->fe_init[i] = adap->fe[i]->ops.init; - adap->fe[i]->ops.init = dvb_usb_fe_init; - adap->fe_sleep[i] = adap->fe[i]->ops.sleep; - adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; - - ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: frontend%d registration " \ - "failed\n", KBUILD_MODNAME, i); - goto err_dvb_unregister_frontend; - } - - count_registered++; - } - - if (d->props->tuner_attach) { - ret = d->props->tuner_attach(adap); - if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n", - __func__, ret); - goto err_dvb_unregister_frontend; - } - } - - return 0; - -err_dvb_unregister_frontend: - for (i = count_registered - 1; i >= 0; i--) - dvb_unregister_frontend(adap->fe[i]); - -err_dvb_frontend_detach: - for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { - if (adap->fe[i]) - dvb_frontend_detach(adap->fe[i]); - } - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) -{ - int i; - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { - if (adap->fe[i]) { - dvb_unregister_frontend(adap->fe[i]); - dvb_frontend_detach(adap->fe[i]); - } - } - - return 0; -} - -static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) -{ - struct dvb_usb_adapter *adap; - int ret, i, adapter_count; - - /* resolve adapter count */ - adapter_count = d->props->num_adapters; - if (d->props->get_adapter_count) { - ret = d->props->get_adapter_count(d); - if (ret < 0) - goto err; - - adapter_count = ret; - } - - for (i = 0; i < adapter_count; i++) { - adap = &d->adapter[i]; - adap->id = i; - adap->props = &d->props->adapter[i]; - - /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && - !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - dev_err(&d->udev->dev, "%s: this USB2.0 device " \ - "cannot be run on a USB1.1 port (it " \ - "lacks a hardware PID filter)\n", - KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } else if ((d->udev->speed == USB_SPEED_FULL && - adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - dev_info(&d->udev->dev, "%s: will use the device's " \ - "hardware PID filter " \ - "(table count: %d)\n", KBUILD_MODNAME, - adap->props->pid_filter_count); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props->pid_filter_count; - } else { - dev_info(&d->udev->dev, "%s: will pass the complete " \ - "MPEG2 transport stream to the " \ - "software demuxer\n", KBUILD_MODNAME); - adap->pid_filtering = 0; - adap->max_feed_count = 255; - } - - if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && - adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - dev_info(&d->udev->dev, "%s: PID filter enabled by " \ - "module option\n", KBUILD_MODNAME); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props->pid_filter_count; - } - - ret = dvb_usbv2_adapter_stream_init(adap); - if (ret) - goto err; - - ret = dvb_usbv2_adapter_dvb_init(adap); - if (ret) - goto err; - - ret = dvb_usbv2_adapter_frontend_init(adap); - if (ret) - goto err; - - /* use exclusive FE lock if there is multiple shared FEs */ - if (adap->fe[1]) - adap->dvb_adap.mfe_shared = 1; - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) -{ - int i; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - if (d->adapter[i].props) { - dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); - dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); - dvb_usbv2_adapter_stream_exit(&d->adapter[i]); - } - } - - return 0; -} - -/* general initialization functions */ -static int dvb_usbv2_exit(struct dvb_usb_device *d) -{ - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - dvb_usbv2_remote_exit(d); - dvb_usbv2_adapter_exit(d); - dvb_usbv2_i2c_exit(d); - kfree(d->priv); - kfree(d); - - return 0; -} - -static int dvb_usbv2_init(struct dvb_usb_device *d) -{ - int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - dvb_usbv2_device_power_ctrl(d, 1); - - if (d->props->read_config) { - ret = d->props->read_config(d); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_i2c_init(d); - if (ret < 0) - goto err; - - ret = dvb_usbv2_adapter_init(d); - if (ret < 0) - goto err; - - if (d->props->init) { - ret = d->props->init(d); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_remote_init(d); - if (ret < 0) - goto err; - - dvb_usbv2_device_power_ctrl(d, 0); - - return 0; -err: - dvb_usbv2_device_power_ctrl(d, 0); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -/* - * udev, which is used for the firmware downloading, requires we cannot - * block during module_init(). module_init() calls USB probe() which - * is this routine. Due to that we delay actual operation using workqueue - * and return always success here. - */ -static void dvb_usbv2_init_work(struct work_struct *work) -{ - int ret; - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, probe_work); - - d->work_pid = current->pid; - dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid); - - if (d->props->size_of_priv) { - d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); - if (!d->priv) { - dev_err(&d->udev->dev, "%s: kzalloc() failed\n", - KBUILD_MODNAME); - ret = -ENOMEM; - goto err_usb_driver_release_interface; - } - } - - if (d->props->identify_state) { - const char *name = NULL; - ret = d->props->identify_state(d, &name); - if (ret == 0) { - ; - } else if (ret == COLD) { - dev_info(&d->udev->dev, "%s: found a '%s' in cold " \ - "state\n", KBUILD_MODNAME, d->name); - - if (!name) - name = d->props->firmware; - - ret = dvb_usbv2_download_firmware(d, name); - if (ret == 0) { - /* device is warm, continue initialization */ - ; - } else if (ret == RECONNECTS_USB) { - /* - * USB core will call disconnect() and then - * probe() as device reconnects itself from the - * USB bus. disconnect() will release all driver - * resources and probe() is called for 'new' - * device. As 'new' device is warm we should - * never go here again. - */ - return; - } else { - /* - * Unexpected error. We must unregister driver - * manually from the device, because device is - * already register by returning from probe() - * with success. usb_driver_release_interface() - * finally calls disconnect() in order to free - * resources. - */ - goto err_usb_driver_release_interface; - } - } else { - goto err_usb_driver_release_interface; - } - } - - dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n", - KBUILD_MODNAME, d->name); - - ret = dvb_usbv2_init(d); - if (ret < 0) - goto err_usb_driver_release_interface; - - dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \ - "connected\n", KBUILD_MODNAME, d->name); - - return; -err_usb_driver_release_interface: - dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n", - KBUILD_MODNAME, d->name, ret); - usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), - d->intf); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return; -} - -int dvb_usbv2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - struct dvb_usb_device *d; - struct usb_device *udev = interface_to_usbdev(intf); - struct dvb_usb_driver_info *driver_info = - (struct dvb_usb_driver_info *) id->driver_info; - - dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - if (!id->driver_info) { - dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (!d) { - dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); - ret = -ENOMEM; - goto err; - } - - d->name = driver_info->name; - d->rc_map = driver_info->rc_map; - d->udev = udev; - d->intf = intf; - d->props = driver_info->props; - - if (d->intf->cur_altsetting->desc.bInterfaceNumber != - d->props->bInterfaceNumber) { - ret = -ENODEV; - goto err_kfree; - } - - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - INIT_WORK(&d->probe_work, dvb_usbv2_init_work); - usb_set_intfdata(intf, d); - ret = schedule_work(&d->probe_work); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: schedule_work() failed\n", - KBUILD_MODNAME); - goto err_kfree; - } - - return 0; -err_kfree: - kfree(d); -err: - dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} -EXPORT_SYMBOL(dvb_usbv2_probe); - -void dvb_usbv2_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = d->name; - struct device dev = d->udev->dev; - dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__, - current->pid, d->work_pid); - - /* ensure initialization work is finished until release resources */ - if (d->work_pid != current->pid) - cancel_work_sync(&d->probe_work); - - if (d->props->exit) - d->props->exit(d); - - dvb_usbv2_exit(d); - - dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n", - KBUILD_MODNAME, name); -} -EXPORT_SYMBOL(dvb_usbv2_disconnect); - -int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - int i; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* stop remote controller poll */ - if (d->rc.query && !d->rc.bulk_mode) - cancel_delayed_work_sync(&d->rc_query_work); - - /* stop streaming */ - for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - if (d->adapter[i].dvb_adap.priv && - d->adapter[i].active_fe != -1) - usb_urb_killv2(&d->adapter[i].stream); - } - - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_suspend); - -int dvb_usbv2_resume(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - int i; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* start streaming */ - for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { - if (d->adapter[i].dvb_adap.priv && - d->adapter[i].active_fe != -1) - usb_urb_submitv2(&d->adapter[i].stream, NULL); - } - - /* start remote controller poll */ - if (d->rc.query && !d->rc.bulk_mode) - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_resume); - -MODULE_VERSION("2.0"); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("DVB USB common"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c deleted file mode 100644 index 0431beed0ef..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "dvb_usb_common.h" - -int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen) -{ - int ret, actual_length; - - if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || - !d->props->generic_bulk_ctrl_endpoint_response) { - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&d->usb_mutex); - if (ret < 0) - return ret; - - dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf); - - ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, - &actual_length, 2000); - if (ret < 0) - dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", - KBUILD_MODNAME, ret); - else - ret = actual_length != wlen ? -EIO : 0; - - /* an answer is expected, and no error before */ - if (!ret && rbuf && rlen) { - if (d->props->generic_bulk_ctrl_delay) - usleep_range(d->props->generic_bulk_ctrl_delay, - d->props->generic_bulk_ctrl_delay - + 20000); - - ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint_response), - rbuf, rlen, &actual_length, 2000); - if (ret) - dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \ - "failed=%d\n", KBUILD_MODNAME, ret); - - dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__, - actual_length, rbuf); - } - - mutex_unlock(&d->usb_mutex); - return ret; -} -EXPORT_SYMBOL(dvb_usbv2_generic_rw); - -int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) -{ - return dvb_usbv2_generic_rw(d, buf, len, NULL, 0); -} -EXPORT_SYMBOL(dvb_usbv2_generic_write); diff --git a/drivers/media/dvb/dvb-usb-v2/ec168.c b/drivers/media/dvb/dvb-usb-v2/ec168.c deleted file mode 100644 index ab77622c383..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/ec168.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * E3C EC168 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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 "ec168.h" -#include "ec100.h" -#include "mxl5005s.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) -{ - int ret; - unsigned int pipe; - u8 request, requesttype; - u8 *buf; - - switch (req->cmd) { - case DOWNLOAD_FIRMWARE: - case GPIO: - case WRITE_I2C: - case STREAMING_CTRL: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = req->cmd; - break; - case READ_I2C: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = req->cmd; - break; - case GET_CONFIG: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = CONFIG; - break; - case SET_CONFIG: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = CONFIG; - break; - case WRITE_DEMOD: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = DEMOD_RW; - break; - case READ_DEMOD: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = DEMOD_RW; - break; - default: - pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd); - ret = -EINVAL; - goto error; - } - - buf = kmalloc(req->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto error; - } - - if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { - /* write */ - memcpy(buf, req->data, req->size); - pipe = usb_sndctrlpipe(d->udev, 0); - } else { - /* read */ - pipe = usb_rcvctrlpipe(d->udev, 0); - } - - msleep(1); /* avoid I2C errors */ - - ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value, - req->index, buf, req->size, EC168_USB_TIMEOUT); - - ec168_debug_dump(request, requesttype, req->value, req->index, buf, - req->size); - - if (ret < 0) - goto err_dealloc; - else - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->size); - - kfree(buf); - return ret; - -err_dealloc: - kfree(buf); -error: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -/* I2C */ -static struct ec100_config ec168_ec100_config; - -static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct ec168_req req; - int i = 0; - int ret; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == ec168_ec100_config.demod_address) { - req.cmd = READ_DEMOD; - req.value = 0; - req.index = 0xff00 + msg[i].buf[0]; /* reg */ - req.size = msg[i+1].len; /* bytes to read */ - req.data = &msg[i+1].buf[0]; - ret = ec168_ctrl_msg(d, &req); - i += 2; - } else { - pr_err("%s: I2C read not implemented\n", - KBUILD_MODNAME); - ret = -EOPNOTSUPP; - i += 2; - } - } else { - if (msg[i].addr == ec168_ec100_config.demod_address) { - req.cmd = WRITE_DEMOD; - req.value = msg[i].buf[1]; /* val */ - req.index = 0xff00 + msg[i].buf[0]; /* reg */ - req.size = 0; - req.data = NULL; - ret = ec168_ctrl_msg(d, &req); - i += 1; - } else { - req.cmd = WRITE_I2C; - req.value = msg[i].buf[0]; /* val */ - req.index = 0x0100 + msg[i].addr; /* I2C addr */ - req.size = msg[i].len-1; - req.data = &msg[i].buf[1]; - ret = ec168_ctrl_msg(d, &req); - i += 1; - } - } - if (ret) - goto error; - - } - ret = i; - -error: - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 ec168_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ec168_i2c_algo = { - .master_xfer = ec168_i2c_xfer, - .functionality = ec168_i2c_func, -}; - -/* Callbacks for DVB USB */ -static int ec168_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 reply; - struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; - pr_debug("%s:\n", __func__); - - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - pr_debug("%s: reply=%02x\n", __func__, reply); - - if (reply == 0x01) - ret = WARM; - else - ret = COLD; - - return ret; -error: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int ec168_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret, len, remaining; - struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; - pr_debug("%s:\n", __func__); - - #define LEN_MAX 2048 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.size = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.index = fw->size - remaining; - - ret = ec168_ctrl_msg(d, &req); - if (ret) { - pr_err("%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); - goto error; - } - } - - req.size = 0; - - /* set "warm"? */ - req.cmd = SET_CONFIG; - req.value = 0; - req.index = 0x0001; - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - /* really needed - no idea what does */ - req.cmd = GPIO; - req.value = 0; - req.index = 0x0206; - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - /* activate tuner I2C? */ - req.cmd = WRITE_I2C; - req.value = 0; - req.index = 0x00c6; - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - return ret; -error: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static struct ec100_config ec168_ec100_config = { - .demod_address = 0xff, /* not real address, demod is integrated */ -}; - -static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) -{ - pr_debug("%s:\n", __func__); - adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -ENODEV; - - return 0; -} - -static struct mxl5005s_config ec168_mxl5003s_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - pr_debug("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; -} - -static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; - pr_debug("%s: onoff=%d\n", __func__, onoff); - if (onoff) - req.index = 0x0102; - return ec168_ctrl_msg(fe_to_d(fe), &req); -} - -/* DVB USB Driver stuff */ -/* bInterfaceNumber 0 is HID - * bInterfaceNumber 1 is DVB-T */ -static struct dvb_usb_device_properties ec168_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .bInterfaceNumber = 1, - - .identify_state = ec168_identify_state, - .firmware = "dvb-usb-ec168.fw", - .download_firmware = ec168_download_firmware, - - .i2c_algo = &ec168_i2c_algo, - .frontend_attach = ec168_ec100_frontend_attach, - .tuner_attach = ec168_mxl5003s_tuner_attach, - .streaming_ctrl = ec168_streaming_ctrl, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512), - } - }, -}; - -static const struct dvb_usb_driver_info ec168_driver_info = { - .name = "E3C EC168 reference design", - .props = &ec168_props, -}; - -static const struct usb_device_id ec168_id[] = { - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - {} -}; -MODULE_DEVICE_TABLE(usb, ec168_id); - -static struct usb_driver ec168_driver = { - .name = KBUILD_MODNAME, - .id_table = ec168_id, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(ec168_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("E3C EC168 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/ec168.h b/drivers/media/dvb/dvb-usb-v2/ec168.h deleted file mode 100644 index 9181236f6eb..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/ec168.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * E3C EC168 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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 EC168_H -#define EC168_H - -#include "dvb_usb.h" - -#define ec168_debug_dump(r, t, v, i, b, l) { \ - char *direction; \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - direction = ">>>"; \ - else \ - direction = "<<<"; \ - pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \ - __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ - l & 0xff, l >> 8, direction); \ -} - -#define EC168_USB_TIMEOUT 1000 - -struct ec168_req { - u8 cmd; /* [1] */ - u16 value; /* [2|3] */ - u16 index; /* [4|5] */ - u16 size; /* [6|7] */ - u8 *data; -}; - -enum ec168_cmd { - DOWNLOAD_FIRMWARE = 0x00, - CONFIG = 0x01, - DEMOD_RW = 0x03, - GPIO = 0x04, - STREAMING_CTRL = 0x10, - READ_I2C = 0x20, - WRITE_I2C = 0x21, - HID_DOWNLOAD = 0x30, - GET_CONFIG, - SET_CONFIG, - READ_DEMOD, - WRITE_DEMOD, -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/gl861.c b/drivers/media/dvb/dvb-usb-v2/gl861.c deleted file mode 100644 index cf29f43e359..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/gl861.c +++ /dev/null @@ -1,175 +0,0 @@ -/* DVB USB compliant linux driver for GL861 USB2.0 devices. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "gl861.h" - -#include "zl10353.h" -#include "qt1010.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -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; - - if (wo) { - req = GL861_REQ_I2C_WRITE; - type = GL861_WRITE; - } else { /* rw */ - req = GL861_REQ_I2C_READ; - type = GL861_READ; - } - - switch (wlen) { - case 1: - index = wbuf[0]; - break; - case 2: - index = wbuf[0]; - value = value + wbuf[1]; - break; - default: - pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen); - return -EINVAL; - } - - msleep(1); /* avoid I2C errors */ - - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), 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 struct i2c_algorithm gl861_i2c_algo = { - .master_xfer = gl861_i2c_xfer, - .functionality = gl861_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config gl861_zl10353_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int gl861_frontend_attach(struct dvb_usb_adapter *adap) -{ - - adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -EIO; - - return 0; -} - -static struct qt1010_config gl861_qt1010_config = { - .i2c_address = 0x62 -}; - -static int gl861_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, - adap->fe[0], &adap_to_d(adap)->i2c_adap, - &gl861_qt1010_config) == NULL ? -ENODEV : 0; -} - -static int gl861_init(struct dvb_usb_device *d) -{ - /* - * There is 2 interfaces. Interface 0 is for TV and interface 1 is - * for HID remote controller. Interface 0 has 2 alternate settings. - * For some reason we need to set interface explicitly, defaulted - * as alternate setting 1? - */ - return usb_set_interface(d->udev, 0, 0); -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties gl861_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - - .i2c_algo = &gl861_i2c_algo, - .frontend_attach = gl861_frontend_attach, - .tuner_attach = gl861_tuner_attach, - .init = gl861_init, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x81, 7, 512), - } - } -}; - -static const struct usb_device_id gl861_id_table[] = { - { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, - &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, - { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, - &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, gl861_id_table); - -static struct usb_driver gl861_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = gl861_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(gl861_usb_driver); - -MODULE_AUTHOR("Carl Lundqvist "); -MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/gl861.h b/drivers/media/dvb/dvb-usb-v2/gl861.h deleted file mode 100644 index b0b80d87bb7..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/gl861.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _DVB_USB_GL861_H_ -#define _DVB_USB_GL861_H_ - -#include "dvb_usb.h" - -#define GL861_WRITE 0x40 -#define GL861_READ 0xc0 - -#define GL861_REQ_I2C_WRITE 0x01 -#define GL861_REQ_I2C_READ 0x02 - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/it913x.c b/drivers/media/dvb/dvb-usb-v2/it913x.c deleted file mode 100644 index 695f9106bc5..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/it913x.c +++ /dev/null @@ -1,799 +0,0 @@ -/* - * DVB USB compliant linux driver for ITE IT9135 and IT9137 - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9135 (C) ITE Tech Inc. - * IT9137 (C) ITE Tech Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * see Documentation/dvb/README.dvb-usb for more information - * see Documentation/dvb/it9137.txt for firmware information - * - */ -#define DVB_USB_LOG_PREFIX "it913x" - -#include -#include -#include - -#include "dvb_usb.h" -#include "it913x-fe.h" - -/* debug */ -static int dvb_usb_it913x_debug; -#define it_debug(var, level, args...) \ - do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \ -} while (0) -#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args) -#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args) - -module_param_named(debug, dvb_usb_it913x_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -static int dvb_usb_it913x_firmware; -module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644); -MODULE_PARM_DESC(firmware, "set firmware 0=auto"\ - "1=IT9137 2=IT9135 V1 3=IT9135 V2"); -#define FW_IT9137 "dvb-usb-it9137-01.fw" -#define FW_IT9135_V1 "dvb-usb-it9135-01.fw" -#define FW_IT9135_V2 "dvb-usb-it9135-02.fw" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct it913x_state { - struct ite_config it913x_config; - u8 pid_filter_onoff; - bool proprietary_ir; - int cmd_counter; -}; - -static u16 check_sum(u8 *p, u8 len) -{ - u16 sum = 0; - u8 i = 1; - while (i < len) - sum += (i++ & 1) ? (*p++) << 8 : *p++; - return ~sum; -} - -static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro, - u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) -{ - struct it913x_state *st = d->priv; - int ret = 0, i, buf_size = 1; - u8 *buff; - u8 rlen; - u16 chk_sum; - - buff = kzalloc(256, GFP_KERNEL); - if (!buff) { - info("USB Buffer Failed"); - return -ENOMEM; - } - - buff[buf_size++] = pro; - buff[buf_size++] = cmd; - buff[buf_size++] = st->cmd_counter; - - switch (mode) { - case READ_LONG: - case WRITE_LONG: - buff[buf_size++] = len; - buff[buf_size++] = 2; - buff[buf_size++] = (reg >> 24); - buff[buf_size++] = (reg >> 16) & 0xff; - buff[buf_size++] = (reg >> 8) & 0xff; - buff[buf_size++] = reg & 0xff; - break; - case READ_SHORT: - buff[buf_size++] = addr; - break; - case WRITE_SHORT: - buff[buf_size++] = len; - buff[buf_size++] = addr; - buff[buf_size++] = (reg >> 8) & 0xff; - buff[buf_size++] = reg & 0xff; - break; - case READ_DATA: - case WRITE_DATA: - break; - case WRITE_CMD: - mode = 7; - break; - default: - kfree(buff); - return -EINVAL; - } - - if (mode & 1) { - for (i = 0; i < len ; i++) - buff[buf_size++] = data[i]; - } - chk_sum = check_sum(&buff[1], buf_size); - - buff[buf_size++] = chk_sum >> 8; - buff[0] = buf_size; - buff[buf_size++] = (chk_sum & 0xff); - - ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ? - 5 : len + 5); - if (ret < 0) - goto error; - - rlen = (mode & 0x1) ? 0x1 : len; - - if (mode & 1) - ret = buff[2]; - else - memcpy(data, &buff[3], rlen); - - st->cmd_counter++; - -error: kfree(buff); - - return ret; -} - -static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data) -{ - int ret; - u8 b[1]; - b[0] = data; - ret = it913x_io(d, WRITE_LONG, pro, - CMD_DEMOD_WRITE, reg, 0, b, sizeof(b)); - - return ret; -} - -static int it913x_read_reg(struct dvb_usb_device *d, u32 reg) -{ - int ret; - u8 data[1]; - - ret = it913x_io(d, READ_LONG, DEV_0, - CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data)); - - return (ret < 0) ? ret : data[0]; -} - -static int it913x_query(struct dvb_usb_device *d, u8 pro) -{ - struct it913x_state *st = d->priv; - int ret, i; - u8 data[4]; - u8 ver; - - for (i = 0; i < 5; i++) { - ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ, - 0x1222, 0, &data[0], 3); - ver = data[0]; - if (ver > 0 && ver < 3) - break; - msleep(100); - } - - if (ver < 1 || ver > 2) { - info("Failed to identify chip version applying 1"); - st->it913x_config.chip_ver = 0x1; - st->it913x_config.chip_type = 0x9135; - return 0; - } - - st->it913x_config.chip_ver = ver; - st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; - - info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver, - st->it913x_config.chip_type); - - ret = it913x_io(d, READ_SHORT, pro, - CMD_QUERYINFO, 0, 0x1, &data[0], 4); - - st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | data[3]; - - return ret; -} - -static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = adap_to_priv(adap); - int ret; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - - mutex_lock(&d->i2c_mutex); - - deb_info(1, "PID_C (%02x)", onoff); - - ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff); - - mutex_unlock(&d->i2c_mutex); - return ret; -} - -static int it913x_pid_filter(struct dvb_usb_adapter *adap, - int index, u16 pid, int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = adap_to_priv(adap); - int ret; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - - mutex_lock(&d->i2c_mutex); - - deb_info(1, "PID_F (%02x)", onoff); - - ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff)); - - ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8)); - - ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff); - - ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f)); - - if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) { - ret |= it913x_wr_reg(d , pro, PID_EN, !onoff); - st->pid_filter_onoff = !onoff; - } else - st->pid_filter_onoff = - adap->pid_filtering; - - mutex_unlock(&d->i2c_mutex); - return 0; -} - - -static int it913x_return_status(struct dvb_usb_device *d) -{ - struct it913x_state *st = d->priv; - int ret = it913x_query(d, DEV_0); - if (st->it913x_config.firmware > 0) - info("Firmware Version %d", st->it913x_config.firmware); - - return ret; -} - -static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - static u8 data[256]; - int ret; - u32 reg; - u8 pro; - - mutex_lock(&d->i2c_mutex); - - deb_info(2, "num of messages %d address %02x", num, msg[0].addr); - - pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0; - pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0; - memcpy(data, msg[0].buf, msg[0].len); - reg = (data[0] << 24) + (data[1] << 16) + - (data[2] << 8) + data[3]; - if (num == 2) { - ret = it913x_io(d, READ_LONG, pro, - CMD_DEMOD_READ, reg, 0, data, msg[1].len); - memcpy(msg[1].buf, data, msg[1].len); - } else - ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE, - reg, 0, &data[4], msg[0].len - 4); - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 it913x_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm it913x_i2c_algo = { - .master_xfer = it913x_i2c_xfer, - .functionality = it913x_i2c_func, -}; - -/* Callbacks for DVB USB */ -#define IT913X_POLL 250 -static int it913x_rc_query(struct dvb_usb_device *d) -{ - u8 ibuf[4]; - int ret; - u32 key; - /* Avoid conflict with frontends*/ - mutex_lock(&d->i2c_mutex); - - ret = it913x_io(d, READ_LONG, PRO_LINK, CMD_IR_GET, - 0, 0, &ibuf[0], sizeof(ibuf)); - - if ((ibuf[2] + ibuf[3]) == 0xff) { - key = ibuf[2]; - key += ibuf[0] << 16; - key += ibuf[1] << 8; - deb_info(1, "NEC Extended Key =%08x", key); - if (d->rc_dev != NULL) - rc_keydown(d->rc_dev, key, 0); - } - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -/* Firmware sets raw */ -static const char fw_it9135_v1[] = FW_IT9135_V1; -static const char fw_it9135_v2[] = FW_IT9135_V2; -static const char fw_it9137[] = FW_IT9137; - -static void ite_get_firmware_name(struct dvb_usb_device *d, - const char **name) -{ - struct it913x_state *st = d->priv; - int sw; - /* auto switch */ - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2) - sw = IT9137_FW; - else if (st->it913x_config.chip_ver == 1) - sw = IT9135_V1_FW; - else - sw = IT9135_V2_FW; - - /* force switch */ - if (dvb_usb_it913x_firmware != IT9135_AUTO) - sw = dvb_usb_it913x_firmware; - - switch (sw) { - case IT9135_V1_FW: - st->it913x_config.firmware_ver = 1; - st->it913x_config.adc_x2 = 1; - st->it913x_config.read_slevel = false; - *name = fw_it9135_v1; - break; - case IT9135_V2_FW: - st->it913x_config.firmware_ver = 1; - st->it913x_config.adc_x2 = 1; - st->it913x_config.read_slevel = false; - *name = fw_it9135_v2; - switch (st->it913x_config.tuner_id_0) { - case IT9135_61: - case IT9135_62: - break; - default: - info("Unknown tuner ID applying default 0x60"); - case IT9135_60: - st->it913x_config.tuner_id_0 = IT9135_60; - } - break; - case IT9137_FW: - default: - st->it913x_config.firmware_ver = 0; - st->it913x_config.adc_x2 = 0; - st->it913x_config.read_slevel = true; - *name = fw_it9137; - } - - return; -} - -#define TS_MPEG_PKT_SIZE 188 -#define EP_LOW 21 -#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) -#define EP_HIGH 348 -#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) - -static int it913x_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - if (adap->pid_filtering) - stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID; - else - stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX; - - return 0; -} - -static int it913x_select_config(struct dvb_usb_device *d) -{ - struct it913x_state *st = d->priv; - int ret, reg; - - ret = it913x_return_status(d); - if (ret < 0) - return ret; - - if (st->it913x_config.chip_ver == 0x02 - && st->it913x_config.chip_type == 0x9135) - reg = it913x_read_reg(d, 0x461d); - else - reg = it913x_read_reg(d, 0x461b); - - if (reg < 0) - return reg; - - if (reg == 0) { - st->it913x_config.dual_mode = 0; - st->it913x_config.tuner_id_0 = IT9135_38; - st->proprietary_ir = true; - } else { - /* TS mode */ - reg = it913x_read_reg(d, 0x49c5); - if (reg < 0) - return reg; - st->it913x_config.dual_mode = reg; - - /* IR mode type */ - reg = it913x_read_reg(d, 0x49ac); - if (reg < 0) - return reg; - if (reg == 5) { - info("Remote propriety (raw) mode"); - st->proprietary_ir = true; - } else if (reg == 1) { - info("Remote HID mode NOT SUPPORTED"); - st->proprietary_ir = false; - } - - /* Tuner_id */ - reg = it913x_read_reg(d, 0x49d0); - if (reg < 0) - return reg; - st->it913x_config.tuner_id_0 = reg; - } - - info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode, - st->it913x_config.tuner_id_0); - - return ret; -} - -static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = fe_to_priv(fe); - int ret = 0; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - - deb_info(1, "STM (%02x)", onoff); - - if (!onoff) { - mutex_lock(&d->i2c_mutex); - - ret = it913x_wr_reg(d, pro, PID_RST, 0x1); - - mutex_unlock(&d->i2c_mutex); - st->pid_filter_onoff = - adap->pid_filtering; - - } - - return ret; -} - -static int it913x_identify_state(struct dvb_usb_device *d, const char **name) -{ - struct it913x_state *st = d->priv; - int ret; - u8 reg; - - /* Read and select config */ - ret = it913x_select_config(d); - if (ret < 0) - return ret; - - ite_get_firmware_name(d, name); - - if (st->it913x_config.firmware > 0) - return WARM; - - if (st->it913x_config.dual_mode) { - st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0); - ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1); - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1); - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1); - msleep(50); - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0); - msleep(50); - reg = it913x_read_reg(d, GPIOH1_O); - if (reg == 0) { - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1); - ret |= it913x_return_status(d); - if (ret != 0) - ret = it913x_wr_reg(d, DEV_0, - GPIOH1_O, 0x0); - } - } - - reg = it913x_read_reg(d, IO_MUX_POWER_CLK); - - if (st->it913x_config.dual_mode) { - ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); - if (st->it913x_config.firmware_ver == 1) - ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x1); - else - ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x1); - } else { - ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0); - if (st->it913x_config.firmware_ver == 1) - ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x0); - else - ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x0); - } - - ret |= it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100); - - return (ret < 0) ? ret : COLD; -} - -static int it913x_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - struct it913x_state *st = d->priv; - int ret = 0, i = 0, pos = 0; - u8 packet_size, min_pkt; - u8 *fw_data; - - ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100); - - info("FRM Starting Firmware Download"); - - /* Multi firmware loader */ - /* This uses scatter write firmware headers */ - /* The firmware must start with 03 XX 00 */ - /* and be the extact firmware length */ - - if (st->it913x_config.chip_ver == 2) - min_pkt = 0x11; - else - min_pkt = 0x19; - - while (i <= fw->size) { - if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0)) - || (i == fw->size)) { - packet_size = i - pos; - if ((packet_size > min_pkt) || (i == fw->size)) { - fw_data = (u8 *)(fw->data + pos); - pos += packet_size; - if (packet_size > 0) { - ret = it913x_io(d, WRITE_DATA, - DEV_0, CMD_SCATTER_WRITE, 0, - 0, fw_data, packet_size); - if (ret < 0) - break; - } - udelay(1000); - } - } - i++; - } - - if (ret < 0) - info("FRM Firmware Download Failed (%d)" , ret); - else - info("FRM Firmware Download Completed - Resetting Device"); - - msleep(30); - - ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); - if (ret < 0) - info("FRM Device not responding to reboot"); - - ret = it913x_return_status(d); - if (st->it913x_config.firmware == 0) { - info("FRM Failed to reboot device"); - return -ENODEV; - } - - msleep(30); - - ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_400); - - msleep(30); - - /* Tuner function */ - if (st->it913x_config.dual_mode) - ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0); - else - ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68); - - if ((st->it913x_config.chip_ver == 1) && - (st->it913x_config.chip_type == 0x9135)) { - ret |= it913x_wr_reg(d, DEV_0, PADODPU, 0x0); - ret |= it913x_wr_reg(d, DEV_0, AGC_O_D, 0x0); - if (st->it913x_config.dual_mode) { - ret |= it913x_wr_reg(d, DEV_1, PADODPU, 0x0); - ret |= it913x_wr_reg(d, DEV_1, AGC_O_D, 0x0); - } - } - - return (ret < 0) ? -ENODEV : 0; -} - -static int it913x_name(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - const char *desc = d->name; - char *fe_name[] = {"_1", "_2", "_3", "_4"}; - char *name = adap->fe[0]->ops.info.name; - - strlcpy(name, desc, 128); - strlcat(name, fe_name[adap->id], 128); - - return 0; -} - -static int it913x_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = d->priv; - int ret = 0; - u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); - u16 ep_size = adap->stream.buf_size / 4; - u8 pkt_size = 0x80; - - if (d->udev->speed != USB_SPEED_HIGH) - pkt_size = 0x10; - - st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK); - - adap->fe[0] = dvb_attach(it913x_fe_attach, - &d->i2c_adap, adap_addr, &st->it913x_config); - - if (adap->id == 0 && adap->fe[0]) { - it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1); - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f); - it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b); - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f); - it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB, - ep_size & 0xff); - it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); - ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size); - } else if (adap->id == 1 && adap->fe[0]) { - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f); - it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB, - ep_size & 0xff); - it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); - it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1); - it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1); - it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1); - it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1); - it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1); - it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0); - ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0); - } else - return -ENODEV; - - ret |= it913x_name(adap); - - return ret; -} - -/* DVB USB Driver */ -static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - struct it913x_state *st = d->priv; - - if (st->proprietary_ir == false) { - rc->map_name = NULL; - return 0; - } - - rc->allowed_protos = RC_TYPE_NEC; - rc->query = it913x_rc_query; - rc->interval = 250; - - return 0; -} - -static int it913x_get_adapter_count(struct dvb_usb_device *d) -{ - struct it913x_state *st = d->priv; - if (st->it913x_config.dual_mode) - return 2; - return 1; -} - -static struct dvb_usb_device_properties it913x_properties = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .bInterfaceNumber = 0, - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct it913x_state), - - .identify_state = it913x_identify_state, - .i2c_algo = &it913x_i2c_algo, - - .download_firmware = it913x_download_firmware, - - .frontend_attach = it913x_frontend_attach, - .get_rc_config = it913x_get_rc_config, - .get_stream_config = it913x_get_stream_config, - .get_adapter_count = it913x_get_adapter_count, - .streaming_ctrl = it913x_streaming_ctrl, - - - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = it913x_pid_filter, - .pid_filter_ctrl = it913x_pid_filter_ctrl, - .stream = - DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX), - }, - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = it913x_pid_filter, - .pid_filter_ctrl = it913x_pid_filter_ctrl, - .stream = - DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX), - } - } -}; - -static const struct usb_device_id it913x_id_table[] = { - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09, - &it913x_properties, "Kworld UB499-2T T09(IT9137)", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135, - &it913x_properties, "ITE 9135 Generic", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137, - &it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005, - &it913x_properties, "ITE 9135(9005) Generic", - RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006, - &it913x_properties, "ITE 9135(9006) Generic", - RC_MAP_IT913X_V1) }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, it913x_id_table); - -static struct usb_driver it913x_driver = { - .name = KBUILD_MODNAME, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .id_table = it913x_id_table, -}; - -module_usb_driver(it913x_driver); - -MODULE_AUTHOR("Malcolm Priestley "); -MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.32"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FW_IT9135_V1); -MODULE_FIRMWARE(FW_IT9135_V2); -MODULE_FIRMWARE(FW_IT9137); - diff --git a/drivers/media/dvb/dvb-usb-v2/lmedm04.c b/drivers/media/dvb/dvb-usb-v2/lmedm04.c deleted file mode 100644 index c41d9d9ec7b..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/lmedm04.c +++ /dev/null @@ -1,1369 +0,0 @@ -/* DVB USB compliant linux driver for - * - * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 - * LME2510C + LG TDQY-P001F - * LME2510C + BS2F7HZ0194 - * LME2510 + LG TDQY-P001F - * LME2510 + BS2F7HZ0194 - * - * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) - * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) - * - * MV001F (LME2510+LGTDQY-P001F) - * LG TDQY - P001F =(TDA8263 + TDA10086H) - * - * MVB0001F (LME2510C+LGTDQT-P001F) - * - * MV0194 (LME2510+SHARP:BS2F7HZ0194) - * SHARP:BS2F7HZ0194 = (STV0299+IX2410) - * - * MVB0194 (LME2510C+SHARP0194) - * - * LME2510C + M88RS2000 - * - * For firmware see Documentation/dvb/lmedm04.txt - * - * I2C addresses: - * 0xd0 - STV0288 - Demodulator - * 0xc0 - Sharp IX2505V - Tuner - * -- - * 0x1c - TDA10086 - Demodulator - * 0xc0 - TDA8263 - Tuner - * -- - * 0xd0 - STV0299 - Demodulator - * 0xc0 - IX2410 - Tuner - * - * - * VID = 3344 PID LME2510=1122 LME2510C=1120 - * - * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com) - * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * see Documentation/dvb/README.dvb-usb for more information - * - * Known Issues : - * LME2510: Non Intel USB chipsets fail to maintain High Speed on - * Boot or Hot Plug. - * - * QQbox suffers from noise on LNB voltage. - * - * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system - * with other tuners. After a cold reset streaming will not start. - * - * M88RS2000 suffers from loss of lock. - */ -#define DVB_USB_LOG_PREFIX "LME2510(C)" -#include -#include -#include - -#include "dvb_usb.h" -#include "lmedm04.h" -#include "tda826x.h" -#include "tda10086.h" -#include "stv0288.h" -#include "ix2505v.h" -#include "stv0299.h" -#include "dvb-pll.h" -#include "z0194a.h" -#include "m88rs2000.h" - - -#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; -#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; -#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; -#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; -#define LME2510_LG "dvb-usb-lme2510-lg.fw"; -#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; - -/* debug */ -static int dvb_usb_lme2510_debug; -#define lme_debug(var, level, args...) do { \ - if ((var >= level)) \ - pr_debug(DVB_USB_LOG_PREFIX": " args); \ -} while (0) -#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args) -#define debug_data_snipet(level, name, p) \ - deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ - *p, *(p+1), *(p+2), *(p+3), *(p+4), \ - *(p+5), *(p+6), *(p+7)); -#define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args) - -module_param_named(debug, dvb_usb_lme2510_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -static int dvb_usb_lme2510_firmware; -module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644); -MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); - -static int pid_filter; -module_param_named(pid, pid_filter, int, 0644); -MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); - - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define TUNER_DEFAULT 0x0 -#define TUNER_LG 0x1 -#define TUNER_S7395 0x2 -#define TUNER_S0194 0x3 -#define TUNER_RS2000 0x4 - -struct lme2510_state { - u8 id; - u8 tuner_config; - u8 signal_lock; - u8 signal_level; - u8 signal_sn; - u8 time_key; - u8 last_key; - u8 key_timeout; - u8 i2c_talk_onoff; - u8 i2c_gate; - u8 i2c_tuner_gate_w; - u8 i2c_tuner_gate_r; - u8 i2c_tuner_addr; - u8 stream_on; - u8 pid_size; - u8 pid_off; - void *buffer; - struct urb *lme_urb; - void *usb_buffer; - int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); - u8 dvb_usb_lme2510_firmware; -}; - -static int lme2510_bulk_write(struct usb_device *dev, - u8 *snd, int len, u8 pipe) -{ - int ret, actual_l; - - ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 100); - return ret; -} - -static int lme2510_bulk_read(struct usb_device *dev, - u8 *rev, int len, u8 pipe) -{ - int ret, actual_l; - - ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 200); - return ret; -} - -static int lme2510_usb_talk(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - struct lme2510_state *st = d->priv; - u8 *buff; - int ret = 0; - - if (st->usb_buffer == NULL) { - st->usb_buffer = kmalloc(64, GFP_KERNEL); - if (st->usb_buffer == NULL) { - info("MEM Error no memory"); - return -ENOMEM; - } - } - buff = st->usb_buffer; - - ret = mutex_lock_interruptible(&d->usb_mutex); - - if (ret < 0) - return -EAGAIN; - - /* the read/write capped at 64 */ - memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); - - ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); - - ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? - rlen : 64 , 0x01); - - if (rlen > 0) - memcpy(rbuf, buff, rlen); - - mutex_unlock(&d->usb_mutex); - - return (ret < 0) ? -ENODEV : 0; -} - -static int lme2510_stream_restart(struct dvb_usb_device *d) -{ - struct lme2510_state *st = d->priv; - u8 all_pids[] = LME_ALL_PIDS; - u8 stream_on[] = LME_ST_ON_W; - int ret; - u8 rbuff[1]; - if (st->pid_off) - ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), - rbuff, sizeof(rbuff)); - /*Restart Stream Command*/ - ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), - rbuff, sizeof(rbuff)); - return ret; -} - -static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) -{ - struct lme2510_state *st = d->priv; - static u8 pid_buff[] = LME_ZERO_PID; - static u8 rbuf[1]; - u8 pid_no = index * 2; - u8 pid_len = pid_no + 2; - int ret = 0; - deb_info(1, "PID Setting Pid %04x", pid_out); - - if (st->pid_size == 0) - ret |= lme2510_stream_restart(d); - - pid_buff[2] = pid_no; - pid_buff[3] = (u8)pid_out & 0xff; - pid_buff[4] = pid_no + 1; - pid_buff[5] = (u8)(pid_out >> 8); - - if (pid_len > st->pid_size) - st->pid_size = pid_len; - pid_buff[7] = 0x80 + st->pid_size; - - ret |= lme2510_usb_talk(d, pid_buff , - sizeof(pid_buff) , rbuf, sizeof(rbuf)); - - if (st->stream_on) - ret |= lme2510_stream_restart(d); - - return ret; -} - -static void lme2510_int_response(struct urb *lme_urb) -{ - struct dvb_usb_adapter *adap = lme_urb->context; - struct lme2510_state *st = adap_to_priv(adap); - static u8 *ibuf, *rbuf; - int i = 0, offset; - u32 key; - - switch (lme_urb->status) { - case 0: - case -ETIMEDOUT: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - default: - info("Error %x", lme_urb->status); - break; - } - - rbuf = (u8 *) lme_urb->transfer_buffer; - - offset = ((lme_urb->actual_length/8) > 4) - ? 4 : (lme_urb->actual_length/8) ; - - for (i = 0; i < offset; ++i) { - ibuf = (u8 *)&rbuf[i*8]; - deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x", - offset, i, ibuf[0], ibuf[1]); - - switch (ibuf[0]) { - case 0xaa: - debug_data_snipet(1, "INT Remote data snipet", ibuf); - if ((ibuf[4] + ibuf[5]) == 0xff) { - key = ibuf[5]; - key += (ibuf[3] > 0) - ? (ibuf[3] ^ 0xff) << 8 : 0; - key += (ibuf[2] ^ 0xff) << 16; - deb_info(1, "INT Key =%08x", key); - if (adap_to_d(adap)->rc_dev != NULL) - rc_keydown(adap_to_d(adap)->rc_dev, - key, 0); - } - break; - case 0xbb: - switch (st->tuner_config) { - case TUNER_LG: - if (ibuf[2] > 0) - st->signal_lock = ibuf[2]; - st->signal_level = ibuf[4]; - st->signal_sn = ibuf[3]; - st->time_key = ibuf[7]; - break; - case TUNER_S7395: - case TUNER_S0194: - /* Tweak for earlier firmware*/ - if (ibuf[1] == 0x03) { - if (ibuf[2] > 1) - st->signal_lock = ibuf[2]; - st->signal_level = ibuf[3]; - st->signal_sn = ibuf[4]; - } else { - st->signal_level = ibuf[4]; - st->signal_sn = ibuf[5]; - st->signal_lock = - (st->signal_lock & 0xf7) + - ((ibuf[2] & 0x01) << 0x03); - } - break; - case TUNER_RS2000: - if (ibuf[1] == 0x3 && ibuf[6] == 0xff) - st->signal_lock = 0xff; - else - st->signal_lock = 0x00; - st->signal_level = ibuf[5]; - st->signal_sn = ibuf[4]; - st->time_key = ibuf[7]; - default: - break; - } - debug_data_snipet(5, "INT Remote data snipet in", ibuf); - break; - case 0xcc: - debug_data_snipet(1, "INT Control data snipet", ibuf); - break; - default: - debug_data_snipet(1, "INT Unknown data snipet", ibuf); - break; - } - } - usb_submit_urb(lme_urb, GFP_ATOMIC); -} - -static int lme2510_int_read(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *lme_int = adap_to_priv(adap); - - lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); - - if (lme_int->lme_urb == NULL) - return -ENOMEM; - - lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC, - &lme_int->lme_urb->transfer_dma); - - if (lme_int->buffer == NULL) - return -ENOMEM; - - usb_fill_int_urb(lme_int->lme_urb, - d->udev, - usb_rcvintpipe(d->udev, 0xa), - lme_int->buffer, - 128, - lme2510_int_response, - adap, - 8); - - lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); - info("INT Interrupt Service Started"); - - return 0; -} - -static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - static u8 clear_pid_reg[] = LME_ALL_PIDS; - static u8 rbuf[1]; - int ret = 0; - - deb_info(1, "PID Clearing Filter"); - - mutex_lock(&d->i2c_mutex); - - if (!onoff) { - ret |= lme2510_usb_talk(d, clear_pid_reg, - sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); - st->pid_off = true; - } else - st->pid_off = false; - - st->pid_size = 0; - - mutex_unlock(&d->i2c_mutex); - - return 0; -} - -static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - int ret = 0; - - deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, - pid, index, onoff); - - if (onoff) { - mutex_lock(&d->i2c_mutex); - ret |= lme2510_enable_pid(d, index, pid); - mutex_unlock(&d->i2c_mutex); - } - - - return ret; -} - - -static int lme2510_return_status(struct dvb_usb_device *d) -{ - int ret = 0; - u8 *data; - - data = kzalloc(10, GFP_KERNEL); - if (!data) - return -ENOMEM; - - ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); - info("Firmware Status: %x (%x)", ret , data[2]); - - ret = (ret < 0) ? -ENODEV : data[2]; - kfree(data); - return ret; -} - -static int lme2510_msg(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int ret = 0; - struct lme2510_state *st = d->priv; - - if (st->i2c_talk_onoff == 1) { - - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - - switch (st->tuner_config) { - case TUNER_LG: - if (wbuf[2] == 0x1c) { - if (wbuf[3] == 0x0e) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x10)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - msleep(80); - } - } - break; - case TUNER_S7395: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x24) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_S0194: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x1b) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_RS2000: - default: - break; - } - } else { - /* TODO rewrite this section */ - switch (st->tuner_config) { - case TUNER_LG: - switch (wbuf[3]) { - case 0x0e: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x43: - rbuf[0] = 0x55; - rbuf[1] = st->signal_level; - break; - case 0x1c: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S7395: - switch (wbuf[3]) { - case 0x10: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x2d: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x2e: - case 0x26: - case 0x27: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S0194: - switch (wbuf[3]) { - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x1b: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x19: - case 0x25: - case 0x1e: - case 0x1d: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_RS2000: - switch (wbuf[3]) { - case 0x8c: - rbuf[0] = 0x55; - rbuf[1] = 0xff; - if (st->last_key == st->time_key) { - st->key_timeout++; - if (st->key_timeout > 5) - rbuf[1] = 0; - } else - st->key_timeout = 0; - st->last_key = st->time_key; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - default: - break; - } - - deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", - wbuf[3], rbuf[1]); - - } - - return ret; -} - - -static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct lme2510_state *st = d->priv; - static u8 obuf[64], ibuf[64]; - int i, read, read_o; - u16 len; - u8 gate = st->i2c_gate; - - mutex_lock(&d->i2c_mutex); - - if (gate == 0) - gate = 5; - - for (i = 0; i < num; i++) { - read_o = 1 & (msg[i].flags & I2C_M_RD); - read = i+1 < num && (msg[i+1].flags & I2C_M_RD); - read |= read_o; - gate = (msg[i].addr == st->i2c_tuner_addr) - ? (read) ? st->i2c_tuner_gate_r - : st->i2c_tuner_gate_w - : st->i2c_gate; - obuf[0] = gate | (read << 7); - - if (gate == 5) - obuf[1] = (read) ? 2 : msg[i].len + 1; - else - obuf[1] = msg[i].len + read + 1; - - obuf[2] = msg[i].addr; - if (read) { - if (read_o) - len = 3; - else { - memcpy(&obuf[3], msg[i].buf, msg[i].len); - obuf[msg[i].len+3] = msg[i+1].len; - len = msg[i].len+4; - } - } else { - memcpy(&obuf[3], msg[i].buf, msg[i].len); - len = msg[i].len+3; - } - - if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { - deb_info(1, "i2c transfer failed."); - mutex_unlock(&d->i2c_mutex); - return -EAGAIN; - } - - if (read) { - if (read_o) - memcpy(msg[i].buf, &ibuf[1], msg[i].len); - else { - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); - i++; - } - } - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 lme2510_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm lme2510_i2c_algo = { - .master_xfer = lme2510_i2c_xfer, - .functionality = lme2510_i2c_func, -}; - -static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - static u8 clear_reg_3[] = LME_ALL_PIDS; - static u8 rbuf[1]; - int ret = 0, rlen = sizeof(rbuf); - - deb_info(1, "STM (%02x)", onoff); - - /* Streaming is started by FE_HAS_LOCK */ - if (onoff == 1) - st->stream_on = 1; - else { - deb_info(1, "STM Steam Off"); - /* mutex is here only to avoid collision with I2C */ - mutex_lock(&d->i2c_mutex); - - ret = lme2510_usb_talk(d, clear_reg_3, - sizeof(clear_reg_3), rbuf, rlen); - st->stream_on = 0; - st->i2c_talk_onoff = 1; - - mutex_unlock(&d->i2c_mutex); - } - - return (ret < 0) ? -ENODEV : 0; -} - -static u8 check_sum(u8 *p, u8 len) -{ - u8 sum = 0; - while (len--) - sum += *p++; - return sum; -} - -static int lme2510_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret = 0; - u8 *data; - u16 j, wlen, len_in, start, end; - u8 packet_size, dlen, i; - u8 *fw_data; - - packet_size = 0x31; - len_in = 1; - - data = kzalloc(128, GFP_KERNEL); - if (!data) { - info("FRM Could not start Firmware Download"\ - "(Buffer allocation failed)"); - return -ENOMEM; - } - - info("FRM Starting Firmware Download"); - - for (i = 1; i < 3; i++) { - start = (i == 1) ? 0 : 512; - end = (i == 1) ? 512 : fw->size; - for (j = start; j < end; j += (packet_size+1)) { - fw_data = (u8 *)(fw->data + j); - if ((end - j) > packet_size) { - data[0] = i; - dlen = packet_size; - } else { - data[0] = i | 0x80; - dlen = (u8)(end - j)-1; - } - data[1] = dlen; - memcpy(&data[2], fw_data, dlen+1); - wlen = (u8) dlen + 4; - data[wlen-1] = check_sum(fw_data, dlen+1); - deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3], - data[dlen+2], data[dlen+3]); - lme2510_usb_talk(d, data, wlen, data, len_in); - ret |= (data[0] == 0x88) ? 0 : -1; - } - } - - data[0] = 0x8a; - len_in = 1; - msleep(2000); - lme2510_usb_talk(d, data, len_in, data, len_in); - msleep(400); - - if (ret < 0) - info("FRM Firmware Download Failed (%04x)" , ret); - else - info("FRM Firmware Download Completed - Resetting Device"); - - kfree(data); - return RECONNECTS_USB; -} - -static void lme_coldreset(struct dvb_usb_device *d) -{ - u8 data[1] = {0}; - data[0] = 0x0a; - info("FRM Firmware Cold Reset"); - - lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data)); - - return; -} - -static const char fw_c_s7395[] = LME2510_C_S7395; -static const char fw_c_lg[] = LME2510_C_LG; -static const char fw_c_s0194[] = LME2510_C_S0194; -static const char fw_c_rs2000[] = LME2510_C_RS2000; -static const char fw_lg[] = LME2510_LG; -static const char fw_s0194[] = LME2510_S0194; - -const char *lme_firmware_switch(struct dvb_usb_device *d, int cold) -{ - struct lme2510_state *st = d->priv; - struct usb_device *udev = d->udev; - const struct firmware *fw = NULL; - const char *fw_lme; - int ret = 0; - - cold = (cold > 0) ? (cold & 1) : 0; - - switch (le16_to_cpu(udev->descriptor.idProduct)) { - case 0x1122: - switch (st->dvb_usb_lme2510_firmware) { - default: - st->dvb_usb_lme2510_firmware = TUNER_S0194; - case TUNER_S0194: - fw_lme = fw_s0194; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) { - cold = 0; - break; - } - st->dvb_usb_lme2510_firmware = TUNER_LG; - case TUNER_LG: - fw_lme = fw_lg; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; - break; - } - break; - case 0x1120: - switch (st->dvb_usb_lme2510_firmware) { - default: - st->dvb_usb_lme2510_firmware = TUNER_S7395; - case TUNER_S7395: - fw_lme = fw_c_s7395; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) { - cold = 0; - break; - } - st->dvb_usb_lme2510_firmware = TUNER_LG; - case TUNER_LG: - fw_lme = fw_c_lg; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - st->dvb_usb_lme2510_firmware = TUNER_S0194; - case TUNER_S0194: - fw_lme = fw_c_s0194; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; - cold = 0; - break; - } - break; - case 0x22f0: - fw_lme = fw_c_rs2000; - st->dvb_usb_lme2510_firmware = TUNER_RS2000; - break; - default: - fw_lme = fw_c_s7395; - } - - release_firmware(fw); - - if (cold) { - dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware; - info("FRM Changing to %s firmware", fw_lme); - lme_coldreset(d); - return NULL; - } - - return fw_lme; -} - -static int lme2510_kill_urb(struct usb_data_stream *stream) -{ - int i; - - for (i = 0; i < stream->urbs_submitted; i++) { - deb_info(3, "killing URB no. %d.", i); - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - - return 0; -} - -static struct tda10086_config tda10086_config = { - .demod_address = 0x1c, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct stv0288_config lme_config = { - .demod_address = 0xd0, - .min_delay_ms = 15, - .inittab = s7395_inittab, -}; - -static struct ix2505v_config lme_tuner = { - .tuner_address = 0xc0, - .min_delay_ms = 100, - .tuner_gain = 0x0, - .tuner_chargepump = 0x3, -}; - -static struct stv0299_config sharp_z0194_config = { - .demod_address = 0xd0, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, - int caller) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = d->priv; - - mutex_lock(&d->i2c_mutex); - if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { - st->i2c_talk_onoff = 0; - lme2510_stream_restart(d); - } - mutex_unlock(&d->i2c_mutex); - - return 0; -} - -static struct m88rs2000_config m88rs2000_config = { - .demod_addr = 0xd0, - .tuner_addr = 0xc0, - .set_ts_params = dm04_rs2000_set_ts_param, -}; - -static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct dvb_usb_device *d = fe_to_d(fe); - struct lme2510_state *st = fe_to_priv(fe); - static u8 voltage_low[] = LME_VOLTAGE_L; - static u8 voltage_high[] = LME_VOLTAGE_H; - static u8 rbuf[1]; - int ret = 0, len = 3, rlen = 1; - - mutex_lock(&d->i2c_mutex); - - switch (voltage) { - case SEC_VOLTAGE_18: - ret |= lme2510_usb_talk(d, - voltage_high, len, rbuf, rlen); - break; - - case SEC_VOLTAGE_OFF: - case SEC_VOLTAGE_13: - default: - ret |= lme2510_usb_talk(d, - voltage_low, len, rbuf, rlen); - break; - } - - mutex_unlock(&d->i2c_mutex); - - if (st->tuner_config == TUNER_RS2000) - if (st->fe_set_voltage) - st->fe_set_voltage(fe, voltage); - - - return (ret < 0) ? -ENODEV : 0; -} - -static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct lme2510_state *st = fe_to_priv(fe); - - *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); - - return 0; -} - -static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct lme2510_state *st = fe_to_priv(fe); - - *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); - - return 0; -} - -static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - *ber = 0; - - return 0; -} - -static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - *ucblocks = 0; - - return 0; -} - -static int lme_name(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - const char *desc = d->name; - char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", - " SHARP:BS2F7HZ0194", " RS2000"}; - char *name = adap->fe[0]->ops.info.name; - - strlcpy(name, desc, 128); - strlcat(name, fe_name[st->tuner_config], 128); - - return 0; -} - -static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = d->priv; - int ret = 0; - - st->i2c_talk_onoff = 1; - switch (le16_to_cpu(d->udev->descriptor.idProduct)) { - case 0x1122: - case 0x1120: - st->i2c_gate = 4; - adap->fe[0] = dvb_attach(tda10086_attach, - &tda10086_config, &d->i2c_adap); - if (adap->fe[0]) { - info("TUN Found Frontend TDA10086"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 4; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_LG; - if (st->dvb_usb_lme2510_firmware != TUNER_LG) { - st->dvb_usb_lme2510_firmware = TUNER_LG; - ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; - } - break; - } - - st->i2c_gate = 4; - adap->fe[0] = dvb_attach(stv0299_attach, - &sharp_z0194_config, &d->i2c_adap); - if (adap->fe[0]) { - info("FE Found Stv0299"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_S0194; - if (st->dvb_usb_lme2510_firmware != TUNER_S0194) { - st->dvb_usb_lme2510_firmware = TUNER_S0194; - ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; - } - break; - } - - st->i2c_gate = 5; - adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, - &d->i2c_adap); - - if (adap->fe[0]) { - info("FE Found Stv0288"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_S7395; - if (st->dvb_usb_lme2510_firmware != TUNER_S7395) { - st->dvb_usb_lme2510_firmware = TUNER_S7395; - ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; - } - break; - } - case 0x22f0: - st->i2c_gate = 5; - adap->fe[0] = dvb_attach(m88rs2000_attach, - &m88rs2000_config, &d->i2c_adap); - - if (adap->fe[0]) { - info("FE Found M88RS2000"); - st->i2c_tuner_gate_w = 5; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_RS2000; - st->fe_set_voltage = - adap->fe[0]->ops.set_voltage; - - adap->fe[0]->ops.read_signal_strength = - dm04_rs2000_read_signal_strength; - adap->fe[0]->ops.read_snr = - dm04_rs2000_read_snr; - adap->fe[0]->ops.read_ber = - dm04_read_ber; - adap->fe[0]->ops.read_ucblocks = - dm04_read_ucblocks; - } - break; - } - - if (adap->fe[0] == NULL) { - info("DM04/QQBOX Not Powered up or not Supported"); - return -ENODEV; - } - - if (ret) { - if (adap->fe[0]) { - dvb_frontend_detach(adap->fe[0]); - adap->fe[0] = NULL; - } - d->rc_map = NULL; - return -ENODEV; - } - - adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; - ret = lme_name(adap); - return ret; -} - -static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = adap_to_priv(adap); - char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; - int ret = 0; - - switch (st->tuner_config) { - case TUNER_LG: - if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, - &d->i2c_adap, 1)) - ret = st->tuner_config; - break; - case TUNER_S7395: - if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, - &d->i2c_adap)) - ret = st->tuner_config; - break; - case TUNER_S0194: - if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, - &d->i2c_adap, DVB_PLL_OPERA1)) - ret = st->tuner_config; - break; - case TUNER_RS2000: - ret = st->tuner_config; - break; - default: - break; - } - - if (ret) - info("TUN Found %s tuner", tun_msg[ret]); - else { - info("TUN No tuner found --- resetting device"); - lme_coldreset(d); - return -ENODEV; - } - - /* Start the Interrupt*/ - ret = lme2510_int_read(adap); - if (ret < 0) { - info("INT Unable to start Interrupt Service"); - return -ENODEV; - } - - return ret; -} - -static int lme2510_powerup(struct dvb_usb_device *d, int onoff) -{ - struct lme2510_state *st = d->priv; - static u8 lnb_on[] = LNB_ON; - static u8 lnb_off[] = LNB_OFF; - static u8 rbuf[1]; - int ret = 0, len = 3, rlen = 1; - - mutex_lock(&d->i2c_mutex); - - if (onoff) - ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); - else - ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); - - st->i2c_talk_onoff = 1; - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static int lme2510_get_adapter_count(struct dvb_usb_device *d) -{ - return 1; -} - -static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) -{ - struct lme2510_state *st = d->priv; - - usb_reset_configuration(d->udev); - - usb_set_interface(d->udev, - d->intf->cur_altsetting->desc.bInterfaceNumber, 1); - - st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; - - if (lme2510_return_status(d) == 0x44) { - *name = lme_firmware_switch(d, 0); - return COLD; - } - - return 0; -} - -static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - - if (adap == NULL) - return 0; - /* Turn PID filter on the fly by module option */ - if (pid_filter == 2) { - adap->pid_filtering = 1; - adap->max_feed_count = 15; - } - - if (!(le16_to_cpu(d->udev->descriptor.idProduct) - == 0x1122)) - stream->endpoint = 0x8; - - return 0; -} - -static int lme2510_get_rc_config(struct dvb_usb_device *d, - struct dvb_usb_rc *rc) -{ - rc->allowed_protos = RC_TYPE_NEC; - return 0; -} - -static void *lme2510_exit_int(struct dvb_usb_device *d) -{ - struct lme2510_state *st = d->priv; - struct dvb_usb_adapter *adap = &d->adapter[0]; - void *buffer = NULL; - - if (adap != NULL) { - lme2510_kill_urb(&adap->stream); - } - - if (st->usb_buffer != NULL) { - st->i2c_talk_onoff = 1; - st->signal_lock = 0; - st->signal_level = 0; - st->signal_sn = 0; - buffer = st->usb_buffer; - } - - if (st->lme_urb != NULL) { - usb_kill_urb(st->lme_urb); - usb_free_coherent(d->udev, 128, st->buffer, - st->lme_urb->transfer_dma); - info("Interrupt Service Stopped"); - } - - return buffer; -} - -static void lme2510_exit(struct dvb_usb_device *d) -{ - void *usb_buffer; - - if (d != NULL) { - usb_buffer = lme2510_exit_int(d); - if (usb_buffer != NULL) - kfree(usb_buffer); - } -} - -static struct dvb_usb_device_properties lme2510_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .bInterfaceNumber = 0, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct lme2510_state), - - .download_firmware = lme2510_download_firmware, - - .power_ctrl = lme2510_powerup, - .identify_state = lme2510_identify_state, - .i2c_algo = &lme2510_i2c_algo, - - .frontend_attach = dm04_lme2510_frontend_attach, - .tuner_attach = dm04_lme2510_tuner, - .get_stream_config = lme2510_get_stream_config, - .get_adapter_count = lme2510_get_adapter_count, - .streaming_ctrl = lme2510_streaming_ctrl, - - .get_rc_config = lme2510_get_rc_config, - - .exit = lme2510_exit, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 15, - .pid_filter = lme2510_pid_filter, - .pid_filter_ctrl = lme2510_pid_filter_ctrl, - .stream = - DVB_USB_STREAM_BULK(0x86, 10, 4096), - }, - { - } - }, -}; - -static const struct usb_device_id lme2510_id_table[] = { - { DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props, - "DM04_LME2510_DVB-S", RC_MAP_LME2510) }, - { DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props, - "DM04_LME2510C_DVB-S", RC_MAP_LME2510) }, - { DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props, - "DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510) }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, lme2510_id_table); - -static struct usb_driver lme2510_driver = { - .name = KBUILD_MODNAME, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .id_table = lme2510_id_table, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(lme2510_driver); - -MODULE_AUTHOR("Malcolm Priestley "); -MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("2.06"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(LME2510_C_S7395); -MODULE_FIRMWARE(LME2510_C_LG); -MODULE_FIRMWARE(LME2510_C_S0194); -MODULE_FIRMWARE(LME2510_C_RS2000); -MODULE_FIRMWARE(LME2510_LG); -MODULE_FIRMWARE(LME2510_S0194); - diff --git a/drivers/media/dvb/dvb-usb-v2/lmedm04.h b/drivers/media/dvb/dvb-usb-v2/lmedm04.h deleted file mode 100644 index e9c207205c2..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/lmedm04.h +++ /dev/null @@ -1,175 +0,0 @@ -/* DVB USB compliant linux driver for - * - * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 - * LME2510C + LG TDQY-P001F - * LME2510 + LG TDQY-P001F - * - * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) - * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) - * - * MVB001F (LME2510+LGTDQT-P001F) - * LG TDQY - P001F =(TDA8263 + TDA10086H) - * - * MVB0001F (LME2510C+LGTDQT-P001F) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_LME2510_H_ -#define _DVB_USB_LME2510_H_ - -/* Streamer & PID - * - * Note: These commands do not actually stop the streaming - * but form some kind of packet filtering/stream count - * or tuning related functions. - * 06 XX - * offset 1 = 00 Enable Streaming - * - * - * PID - * 03 XX XX ----> reg number ---> setting....20 XX - * offset 1 = length - * offset 2 = start of data - * end byte -1 = 20 - * end byte = clear pid always a0, other wise 9c, 9a ?? - * -*/ -#define LME_ST_ON_W {0x06, 0x00} -#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} -#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} -#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} - -/* LNB Voltage - * 07 XX XX - * offset 1 = 01 - * offset 2 = 00=Voltage low 01=Voltage high - * - * LNB Power - * 03 01 XX - * offset 2 = 00=ON 01=OFF - */ - -#define LME_VOLTAGE_L {0x07, 0x01, 0x00} -#define LME_VOLTAGE_H {0x07, 0x01, 0x01} -#define LNB_ON {0x3a, 0x01, 0x00} -#define LNB_OFF {0x3a, 0x01, 0x01} - -/* Initial stv0288 settings for 7395 Frontend */ -static u8 s7395_inittab[] = { - 0x01, 0x15, - 0x02, 0x20, - 0x03, 0xa0, - 0x04, 0xa0, - 0x05, 0x12, - 0x06, 0x00, - 0x09, 0x00, - 0x0a, 0x04, - 0x0b, 0x00, - 0x0c, 0x00, - 0x0d, 0x00, - 0x0e, 0xc1, - 0x0f, 0x54, - 0x11, 0x7a, - 0x12, 0x03, - 0x13, 0x48, - 0x14, 0x84, - 0x15, 0xc5, - 0x16, 0xb8, - 0x17, 0x9c, - 0x18, 0x00, - 0x19, 0xa6, - 0x1a, 0x88, - 0x1b, 0x8f, - 0x1c, 0xf0, - 0x20, 0x0b, - 0x21, 0x54, - 0x22, 0xff, - 0x23, 0x01, - 0x28, 0x46, - 0x29, 0x66, - 0x2a, 0x90, - 0x2b, 0xfa, - 0x2c, 0xd9, - 0x30, 0x0, - 0x31, 0x1e, - 0x32, 0x14, - 0x33, 0x0f, - 0x34, 0x09, - 0x35, 0x0c, - 0x36, 0x05, - 0x37, 0x2f, - 0x38, 0x16, - 0x39, 0xbd, - 0x3a, 0x0, - 0x3b, 0x13, - 0x3c, 0x11, - 0x3d, 0x30, - 0x40, 0x63, - 0x41, 0x04, - 0x42, 0x20, - 0x43, 0x00, - 0x44, 0x00, - 0x45, 0x00, - 0x46, 0x00, - 0x47, 0x00, - 0x4a, 0x00, - 0x50, 0x10, - 0x51, 0x36, - 0x52, 0x21, - 0x53, 0x94, - 0x54, 0xb2, - 0x55, 0x29, - 0x56, 0x64, - 0x57, 0x2b, - 0x58, 0x54, - 0x59, 0x86, - 0x5a, 0x00, - 0x5b, 0x9b, - 0x5c, 0x08, - 0x5d, 0x7f, - 0x5e, 0xff, - 0x5f, 0x8d, - 0x70, 0x0, - 0x71, 0x0, - 0x72, 0x0, - 0x74, 0x0, - 0x75, 0x0, - 0x76, 0x0, - 0x81, 0x0, - 0x82, 0x3f, - 0x83, 0x3f, - 0x84, 0x0, - 0x85, 0x0, - 0x88, 0x0, - 0x89, 0x0, - 0x8a, 0x0, - 0x8b, 0x0, - 0x8c, 0x0, - 0x90, 0x0, - 0x91, 0x0, - 0x92, 0x0, - 0x93, 0x0, - 0x94, 0x1c, - 0x97, 0x0, - 0xa0, 0x48, - 0xa1, 0x0, - 0xb0, 0xb8, - 0xb1, 0x3a, - 0xb2, 0x10, - 0xb3, 0x82, - 0xb4, 0x80, - 0xb5, 0x82, - 0xb6, 0x82, - 0xb7, 0x82, - 0xb8, 0x20, - 0xb9, 0x0, - 0xf0, 0x0, - 0xf1, 0x0, - 0xf2, 0xc0, - 0xff, 0xff, -}; -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c deleted file mode 100644 index d83df4bb72d..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator - * - * Copyright (C) 2010 Michael Krufky - * - * 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 "mxl111sf-demod.h" -#include "mxl111sf-reg.h" - -/* debug */ -static int mxl111sf_demod_debug; -module_param_named(debug, mxl111sf_demod_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -#define mxl_dbg(fmt, arg...) \ - if (mxl111sf_demod_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -/* ------------------------------------------------------------------------ */ - -struct mxl111sf_demod_state { - struct mxl111sf_state *mxl_state; - - struct mxl111sf_demod_config *cfg; - - struct dvb_frontend fe; -}; - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, - u8 addr, u8 *data) -{ - return (state->cfg->read_reg) ? - state->cfg->read_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, - u8 addr, u8 data) -{ - return (state->cfg->write_reg) ? - state->cfg->write_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static -int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info) -{ - return (state->cfg->program_regs) ? - state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : - -EINVAL; -} - -/* ------------------------------------------------------------------------ */ -/* TPS */ - -static -int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, - fe_code_rate_t *code_rate) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); - /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ - if (mxl_fail(ret)) - goto fail; - - switch (val & V6_CODE_RATE_TPS_MASK) { - case 0: - *code_rate = FEC_1_2; - break; - case 1: - *code_rate = FEC_2_3; - break; - case 2: - *code_rate = FEC_3_4; - break; - case 3: - *code_rate = FEC_5_6; - break; - case 4: - *code_rate = FEC_7_8; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, - fe_modulation_t *modulation) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); - /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { - case 0: - *modulation = QPSK; - break; - case 1: - *modulation = QAM_16; - break; - case 2: - *modulation = QAM_64; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, - fe_transmit_mode_t *fft_mode) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); - /* FFT Mode, 00:2K, 01:8K, 10:4K */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { - case 0: - *fft_mode = TRANSMISSION_MODE_2K; - break; - case 1: - *fft_mode = TRANSMISSION_MODE_8K; - break; - case 2: - *fft_mode = TRANSMISSION_MODE_4K; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, - fe_guard_interval_t *guard) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); - /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_PARAM_GI_MASK) >> 4) { - case 0: - *guard = GUARD_INTERVAL_1_32; - break; - case 1: - *guard = GUARD_INTERVAL_1_16; - break; - case 2: - *guard = GUARD_INTERVAL_1_8; - break; - case 3: - *guard = GUARD_INTERVAL_1_4; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, - fe_hierarchy_t *hierarchy) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); - /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { - case 0: - *hierarchy = HIERARCHY_NONE; - break; - case 1: - *hierarchy = HIERARCHY_1; - break; - case 2: - *hierarchy = HIERARCHY_2; - break; - case 3: - *hierarchy = HIERARCHY_4; - break; - } -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ -/* LOCKS */ - -static -int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, - int *sync_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); - if (mxl_fail(ret)) - goto fail; - *sync_lock = (val & SYNC_LOCK_MASK) >> 4; -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, - int *rs_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); - if (mxl_fail(ret)) - goto fail; - *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, - int *tps_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); - if (mxl_fail(ret)) - goto fail; - *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, - int *fec_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); - if (mxl_fail(ret)) - goto fail; - *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; -fail: - return ret; -} - -#if 0 -static -int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, - int *cp_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); - if (mxl_fail(ret)) - goto fail; - *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; -fail: - return ret; -} -#endif - -static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) -{ - return mxl111sf_demod_write_reg(state, 0x0e, 0xff); -} - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - int ret = 0; - - struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { - {0x00, 0xff, 0x01}, /* change page to 1 */ - {0x40, 0xff, 0x05}, - {0x40, 0xff, 0x01}, - {0x41, 0xff, 0xca}, - {0x41, 0xff, 0xc0}, - {0x00, 0xff, 0x00}, /* change page to 0 */ - {0, 0, 0} - }; - - mxl_dbg("()"); - - if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe); - if (mxl_fail(ret)) - goto fail; - msleep(50); - } - ret = mxl111sf_demod_program_regs(state, phy_pll_patch); - mxl_fail(ret); - msleep(50); - ret = mxl1x1sf_demod_reset_irq_status(state); - mxl_fail(ret); - msleep(100); -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -#if 0 -/* resets TS Packet error count */ -/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ -static -int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) -{ - struct mxl111sf_reg_ctrl_info reset_per_count[] = { - {0x20, 0x01, 0x01}, - {0x20, 0x01, 0x00}, - {0, 0, 0} - }; - return mxl111sf_demod_program_regs(state, reset_per_count); -} -#endif - -/* returns TS Packet error count */ -/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ -static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - u32 fec_per_count, fec_per_scale; - u8 val; - int ret; - - *ucblocks = 0; - - /* FEC_PER_COUNT Register */ - ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); - if (mxl_fail(ret)) - goto fail; - - fec_per_count = val; - - /* FEC_PER_SCALE Register */ - ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); - if (mxl_fail(ret)) - goto fail; - - val &= V6_FEC_PER_SCALE_MASK; - val *= 4; - - fec_per_scale = 1 << val; - - fec_per_count *= fec_per_scale; - - *ucblocks = fec_per_count; -fail: - return ret; -} - -#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS -/* FIXME: leaving this enabled breaks the build on some architectures, - * and we shouldn't have any floating point math in the kernel, anyway. - * - * These macros need to be re-written, but it's harmless to simply - * return zero for now. */ -#define CALCULATE_BER(avg_errors, count) \ - ((u32)(avg_errors * 4)/(count*64*188*8)) -#define CALCULATE_SNR(data) \ - ((u32)((10 * (u32)data / 64) - 2.5)) -#else -#define CALCULATE_BER(avg_errors, count) 0 -#define CALCULATE_SNR(data) 0 -#endif - -static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - u8 val1, val2, val3; - int ret; - - *ber = 0; - - ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); - if (mxl_fail(ret)) - goto fail; - - *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); -fail: - return ret; -} - -static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, - u16 *snr) -{ - u8 val1, val2; - int ret; - - *snr = 0; - - ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); - if (mxl_fail(ret)) - goto fail; - - *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); -fail: - return ret; -} - -static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - - int ret = mxl111sf_demod_calc_snr(state, snr); - if (mxl_fail(ret)) - goto fail; - - *snr /= 10; /* 0.1 dB */ -fail: - return ret; -} - -static int mxl111sf_demod_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - int ret, locked, cr_lock, sync_lock, fec_lock; - - *status = 0; - - ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); - if (mxl_fail(ret)) - goto fail; - - if (locked) - *status |= FE_HAS_SIGNAL; - if (cr_lock) - *status |= FE_HAS_CARRIER; - if (sync_lock) - *status |= FE_HAS_SYNC; - if (fec_lock) /* false positives? */ - *status |= FE_HAS_VITERBI; - - if ((locked) && (cr_lock) && (sync_lock)) - *status |= FE_HAS_LOCK; -fail: - return ret; -} - -static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - fe_modulation_t modulation; - u16 snr; - - mxl111sf_demod_calc_snr(state, &snr); - mxl1x1sf_demod_get_tps_modulation(state, &modulation); - - switch (modulation) { - case QPSK: - *signal_strength = (snr >= 1300) ? - min(65535, snr * 44) : snr * 38; - break; - case QAM_16: - *signal_strength = (snr >= 1500) ? - min(65535, snr * 38) : snr * 33; - break; - case QAM_64: - *signal_strength = (snr >= 2000) ? - min(65535, snr * 29) : snr * 25; - break; - default: - *signal_strength = 0; - return -EINVAL; - } - - return 0; -} - -static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct mxl111sf_demod_state *state = fe->demodulator_priv; - - mxl_dbg("()"); -#if 0 - p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; -#endif - if (fe->ops.tuner_ops.get_bandwidth) - fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz); - if (fe->ops.tuner_ops.get_frequency) - fe->ops.tuner_ops.get_frequency(fe, &p->frequency); - mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP); - mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP); - mxl1x1sf_demod_get_tps_modulation(state, &p->modulation); - mxl1x1sf_demod_get_tps_guard_fft_mode(state, - &p->transmission_mode); - mxl1x1sf_demod_get_tps_guard_interval(state, - &p->guard_interval); - mxl1x1sf_demod_get_tps_hierarchy(state, - &p->hierarchy); - - return 0; -} - -static -int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void mxl111sf_demod_release(struct dvb_frontend *fe) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - mxl_dbg("()"); - kfree(state); - fe->demodulator_priv = NULL; -} - -static struct dvb_frontend_ops mxl111sf_demod_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "MaxLinear MxL111SF DVB-T demodulator", - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER - }, - .release = mxl111sf_demod_release, -#if 0 - .init = mxl111sf_init, - .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, -#endif - .set_frontend = mxl111sf_demod_set_frontend, - .get_frontend = mxl111sf_demod_get_frontend, - .get_tune_settings = mxl111sf_demod_get_tune_settings, - .read_status = mxl111sf_demod_read_status, - .read_signal_strength = mxl111sf_demod_read_signal_strength, - .read_ber = mxl111sf_demod_read_ber, - .read_snr = mxl111sf_demod_read_snr, - .read_ucblocks = mxl111sf_demod_read_ucblocks, -}; - -struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg) -{ - struct mxl111sf_demod_state *state = NULL; - - mxl_dbg("()"); - - state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->mxl_state = mxl_state; - state->cfg = cfg; - - memcpy(&state->fe.ops, &mxl111sf_demod_ops, - sizeof(struct dvb_frontend_ops)); - - state->fe.demodulator_priv = state; - return &state->fe; -} -EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); - -MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h deleted file mode 100644 index 432706ae527..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator - * - * Copyright (C) 2010 Michael Krufky - * - * 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 __MXL111SF_DEMOD_H__ -#define __MXL111SF_DEMOD_H__ - -#include "dvb_frontend.h" -#include "mxl111sf.h" - -struct mxl111sf_demod_config { - int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); - int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); - int (*program_regs)(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info); -}; - -#if defined(CONFIG_DVB_USB_MXL111SF) || \ - (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) -extern -struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg); -#else -static inline -struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_USB_MXL111SF */ - -#endif /* __MXL111SF_DEMOD_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c deleted file mode 100644 index e4121cb8f5e..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c +++ /dev/null @@ -1,763 +0,0 @@ -/* - * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 "mxl111sf-gpio.h" -#include "mxl111sf-i2c.h" -#include "mxl111sf.h" - -/* ------------------------------------------------------------------------- */ - -#define MXL_GPIO_MUX_REG_0 0x84 -#define MXL_GPIO_MUX_REG_1 0x89 -#define MXL_GPIO_MUX_REG_2 0x82 - -#define MXL_GPIO_DIR_INPUT 0 -#define MXL_GPIO_DIR_OUTPUT 1 - - -static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val) -{ - int ret; - u8 tmp; - - mxl_debug_adv("(%d, %d)", pin, val); - - if ((pin > 0) && (pin < 8)) { - ret = mxl111sf_read_reg(state, 0x19, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (pin - 1)); - tmp |= (val << (pin - 1)); - ret = mxl111sf_write_reg(state, 0x19, tmp); - if (mxl_fail(ret)) - goto fail; - } else if (pin <= 10) { - if (pin == 0) - pin += 7; - ret = mxl111sf_read_reg(state, 0x30, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (pin - 3)); - tmp |= (val << (pin - 3)); - ret = mxl111sf_write_reg(state, 0x30, tmp); - if (mxl_fail(ret)) - goto fail; - } else - ret = -EINVAL; -fail: - return ret; -} - -static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val) -{ - int ret; - u8 tmp; - - mxl_debug("(0x%02x)", pin); - - *val = 0; - - switch (pin) { - case 0: - case 1: - case 2: - case 3: - ret = mxl111sf_read_reg(state, 0x23, &tmp); - if (mxl_fail(ret)) - goto fail; - *val = (tmp >> (pin + 4)) & 0x01; - break; - case 4: - case 5: - case 6: - case 7: - ret = mxl111sf_read_reg(state, 0x2f, &tmp); - if (mxl_fail(ret)) - goto fail; - *val = (tmp >> pin) & 0x01; - break; - case 8: - case 9: - case 10: - ret = mxl111sf_read_reg(state, 0x22, &tmp); - if (mxl_fail(ret)) - goto fail; - *val = (tmp >> (pin - 3)) & 0x01; - break; - default: - return -EINVAL; /* invalid pin */ - } -fail: - return ret; -} - -struct mxl_gpio_cfg { - u8 pin; - u8 dir; - u8 val; -}; - -static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state, - struct mxl_gpio_cfg *gpio_cfg) -{ - int ret; - u8 tmp; - - mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir); - - switch (gpio_cfg->pin) { - case 0: - case 1: - case 2: - case 3: - ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (gpio_cfg->pin + 4)); - tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4)); - ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp); - if (mxl_fail(ret)) - goto fail; - break; - case 4: - case 5: - case 6: - case 7: - ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << gpio_cfg->pin); - tmp |= (gpio_cfg->dir << gpio_cfg->pin); - ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp); - if (mxl_fail(ret)) - goto fail; - break; - case 8: - case 9: - case 10: - ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (gpio_cfg->pin - 3)); - tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3)); - ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp); - if (mxl_fail(ret)) - goto fail; - break; - default: - return -EINVAL; /* invalid pin */ - } - - ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ? - mxl111sf_set_gpo_state(state, - gpio_cfg->pin, gpio_cfg->val) : - mxl111sf_get_gpi_state(state, - gpio_cfg->pin, &gpio_cfg->val); - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state, - int gpio, int direction, int val) -{ - struct mxl_gpio_cfg gpio_config = { - .pin = gpio, - .dir = direction, - .val = val, - }; - - mxl_debug("(%d, %d, %d)", gpio, direction, val); - - return mxl111sf_config_gpio_pins(state, &gpio_config); -} - -/* ------------------------------------------------------------------------- */ - -#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */ -#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */ -#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */ -#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */ -#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */ -#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */ -#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */ -#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */ -#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */ -#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */ -#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */ -#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */ -#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */ -#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */ -#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */ -#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */ -#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */ -#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */ -#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */ - -int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, - enum mxl111sf_mux_config pin_mux_config) -{ - u8 r12, r15, r17, r18, r3D, r82, r84, r89; - int ret; - - mxl_debug("(%d)", pin_mux_config); - - ret = mxl111sf_read_reg(state, 0x17, &r17); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x18, &r18); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x12, &r12); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x15, &r15); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x82, &r82); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x84, &r84); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x89, &r89); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x3D, &r3D); - if (mxl_fail(ret)) - goto fail; - - switch (pin_mux_config) { - case PIN_MUX_TS_OUT_PARALLEL: - /* mpeg_mode = 1 */ - r17 |= PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 1 */ - r18 |= PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 1 */ - r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 1 */ - r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 1 */ - r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 1 */ - r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0xF */ - r84 |= 0xF0; - /* mdat_en_ctrl[7:4] = 0xF */ - r89 |= 0xF0; - break; - case PIN_MUX_TS_OUT_SERIAL: - /* mpeg_mode = 1 */ - r17 |= PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 1 */ - r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 1 */ - r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 1 */ - r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 1 */ - r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0xF */ - r84 |= 0xF0; - /* mdat_en_ctrl[7:4] = 0xF */ - r89 |= 0xF0; - break; - case PIN_MUX_GPIO_MODE: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SERIAL_IN_MODE_0: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SERIAL_IN_MODE_1: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 1 */ - r3D |= PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SPI_IN_MODE_1: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 1 */ - r3D |= PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 1 */ - r15 |= PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 1 */ - r3D |= PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SPI_IN_MODE_0: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 1 */ - r15 |= PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 1 */ - r3D |= PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_PARALLEL_IN: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 1 */ - r18 |= PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_BT656_I2S_MODE: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 1 */ - r12 |= PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 1 */ - r15 |= PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_DEFAULT: - default: - /* mpeg_mode = 1 */ - r17 |= PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - } - - ret = mxl111sf_write_reg(state, 0x17, r17); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x18, r18); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x12, r12); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x15, r15); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x82, r82); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x84, r84); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x89, r89); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x3D, r3D); - if (mxl_fail(ret)) - goto fail; -fail: - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val) -{ - return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val); -} - -static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state) -{ - u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */ - int i, ret; - - mxl_debug("()"); - - for (i = 3; i < 8; i++) { - ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01); - if (mxl_fail(ret)) - break; - } - - return ret; -} - -#define PCA9534_I2C_ADDR (0x40 >> 1) -static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val) -{ - u8 w[2] = { 1, 0 }; - u8 r = 0; - struct i2c_msg msg[] = { - { .addr = PCA9534_I2C_ADDR, - .flags = 0, .buf = w, .len = 1 }, - { .addr = PCA9534_I2C_ADDR, - .flags = I2C_M_RD, .buf = &r, .len = 1 }, - }; - - mxl_debug("(%d, %d)", gpio, val); - - /* read current GPIO levels from flip-flop */ - i2c_transfer(&state->d->i2c_adap, msg, 2); - - /* prepare write buffer with current GPIO levels */ - msg[0].len = 2; -#if 0 - w[0] = 1; -#endif - w[1] = r; - - /* clear the desired GPIO */ - w[1] &= ~(1 << gpio); - - /* set the desired GPIO value */ - w[1] |= ((val ? 1 : 0) << gpio); - - /* write new GPIO levels to flip-flop */ - i2c_transfer(&state->d->i2c_adap, &msg[0], 1); - - return 0; -} - -static int pca9534_init_port_expander(struct mxl111sf_state *state) -{ - u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */ - - struct i2c_msg msg = { - .addr = PCA9534_I2C_ADDR, - .flags = 0, .buf = w, .len = 2 - }; - - mxl_debug("()"); - - i2c_transfer(&state->d->i2c_adap, &msg, 1); - - /* configure all pins as outputs */ - w[0] = 3; - w[1] = 0; - - i2c_transfer(&state->d->i2c_adap, &msg, 1); - - return 0; -} - -int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val) -{ - mxl_debug("(%d, %d)", gpio, val); - - switch (state->gpio_port_expander) { - default: - mxl_printk(KERN_ERR, - "gpio_port_expander undefined, assuming PCA9534"); - /* fall-thru */ - case mxl111sf_PCA9534: - return pca9534_set_gpio(state, gpio, val); - case mxl111sf_gpio_hw: - return mxl111sf_hw_set_gpio(state, gpio, val); - } -} - -static int mxl111sf_probe_port_expander(struct mxl111sf_state *state) -{ - int ret; - u8 w = 1; - u8 r = 0; - struct i2c_msg msg[] = { - { .flags = 0, .buf = &w, .len = 1 }, - { .flags = I2C_M_RD, .buf = &r, .len = 1 }, - }; - - mxl_debug("()"); - - msg[0].addr = 0x70 >> 1; - msg[1].addr = 0x70 >> 1; - - /* read current GPIO levels from flip-flop */ - ret = i2c_transfer(&state->d->i2c_adap, msg, 2); - if (ret == 2) { - state->port_expander_addr = msg[0].addr; - state->gpio_port_expander = mxl111sf_PCA9534; - mxl_debug("found port expander at 0x%02x", - state->port_expander_addr); - return 0; - } - - msg[0].addr = 0x40 >> 1; - msg[1].addr = 0x40 >> 1; - - ret = i2c_transfer(&state->d->i2c_adap, msg, 2); - if (ret == 2) { - state->port_expander_addr = msg[0].addr; - state->gpio_port_expander = mxl111sf_PCA9534; - mxl_debug("found port expander at 0x%02x", - state->port_expander_addr); - return 0; - } - state->port_expander_addr = 0xff; - state->gpio_port_expander = mxl111sf_gpio_hw; - mxl_debug("using hardware gpio"); - return 0; -} - -int mxl111sf_init_port_expander(struct mxl111sf_state *state) -{ - mxl_debug("()"); - - if (0x00 == state->port_expander_addr) - mxl111sf_probe_port_expander(state); - - switch (state->gpio_port_expander) { - default: - mxl_printk(KERN_ERR, - "gpio_port_expander undefined, assuming PCA9534"); - /* fall-thru */ - case mxl111sf_PCA9534: - return pca9534_init_port_expander(state); - case mxl111sf_gpio_hw: - return mxl111sf_hw_gpio_initialize(state); - } -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) -{ -/* GPO: - * 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0 - * 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0 - * 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0 - * 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0 - * 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0 - */ - mxl_debug("(%d)", mode); - - switch (mode) { - case MXL111SF_GPIO_MOD_MH: - mxl111sf_set_gpio(state, 4, 0); - mxl111sf_set_gpio(state, 5, 0); - msleep(50); - mxl111sf_set_gpio(state, 7, 1); - msleep(50); - mxl111sf_set_gpio(state, 6, 1); - msleep(50); - - mxl111sf_set_gpio(state, 3, 0); - break; - case MXL111SF_GPIO_MOD_ATSC: - mxl111sf_set_gpio(state, 6, 0); - mxl111sf_set_gpio(state, 7, 0); - msleep(50); - mxl111sf_set_gpio(state, 5, 1); - msleep(50); - mxl111sf_set_gpio(state, 4, 1); - msleep(50); - mxl111sf_set_gpio(state, 3, 1); - break; - default: /* DVBT / STANDBY */ - mxl111sf_init_port_expander(state); - break; - } - return 0; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h deleted file mode 100644 index 0220f54299a..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * mxl111sf-gpio.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 _DVB_USB_MXL111SF_GPIO_H_ -#define _DVB_USB_MXL111SF_GPIO_H_ - -#include "mxl111sf.h" - -int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val); -int mxl111sf_init_port_expander(struct mxl111sf_state *state); - -#define MXL111SF_GPIO_MOD_DVBT 0 -#define MXL111SF_GPIO_MOD_MH 1 -#define MXL111SF_GPIO_MOD_ATSC 2 -int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode); - -enum mxl111sf_mux_config { - PIN_MUX_DEFAULT = 0, - PIN_MUX_TS_OUT_PARALLEL, - PIN_MUX_TS_OUT_SERIAL, - PIN_MUX_GPIO_MODE, - PIN_MUX_TS_SERIAL_IN_MODE_0, - PIN_MUX_TS_SERIAL_IN_MODE_1, - PIN_MUX_TS_SPI_IN_MODE_0, - PIN_MUX_TS_SPI_IN_MODE_1, - PIN_MUX_TS_PARALLEL_IN, - PIN_MUX_BT656_I2S_MODE, -}; - -int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, - enum mxl111sf_mux_config pin_mux_config); - -#endif /* _DVB_USB_MXL111SF_GPIO_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c deleted file mode 100644 index 34434557ef6..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c +++ /dev/null @@ -1,850 +0,0 @@ -/* - * mxl111sf-i2c.c - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 "mxl111sf-i2c.h" -#include "mxl111sf.h" - -/* SW-I2C ----------------------------------------------------------------- */ - -#define SW_I2C_ADDR 0x1a -#define SW_I2C_EN 0x02 -#define SW_SCL_OUT 0x04 -#define SW_SDA_OUT 0x08 -#define SW_SDA_IN 0x04 - -#define SW_I2C_BUSY_ADDR 0x2f -#define SW_I2C_BUSY 0x02 - -static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state, - u8 byte) -{ - int i, ret; - u8 data = 0; - - mxl_i2c("(0x%02x)", byte); - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); - if (mxl_fail(ret)) - goto fail; - - for (i = 0; i < 8; i++) { - - data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | data); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | data | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | data); - if (mxl_fail(ret)) - goto fail; - } - - /* last bit was 0 so we need to release SDA */ - if (!(byte & 1)) { - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - } - - /* CLK high for ACK readback */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); - if (mxl_fail(ret)) - goto fail; - - /* drop the CLK after getting ACK, SDA will go high right away */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - if (data & SW_SDA_IN) - ret = -EIO; -fail: - return ret; -} - -static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state, - u8 *pbyte) -{ - int i, ret; - u8 byte = 0; - u8 data = 0; - - mxl_i2c("()"); - - *pbyte = 0; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - for (i = 0; i < 8; i++) { - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | - SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); - if (mxl_fail(ret)) - goto fail; - - if (data & SW_SDA_IN) - byte |= (0x80 >> i); - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - } - *pbyte = byte; -fail: - return ret; -} - -static int mxl111sf_i2c_start(struct mxl111sf_state *state) -{ - int ret; - - mxl_i2c("()"); - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN); /* start */ - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_i2c_stop(struct mxl111sf_state *state) -{ - int ret; - - mxl_i2c("()"); - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN); /* stop */ - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_SCL_OUT | SW_SDA_OUT); - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_i2c_ack(struct mxl111sf_state *state) -{ - int ret; - u8 b = 0; - - mxl_i2c("()"); - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN); - if (mxl_fail(ret)) - goto fail; - - /* pull SDA low */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_i2c_nack(struct mxl111sf_state *state) -{ - int ret; - - mxl_i2c("()"); - - /* SDA high to signal last byte read from slave */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - mxl_fail(ret); -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state, - struct i2c_msg *msg) -{ - int i, ret; - - mxl_i2c("()"); - - if (msg->flags & I2C_M_RD) { - - ret = mxl111sf_i2c_start(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_i2c_bitbang_sendbyte(state, - (msg->addr << 1) | 0x01); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - - for (i = 0; i < msg->len; i++) { - ret = mxl111sf_i2c_bitbang_recvbyte(state, - &msg->buf[i]); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - - if (i < msg->len - 1) - mxl111sf_i2c_ack(state); - } - - mxl111sf_i2c_nack(state); - - ret = mxl111sf_i2c_stop(state); - if (mxl_fail(ret)) - goto fail; - - } else { - - ret = mxl111sf_i2c_start(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_i2c_bitbang_sendbyte(state, - (msg->addr << 1) & 0xfe); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - - for (i = 0; i < msg->len; i++) { - ret = mxl111sf_i2c_bitbang_sendbyte(state, - msg->buf[i]); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - } - - /* FIXME: we only want to do this on the last transaction */ - mxl111sf_i2c_stop(state); - } -fail: - return ret; -} - -/* HW-I2C ----------------------------------------------------------------- */ - -#define USB_WRITE_I2C_CMD 0x99 -#define USB_READ_I2C_CMD 0xdd -#define USB_END_I2C_CMD 0xfe - -#define USB_WRITE_I2C_CMD_LEN 26 -#define USB_READ_I2C_CMD_LEN 24 - -#define I2C_MUX_REG 0x30 -#define I2C_CONTROL_REG 0x00 -#define I2C_SLAVE_ADDR_REG 0x08 -#define I2C_DATA_REG 0x0c -#define I2C_INT_STATUS_REG 0x10 - -static int mxl111sf_i2c_send_data(struct mxl111sf_state *state, - u8 index, u8 *wdata) -{ - int ret = mxl111sf_ctrl_msg(state->d, wdata[0], - &wdata[1], 25, NULL, 0); - mxl_fail(ret); - - return ret; -} - -static int mxl111sf_i2c_get_data(struct mxl111sf_state *state, - u8 index, u8 *wdata, u8 *rdata) -{ - int ret = mxl111sf_ctrl_msg(state->d, wdata[0], - &wdata[1], 25, rdata, 24); - mxl_fail(ret); - - return ret; -} - -static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state) -{ - u8 status = 0; - u8 buf[26]; - - mxl_i2c_adv("()"); - - buf[0] = USB_READ_I2C_CMD; - buf[1] = 0x00; - - buf[2] = I2C_INT_STATUS_REG; - buf[3] = 0x00; - buf[4] = 0x00; - - buf[5] = USB_END_I2C_CMD; - - mxl111sf_i2c_get_data(state, 0, buf, buf); - - if (buf[1] & 0x04) - status = 1; - - return status; -} - -static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state) -{ - u8 status = 0; - u8 buf[26]; - - mxl_i2c("()"); - - buf[0] = USB_READ_I2C_CMD; - buf[1] = 0x00; - - buf[2] = I2C_MUX_REG; - buf[3] = 0x00; - buf[4] = 0x00; - - buf[5] = I2C_INT_STATUS_REG; - buf[6] = 0x00; - buf[7] = 0x00; - buf[8] = USB_END_I2C_CMD; - - mxl111sf_i2c_get_data(state, 0, buf, buf); - - if (0x08 == (buf[1] & 0x08)) - status = 1; - - if ((buf[5] & 0x02) == 0x02) - mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */ - - return status; -} - -static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, - u8 count, u8 *rbuf) -{ - u8 i2c_w_data[26]; - u8 i2c_r_data[24]; - u8 i = 0; - u8 fifo_status = 0; - int status = 0; - - mxl_i2c("read %d bytes", count); - - while ((fifo_status == 0) && (i++ < 5)) - fifo_status = mxl111sf_i2c_check_fifo(state); - - i2c_w_data[0] = 0xDD; - i2c_w_data[1] = 0x00; - - for (i = 2; i < 26; i++) - i2c_w_data[i] = 0xFE; - - for (i = 0; i < count; i++) { - i2c_w_data[2+(i*3)] = 0x0C; - i2c_w_data[3+(i*3)] = 0x00; - i2c_w_data[4+(i*3)] = 0x00; - } - - mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); - - /* Check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("error!"); - } else { - for (i = 0; i < count; i++) { - rbuf[i] = i2c_r_data[(i*3)+1]; - mxl_i2c("%02x\t %02x", - i2c_r_data[(i*3)+1], - i2c_r_data[(i*3)+2]); - } - - status = 1; - } - - return status; -} - -#define HWI2C400 1 -static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, - struct i2c_msg *msg) -{ - int i, k, ret = 0; - u16 index = 0; - u8 buf[26]; - u8 i2c_r_data[24]; - u16 block_len; - u16 left_over_len; - u8 rd_status[8]; - u8 ret_status; - u8 readbuff[26]; - - mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d", - msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0, - (!(msg->flags & I2C_M_RD)) ? msg->len : 0); - - for (index = 0; index < 26; index++) - buf[index] = USB_END_I2C_CMD; - - /* command to indicate data payload is destined for I2C interface */ - buf[0] = USB_WRITE_I2C_CMD; - buf[1] = 0x00; - - /* enable I2C interface */ - buf[2] = I2C_MUX_REG; - buf[3] = 0x80; - buf[4] = 0x00; - - /* enable I2C interface */ - buf[5] = I2C_MUX_REG; - buf[6] = 0x81; - buf[7] = 0x00; - - /* set Timeout register on I2C interface */ - buf[8] = 0x14; - buf[9] = 0xff; - buf[10] = 0x00; -#if 0 - /* enable Interrupts on I2C interface */ - buf[8] = 0x24; - buf[9] = 0xF7; - buf[10] = 0x00; -#endif - buf[11] = 0x24; - buf[12] = 0xF7; - buf[13] = 0x00; - - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* write data on I2C bus */ - if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) { - mxl_i2c("%d\t%02x", msg->len, msg->buf[0]); - - /* control register on I2C interface to initialize I2C bus */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x5E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - /* I2C Slave device Address */ - buf[5] = I2C_SLAVE_ADDR_REG; - buf[6] = (msg->addr); - buf[7] = 0x00; - buf[8] = USB_END_I2C_CMD; - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for slave device status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK writing slave address %02x", - msg->addr); - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - /* I2C interface can do I2C operations in block of 8 bytes of - I2C data. calculation to figure out number of blocks of i2c - data required to program */ - block_len = (msg->len / 8); - left_over_len = (msg->len % 8); - index = 0; - - mxl_i2c("block_len %d, left_over_len %d", - block_len, left_over_len); - - for (index = 0; index < block_len; index++) { - for (i = 0; i < 8; i++) { - /* write data on I2C interface */ - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = msg->buf[(index*8)+i]; - buf[4+(i*3)] = 0x00; - } - - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK writing slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - } - - if (left_over_len) { - for (k = 0; k < 26; k++) - buf[k] = USB_END_I2C_CMD; - - buf[0] = 0x99; - buf[1] = 0x00; - - for (i = 0; i < left_over_len; i++) { - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = msg->buf[(index*8)+i]; - mxl_i2c("index = %d %d data %d", - index, i, msg->buf[(index*8)+i]); - buf[4+(i*3)] = 0x00; - } - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK writing slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - } - - /* issue I2C STOP after write */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - } - - /* read data from I2C bus */ - if ((msg->flags & I2C_M_RD) && (msg->len > 0)) { - mxl_i2c("read buf len %d", msg->len); - - /* command to indicate data payload is - destined for I2C interface */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xDF; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - /* I2C xfer length */ - buf[5] = 0x14; - buf[6] = (msg->len & 0xFF); - buf[7] = 0; - - /* I2C slave device Address */ - buf[8] = I2C_SLAVE_ADDR_REG; - buf[9] = msg->addr; - buf[10] = 0x00; - buf[11] = USB_END_I2C_CMD; - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK reading slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - /* I2C interface can do I2C operations in block of 8 bytes of - I2C data. calculation to figure out number of blocks of - i2c data required to program */ - block_len = ((msg->len) / 8); - left_over_len = ((msg->len) % 8); - index = 0; - - mxl_i2c("block_len %d, left_over_len %d", - block_len, left_over_len); - - /* command to read data from I2C interface */ - buf[0] = USB_READ_I2C_CMD; - buf[1] = 0x00; - - for (index = 0; index < block_len; index++) { - /* setup I2C read request packet on I2C interface */ - for (i = 0; i < 8; i++) { - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = 0x00; - buf[4+(i*3)] = 0x00; - } - - ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK reading slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - /* copy data from i2c data payload to read buffer */ - for (i = 0; i < 8; i++) { - rd_status[i] = i2c_r_data[(i*3)+2]; - - if (rd_status[i] == 0x04) { - if (i < 7) { - mxl_i2c("i2c fifo empty!" - " @ %d", i); - msg->buf[(index*8)+i] = - i2c_r_data[(i*3)+1]; - /* read again */ - ret_status = - mxl111sf_i2c_readagain( - state, 8-(i+1), - readbuff); - if (ret_status == 1) { - for (k = 0; - k < 8-(i+1); - k++) { - - msg->buf[(index*8)+(k+i+1)] = - readbuff[k]; - mxl_i2c("read data: %02x\t %02x", - msg->buf[(index*8)+(k+i)], - (index*8)+(k+i)); - mxl_i2c("read data: %02x\t %02x", - msg->buf[(index*8)+(k+i+1)], - readbuff[k]); - - } - goto stop_copy; - } else { - mxl_i2c("readagain " - "ERROR!"); - } - } else { - msg->buf[(index*8)+i] = - i2c_r_data[(i*3)+1]; - } - } else { - msg->buf[(index*8)+i] = - i2c_r_data[(i*3)+1]; - } - } -stop_copy: - ; - - } - - if (left_over_len) { - for (k = 0; k < 26; k++) - buf[k] = USB_END_I2C_CMD; - - buf[0] = 0xDD; - buf[1] = 0x00; - - for (i = 0; i < left_over_len; i++) { - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = 0x00; - buf[4+(i*3)] = 0x00; - } - ret = mxl111sf_i2c_get_data(state, 0, buf, - i2c_r_data); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK reading slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - for (i = 0; i < left_over_len; i++) { - msg->buf[(block_len*8)+i] = - i2c_r_data[(i*3)+1]; - mxl_i2c("read data: %02x\t %02x", - i2c_r_data[(i*3)+1], - i2c_r_data[(i*3)+2]); - } - } - - /* indicate I2C interface to issue NACK - after next I2C read op */ - buf[0] = USB_WRITE_I2C_CMD; - buf[1] = 0x00; - - /* control register */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x17; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - buf[5] = USB_END_I2C_CMD; - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* control register */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - } -exit: - /* STOP and disable I2C MUX */ - buf[0] = USB_WRITE_I2C_CMD; - buf[1] = 0x00; - - /* de-initilize I2C BUS */ - buf[5] = USB_END_I2C_CMD; - mxl111sf_i2c_send_data(state, 0, buf); - - /* Control Register */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xDF; - buf[4] = 0x03; - - /* disable I2C interface */ - buf[5] = I2C_MUX_REG; - buf[6] = 0x00; - buf[7] = 0x00; - - /* de-initilize I2C BUS */ - buf[8] = USB_END_I2C_CMD; - mxl111sf_i2c_send_data(state, 0, buf); - - /* disable I2C interface */ - buf[2] = I2C_MUX_REG; - buf[3] = 0x81; - buf[4] = 0x00; - - /* disable I2C interface */ - buf[5] = I2C_MUX_REG; - buf[6] = 0x00; - buf[7] = 0x00; - - /* disable I2C interface */ - buf[8] = I2C_MUX_REG; - buf[9] = 0x00; - buf[10] = 0x00; - - buf[11] = USB_END_I2C_CMD; - mxl111sf_i2c_send_data(state, 0, buf); - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct mxl111sf_state *state = d->priv; - int hwi2c = (state->chip_rev > MXL111SF_V6); - int i, ret; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - ret = (hwi2c) ? - mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) : - mxl111sf_i2c_sw_xfer_msg(state, &msg[i]); - if (mxl_fail(ret)) { - mxl_debug_adv("failed with error %d on i2c " - "transaction %d of %d, %sing %d bytes " - "to/from 0x%02x", ret, i+1, num, - (msg[i].flags & I2C_M_RD) ? - "read" : "writ", - msg[i].len, msg[i].addr); - - break; - } - } - - mutex_unlock(&d->i2c_mutex); - - return i == num ? num : -EREMOTEIO; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h deleted file mode 100644 index a57a45ffb9e..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * mxl111sf-i2c.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 _DVB_USB_MXL111SF_I2C_H_ -#define _DVB_USB_MXL111SF_I2C_H_ - -#include - -int mxl111sf_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num); - -#endif /* _DVB_USB_MXL111SF_I2C_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c deleted file mode 100644 index b741b3a7a32..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * mxl111sf-phy.c - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 "mxl111sf-phy.h" -#include "mxl111sf-reg.h" - -int mxl111sf_init_tuner_demod(struct mxl111sf_state *state) -{ - struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = { - {0x07, 0xff, 0x0c}, - {0x58, 0xff, 0x9d}, - {0x09, 0xff, 0x00}, - {0x06, 0xff, 0x06}, - {0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */ - {0x8d, 0x01, 0x01}, /* NEGATE_Q */ - {0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */ - {0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */ - {0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */ - {0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */ - {0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */ - {0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */ - {0x88, 0xff, 0xf0}, /* INF_THD = 240 */ - {0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */ - {0x00, 0xff, 0x01}, /* Change to page 1 */ - {0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */ - {0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */ - {0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */ - {0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */ - {0x00, 0xff, 0x00}, /* Change to page 0 */ - {0, 0, 0} - }; - - mxl_debug("()"); - - return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default); -} - -int mxl1x1sf_soft_reset(struct mxl111sf_state *state) -{ - int ret; - mxl_debug("()"); - - ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */ - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */ - mxl_fail(ret); -fail: - return ret; -} - -int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode) -{ - int ret; - - mxl_debug("(%s)", MXL_SOC_MODE == mode ? - "MXL_SOC_MODE" : "MXL_TUNER_MODE"); - - /* set device mode */ - ret = mxl111sf_write_reg(state, 0x03, - MXL_SOC_MODE == mode ? 0x01 : 0x00); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg_mask(state, - 0x7d, 0x40, MXL_SOC_MODE == mode ? - 0x00 : /* enable impulse noise filter, - INF_BYP = 0 */ - 0x40); /* disable impulse noise filter, - INF_BYP = 1 */ - if (mxl_fail(ret)) - goto fail; - - state->device_mode = mode; -fail: - return ret; -} - -/* power up tuner */ -int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff) -{ - mxl_debug("(%d)", onoff); - - return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00); -} - -int mxl111sf_disable_656_port(struct mxl111sf_state *state) -{ - mxl_debug("()"); - - return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00); -} - -int mxl111sf_enable_usb_output(struct mxl111sf_state *state) -{ - mxl_debug("()"); - - return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00); -} - -/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */ -int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, - unsigned int parallel_serial, - unsigned int msb_lsb_1st, - unsigned int clock_phase, - unsigned int mpeg_valid_pol, - unsigned int mpeg_sync_pol) -{ - int ret; - u8 mode, tmp; - - mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st, - clock_phase, mpeg_valid_pol, mpeg_sync_pol); - - /* Enable PIN MUX */ - ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX); - mxl_fail(ret); - - /* Configure MPEG Clock phase */ - mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode); - - if (clock_phase == TSIF_NORMAL) - mode &= ~V6_INVERTED_CLK_PHASE; - else - mode |= V6_INVERTED_CLK_PHASE; - - ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode); - mxl_fail(ret); - - /* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity - * Get current configuration */ - ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode); - mxl_fail(ret); - - /* Data Input mode */ - if (parallel_serial == TSIF_INPUT_PARALLEL) { - /* Disable serial mode */ - mode &= ~V6_MPEG_IN_DATA_SERIAL; - - /* Enable Parallel mode */ - mode |= V6_MPEG_IN_DATA_PARALLEL; - } else { - /* Disable Parallel mode */ - mode &= ~V6_MPEG_IN_DATA_PARALLEL; - - /* Enable Serial Mode */ - mode |= V6_MPEG_IN_DATA_SERIAL; - - /* If serial interface is chosen, configure - MSB or LSB order in transmission */ - ret = mxl111sf_read_reg(state, - V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, - &tmp); - mxl_fail(ret); - - if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED) - tmp |= V6_MPEG_SER_MSB_FIRST; - else - tmp &= ~V6_MPEG_SER_MSB_FIRST; - - ret = mxl111sf_write_reg(state, - V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, - tmp); - mxl_fail(ret); - } - - /* MPEG Sync polarity */ - if (mpeg_sync_pol == TSIF_NORMAL) - mode &= ~V6_INVERTED_MPEG_SYNC; - else - mode |= V6_INVERTED_MPEG_SYNC; - - /* MPEG Valid polarity */ - if (mpeg_valid_pol == 0) - mode &= ~V6_INVERTED_MPEG_VALID; - else - mode |= V6_INVERTED_MPEG_VALID; - - ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode); - mxl_fail(ret); - - return ret; -} - -int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size) -{ - static struct mxl111sf_reg_ctrl_info init_i2s[] = { - {0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */ - {0x15, 0x60, 0x60}, /* Enable I2S */ - {0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB, - Inverted 656 Clock, I2S_SOFT_RESET, - 0 : Normal operation, 1 : Reset State */ -#if 0 - {0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */ -#endif - {0x00, 0xff, 0x02}, /* Change to Control Page */ - {0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */ - {0x00, 0xff, 0x00}, - {0, 0, 0} - }; - int ret; - - mxl_debug("(0x%02x)", sample_size); - - ret = mxl111sf_ctrl_program_regs(state, init_i2s); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size); - mxl_fail(ret); -fail: - return ret; -} - -int mxl111sf_disable_i2s_port(struct mxl111sf_state *state) -{ - static struct mxl111sf_reg_ctrl_info disable_i2s[] = { - {0x15, 0x40, 0x00}, - {0, 0, 0} - }; - - mxl_debug("()"); - - return mxl111sf_ctrl_program_regs(state, disable_i2s); -} - -int mxl111sf_config_i2s(struct mxl111sf_state *state, - u8 msb_start_pos, u8 data_width) -{ - int ret; - u8 tmp; - - mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width); - - ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp); - if (mxl_fail(ret)) - goto fail; - - tmp &= 0xe0; - tmp |= msb_start_pos; - ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp); - if (mxl_fail(ret)) - goto fail; - - tmp &= 0xe0; - tmp |= data_width; - ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp); - mxl_fail(ret); -fail: - return ret; -} - -int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff) -{ - u8 val; - int ret; - - mxl_debug("(%d)", onoff); - - ret = mxl111sf_write_reg(state, 0x00, 0x02); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val); - if (mxl_fail(ret)) - goto fail; - - if (onoff) - val |= 0x04; - else - val &= ~0x04; - - ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, 0x00, 0x00); - mxl_fail(ret); -fail: - return ret; -} - -int mxl111sf_idac_config(struct mxl111sf_state *state, - u8 control_mode, u8 current_setting, - u8 current_value, u8 hysteresis_value) -{ - int ret; - u8 val; - /* current value will be set for both automatic & manual IDAC control */ - val = current_value; - - if (control_mode == IDAC_MANUAL_CONTROL) { - /* enable manual control of IDAC */ - val |= IDAC_MANUAL_CONTROL_BIT_MASK; - - if (current_setting == IDAC_CURRENT_SINKING_ENABLE) - /* enable current sinking in manual mode */ - val |= IDAC_CURRENT_SINKING_BIT_MASK; - else - /* disable current sinking in manual mode */ - val &= ~IDAC_CURRENT_SINKING_BIT_MASK; - } else { - /* disable manual control of IDAC */ - val &= ~IDAC_MANUAL_CONTROL_BIT_MASK; - - /* set hysteresis value reg: 0x0B<5:0> */ - ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG, - (hysteresis_value & 0x3F)); - mxl_fail(ret); - } - - ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val); - mxl_fail(ret); - - return ret; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h deleted file mode 100644 index f0756071d34..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * mxl111sf-phy.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 _DVB_USB_MXL111SF_PHY_H_ -#define _DVB_USB_MXL111SF_PHY_H_ - -#include "mxl111sf.h" - -int mxl1x1sf_soft_reset(struct mxl111sf_state *state); -int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode); -int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff); -int mxl111sf_disable_656_port(struct mxl111sf_state *state); -int mxl111sf_init_tuner_demod(struct mxl111sf_state *state); -int mxl111sf_enable_usb_output(struct mxl111sf_state *state); -int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, - unsigned int parallel_serial, - unsigned int msb_lsb_1st, - unsigned int clock_phase, - unsigned int mpeg_valid_pol, - unsigned int mpeg_sync_pol); -int mxl111sf_config_i2s(struct mxl111sf_state *state, - u8 msb_start_pos, u8 data_width); -int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size); -int mxl111sf_disable_i2s_port(struct mxl111sf_state *state); -int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff); -int mxl111sf_idac_config(struct mxl111sf_state *state, - u8 control_mode, u8 current_setting, - u8 current_value, u8 hysteresis_value); - -#endif /* _DVB_USB_MXL111SF_PHY_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h deleted file mode 100644 index 17831b0fb9d..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * mxl111sf-reg.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * 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 _DVB_USB_MXL111SF_REG_H_ -#define _DVB_USB_MXL111SF_REG_H_ - -#define CHIP_ID_REG 0xFC -#define TOP_CHIP_REV_ID_REG 0xFA - -#define V6_SNR_RB_LSB_REG 0x27 -#define V6_SNR_RB_MSB_REG 0x28 - -#define V6_N_ACCUMULATE_REG 0x11 -#define V6_RS_AVG_ERRORS_LSB_REG 0x2C -#define V6_RS_AVG_ERRORS_MSB_REG 0x2D - -#define V6_IRQ_STATUS_REG 0x24 -#define IRQ_MASK_FEC_LOCK 0x10 - -#define V6_SYNC_LOCK_REG 0x28 -#define SYNC_LOCK_MASK 0x10 - -#define V6_RS_LOCK_DET_REG 0x28 -#define RS_LOCK_DET_MASK 0x08 - -#define V6_INITACQ_NODETECT_REG 0x20 -#define V6_FORCE_NFFT_CPSIZE_REG 0x20 - -#define V6_CODE_RATE_TPS_REG 0x29 -#define V6_CODE_RATE_TPS_MASK 0x07 - - -#define V6_CP_LOCK_DET_REG 0x28 -#define V6_CP_LOCK_DET_MASK 0x04 - -#define V6_TPS_HIERACHY_REG 0x29 -#define V6_TPS_HIERARCHY_INFO_MASK 0x40 - -#define V6_MODORDER_TPS_REG 0x2A -#define V6_PARAM_CONSTELLATION_MASK 0x30 - -#define V6_MODE_TPS_REG 0x2A -#define V6_PARAM_FFT_MODE_MASK 0x0C - - -#define V6_CP_TPS_REG 0x29 -#define V6_PARAM_GI_MASK 0x30 - -#define V6_TPS_LOCK_REG 0x2A -#define V6_PARAM_TPS_LOCK_MASK 0x40 - -#define V6_FEC_PER_COUNT_REG 0x2E -#define V6_FEC_PER_SCALE_REG 0x2B -#define V6_FEC_PER_SCALE_MASK 0x03 -#define V6_FEC_PER_CLR_REG 0x20 -#define V6_FEC_PER_CLR_MASK 0x01 - -#define V6_PIN_MUX_MODE_REG 0x1B -#define V6_ENABLE_PIN_MUX 0x1E - -#define V6_I2S_NUM_SAMPLES_REG 0x16 - -#define V6_MPEG_IN_CLK_INV_REG 0x17 -#define V6_MPEG_IN_CTRL_REG 0x18 - -#define V6_INVERTED_CLK_PHASE 0x20 -#define V6_MPEG_IN_DATA_PARALLEL 0x01 -#define V6_MPEG_IN_DATA_SERIAL 0x02 - -#define V6_INVERTED_MPEG_SYNC 0x04 -#define V6_INVERTED_MPEG_VALID 0x08 - -#define TSIF_INPUT_PARALLEL 0 -#define TSIF_INPUT_SERIAL 1 -#define TSIF_NORMAL 0 - -#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19 -#define V6_MPEG_SER_MSB_FIRST 0x80 -#define MPEG_SER_MSB_FIRST_ENABLED 0x01 - -#define V6_656_I2S_BUFF_STATUS_REG 0x2F -#define V6_656_OVERFLOW_MASK_BIT 0x08 -#define V6_I2S_OVERFLOW_MASK_BIT 0x01 - -#define V6_I2S_STREAM_START_BIT_REG 0x14 -#define V6_I2S_STREAM_END_BIT_REG 0x15 -#define I2S_RIGHT_JUSTIFIED 0 -#define I2S_LEFT_JUSTIFIED 1 -#define I2S_DATA_FORMAT 2 - -#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09 -#define V6_ENABLE_LOOP_THRU 0x01 - -#define TOTAL_NUM_IF_OUTPUT_FREQ 16 - -#define TUNER_NORMAL_IF_SPECTRUM 0x0 -#define TUNER_INVERT_IF_SPECTRUM 0x10 - -#define V6_TUNER_IF_SEL_REG 0x06 -#define V6_TUNER_IF_FCW_REG 0x3C -#define V6_TUNER_IF_FCW_BYP_REG 0x3D -#define V6_RF_LOCK_STATUS_REG 0x23 - -#define NUM_DIG_TV_CHANNEL 1000 - -#define V6_DIG_CLK_FREQ_SEL_REG 0x07 -#define V6_REF_SYNTH_INT_REG 0x5C -#define V6_REF_SYNTH_REMAIN_REG 0x58 -#define V6_DIG_RFREFSELECT_REG 0x32 -#define V6_XTAL_CLK_OUT_GAIN_REG 0x31 -#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09 -#define V6_DIG_XTAL_ENABLE_REG 0x06 -#define V6_DIG_XTAL_BIAS_REG 0x66 -#define V6_XTAL_CAP_REG 0x08 - -#define V6_GPO_CTRL_REG 0x18 -#define MXL_GPO_0 0x00 -#define MXL_GPO_1 0x01 -#define V6_GPO_0_MASK 0x10 -#define V6_GPO_1_MASK 0x20 - -#define V6_111SF_GPO_CTRL_REG 0x19 -#define MXL_111SF_GPO_1 0x00 -#define MXL_111SF_GPO_2 0x01 -#define MXL_111SF_GPO_3 0x02 -#define MXL_111SF_GPO_4 0x03 -#define MXL_111SF_GPO_5 0x04 -#define MXL_111SF_GPO_6 0x05 -#define MXL_111SF_GPO_7 0x06 - -#define MXL_111SF_GPO_0_MASK 0x01 -#define MXL_111SF_GPO_1_MASK 0x02 -#define MXL_111SF_GPO_2_MASK 0x04 -#define MXL_111SF_GPO_3_MASK 0x08 -#define MXL_111SF_GPO_4_MASK 0x10 -#define MXL_111SF_GPO_5_MASK 0x20 -#define MXL_111SF_GPO_6_MASK 0x40 - -#define V6_ATSC_CONFIG_REG 0x0A - -#define MXL_MODE_REG 0x03 -#define START_TUNE_REG 0x1C - -#define V6_IDAC_HYSTERESIS_REG 0x0B -#define V6_IDAC_SETTINGS_REG 0x0C -#define IDAC_MANUAL_CONTROL 1 -#define IDAC_CURRENT_SINKING_ENABLE 1 -#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80 -#define IDAC_CURRENT_SINKING_BIT_MASK 0x40 - -#define V8_SPI_MODE_REG 0xE9 - -#define V6_DIG_RF_PWR_LSB_REG 0x46 -#define V6_DIG_RF_PWR_MSB_REG 0x47 - -#endif /* _DVB_USB_MXL111SF_REG_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c deleted file mode 100644 index ef4c65fcbb7..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner - * - * Copyright (C) 2010 Michael Krufky - * - * 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 "mxl111sf-tuner.h" -#include "mxl111sf-phy.h" -#include "mxl111sf-reg.h" - -/* debug */ -static int mxl111sf_tuner_debug; -module_param_named(debug, mxl111sf_tuner_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -#define mxl_dbg(fmt, arg...) \ - if (mxl111sf_tuner_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define err pr_err - -/* ------------------------------------------------------------------------ */ - -struct mxl111sf_tuner_state { - struct mxl111sf_state *mxl_state; - - struct mxl111sf_tuner_config *cfg; - - enum mxl_if_freq if_freq; - - u32 frequency; - u32 bandwidth; -}; - -static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state, - u8 addr, u8 *data) -{ - return (state->cfg->read_reg) ? - state->cfg->read_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state, - u8 addr, u8 data) -{ - return (state->cfg->write_reg) ? - state->cfg->write_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info) -{ - return (state->cfg->program_regs) ? - state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : - -EINVAL; -} - -static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state, - int onoff) -{ - return (state->cfg->top_master_ctrl) ? - state->cfg->top_master_ctrl(state->mxl_state, onoff) : - -EINVAL; -} - -/* ------------------------------------------------------------------------ */ - -static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = { - {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3, - DIG_MODEINDEX, _A, _CSF, */ - {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */ - {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */ - {0, 0, 0} -}; - -/* ------------------------------------------------------------------------ */ - -static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq, - u8 bw) -{ - u8 filt_bw; - - /* set channel bandwidth */ - switch (bw) { - case 0: /* ATSC */ - filt_bw = 25; - break; - case 1: /* QAM */ - filt_bw = 69; - break; - case 6: - filt_bw = 21; - break; - case 7: - filt_bw = 42; - break; - case 8: - filt_bw = 63; - break; - default: - err("%s: invalid bandwidth setting!", __func__); - return NULL; - } - - /* calculate RF channel */ - freq /= 1000000; - - freq *= 64; -#if 0 - /* do round */ - freq += 0.5; -#endif - /* set bandwidth */ - mxl_phy_tune_rf[0].data = filt_bw; - - /* set RF */ - mxl_phy_tune_rf[1].data = (freq & 0xff); - mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff; - - /* start tune */ - return mxl_phy_tune_rf; -} - -static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) -{ - int ret; - u8 ctrl; -#if 0 - u16 iffcw; - u32 if_freq; -#endif - mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)", - state->cfg->invert_spectrum, state->cfg->if_freq); - - /* set IF polarity */ - ctrl = state->cfg->invert_spectrum; - - ctrl |= state->cfg->if_freq; - - ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl); - if (mxl_fail(ret)) - goto fail; - -#if 0 - if_freq /= 1000000; - - /* do round */ - if_freq += 0.5; - - if (MXL_IF_LO == state->cfg->if_freq) { - ctrl = 0x08; - iffcw = (u16)(if_freq / (108 * 4096)); - } else if (MXL_IF_HI == state->cfg->if_freq) { - ctrl = 0x08; - iffcw = (u16)(if_freq / (216 * 4096)); - } else { - ctrl = 0; - iffcw = 0; - } - - ctrl |= (iffcw >> 8); -#endif - ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl); - if (mxl_fail(ret)) - goto fail; - - ctrl &= 0xf0; - ctrl |= 0x90; - - ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl); - if (mxl_fail(ret)) - goto fail; - -#if 0 - ctrl = iffcw & 0x00ff; -#endif - ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); - if (mxl_fail(ret)) - goto fail; - - state->if_freq = state->cfg->if_freq; -fail: - return ret; -} - -static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - static struct mxl111sf_reg_ctrl_info *reg_ctrl_array; - int ret; - u8 mxl_mode; - - mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw); - - /* stop tune */ - ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0); - if (mxl_fail(ret)) - goto fail; - - /* check device mode */ - ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode); - if (mxl_fail(ret)) - goto fail; - - /* Fill out registers for channel tune */ - reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw); - if (!reg_ctrl_array) - return -EINVAL; - - ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array); - if (mxl_fail(ret)) - goto fail; - - if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) { - /* IF tuner mode only */ - mxl1x1sf_tuner_top_master_ctrl(state, 0); - mxl1x1sf_tuner_top_master_ctrl(state, 1); - mxl1x1sf_tuner_set_if_output_freq(state); - } - - ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1); - if (mxl_fail(ret)) - goto fail; - - if (state->cfg->ant_hunt) - state->cfg->ant_hunt(fe); -fail: - return ret; -} - -static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state, - int *rf_synth_lock, - int *ref_synth_lock) -{ - int ret; - u8 data; - - *rf_synth_lock = 0; - *ref_synth_lock = 0; - - ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data); - if (mxl_fail(ret)) - goto fail; - - *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0; - *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0; -fail: - return ret; -} - -#if 0 -static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, - int onoff) -{ - return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG, - onoff ? 1 : 0); -} -#endif - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int ret; - u8 bw; - - mxl_dbg("()"); - - switch (delsys) { - case SYS_ATSC: - case SYS_ATSCMH: - bw = 0; /* ATSC */ - break; - case SYS_DVBC_ANNEX_B: - bw = 1; /* US CABLE */ - break; - case SYS_DVBT: - switch (c->bandwidth_hz) { - case 6000000: - bw = 6; - break; - case 7000000: - bw = 7; - break; - case 8000000: - bw = 8; - break; - default: - err("%s: bandwidth not set!", __func__); - return -EINVAL; - } - break; - default: - err("%s: modulation type not supported!", __func__); - return -EINVAL; - } - ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); - if (mxl_fail(ret)) - goto fail; - - state->frequency = c->frequency; - state->bandwidth = c->bandwidth_hz; -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -#if 0 -static int mxl111sf_tuner_init(struct dvb_frontend *fe) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int ret; - - /* wake from standby handled by usb driver */ - - return ret; -} - -static int mxl111sf_tuner_sleep(struct dvb_frontend *fe) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int ret; - - /* enter standby mode handled by usb driver */ - - return ret; -} -#endif - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int rf_locked, ref_locked, ret; - - *status = 0; - - ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked); - if (mxl_fail(ret)) - goto fail; - mxl_info("%s%s", rf_locked ? "rf locked " : "", - ref_locked ? "ref locked" : ""); - - if ((rf_locked) || (ref_locked)) - *status |= TUNER_STATUS_LOCKED; -fail: - return ret; -} - -static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - u8 val1, val2; - int ret; - - *strength = 0; - - ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2); - if (mxl_fail(ret)) - goto fail; - - *strength = val1 | ((val2 & 0x07) << 8); -fail: - ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00); - mxl_fail(ret); - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - *frequency = state->frequency; - return 0; -} - -static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - *bandwidth = state->bandwidth; - return 0; -} - -static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, - u32 *frequency) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - - *frequency = 0; - - switch (state->if_freq) { - case MXL_IF_4_0: /* 4.0 MHz */ - *frequency = 4000000; - break; - case MXL_IF_4_5: /* 4.5 MHz */ - *frequency = 4500000; - break; - case MXL_IF_4_57: /* 4.57 MHz */ - *frequency = 4570000; - break; - case MXL_IF_5_0: /* 5.0 MHz */ - *frequency = 5000000; - break; - case MXL_IF_5_38: /* 5.38 MHz */ - *frequency = 5380000; - break; - case MXL_IF_6_0: /* 6.0 MHz */ - *frequency = 6000000; - break; - case MXL_IF_6_28: /* 6.28 MHz */ - *frequency = 6280000; - break; - case MXL_IF_7_2: /* 7.2 MHz */ - *frequency = 7200000; - break; - case MXL_IF_35_25: /* 35.25 MHz */ - *frequency = 35250000; - break; - case MXL_IF_36: /* 36 MHz */ - *frequency = 36000000; - break; - case MXL_IF_36_15: /* 36.15 MHz */ - *frequency = 36150000; - break; - case MXL_IF_44: /* 44 MHz */ - *frequency = 44000000; - break; - } - return 0; -} - -static int mxl111sf_tuner_release(struct dvb_frontend *fe) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - mxl_dbg("()"); - kfree(state); - fe->tuner_priv = NULL; - return 0; -} - -/* ------------------------------------------------------------------------- */ - -static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { - .info = { - .name = "MaxLinear MxL111SF", -#if 0 - .frequency_min = , - .frequency_max = , - .frequency_step = , -#endif - }, -#if 0 - .init = mxl111sf_tuner_init, - .sleep = mxl111sf_tuner_sleep, -#endif - .set_params = mxl111sf_tuner_set_params, - .get_status = mxl111sf_tuner_get_status, - .get_rf_strength = mxl111sf_get_rf_strength, - .get_frequency = mxl111sf_tuner_get_frequency, - .get_bandwidth = mxl111sf_tuner_get_bandwidth, - .get_if_frequency = mxl111sf_tuner_get_if_frequency, - .release = mxl111sf_tuner_release, -}; - -struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state, - struct mxl111sf_tuner_config *cfg) -{ - struct mxl111sf_tuner_state *state = NULL; - - mxl_dbg("()"); - - state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->mxl_state = mxl_state; - state->cfg = cfg; - - memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = state; - return fe; -} -EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); - -MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h deleted file mode 100644 index ff333960b18..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner - * - * Copyright (C) 2010 Michael Krufky - * - * 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 __MXL111SF_TUNER_H__ -#define __MXL111SF_TUNER_H__ - -#include "dvb_frontend.h" - -#include "mxl111sf.h" - -enum mxl_if_freq { -#if 0 - MXL_IF_LO = 0x00, /* other IF < 9MHz */ -#endif - MXL_IF_4_0 = 0x01, /* 4.0 MHz */ - MXL_IF_4_5 = 0x02, /* 4.5 MHz */ - MXL_IF_4_57 = 0x03, /* 4.57 MHz */ - MXL_IF_5_0 = 0x04, /* 5.0 MHz */ - MXL_IF_5_38 = 0x05, /* 5.38 MHz */ - MXL_IF_6_0 = 0x06, /* 6.0 MHz */ - MXL_IF_6_28 = 0x07, /* 6.28 MHz */ - MXL_IF_7_2 = 0x08, /* 7.2 MHz */ - MXL_IF_35_25 = 0x09, /* 35.25 MHz */ - MXL_IF_36 = 0x0a, /* 36 MHz */ - MXL_IF_36_15 = 0x0b, /* 36.15 MHz */ - MXL_IF_44 = 0x0c, /* 44 MHz */ -#if 0 - MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */ -#endif -}; - -struct mxl111sf_tuner_config { - enum mxl_if_freq if_freq; - unsigned int invert_spectrum:1; - - int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); - int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); - int (*program_regs)(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info); - int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff); - int (*ant_hunt)(struct dvb_frontend *fe); -}; - -/* ------------------------------------------------------------------------ */ - -#if defined(CONFIG_DVB_USB_MXL111SF) || \ - (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) -extern -struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state, - struct mxl111sf_tuner_config *cfg); -#else -static inline -struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state - struct mxl111sf_tuner_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __MXL111SF_TUNER_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf.c deleted file mode 100644 index efdcb15358f..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf.c +++ /dev/null @@ -1,1431 +0,0 @@ -/* - * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ - -#include -#include - -#include "mxl111sf.h" -#include "mxl111sf-reg.h" -#include "mxl111sf-phy.h" -#include "mxl111sf-i2c.h" -#include "mxl111sf-gpio.h" - -#include "mxl111sf-demod.h" -#include "mxl111sf-tuner.h" - -#include "lgdt3305.h" -#include "lg2160.h" - -int dvb_usb_mxl111sf_debug; -module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level " - "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); - -int dvb_usb_mxl111sf_isoc; -module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); -MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); - -int dvb_usb_mxl111sf_spi; -module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644); -MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); - -#define ANT_PATH_AUTO 0 -#define ANT_PATH_EXTERNAL 1 -#define ANT_PATH_INTERNAL 2 - -int dvb_usb_mxl111sf_rfswitch = -#if 0 - ANT_PATH_AUTO; -#else - ANT_PATH_EXTERNAL; -#endif - -module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644); -MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_info pr_debug -#define deb_reg pr_debug -#define deb_adv pr_debug -#define err pr_err -#define info pr_info - -int mxl111sf_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - int ret; - u8 sndbuf[1+wlen]; - - deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); - - memset(sndbuf, 0, 1+wlen); - - sndbuf[0] = cmd; - memcpy(&sndbuf[1], wbuf, wlen); - - ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) : - dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen); - mxl_fail(ret); - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -#define MXL_CMD_REG_READ 0xaa -#define MXL_CMD_REG_WRITE 0x55 - -int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) -{ - u8 buf[2]; - int ret; - - ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); - if (mxl_fail(ret)) { - mxl_debug("error reading reg: 0x%02x", addr); - goto fail; - } - - if (buf[0] == addr) - *data = buf[1]; - else { - err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x", - addr, buf[0], buf[1]); - ret = -EINVAL; - } - - deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data); -fail: - return ret; -} - -int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data) -{ - u8 buf[] = { addr, data }; - int ret; - - deb_reg("W: (0x%02x, 0x%02x)\n", addr, data); - - ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); - if (mxl_fail(ret)) - err("error writing reg: 0x%02x, val: 0x%02x", addr, data); - return ret; -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_write_reg_mask(struct mxl111sf_state *state, - u8 addr, u8 mask, u8 data) -{ - int ret; - u8 val; - - if (mask != 0xff) { - ret = mxl111sf_read_reg(state, addr, &val); -#if 1 - /* dont know why this usually errors out on the first try */ - if (mxl_fail(ret)) - err("error writing addr: 0x%02x, mask: 0x%02x, " - "data: 0x%02x, retrying...", addr, mask, data); - - ret = mxl111sf_read_reg(state, addr, &val); -#endif - if (mxl_fail(ret)) - goto fail; - } - val &= ~mask; - val |= data; - - ret = mxl111sf_write_reg(state, addr, val); - mxl_fail(ret); -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info) -{ - int i, ret = 0; - - for (i = 0; ctrl_reg_info[i].addr | - ctrl_reg_info[i].mask | - ctrl_reg_info[i].data; i++) { - - ret = mxl111sf_write_reg_mask(state, - ctrl_reg_info[i].addr, - ctrl_reg_info[i].mask, - ctrl_reg_info[i].data); - if (mxl_fail(ret)) { - err("failed on reg #%d (0x%02x)", i, - ctrl_reg_info[i].addr); - break; - } - } - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state) -{ - int ret; - u8 id, ver; - char *mxl_chip, *mxl_rev; - - if ((state->chip_id) && (state->chip_ver)) - return 0; - - ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id); - if (mxl_fail(ret)) - goto fail; - state->chip_id = id; - - ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver); - if (mxl_fail(ret)) - goto fail; - state->chip_ver = ver; - - switch (id) { - case 0x61: - mxl_chip = "MxL101SF"; - break; - case 0x63: - mxl_chip = "MxL111SF"; - break; - default: - mxl_chip = "UNKNOWN MxL1X1"; - break; - } - switch (ver) { - case 0x36: - state->chip_rev = MXL111SF_V6; - mxl_rev = "v6"; - break; - case 0x08: - state->chip_rev = MXL111SF_V8_100; - mxl_rev = "v8_100"; - break; - case 0x18: - state->chip_rev = MXL111SF_V8_200; - mxl_rev = "v8_200"; - break; - default: - state->chip_rev = 0; - mxl_rev = "UNKNOWN REVISION"; - break; - } - info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver); -fail: - return ret; -} - -#define get_chip_info(state) \ -({ \ - int ___ret; \ - ___ret = mxl1x1sf_get_chip_info(state); \ - if (mxl_fail(___ret)) { \ - mxl_debug("failed to get chip info" \ - " on first probe attempt"); \ - ___ret = mxl1x1sf_get_chip_info(state); \ - if (mxl_fail(___ret)) \ - err("failed to get chip info during probe"); \ - else \ - mxl_debug("probe needed a retry " \ - "in order to succeed."); \ - } \ - ___ret; \ -}) - -/* ------------------------------------------------------------------------ */ -#if 0 -static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - /* power control depends on which adapter is being woken: - * save this for init, instead, via mxl111sf_adap_fe_init */ - return 0; -} -#endif - -static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) -{ - struct dvb_usb_device *d = fe_to_d(fe); - struct mxl111sf_state *state = fe_to_priv(fe); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; - int err; - - /* exit if we didnt initialize the driver yet */ - if (!state->chip_id) { - mxl_debug("driver not yet initialized, exit."); - goto fail; - } - - deb_info("%s()\n", __func__); - - mutex_lock(&state->fe_lock); - - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - err = mxl1x1sf_soft_reset(state); - mxl_fail(err); - err = mxl111sf_init_tuner_demod(state); - mxl_fail(err); - err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - - mxl_fail(err); - mxl111sf_enable_usb_output(state); - mxl_fail(err); - mxl1x1sf_top_master_ctrl(state, 1); - mxl_fail(err); - - if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && - (state->chip_rev > MXL111SF_V6)) { - mxl111sf_config_pin_mux_modes(state, - PIN_MUX_TS_SPI_IN_MODE_1); - mxl_fail(err); - } - err = mxl111sf_init_port_expander(state); - if (!mxl_fail(err)) { - state->gpio_mode = adap_state->gpio_mode; - err = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - mxl_fail(err); -#if 0 - err = fe->ops.init(fe); -#endif - msleep(100); /* add short delay after enabling - * the demod before touching it */ - } - - return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0; -fail: - return -ENODEV; -} - -static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; - int err; - - /* exit if we didnt initialize the driver yet */ - if (!state->chip_id) { - mxl_debug("driver not yet initialized, exit."); - goto fail; - } - - deb_info("%s()\n", __func__); - - err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0; - - mutex_unlock(&state->fe_lock); - - return err; -fail: - return -ENODEV; -} - - -static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; - int ret = 0; - - deb_info("%s(%d)\n", __func__, onoff); - - if (onoff) { - ret = mxl111sf_enable_usb_output(state); - mxl_fail(ret); - ret = mxl111sf_config_mpeg_in(state, 1, 1, - adap_state->ep6_clockphase, - 0, 0); - mxl_fail(ret); -#if 0 - } else { - ret = mxl111sf_disable_656_port(state); - mxl_fail(ret); -#endif - } - - return ret; -} - -static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - int ret = 0; - - deb_info("%s(%d)\n", __func__, onoff); - - if (onoff) { - ret = mxl111sf_enable_usb_output(state); - mxl_fail(ret); - - ret = mxl111sf_init_i2s_port(state, 200); - mxl_fail(ret); - ret = mxl111sf_config_i2s(state, 0, 15); - mxl_fail(ret); - } else { - ret = mxl111sf_disable_i2s_port(state); - mxl_fail(ret); - } - if (state->chip_rev > MXL111SF_V6) - ret = mxl111sf_config_spi(state, onoff); - mxl_fail(ret); - - return ret; -} - -static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - int ret = 0; - - deb_info("%s(%d)\n", __func__, onoff); - - if (onoff) { - ret = mxl111sf_enable_usb_output(state); - mxl_fail(ret); - } - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static struct lgdt3305_config hauppauge_lgdt3305_config = { - .i2c_addr = 0xb2 >> 1, - .mpeg_mode = LGDT3305_MPEG_SERIAL, - .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .qam_if_khz = 6000, - .vsb_if_khz = 6000, -}; - -static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lgdt3305_attach, - &hauppauge_lgdt3305_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct lg2160_config hauppauge_lg2160_config = { - .lg_chip = LG2160, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, -}; - -static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_MH; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lg2160_attach, - &hauppauge_lg2160_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct lg2160_config hauppauge_lg2161_1019_config = { - .lg_chip = LG2161_1019, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 2, /* LG2161_OIF_SPI_MAS */ -}; - -static struct lg2160_config hauppauge_lg2161_1040_config = { - .lg_chip = LG2161_1040, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 4, /* LG2161_OIF_SPI_MAS */ -}; - -static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_MH; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lg2160_attach, - (MXL111SF_V8_200 == state->chip_rev) ? - &hauppauge_lg2161_1040_config : - &hauppauge_lg2161_1019_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct lg2160_config hauppauge_lg2161_1019_ep6_config = { - .lg_chip = LG2161_1019, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 1, /* LG2161_OIF_SERIAL_TS */ -}; - -static struct lg2160_config hauppauge_lg2161_1040_ep6_config = { - .lg_chip = LG2161_1040, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 7, /* LG2161_OIF_SERIAL_TS */ -}; - -static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_MH; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 0; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lg2160_attach, - (MXL111SF_V8_200 == state->chip_rev) ? - &hauppauge_lg2161_1040_ep6_config : - &hauppauge_lg2161_1019_ep6_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct mxl111sf_demod_config mxl_demod_config = { - .read_reg = mxl111sf_read_reg, - .write_reg = mxl111sf_write_reg, - .program_regs = mxl111sf_ctrl_program_regs, -}; - -static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_SOC_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - /* dont care if this fails */ - mxl111sf_init_port_expander(state); - - adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state, - &mxl_demod_config); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, - int antpath) -{ - return mxl111sf_idac_config(state, 1, 1, - (antpath == ANT_PATH_INTERNAL) ? - 0x3f : 0x00, 0); -} - -#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \ - err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \ - __func__, __LINE__, \ - (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \ - pwr0, pwr1, pwr2, pwr3) - -#define ANT_HUNT_SLEEP 90 -#define ANT_EXT_TWEAK 0 - -static int mxl111sf_ant_hunt(struct dvb_frontend *fe) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - int antctrl = dvb_usb_mxl111sf_rfswitch; - - u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; - - /* FIXME: must force EXTERNAL for QAM - done elsewhere */ - mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ? - ANT_PATH_EXTERNAL : antctrl); - - if (antctrl == ANT_PATH_AUTO) { -#if 0 - msleep(ANT_HUNT_SLEEP); -#endif - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA); - - mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); - msleep(ANT_HUNT_SLEEP); - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0); - - mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); - msleep(ANT_HUNT_SLEEP); - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1); - - mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL); - msleep(ANT_HUNT_SLEEP); - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2); - - if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) { - /* return with EXTERNAL enabled */ - mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); - DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA, - rxPwr0, rxPwr1, rxPwr2); - } else { - /* return with INTERNAL enabled */ - DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA, - rxPwr0, rxPwr1, rxPwr2); - } - } - return 0; -} - -static struct mxl111sf_tuner_config mxl_tuner_config = { - .if_freq = MXL_IF_6_0, /* applies to external IF output, only */ - .invert_spectrum = 0, - .read_reg = mxl111sf_read_reg, - .write_reg = mxl111sf_write_reg, - .program_regs = mxl111sf_ctrl_program_regs, - .top_master_ctrl = mxl1x1sf_top_master_ctrl, - .ant_hunt = mxl111sf_ant_hunt, -}; - -static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) -{ - struct mxl111sf_state *state = adap_to_priv(adap); - int i; - - deb_adv("%s()\n", __func__); - - for (i = 0; i < state->num_frontends; i++) { - if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state, - &mxl_tuner_config) == NULL) - return -EIO; - adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength; - } - - return 0; -} - -static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm mxl111sf_i2c_algo = { - .master_xfer = mxl111sf_i2c_xfer, - .functionality = mxl111sf_i2c_func, -#ifdef NEED_ALGO_CONTROL - .algo_control = dummy_algo_control, -#endif -}; - -static int mxl111sf_init(struct dvb_usb_device *d) -{ - struct mxl111sf_state *state = d_to_priv(d); - int ret; - static u8 eeprom[256]; - struct i2c_client c; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - err("failed to get chip info during probe"); - - mutex_init(&state->fe_lock); - - if (state->chip_rev > MXL111SF_V6) - mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); - - c.adapter = &d->i2c_adap; - c.addr = 0xa0 >> 1; - - ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); - if (mxl_fail(ret)) - return 0; - tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? - eeprom + 0xa0 : eeprom + 0x80); -#if 0 - switch (state->tv.model) { - case 117001: - case 126001: - case 138001: - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", - __func__, state->tv.model); - } -#endif - return 0; -} - -static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap) -{ - return mxl111sf_attach_demod(adap, 0); -} - -static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap) -{ - return mxl111sf_lgdt3305_frontend_attach(adap, 0); -} - -static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap) -{ - return mxl111sf_lg2160_frontend_attach(adap, 0); -} - -static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s\n", __func__); - - ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); - if (ret < 0) - return ret; - - ret = mxl111sf_attach_demod(adap, 1); - if (ret < 0) - return ret; - - ret = mxl111sf_lg2160_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; -} - -static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s\n", __func__); - - ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); - if (ret < 0) - return ret; - - ret = mxl111sf_attach_demod(adap, 1); - if (ret < 0) - return ret; - - ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; -} - -static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s\n", __func__); - - ret = mxl111sf_attach_demod(adap, 0); - if (ret < 0) - return ret; - - if (dvb_usb_mxl111sf_spi) - ret = mxl111sf_lg2161_frontend_attach(adap, 1); - else - ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1); - - return ret; -} - -static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint) -{ - deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint); - stream->type = USB_BULK; - stream->count = 5; - stream->endpoint = endpoint; - stream->u.bulk.buffersize = 8192; -} - -static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream, - u8 endpoint, int framesperurb, int framesize) -{ - deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint, - framesperurb * framesize); - stream->type = USB_ISOC; - stream->count = 5; - stream->endpoint = endpoint; - stream->u.isoc.framesperurb = framesperurb; - stream->u.isoc.framesize = framesize; - stream->u.isoc.interval = 1; -} - -/* DVB USB Driver stuff */ - -/* dvbt mxl111sf - * bulk EP4/BULK/5/8192 - * isoc EP4/ISOC/5/96/564 - */ -static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_dvbt = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_dvbt, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, - .get_stream_config = mxl111sf_get_stream_config_dvbt, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* atsc lgdt3305 - * bulk EP6/BULK/5/8192 - * isoc EP6/ISOC/5/24/3072 - */ -static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_atsc = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_atsc, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, - .get_stream_config = mxl111sf_get_stream_config_atsc, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* mh lg2160 - * bulk EP5/BULK/5/8192/RAW - * isoc EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_mh = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_mh, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, - .get_stream_config = mxl111sf_get_stream_config_mh, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* atsc mh lgdt3305 mxl111sf lg2160 - * bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW - * isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - if (fe->id == 0) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } else if (fe->id == 1) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - } else if (fe->id == 2) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - } - return 0; -} - -static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff) -{ - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - if (fe->id == 0) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - else if (fe->id == 1) - return mxl111sf_ep4_streaming_ctrl(fe, onoff); - else if (fe->id == 2) - return mxl111sf_ep5_streaming_ctrl(fe, onoff); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_atsc_mh, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_streaming_ctrl_atsc_mh, - .get_stream_config = mxl111sf_get_stream_config_atsc_mh, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* mercury lgdt3305 mxl111sf lg2161 - * tp bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP6/BULK/5/8192/RAW - * tp isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW - * spi bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW - * spi isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - if (fe->id == 0) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } else if (fe->id == 1) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } - return 0; -} - -static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff) -{ - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - if (fe->id == 0) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - else if (fe->id == 1) - return mxl111sf_ep4_streaming_ctrl(fe, onoff); - else if (fe->id == 2 && dvb_usb_mxl111sf_spi) - return mxl111sf_ep5_streaming_ctrl(fe, onoff); - else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_mercury = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_mercury, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_streaming_ctrl_mercury, - .get_stream_config = mxl111sf_get_stream_config_mercury, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* mercury mh mxl111sf lg2161 - * tp bulk EP4/BULK/5/8192 EP6/BULK/5/8192/RAW - * tp isoc EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW - * spi bulk EP4/BULK/5/8192 EP5/BULK/5/8192/RAW - * spi isoc EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - if (fe->id == 0) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } - return 0; -} - -static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff) -{ - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - if (fe->id == 0) - return mxl111sf_ep4_streaming_ctrl(fe, onoff); - else if (fe->id == 1 && dvb_usb_mxl111sf_spi) - return mxl111sf_ep5_streaming_ctrl(fe, onoff); - else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_mercury_mh, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_streaming_ctrl_mercury_mh, - .get_stream_config = mxl111sf_get_stream_config_mercury_mh, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -static const struct usb_device_id mxl111sf_id_table[] = { - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, mxl111sf_id_table); - -static struct usb_driver mxl111sf_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = mxl111sf_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(mxl111sf_usb_driver); - -MODULE_AUTHOR("Michael Krufky "); -MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf.h deleted file mode 100644 index 9816de86e48..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/mxl111sf.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ - -#ifndef _DVB_USB_MXL111SF_H_ -#define _DVB_USB_MXL111SF_H_ - -#ifdef DVB_USB_LOG_PREFIX -#undef DVB_USB_LOG_PREFIX -#endif -#define DVB_USB_LOG_PREFIX "mxl111sf" -#include "dvb_usb.h" -#include - -#define MXL_EP1_REG_READ 1 -#define MXL_EP2_REG_WRITE 2 -#define MXL_EP3_INTERRUPT 3 -#define MXL_EP4_MPEG2 4 -#define MXL_EP5_I2S 5 -#define MXL_EP6_656 6 -#define MXL_EP6_MPEG2 6 - -#ifdef USING_ENUM_mxl111sf_current_mode -enum mxl111sf_current_mode { - mxl_mode_dvbt = MXL_EP4_MPEG2, - mxl_mode_mh = MXL_EP5_I2S, - mxl_mode_atsc = MXL_EP6_MPEG2, -}; -#endif - -enum mxl111sf_gpio_port_expander { - mxl111sf_gpio_hw, - mxl111sf_PCA9534, -}; - -struct mxl111sf_adap_state { - int alt_mode; - int gpio_mode; - int device_mode; - int ep6_clockphase; - int (*fe_init)(struct dvb_frontend *); - int (*fe_sleep)(struct dvb_frontend *); -}; - -struct mxl111sf_state { - struct dvb_usb_device *d; - - enum mxl111sf_gpio_port_expander gpio_port_expander; - u8 port_expander_addr; - - u8 chip_id; - u8 chip_ver; -#define MXL111SF_V6 1 -#define MXL111SF_V8_100 2 -#define MXL111SF_V8_200 3 - u8 chip_rev; - -#ifdef USING_ENUM_mxl111sf_current_mode - enum mxl111sf_current_mode current_mode; -#endif - -#define MXL_TUNER_MODE 0 -#define MXL_SOC_MODE 1 -#define MXL_DEV_MODE_MASK 0x01 -#if 1 - int device_mode; -#endif - /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), - EP5 BULK transfer (atsc-mh), - EP6 BULK transfer (atsc/qam), - use usb alt setting 2 for EP4 BULK transfer (dvb-t), - EP5 ISOC transfer (atsc-mh), - EP6 ISOC transfer (atsc/qam), - */ - int alt_mode; - int gpio_mode; - struct tveeprom tv; - - struct mutex fe_lock; - u8 num_frontends; - struct mxl111sf_adap_state adap_state[3]; -}; - -int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); -int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data); - -struct mxl111sf_reg_ctrl_info { - u8 addr; - u8 mask; - u8 data; -}; - -int mxl111sf_write_reg_mask(struct mxl111sf_state *state, - u8 addr, u8 mask, u8 data); -int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info); - -/* needed for hardware i2c functions in mxl111sf-i2c.c: - * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */ -int mxl111sf_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen); - -#define mxl_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define mxl_info(fmt, arg...) \ - mxl_printk(KERN_INFO, fmt, ##arg) - -extern int dvb_usb_mxl111sf_debug; -#define mxl_debug(fmt, arg...) \ - if (dvb_usb_mxl111sf_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define MXL_I2C_DBG 0x04 -#define MXL_ADV_DBG 0x10 -#define mxl_debug_adv(fmt, arg...) \ - if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define mxl_i2c(fmt, arg...) \ - if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define mxl_i2c_adv(fmt, arg...) \ - if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \ - (MXL_I2C_DBG | MXL_ADV_DBG)) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -/* The following allows the mxl_fail() macro defined below to work - * in externel modules, such as mxl111sf-tuner.ko, even though - * dvb_usb_mxl111sf_debug is not defined within those modules */ -#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) -#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG -#else -#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug -#endif - -#define mxl_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \ - mxl_printk(KERN_ERR, "error %d on line %d", \ - ret, __LINE__); \ - __ret; \ -}) - -#endif /* _DVB_USB_MXL111SF_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb-v2/rtl28xxu.c b/drivers/media/dvb/dvb-usb-v2/rtl28xxu.c deleted file mode 100644 index a2d1e5b9d9d..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/rtl28xxu.c +++ /dev/null @@ -1,1259 +0,0 @@ -/* - * Realtek RTL28xxU DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * Copyright (C) 2011 Antti Palosaari - * Copyright (C) 2012 Thomas Mair - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "rtl28xxu.h" - -#include "rtl2830.h" -#include "rtl2832.h" - -#include "qt1010.h" -#include "mt2060.h" -#include "mxl5005s.h" -#include "fc0012.h" -#include "fc0013.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) -{ - int ret; - unsigned int pipe; - u8 requesttype; - u8 *buf; - - buf = kmalloc(req->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto err; - } - - if (req->index & CMD_WR_FLAG) { - /* write */ - memcpy(buf, req->data, req->size); - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - pipe = usb_sndctrlpipe(d->udev, 0); - } else { - /* read */ - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - pipe = usb_rcvctrlpipe(d->udev, 0); - } - - ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, - req->index, buf, req->size, 1000); - if (ret > 0) - ret = 0; - - deb_dump(0, requesttype, req->value, req->index, buf, req->size); - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->size); - - kfree(buf); - - if (ret) - goto err; - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) -{ - struct rtl28xxu_req req; - - if (reg < 0x3000) - req.index = CMD_USB_WR; - else if (reg < 0x4000) - req.index = CMD_SYS_WR; - else - req.index = CMD_IR_WR; - - req.value = reg; - req.size = len; - req.data = val; - - return rtl28xxu_ctrl_msg(d, &req); -} - -static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) -{ - struct rtl28xxu_req req; - - if (reg < 0x3000) - req.index = CMD_USB_RD; - else if (reg < 0x4000) - req.index = CMD_SYS_RD; - else - req.index = CMD_IR_RD; - - req.value = reg; - req.size = len; - req.data = val; - - return rtl28xxu_ctrl_msg(d, &req); -} - -static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) -{ - return rtl28xx_wr_regs(d, reg, &val, 1); -} - -static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) -{ - return rtl2831_rd_regs(d, reg, val, 1); -} - -/* I2C */ -static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - int ret; - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct rtl28xxu_priv *priv = d->priv; - struct rtl28xxu_req req; - - /* - * It is not known which are real I2C bus xfer limits, but testing - * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes. - * TODO: find out RTL2832U lens - */ - - /* - * I2C adapter logic looks rather complicated due to fact it handles - * three different access methods. Those methods are; - * 1) integrated demod access - * 2) old I2C access - * 3) new I2C access - * - * Used method is selected in order 1, 2, 3. Method 3 can handle all - * requests but there is two reasons why not use it always; - * 1) It is most expensive, usually two USB messages are needed - * 2) At least RTL2831U does not support it - * - * Method 3 is needed in case of I2C write+read (typical register read) - * where write is more than one byte. - */ - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num == 2 && !(msg[0].flags & I2C_M_RD) && - (msg[1].flags & I2C_M_RD)) { - if (msg[0].len > 24 || msg[1].len > 24) { - /* TODO: check msg[0].len max */ - ret = -EOPNOTSUPP; - goto err_mutex_unlock; - } else if (msg[0].addr == 0x10) { - /* method 1 - integrated demod */ - req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); - req.index = CMD_DEMOD_RD | priv->page; - req.size = msg[1].len; - req.data = &msg[1].buf[0]; - ret = rtl28xxu_ctrl_msg(d, &req); - } else if (msg[0].len < 2) { - /* method 2 - old I2C */ - req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); - req.index = CMD_I2C_RD; - req.size = msg[1].len; - req.data = &msg[1].buf[0]; - ret = rtl28xxu_ctrl_msg(d, &req); - } else { - /* method 3 - new I2C */ - req.value = (msg[0].addr << 1); - req.index = CMD_I2C_DA_WR; - req.size = msg[0].len; - req.data = msg[0].buf; - ret = rtl28xxu_ctrl_msg(d, &req); - if (ret) - goto err_mutex_unlock; - - req.value = (msg[0].addr << 1); - req.index = CMD_I2C_DA_RD; - req.size = msg[1].len; - req.data = msg[1].buf; - ret = rtl28xxu_ctrl_msg(d, &req); - } - } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { - if (msg[0].len > 22) { - /* TODO: check msg[0].len max */ - ret = -EOPNOTSUPP; - goto err_mutex_unlock; - } else if (msg[0].addr == 0x10) { - /* method 1 - integrated demod */ - if (msg[0].buf[0] == 0x00) { - /* save demod page for later demod access */ - priv->page = msg[0].buf[1]; - ret = 0; - } else { - req.value = (msg[0].buf[0] << 8) | - (msg[0].addr << 1); - req.index = CMD_DEMOD_WR | priv->page; - req.size = msg[0].len-1; - req.data = &msg[0].buf[1]; - ret = rtl28xxu_ctrl_msg(d, &req); - } - } else if (msg[0].len < 23) { - /* method 2 - old I2C */ - req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); - req.index = CMD_I2C_WR; - req.size = msg[0].len-1; - req.data = &msg[0].buf[1]; - ret = rtl28xxu_ctrl_msg(d, &req); - } else { - /* method 3 - new I2C */ - req.value = (msg[0].addr << 1); - req.index = CMD_I2C_DA_WR; - req.size = msg[0].len; - req.data = msg[0].buf; - ret = rtl28xxu_ctrl_msg(d, &req); - } - } else { - ret = -EINVAL; - } - -err_mutex_unlock: - mutex_unlock(&d->i2c_mutex); - - return ret ? ret : num; -} - -static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm rtl28xxu_i2c_algo = { - .master_xfer = rtl28xxu_i2c_xfer, - .functionality = rtl28xxu_i2c_func, -}; - -static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .ts_mode = 0, - .spec_inv = 1, - .if_dvbt = 36150000, - .vtop = 0x20, - .krf = 0x04, - .agc_targ_val = 0x2d, - -}; - -static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .ts_mode = 0, - .spec_inv = 1, - .if_dvbt = 36125000, - .vtop = 0x20, - .krf = 0x04, - .agc_targ_val = 0x2d, -}; - -static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .ts_mode = 0, - .spec_inv = 0, - .if_dvbt = 4570000, - .vtop = 0x3f, - .krf = 0x04, - .agc_targ_val = 0x3e, -}; - -static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - u8 buf[1]; - struct rtl2830_config *rtl2830_config; - /* open RTL2831U/RTL2830 I2C gate */ - struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" }; - /* for MT2060 tuner probe */ - struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf }; - /* for QT1010 tuner probe */ - struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf }; - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* - * RTL2831U GPIOs - * ========================================================= - * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?) - * GPIO2 | LED | 0 off | 1 on | - * GPIO4 | tuner#1 | 0 on | 1 off | MT2060 - */ - - /* GPIO direction */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a); - if (ret) - goto err; - - /* enable as output GPIO0, GPIO2, GPIO4 */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, 0x15); - if (ret) - goto err; - - /* - * Probe used tuner. We need to know used tuner before demod attach - * since there is some demod params needed to set according to tuner. - */ - - /* demod needs some time to wake up */ - msleep(20); - - /* open demod I2C gate */ - ret = rtl28xxu_ctrl_msg(d, &req_gate); - if (ret) - goto err; - - /* check QT1010 ID(?) register; reg=0f val=2c */ - ret = rtl28xxu_ctrl_msg(d, &req_qt1010); - if (ret == 0 && buf[0] == 0x2c) { - priv->tuner = TUNER_RTL2830_QT1010; - rtl2830_config = &rtl28xxu_rtl2830_qt1010_config; - dev_dbg(&d->udev->dev, "%s: QT1010\n", __func__); - goto found; - } else { - dev_dbg(&d->udev->dev, "%s: QT1010 probe failed=%d - %02x\n", - __func__, ret, buf[0]); - } - - /* open demod I2C gate */ - ret = rtl28xxu_ctrl_msg(d, &req_gate); - if (ret) - goto err; - - /* check MT2060 ID register; reg=00 val=63 */ - ret = rtl28xxu_ctrl_msg(d, &req_mt2060); - if (ret == 0 && buf[0] == 0x63) { - priv->tuner = TUNER_RTL2830_MT2060; - rtl2830_config = &rtl28xxu_rtl2830_mt2060_config; - dev_dbg(&d->udev->dev, "%s: MT2060\n", __func__); - goto found; - } else { - dev_dbg(&d->udev->dev, "%s: MT2060 probe failed=%d - %02x\n", - __func__, ret, buf[0]); - } - - /* assume MXL5005S */ - ret = 0; - priv->tuner = TUNER_RTL2830_MXL5005S; - rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config; - dev_dbg(&d->udev->dev, "%s: MXL5005S\n", __func__); - goto found; - -found: - /* attach demodulator */ - adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config, - &d->i2c_adap); - if (adap->fe[0] == NULL) { - ret = -ENODEV; - goto err; - } - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .if_dvbt = 0, - .tuner = TUNER_RTL2832_FC0012 -}; - -static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .if_dvbt = 0, - .tuner = TUNER_RTL2832_FC0013 -}; - -static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, - int cmd, int arg) -{ - int ret; - u8 val; - - dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg); - - switch (cmd) { - case FC_FE_CALLBACK_VHF_ENABLE: - /* set output values */ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); - if (ret) - goto err; - - if (arg) - val &= 0xbf; /* set GPIO6 low */ - else - val |= 0x40; /* set GPIO6 high */ - - - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); - if (ret) - goto err; - break; - default: - ret = -EINVAL; - goto err; - } - return 0; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - - -static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d, - int cmd, int arg) -{ - /* TODO implement*/ - return 0; -} - -static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) -{ - struct rtl28xxu_priv *priv = d->priv; - - switch (priv->tuner) { - case TUNER_RTL2832_FC0012: - return rtl2832u_fc0012_tuner_callback(d, cmd, arg); - - case TUNER_RTL2832_FC0013: - return rtl2832u_fc0013_tuner_callback(d, cmd, arg); - default: - break; - } - - return -ENODEV; -} - -static int rtl2832u_frontend_callback(void *adapter_priv, int component, - int cmd, int arg) -{ - struct i2c_adapter *adap = adapter_priv; - struct dvb_usb_device *d = i2c_get_adapdata(adap); - - switch (component) { - case DVB_FRONTEND_COMPONENT_TUNER: - return rtl2832u_tuner_callback(d, cmd, arg); - default: - break; - } - - return -EINVAL; -} - -static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - struct rtl2832_config *rtl2832_config; - u8 buf[2], val; - /* open RTL2832U/RTL2832 I2C gate */ - struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"}; - /* close RTL2832U/RTL2832 I2C gate */ - struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"}; - /* for FC0012 tuner probe */ - struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf}; - /* for FC0013 tuner probe */ - struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf}; - /* for MT2266 tuner probe */ - struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf}; - /* for FC2580 tuner probe */ - struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf}; - /* for MT2063 tuner probe */ - struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf}; - /* for MAX3543 tuner probe */ - struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf}; - /* for TUA9001 tuner probe */ - struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf}; - /* for MXL5007T tuner probe */ - struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; - /* for E4000 tuner probe */ - struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; - /* for TDA18272 tuner probe */ - struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - ret = rtl28xx_rd_reg(d, SYS_GPIO_DIR, &val); - if (ret) - goto err; - - val &= 0xbf; - - ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, val); - if (ret) - goto err; - - /* enable as output GPIO3 and GPIO6*/ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_EN, &val); - if (ret) - goto err; - - val |= 0x48; - - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, val); - if (ret) - goto err; - - /* - * Probe used tuner. We need to know used tuner before demod attach - * since there is some demod params needed to set according to tuner. - */ - - /* open demod I2C gate */ - ret = rtl28xxu_ctrl_msg(d, &req_gate_open); - if (ret) - goto err; - - priv->tuner = TUNER_NONE; - - /* check FC0012 ID register; reg=00 val=a1 */ - ret = rtl28xxu_ctrl_msg(d, &req_fc0012); - if (ret == 0 && buf[0] == 0xa1) { - priv->tuner = TUNER_RTL2832_FC0012; - rtl2832_config = &rtl28xxu_rtl2832_fc0012_config; - dev_info(&d->udev->dev, "%s: FC0012 tuner found", - KBUILD_MODNAME); - goto found; - } - - /* check FC0013 ID register; reg=00 val=a3 */ - ret = rtl28xxu_ctrl_msg(d, &req_fc0013); - if (ret == 0 && buf[0] == 0xa3) { - priv->tuner = TUNER_RTL2832_FC0013; - rtl2832_config = &rtl28xxu_rtl2832_fc0013_config; - dev_info(&d->udev->dev, "%s: FC0013 tuner found", - KBUILD_MODNAME); - goto found; - } - - /* check MT2266 ID register; reg=00 val=85 */ - ret = rtl28xxu_ctrl_msg(d, &req_mt2266); - if (ret == 0 && buf[0] == 0x85) { - priv->tuner = TUNER_RTL2832_MT2266; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: MT2266 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check FC2580 ID register; reg=01 val=56 */ - ret = rtl28xxu_ctrl_msg(d, &req_fc2580); - if (ret == 0 && buf[0] == 0x56) { - priv->tuner = TUNER_RTL2832_FC2580; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: FC2580 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check MT2063 ID register; reg=00 val=9e || 9c */ - ret = rtl28xxu_ctrl_msg(d, &req_mt2063); - if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) { - priv->tuner = TUNER_RTL2832_MT2063; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: MT2063 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check MAX3543 ID register; reg=00 val=38 */ - ret = rtl28xxu_ctrl_msg(d, &req_max3543); - if (ret == 0 && buf[0] == 0x38) { - priv->tuner = TUNER_RTL2832_MAX3543; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: MAX3534 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check TUA9001 ID register; reg=7e val=2328 */ - ret = rtl28xxu_ctrl_msg(d, &req_tua9001); - if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) { - priv->tuner = TUNER_RTL2832_TUA9001; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: TUA9001 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check MXL5007R ID register; reg=d9 val=14 */ - ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t); - if (ret == 0 && buf[0] == 0x14) { - priv->tuner = TUNER_RTL2832_MXL5007T; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: MXL5007T tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check E4000 ID register; reg=02 val=40 */ - ret = rtl28xxu_ctrl_msg(d, &req_e4000); - if (ret == 0 && buf[0] == 0x40) { - priv->tuner = TUNER_RTL2832_E4000; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: E4000 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - - /* check TDA18272 ID register; reg=00 val=c760 */ - ret = rtl28xxu_ctrl_msg(d, &req_tda18272); - if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) { - priv->tuner = TUNER_RTL2832_TDA18272; - /* TODO implement tuner */ - dev_info(&d->udev->dev, "%s: TDA18272 tuner found", - KBUILD_MODNAME); - goto unsupported; - } - -unsupported: - /* close demod I2C gate */ - ret = rtl28xxu_ctrl_msg(d, &req_gate_close); - if (ret) - goto err; - - /* tuner not found */ - dev_dbg(&d->udev->dev, "%s: No compatible tuner found\n", __func__); - ret = -ENODEV; - return ret; - -found: - /* close demod I2C gate */ - ret = rtl28xxu_ctrl_msg(d, &req_gate_close); - if (ret) - goto err; - - /* attach demodulator */ - adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config, - &d->i2c_adap); - if (adap->fe[0] == NULL) { - ret = -ENODEV; - goto err; - } - - /* set fe callbacks */ - adap->fe[0]->callback = rtl2832u_frontend_callback; - - return ret; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static struct qt1010_config rtl28xxu_qt1010_config = { - .i2c_address = 0x62, /* 0xc4 */ -}; - -static struct mt2060_config rtl28xxu_mt2060_config = { - .i2c_address = 0x60, /* 0xc0 */ - .clock_out = 0, -}; - -static struct mxl5005s_config rtl28xxu_mxl5005s_config = { - .i2c_address = 0x63, /* 0xc6 */ - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C_H, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - struct i2c_adapter *rtl2830_tuner_i2c; - struct dvb_frontend *fe; - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */ - rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]); - - switch (priv->tuner) { - case TUNER_RTL2830_QT1010: - fe = dvb_attach(qt1010_attach, adap->fe[0], - rtl2830_tuner_i2c, &rtl28xxu_qt1010_config); - break; - case TUNER_RTL2830_MT2060: - fe = dvb_attach(mt2060_attach, adap->fe[0], - rtl2830_tuner_i2c, &rtl28xxu_mt2060_config, - 1220); - break; - case TUNER_RTL2830_MXL5005S: - fe = dvb_attach(mxl5005s_attach, adap->fe[0], - rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config); - break; - default: - fe = NULL; - dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, - priv->tuner); - } - - if (fe == NULL) { - ret = -ENODEV; - goto err; - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - struct dvb_frontend *fe; - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - switch (priv->tuner) { - case TUNER_RTL2832_FC0012: - fe = dvb_attach(fc0012_attach, adap->fe[0], - &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); - - /* since fc0012 includs reading the signal strength delegate - * that to the tuner driver */ - adap->fe[0]->ops.read_signal_strength = - adap->fe[0]->ops.tuner_ops.get_rf_strength; - return 0; - break; - case TUNER_RTL2832_FC0013: - fe = dvb_attach(fc0013_attach, adap->fe[0], - &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); - - /* fc0013 also supports signal strength reading */ - adap->fe[0]->ops.read_signal_strength = - adap->fe[0]->ops.tuner_ops.get_rf_strength; - return 0; - default: - fe = NULL; - dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, - priv->tuner); - } - - if (fe == NULL) { - ret = -ENODEV; - goto err; - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl28xxu_init(struct dvb_usb_device *d) -{ - int ret; - u8 val; - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* init USB endpoints */ - ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val); - if (ret) - goto err; - - /* enable DMA and Full Packet Mode*/ - val |= 0x09; - ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val); - if (ret) - goto err; - - /* set EPA maximum packet size to 0x0200 */ - ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); - if (ret) - goto err; - - /* change EPA FIFO length */ - ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); - if (ret) - goto err; - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl28xxu_streaming_ctrl(struct dvb_frontend *fe , int onoff) -{ - int ret; - u8 buf[2]; - struct dvb_usb_device *d = fe_to_d(fe); - - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); - - if (onoff) { - buf[0] = 0x00; - buf[1] = 0x00; - } else { - buf[0] = 0x10; /* stall EPA */ - buf[1] = 0x02; /* reset EPA */ - } - - ret = rtl28xx_wr_regs(d, USB_EPA_CTL, buf, 2); - if (ret) - goto err; - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - u8 gpio, sys0; - - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); - - /* demod adc */ - ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0); - if (ret) - goto err; - - /* tuner power, read GPIOs */ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); - if (ret) - goto err; - - dev_dbg(&d->udev->dev, "%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, - sys0, gpio); - - if (onoff) { - gpio |= 0x01; /* GPIO0 = 1 */ - gpio &= (~0x10); /* GPIO4 = 0 */ - gpio |= 0x04; /* GPIO2 = 1, LED on */ - sys0 = sys0 & 0x0f; - sys0 |= 0xe0; - } else { - gpio &= (~0x01); /* GPIO0 = 0 */ - gpio |= 0x10; /* GPIO4 = 1 */ - gpio &= (~0x04); /* GPIO2 = 1, LED off */ - sys0 = sys0 & (~0xc0); - } - - dev_dbg(&d->udev->dev, "%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, - sys0, gpio); - - /* demod adc */ - ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0); - if (ret) - goto err; - - /* tuner power, write GPIOs */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); - if (ret) - goto err; - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - u8 val; - - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); - - if (onoff) { - /* set output values */ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); - if (ret) - goto err; - - val |= 0x08; - val &= 0xef; - - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); - if (ret) - goto err; - - /* demod_ctl_1 */ - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val); - if (ret) - goto err; - - val &= 0xef; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val); - if (ret) - goto err; - - /* demod control */ - /* PLL enable */ - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); - if (ret) - goto err; - - /* bit 7 to 1 */ - val |= 0x80; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); - if (ret) - goto err; - - /* demod HW reset */ - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); - if (ret) - goto err; - /* bit 5 to 0 */ - val &= 0xdf; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); - if (ret) - goto err; - - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); - if (ret) - goto err; - - val |= 0x20; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); - if (ret) - goto err; - - mdelay(5); - - /*enable ADC_Q and ADC_I */ - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); - if (ret) - goto err; - - val |= 0x48; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); - if (ret) - goto err; - - - } else { - /* demod_ctl_1 */ - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val); - if (ret) - goto err; - - val |= 0x0c; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val); - if (ret) - goto err; - - /* set output values */ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); - if (ret) - goto err; - - val |= 0x10; - - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); - if (ret) - goto err; - - /* demod control */ - ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); - if (ret) - goto err; - - val &= 0x37; - - ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); - if (ret) - goto err; - - } - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - - -static int rtl2831u_rc_query(struct dvb_usb_device *d) -{ - int ret, i; - struct rtl28xxu_priv *priv = d->priv; - u8 buf[5]; - u32 rc_code; - struct rtl28xxu_reg_val rc_nec_tab[] = { - { 0x3033, 0x80 }, - { 0x3020, 0x43 }, - { 0x3021, 0x16 }, - { 0x3022, 0x16 }, - { 0x3023, 0x5a }, - { 0x3024, 0x2d }, - { 0x3025, 0x16 }, - { 0x3026, 0x01 }, - { 0x3028, 0xb0 }, - { 0x3029, 0x04 }, - { 0x302c, 0x88 }, - { 0x302e, 0x13 }, - { 0x3030, 0xdf }, - { 0x3031, 0x05 }, - }; - - /* init remote controller */ - if (!priv->rc_active) { - for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { - ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, - rc_nec_tab[i].val); - if (ret) - goto err; - } - priv->rc_active = true; - } - - ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5); - if (ret) - goto err; - - if (buf[4] & 0x01) { - if (buf[2] == (u8) ~buf[3]) { - if (buf[0] == (u8) ~buf[1]) { - /* NEC standard (16 bit) */ - rc_code = buf[0] << 8 | buf[2]; - } else { - /* NEC extended (24 bit) */ - rc_code = buf[0] << 16 | - buf[1] << 8 | buf[2]; - } - } else { - /* NEC full (32 bit) */ - rc_code = buf[0] << 24 | buf[1] << 16 | - buf[2] << 8 | buf[3]; - } - - rc_keydown(d->rc_dev, rc_code, 0); - - ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); - if (ret) - goto err; - - /* repeated intentionally to avoid extra keypress */ - ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); - if (ret) - goto err; - } - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl2831u_get_rc_config(struct dvb_usb_device *d, - struct dvb_usb_rc *rc) -{ - rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_TYPE_NEC; - rc->query = rtl2831u_rc_query; - rc->interval = 400; - - return 0; -} - -static int rtl2832u_rc_query(struct dvb_usb_device *d) -{ - int ret, i; - struct rtl28xxu_priv *priv = d->priv; - u8 buf[128]; - int len; - struct rtl28xxu_reg_val rc_nec_tab[] = { - { IR_RX_CTRL, 0x20 }, - { IR_RX_BUF_CTRL, 0x80 }, - { IR_RX_IF, 0xff }, - { IR_RX_IE, 0xff }, - { IR_MAX_DURATION0, 0xd0 }, - { IR_MAX_DURATION1, 0x07 }, - { IR_IDLE_LEN0, 0xc0 }, - { IR_IDLE_LEN1, 0x00 }, - { IR_GLITCH_LEN, 0x03 }, - { IR_RX_CLK, 0x09 }, - { IR_RX_CFG, 0x1c }, - { IR_MAX_H_TOL_LEN, 0x1e }, - { IR_MAX_L_TOL_LEN, 0x1e }, - { IR_RX_CTRL, 0x80 }, - }; - - /* init remote controller */ - if (!priv->rc_active) { - for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { - ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, - rc_nec_tab[i].val); - if (ret) - goto err; - } - priv->rc_active = true; - } - - ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]); - if (ret) - goto err; - - if (buf[0] != 0x83) - goto exit; - - ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]); - if (ret) - goto err; - - len = buf[0]; - ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len); - - /* TODO: pass raw IR to Kernel IR decoder */ - - ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03); - ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80); - ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80); - -exit: - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int rtl2832u_get_rc_config(struct dvb_usb_device *d, - struct dvb_usb_rc *rc) -{ - rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_TYPE_NEC; - rc->query = rtl2832u_rc_query; - rc->interval = 400; - - return 0; -} - -static const struct dvb_usb_device_properties rtl2831u_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct rtl28xxu_priv), - - .power_ctrl = rtl2831u_power_ctrl, - .i2c_algo = &rtl28xxu_i2c_algo, - .frontend_attach = rtl2831u_frontend_attach, - .tuner_attach = rtl2831u_tuner_attach, - .init = rtl28xxu_init, - .get_rc_config = rtl2831u_get_rc_config, - .streaming_ctrl = rtl28xxu_streaming_ctrl, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512), - }, - }, -}; - -static const struct dvb_usb_device_properties rtl2832u_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct rtl28xxu_priv), - - .power_ctrl = rtl2832u_power_ctrl, - .i2c_algo = &rtl28xxu_i2c_algo, - .frontend_attach = rtl2832u_frontend_attach, - .tuner_attach = rtl2832u_tuner_attach, - .init = rtl28xxu_init, - .get_rc_config = rtl2832u_get_rc_config, - .streaming_ctrl = rtl28xxu_streaming_ctrl, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512), - }, - }, -}; - -static const struct usb_device_id rtl28xxu_id_table[] = { - { DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U, - &rtl2831u_props, "Realtek RTL2831U reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT, - &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, - { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2, - &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, - - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1, - &rtl2832u_props, "Terratec Cinergy T Stick Black", NULL) }, - { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT, - &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK, - &rtl2832u_props, "NOXON DAB/DAB+ USB dongle", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); - -static struct usb_driver rtl28xxu_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = rtl28xxu_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(rtl28xxu_usb_driver); - -MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_AUTHOR("Thomas Mair "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/rtl28xxu.h b/drivers/media/dvb/dvb-usb-v2/rtl28xxu.h deleted file mode 100644 index 575edbf13a9..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/rtl28xxu.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Realtek RTL28xxU DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * Copyright (C) 2011 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef RTL28XXU_H -#define RTL28XXU_H - -#include "dvb_usb.h" - -#define deb_dump(r, t, v, i, b, l) { \ - char *direction; \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - direction = ">>>"; \ - else \ - direction = "<<<"; \ - dev_dbg(&d->udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \ - "%s [%d bytes]\n", __func__, t, r, v & 0xff, v >> 8, \ - i & 0xff, i >> 8, l & 0xff, l >> 8, direction, l); \ -} - -/* - * USB commands - * (usb_control_msg() index parameter) - */ - -#define DEMOD 0x0000 -#define USB 0x0100 -#define SYS 0x0200 -#define I2C 0x0300 -#define I2C_DA 0x0600 - -#define CMD_WR_FLAG 0x0010 -#define CMD_DEMOD_RD 0x0000 -#define CMD_DEMOD_WR 0x0010 -#define CMD_USB_RD 0x0100 -#define CMD_USB_WR 0x0110 -#define CMD_SYS_RD 0x0200 -#define CMD_IR_RD 0x0201 -#define CMD_IR_WR 0x0211 -#define CMD_SYS_WR 0x0210 -#define CMD_I2C_RD 0x0300 -#define CMD_I2C_WR 0x0310 -#define CMD_I2C_DA_RD 0x0600 -#define CMD_I2C_DA_WR 0x0610 - - -struct rtl28xxu_priv { - u8 chip_id; - u8 tuner; - u8 page; /* integrated demod active register page */ - bool rc_active; -}; - -enum rtl28xxu_chip_id { - CHIP_ID_NONE, - CHIP_ID_RTL2831U, - CHIP_ID_RTL2832U, -}; - -enum rtl28xxu_tuner { - TUNER_NONE, - - TUNER_RTL2830_QT1010, - TUNER_RTL2830_MT2060, - TUNER_RTL2830_MXL5005S, - - TUNER_RTL2832_MT2266, - TUNER_RTL2832_FC2580, - TUNER_RTL2832_MT2063, - TUNER_RTL2832_MAX3543, - TUNER_RTL2832_TUA9001, - TUNER_RTL2832_MXL5007T, - TUNER_RTL2832_FC0012, - TUNER_RTL2832_E4000, - TUNER_RTL2832_TDA18272, - TUNER_RTL2832_FC0013, -}; - -struct rtl28xxu_req { - u16 value; - u16 index; - u16 size; - u8 *data; -}; - -struct rtl28xxu_reg_val { - u16 reg; - u8 val; -}; - -/* - * memory map - * - * 0x0000 DEMOD : demodulator - * 0x2000 USB : SIE, USB endpoint, debug, DMA - * 0x3000 SYS : system - * 0xfc00 RC : remote controller (not RTL2831U) - */ - -/* - * USB registers - */ -/* SIE Control Registers */ -#define USB_SYSCTL 0x2000 /* USB system control */ -#define USB_SYSCTL_0 0x2000 /* USB system control */ -#define USB_SYSCTL_1 0x2001 /* USB system control */ -#define USB_SYSCTL_2 0x2002 /* USB system control */ -#define USB_SYSCTL_3 0x2003 /* USB system control */ -#define USB_IRQSTAT 0x2008 /* SIE interrupt status */ -#define USB_IRQEN 0x200C /* SIE interrupt enable */ -#define USB_CTRL 0x2010 /* USB control */ -#define USB_STAT 0x2014 /* USB status */ -#define USB_DEVADDR 0x2018 /* USB device address */ -#define USB_TEST 0x201C /* USB test mode */ -#define USB_FRAME_NUMBER 0x2020 /* frame number */ -#define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */ -#define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */ -#define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */ -/* Endpoint Registers */ -#define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */ -#define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */ -#define USB_EP0_CFG 0x2104 /* EP 0 configure */ -#define USB_EP0_CTL 0x2108 /* EP 0 control */ -#define USB_EP0_STAT 0x210C /* EP 0 status */ -#define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */ -#define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */ -#define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */ -#define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */ -#define USB_EPA_CFG 0x2144 /* EP A configure */ -#define USB_EPA_CFG_0 0x2144 /* EP A configure */ -#define USB_EPA_CFG_1 0x2145 /* EP A configure */ -#define USB_EPA_CFG_2 0x2146 /* EP A configure */ -#define USB_EPA_CFG_3 0x2147 /* EP A configure */ -#define USB_EPA_CTL 0x2148 /* EP A control */ -#define USB_EPA_CTL_0 0x2148 /* EP A control */ -#define USB_EPA_CTL_1 0x2149 /* EP A control */ -#define USB_EPA_CTL_2 0x214A /* EP A control */ -#define USB_EPA_CTL_3 0x214B /* EP A control */ -#define USB_EPA_STAT 0x214C /* EP A status */ -#define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */ -#define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */ -#define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */ -#define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */ -#define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */ -#define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */ -#define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */ -#define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */ -#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */ -#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */ -#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */ -#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */ -/* Debug Registers */ -#define USB_PHYTSTDIS 0x2F04 /* PHY test disable */ -#define USB_TOUT_VAL 0x2F08 /* USB time-out time */ -#define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */ -#define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */ -#define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */ -#define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */ -#define USB_UTMI_TST 0x2F80 /* UTMI test */ -#define USB_UTMI_STATUS 0x2F84 /* UTMI status */ -#define USB_TSTCTL 0x2F88 /* test control */ -#define USB_TSTCTL2 0x2F8C /* test control 2 */ -#define USB_PID_FORCE 0x2F90 /* force PID */ -#define USB_PKTERR_CNT 0x2F94 /* packet error counter */ -#define USB_RXERR_CNT 0x2F98 /* RX error counter */ -#define USB_MEM_BIST 0x2F9C /* MEM BIST test */ -#define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */ -#define USB_CNTTEST 0x2FA4 /* counter test */ -#define USB_PHYTST 0x2FC0 /* USB PHY test */ -#define USB_DBGIDX 0x2FF0 /* select individual block debug signal */ -#define USB_DBGMUX 0x2FF4 /* debug signal module mux */ - -/* - * SYS registers - */ -/* demod control registers */ -#define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */ -#define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */ -/* GPIO registers */ -#define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */ -#define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */ -#define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */ -#define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */ -#define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */ -#define SYS_SYSINTE 0x3005 /* system interrupt enable */ -#define SYS_SYSINTS 0x3006 /* system interrupt status */ -#define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */ -#define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */ -#define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */ -#define SYS_DEMOD_CTL1 0x300B - -/* IrDA registers */ -#define SYS_IRRC_PSR 0x3020 /* IR protocol selection */ -#define SYS_IRRC_PER 0x3024 /* IR protocol extension */ -#define SYS_IRRC_SF 0x3028 /* IR sampling frequency */ -#define SYS_IRRC_DPIR 0x302C /* IR data package interval */ -#define SYS_IRRC_CR 0x3030 /* IR control */ -#define SYS_IRRC_RP 0x3034 /* IR read port */ -#define SYS_IRRC_SR 0x3038 /* IR status */ -/* I2C master registers */ -#define SYS_I2CCR 0x3040 /* I2C clock */ -#define SYS_I2CMCR 0x3044 /* I2C master control */ -#define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */ -#define SYS_I2CMSR 0x304C /* I2C master status */ -#define SYS_I2CMFR 0x3050 /* I2C master FIFO */ - -/* - * IR registers - */ -#define IR_RX_BUF 0xFC00 -#define IR_RX_IE 0xFD00 -#define IR_RX_IF 0xFD01 -#define IR_RX_CTRL 0xFD02 -#define IR_RX_CFG 0xFD03 -#define IR_MAX_DURATION0 0xFD04 -#define IR_MAX_DURATION1 0xFD05 -#define IR_IDLE_LEN0 0xFD06 -#define IR_IDLE_LEN1 0xFD07 -#define IR_GLITCH_LEN 0xFD08 -#define IR_RX_BUF_CTRL 0xFD09 -#define IR_RX_BUF_DATA 0xFD0A -#define IR_RX_BC 0xFD0B -#define IR_RX_CLK 0xFD0C -#define IR_RX_C_COUNT_L 0xFD0D -#define IR_RX_C_COUNT_H 0xFD0E -#define IR_SUSPEND_CTRL 0xFD10 -#define IR_ERR_TOL_CTRL 0xFD11 -#define IR_UNIT_LEN 0xFD12 -#define IR_ERR_TOL_LEN 0xFD13 -#define IR_MAX_H_TOL_LEN 0xFD14 -#define IR_MAX_L_TOL_LEN 0xFD15 -#define IR_MASK_CTRL 0xFD16 -#define IR_MASK_DATA 0xFD17 -#define IR_RES_MASK_ADDR 0xFD18 -#define IR_RES_MASK_T_LEN 0xFD19 - -#endif diff --git a/drivers/media/dvb/dvb-usb-v2/usb_urb.c b/drivers/media/dvb/dvb-usb-v2/usb_urb.c deleted file mode 100644 index eaf673a3978..00000000000 --- a/drivers/media/dvb/dvb-usb-v2/usb_urb.c +++ /dev/null @@ -1,357 +0,0 @@ -/* usb-urb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file keeps functions for initializing and handling the - * BULK and ISOC USB data transfers in a generic way. - * Can be used for DVB-only and also, that's the plan, for - * Hybrid USB devices (analog and DVB). - */ -#include "dvb_usb_common.h" - -/* URB stuff for streaming */ - -int usb_urb_reconfig(struct usb_data_stream *stream, - struct usb_data_stream_properties *props); - -static void usb_urb_complete(struct urb *urb) -{ - struct usb_data_stream *stream = urb->context; - int ptype = usb_pipetype(urb->pipe); - int i; - u8 *b; - - dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \ - "length=%d/%d pack_num=%d errors=%d\n", __func__, - ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", - urb->status, urb->actual_length, - urb->transfer_buffer_length, - urb->number_of_packets, urb->error_count); - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n", - __func__, urb->status); - break; - } - - b = (u8 *) urb->transfer_buffer; - switch (ptype) { - case PIPE_ISOCHRONOUS: - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status != 0) - dev_dbg(&stream->udev->dev, "%s: iso frame " \ - "descriptor has an error=%d\n", - __func__, - urb->iso_frame_desc[i].status); - else if (urb->iso_frame_desc[i].actual_length > 0) - stream->complete(stream, - b + urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - break; - case PIPE_BULK: - if (urb->actual_length > 0) - stream->complete(stream, b, urb->actual_length); - break; - default: - dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \ - "completition handler\n", KBUILD_MODNAME); - return; - } - usb_submit_urb(urb, GFP_ATOMIC); -} - -int usb_urb_killv2(struct usb_data_stream *stream) -{ - int i; - for (i = 0; i < stream->urbs_submitted; i++) { - dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i); - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - return 0; -} - -int usb_urb_submitv2(struct usb_data_stream *stream, - struct usb_data_stream_properties *props) -{ - int i, ret; - - if (props) { - ret = usb_urb_reconfig(stream, props); - if (ret < 0) - return ret; - } - - for (i = 0; i < stream->urbs_initialized; i++) { - dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); - ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); - if (ret) { - dev_err(&stream->udev->dev, "%s: could not submit " \ - "urb no. %d - get them all back\n", - KBUILD_MODNAME, i); - usb_urb_killv2(stream); - return ret; - } - stream->urbs_submitted++; - } - return 0; -} - -int usb_urb_free_urbs(struct usb_data_stream *stream) -{ - int i; - - usb_urb_killv2(stream); - - for (i = stream->urbs_initialized - 1; i >= 0; i--) { - if (stream->urb_list[i]) { - dev_dbg(&stream->udev->dev, "%s: free urb=%d\n", - __func__, i); - /* free the URBs */ - usb_free_urb(stream->urb_list[i]); - } - } - stream->urbs_initialized = 0; - - return 0; -} - -static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) -{ - int i, j; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); - stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); - if (!stream->urb_list[i]) { - dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - usb_fill_bulk_urb(stream->urb_list[i], - stream->udev, - usb_rcvbulkpipe(stream->udev, - stream->props.endpoint), - stream->buf_list[i], - stream->props.u.bulk.buffersize, - usb_urb_complete, stream); - - stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; - stream->urbs_initialized++; - } - return 0; -} - -static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) -{ - int i, j; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - struct urb *urb; - int frame_offset = 0; - dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); - stream->urb_list[i] = usb_alloc_urb( - stream->props.u.isoc.framesperurb, GFP_ATOMIC); - if (!stream->urb_list[i]) { - dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - - urb = stream->urb_list[i]; - - urb->dev = stream->udev; - urb->context = stream; - urb->complete = usb_urb_complete; - urb->pipe = usb_rcvisocpipe(stream->udev, - stream->props.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = stream->props.u.isoc.interval; - urb->number_of_packets = stream->props.u.isoc.framesperurb; - urb->transfer_buffer_length = stream->props.u.isoc.framesize * - stream->props.u.isoc.framesperurb; - urb->transfer_buffer = stream->buf_list[i]; - urb->transfer_dma = stream->dma_addr[i]; - - for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = - stream->props.u.isoc.framesize; - frame_offset += stream->props.u.isoc.framesize; - } - - stream->urbs_initialized++; - } - return 0; -} - -int usb_free_stream_buffers(struct usb_data_stream *stream) -{ - if (stream->state & USB_STATE_URB_BUF) { - while (stream->buf_num) { - stream->buf_num--; - dev_dbg(&stream->udev->dev, "%s: free buf=%d\n", - __func__, stream->buf_num); - usb_free_coherent(stream->udev, stream->buf_size, - stream->buf_list[stream->buf_num], - stream->dma_addr[stream->buf_num]); - } - } - - stream->state &= ~USB_STATE_URB_BUF; - - return 0; -} - -int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, - unsigned long size) -{ - stream->buf_num = 0; - stream->buf_size = size; - - dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \ - "streaming\n", __func__, num * size); - - for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - stream->buf_list[stream->buf_num] = usb_alloc_coherent( - stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]); - if (!stream->buf_list[stream->buf_num]) { - dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", - __func__, stream->buf_num); - usb_free_stream_buffers(stream); - return -ENOMEM; - } - - dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", - __func__, stream->buf_num, - stream->buf_list[stream->buf_num], - (long long)stream->dma_addr[stream->buf_num]); - memset(stream->buf_list[stream->buf_num], 0, size); - stream->state |= USB_STATE_URB_BUF; - } - - return 0; -} - -int usb_urb_reconfig(struct usb_data_stream *stream, - struct usb_data_stream_properties *props) -{ - int buf_size; - - if (!props) - return 0; - - /* check allocated buffers are large enough for the request */ - if (props->type == USB_BULK) { - buf_size = stream->props.u.bulk.buffersize; - } else if (props->type == USB_ISOC) { - buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; - } else { - dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n", - KBUILD_MODNAME, props->type); - return -EINVAL; - } - - if (stream->buf_num < props->count || stream->buf_size < buf_size) { - dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \ - "allocated buffers are too small\n", - KBUILD_MODNAME); - return -EINVAL; - } - - /* check if all fields are same */ - if (stream->props.type == props->type && - stream->props.count == props->count && - stream->props.endpoint == props->endpoint) { - if (props->type == USB_BULK && - props->u.bulk.buffersize == - stream->props.u.bulk.buffersize) - return 0; - else if (props->type == USB_ISOC && - props->u.isoc.framesperurb == - stream->props.u.isoc.framesperurb && - props->u.isoc.framesize == - stream->props.u.isoc.framesize && - props->u.isoc.interval == - stream->props.u.isoc.interval) - return 0; - } - - dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__); - - usb_urb_free_urbs(stream); - memcpy(&stream->props, props, sizeof(*props)); - if (props->type == USB_BULK) - return usb_urb_alloc_bulk_urbs(stream); - else if (props->type == USB_ISOC) - return usb_urb_alloc_isoc_urbs(stream); - - return 0; -} - -int usb_urb_initv2(struct usb_data_stream *stream, - const struct usb_data_stream_properties *props) -{ - int ret; - - if (!stream || !props) - return -EINVAL; - - memcpy(&stream->props, props, sizeof(*props)); - - if (!stream->complete) { - dev_err(&stream->udev->dev, "%s: there is no data callback - " \ - "this doesn't make sense\n", KBUILD_MODNAME); - return -EINVAL; - } - - switch (stream->props.type) { - case USB_BULK: - ret = usb_alloc_stream_buffers(stream, stream->props.count, - stream->props.u.bulk.buffersize); - if (ret < 0) - return ret; - - return usb_urb_alloc_bulk_urbs(stream); - case USB_ISOC: - ret = usb_alloc_stream_buffers(stream, stream->props.count, - stream->props.u.isoc.framesize * - stream->props.u.isoc.framesperurb); - if (ret < 0) - return ret; - - return usb_urb_alloc_isoc_urbs(stream); - default: - dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \ - "transfer\n", KBUILD_MODNAME); - return -EINVAL; - } -} - -int usb_urb_exitv2(struct usb_data_stream *stream) -{ - usb_urb_free_urbs(stream); - usb_free_stream_buffers(stream); - - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig deleted file mode 100644 index 00173ee15d4..00000000000 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ /dev/null @@ -1,313 +0,0 @@ -config DVB_USB - tristate "Support for various USB DVB devices" - depends on DVB_CORE && USB && I2C && RC_CORE - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_DEBUG - bool "Enable extended debug support for all DVB-USB devices" - depends on DVB_USB - help - Say Y if you want to enable debugging. See modinfo dvb-usb (and the - appropriate drivers) for debug levels. - -config DVB_USB_A800 - tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" - depends on DVB_USB - select DVB_DIB3000MC - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. - -config DVB_USB_DIBUSB_MB - tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_DIB3000MB - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by - DiBcom () equipped with a DiB3000M-B demodulator. - - For an up-to-date list of devices supported by this driver, have a look - on the Linux-DVB Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_DIBUSB_MB_FAULTY - bool "Support faulty USB IDs" - depends on DVB_USB_DIBUSB_MB - help - Support for faulty USB IDs due to an invalid EEPROM on some Artec devices. - -config DVB_USB_DIBUSB_MC - tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" - depends on DVB_USB - select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Support for USB2.0 DVB-T receivers based on reference designs made by - DiBcom () equipped with a DiB3000M-C/P demodulator. - - For an up-to-date list of devices supported by this driver, have a look - on the Linux-DVB Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_DIB0700 - tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" - depends on DVB_USB - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_DIB7000M if !DVB_FE_CUSTOMISE - select DVB_DIB8000 if !DVB_FE_CUSTOMISE - select DVB_DIB3000MC if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - help - Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The - USB bridge is also present in devices having the DiB7700 DVB-T-USB - silicon. This chip can be found in devices offered by Hauppauge, - Avermedia and other big and small companies. - - For an up-to-date list of devices supported by this driver, have a look - on the LinuxTV Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_UMT_010 - tristate "HanfTek UMT-010 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - help - Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. - -config DVB_USB_CXUSB - tristate "Conexant USB2.0 hybrid reference design support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_CX22702 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select DVB_ATBM8830 if !DVB_FE_CUSTOMISE - select DVB_LGS8GXX if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Conexant USB2.0 hybrid reference design. - Currently, only DVB and ATSC modes are supported, analog mode - shall be added in the future. Devices that require this module: - - Medion MD95700 hybrid USB2.0 device. - DViCO FusionHDTV (Bluebird) USB2.0 devices - -config DVB_USB_M920X - tristate "Uli m920x DVB-T USB2.0 support" - depends on DVB_USB - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. - Currently, only devices with a product id of - "DTV USB MINI" (in cold state) are supported. - Firmware required. - -config DVB_USB_DIGITV - tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_NXT6000 if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - help - Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. - -config DVB_USB_VP7045 - tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" - depends on DVB_USB - help - Say Y here to support the - - TwinhanDTV Alpha (stick) (VP-7045), - TwinhanDTV MagicBox II (VP-7046), - DigitalNow TinyUSB 2 DVB-t, - DigitalRise USB 2.0 Ter (Beetle) and - TYPHOON DVB-T USB DRIVE - - DVB-T USB2.0 receivers. - -config DVB_USB_VP702X - tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" - depends on DVB_USB - help - Say Y here to support the - - TwinhanDTV StarBox, - DigitalRise USB Starbox and - TYPHOON DVB-S USB 2.0 BOX - - DVB-S USB2.0 receivers. - -config DVB_USB_GP8PSK - tristate "GENPIX 8PSK->USB module support" - depends on DVB_USB - help - Say Y here to support the - GENPIX 8psk module - - DVB-S USB2.0 receivers. - -config DVB_USB_NOVA_T_USB2 - tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_DIB3000MC - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. - -config DVB_USB_TTUSB2 - tristate "Pinnacle 400e DVB-S USB2.0 support" - depends on DVB_USB - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - help - Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The - firmware protocol used by this module is similar to the one used by the - old ttusb-driver - that's why the module is called dvb-usb-ttusb2. - -config DVB_USB_DTT200U - tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" - depends on DVB_USB - help - Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. - - The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). - - The WT-220U and its clones are pen-sized. - -config DVB_USB_OPERA1 - tristate "Opera1 DVB-S USB2.0 receiver" - depends on DVB_USB - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE - help - Say Y here to support the Opera DVB-S USB2.0 receiver. - -config DVB_USB_AF9005 - tristate "Afatech AF9005 DVB-T USB1.1 support" - depends on DVB_USB && EXPERIMENTAL - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver - and the TerraTec Cinergy T USB XE (Rev.1) - -config DVB_USB_AF9005_REMOTE - tristate "Afatech AF9005 default remote control support" - depends on DVB_USB_AF9005 - help - Say Y here to support the default remote control decoding for the - Afatech AF9005 based receiver. - -config DVB_USB_PCTV452E - tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600" - depends on DVB_USB - select TTPCI_EEPROM - select DVB_LNBP22 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - help - Support for external USB adapter designed by Pinnacle, - shipped under the brand name 'PCTV HDTV Pro USB'. - Also supports TT Connect S2-3600/3650 cards. - Say Y if you own such a device and want to use it. - -config DVB_USB_DW2102 - tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_ZL10039 if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - help - Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 - receivers. - -config DVB_USB_CINERGY_T2 - tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" - depends on DVB_USB - help - Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers - - Say Y if you own such a device and want to use it. - -config DVB_USB_DTV5100 - tristate "AME DTV-5100 USB2.0 DVB-T support" - depends on DVB_USB - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the AME DTV-5100 USB2.0 DVB-T 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. - -config DVB_USB_AZ6027 - tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" - depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - help - Say Y here to support the AZ6027 device - -config DVB_USB_TECHNISAT_USB2 - tristate "Technisat DVB-S/S2 USB2.0 support" - depends on DVB_USB - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - help - Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile deleted file mode 100644 index a5630e30ead..00000000000 --- a/drivers/media/dvb/dvb-usb/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o -obj-$(CONFIG_DVB_USB) += dvb-usb.o - -dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o -obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o - -dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o -obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o - -dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o -obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o - -dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o -obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o - -dvb-usb-dibusb-common-objs = dibusb-common.o - -dvb-usb-a800-objs = a800.o -obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o - -dvb-usb-dibusb-mb-objs = dibusb-mb.o -obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o - -dvb-usb-dibusb-mc-objs = dibusb-mc.o -obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o - -dvb-usb-nova-t-usb2-objs = nova-t-usb2.o -obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o - -dvb-usb-umt-010-objs = umt-010.o -obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o - -dvb-usb-m920x-objs = m920x.o -obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o - -dvb-usb-digitv-objs = digitv.o -obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o - -dvb-usb-cxusb-objs = cxusb.o -obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o - -dvb-usb-ttusb2-objs = ttusb2.o -obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o - -dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o -obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o - -dvb-usb-opera-objs = opera1.o -obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o - -dvb-usb-af9005-objs = af9005.o af9005-fe.o -obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o - -dvb-usb-af9005-remote-objs = af9005-remote.o -obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o - -dvb-usb-pctv452e-objs = pctv452e.o -obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o - -dvb-usb-dw2102-objs = dw2102.o -obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o - -dvb-usb-dtv5100-objs = dtv5100.o -obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o - -dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o -obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o - -dvb-usb-friio-objs = friio.o friio-fe.o -obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o - -dvb-usb-az6027-objs = az6027.o -obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o - -dvb-usb-technisat-usb2-objs = technisat-usb2.o -obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o - -ccflags-y += -I$(srctree)/drivers/media/dvb-core -ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/ -# due to tuner-xc3028 -ccflags-y += -I$(srctree)/drivers/media/common/tuners -ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c deleted file mode 100644 index 8d7fef84afd..00000000000 --- a/drivers/media/dvb/dvb-usb/a800.c +++ /dev/null @@ -1,191 +0,0 @@ -/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T - * USB2.0 (A800) DVB-T receiver. - * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to - * - AVerMedia who kindly provided information and - * - Glen Harris who suffered from my mistakes during development. - * - * 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 "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_rc(args...) dprintk(debug,0x01,args) - -static int a800_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - /* do nothing for the AVerMedia */ - return 0; -} - -/* assure to put cold to 0 for iManufacturer == 1 */ -static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - *cold = udev->descriptor.iManufacturer != 1; - return 0; -} - -static struct rc_map_table rc_map_a800_table[] = { - { 0x0201, KEY_MODE }, /* SOURCE */ - { 0x0200, KEY_POWER2 }, /* POWER */ - { 0x0205, KEY_1 }, /* 1 */ - { 0x0206, KEY_2 }, /* 2 */ - { 0x0207, KEY_3 }, /* 3 */ - { 0x0209, KEY_4 }, /* 4 */ - { 0x020a, KEY_5 }, /* 5 */ - { 0x020b, KEY_6 }, /* 6 */ - { 0x020d, KEY_7 }, /* 7 */ - { 0x020e, KEY_8 }, /* 8 */ - { 0x020f, KEY_9 }, /* 9 */ - { 0x0212, KEY_LEFT }, /* L / DISPLAY */ - { 0x0211, KEY_0 }, /* 0 */ - { 0x0213, KEY_RIGHT }, /* R / CH RTN */ - { 0x0217, KEY_CAMERA }, /* SNAP SHOT */ - { 0x0210, KEY_LAST }, /* 16-CH PREV */ - { 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */ - { 0x020c, KEY_ZOOM }, /* FULL SCREEN */ - { 0x021f, KEY_VOLUMEUP }, /* VOL UP */ - { 0x0214, KEY_MUTE }, /* MUTE */ - { 0x0208, KEY_AUDIO }, /* AUDIO */ - { 0x0219, KEY_RECORD }, /* RECORD */ - { 0x0218, KEY_PLAY }, /* PLAY */ - { 0x021b, KEY_STOP }, /* STOP */ - { 0x021a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ - { 0x021d, KEY_BACK }, /* << / RED */ - { 0x021c, KEY_FORWARD }, /* >> / YELLOW */ - { 0x0203, KEY_TEXT }, /* TELETEXT */ - { 0x0204, KEY_EPG }, /* EPG */ - { 0x0215, KEY_MENU }, /* MENU */ - - { 0x0303, KEY_CHANNELUP }, /* CH UP */ - { 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */ - { 0x0301, KEY_FIRST }, /* |<< / GREEN */ - { 0x0300, KEY_LAST }, /* >>| / BLUE */ - -}; - -static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - int ret; - u8 *key = kmalloc(5, GFP_KERNEL); - if (!key) - return -ENOMEM; - - if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), - 0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5, - 2000) != 5) { - ret = -ENODEV; - goto out; - } - - /* call the universal NEC remote processor, to find out the key's state and event */ - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - ret = 0; -out: - kfree(key); - return ret; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties a800_properties; - -static int a800_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &a800_properties, - THIS_MODULE, NULL, adapter_nr); -} - -/* do not change the order of the ID table */ -static struct usb_device_id a800_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, a800_table); - -static struct dvb_usb_device_properties a800_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-avertv-a800-02.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - }, - }, - - .power_ctrl = a800_power_ctrl, - .identify_state = a800_identify_state, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_a800_table, - .rc_map_size = ARRAY_SIZE(rc_map_a800_table), - .rc_query = a800_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, - .devices = { - { "AVerMedia AverTV DVB-T USB 2.0 (A800)", - { &a800_table[0], NULL }, - { &a800_table[1], NULL }, - }, - } -}; - -static struct usb_driver a800_driver = { - .name = "dvb_usb_a800", - .probe = a800_probe, - .disconnect = dvb_usb_device_exit, - .id_table = a800_table, -}; - -module_usb_driver(a800_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c deleted file mode 100644 index 740f3f496f1..00000000000 --- a/drivers/media/dvb/dvb-usb/af9005-fe.c +++ /dev/null @@ -1,1487 +0,0 @@ -/* Frontend part of the Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "af9005.h" -#include "af9005-script.h" -#include "mt2060.h" -#include "qt1010.h" -#include - -struct af9005_fe_state { - struct dvb_usb_device *d; - fe_status_t stat; - - /* retraining parameters */ - u32 original_fcw; - u16 original_rf_top; - u16 original_if_top; - u16 original_if_min; - u16 original_aci0_if_top; - u16 original_aci1_if_top; - u16 original_aci0_if_min; - u8 original_if_unplug_th; - u8 original_rf_unplug_th; - u8 original_dtop_if_unplug_th; - u8 original_dtop_rf_unplug_th; - - /* statistics */ - u32 pre_vit_error_count; - u32 pre_vit_bit_count; - u32 ber; - u32 post_vit_error_count; - u32 post_vit_bit_count; - u32 unc; - u16 abort_count; - - int opened; - int strong; - unsigned long next_status_check; - struct dvb_frontend frontend; -}; - -static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, - u16 reglo, u8 pos, u8 len, u16 value) -{ - int ret; - - if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) - return ret; - return af9005_write_register_bits(d, reghi, pos, len, - (u8) ((value & 0x300) >> 8)); -} - -static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi, - u16 reglo, u8 pos, u8 len, u16 * value) -{ - int ret; - u8 temp0, temp1; - - if ((ret = af9005_read_ofdm_register(d, reglo, &temp0))) - return ret; - if ((ret = af9005_read_ofdm_register(d, reghi, &temp1))) - return ret; - switch (pos) { - case 0: - *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0; - break; - case 2: - *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0; - break; - case 4: - *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0; - break; - case 6: - *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0; - break; - default: - err("invalid pos in read word agc"); - return -EINVAL; - } - return 0; - -} - -static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 temp; - - *available = false; - - ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, - fec_vtb_rsd_mon_en_pos, - fec_vtb_rsd_mon_en_len, &temp); - if (ret) - return ret; - if (temp & 1) { - ret = - af9005_read_register_bits(state->d, - xd_p_reg_ofsm_read_rbc_en, - reg_ofsm_read_rbc_en_pos, - reg_ofsm_read_rbc_en_len, &temp); - if (ret) - return ret; - if ((temp & 1) == 0) - *available = true; - - } - return 0; -} - -static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe, - u32 * post_err_count, - u32 * post_cw_count, - u16 * abort_count) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u32 err_count; - u32 cw_count; - u8 temp, temp0, temp1, temp2; - u16 loc_abort_count; - - *post_err_count = 0; - *post_cw_count = 0; - - /* check if error bit count is ready */ - ret = - af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy, - fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len, - &temp); - if (ret) - return ret; - if (!temp) { - deb_info("rsd counter not ready\n"); - return 100; - } - /* get abort count */ - ret = - af9005_read_ofdm_register(state->d, - xd_r_fec_rsd_abort_packet_cnt_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, - xd_r_fec_rsd_abort_packet_cnt_15_8, - &temp1); - if (ret) - return ret; - loc_abort_count = ((u16) temp1 << 8) + temp0; - - /* get error count */ - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8, - &temp1); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16, - &temp2); - if (ret) - return ret; - err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; - *post_err_count = err_count - (u32) loc_abort_count *8 * 8; - - /* get RSD packet number */ - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, - &temp1); - if (ret) - return ret; - cw_count = ((u32) temp1 << 8) + temp0; - if (cw_count == 0) { - err("wrong RSD packet count"); - return -EIO; - } - deb_info("POST abort count %d err count %d rsd packets %d\n", - loc_abort_count, err_count, cw_count); - *post_cw_count = cw_count - (u32) loc_abort_count; - *abort_count = loc_abort_count; - return 0; - -} - -static int af9005_get_post_vit_ber(struct dvb_frontend *fe, - u32 * post_err_count, u32 * post_cw_count, - u16 * abort_count) -{ - u32 loc_cw_count = 0, loc_err_count; - u16 loc_abort_count = 0; - int ret; - - ret = - af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count, - &loc_abort_count); - if (ret) - return ret; - *post_err_count = loc_err_count; - *post_cw_count = loc_cw_count * 204 * 8; - *abort_count = loc_abort_count; - - return 0; -} - -static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, - u32 * pre_err_count, - u32 * pre_bit_count) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - u8 temp, temp0, temp1, temp2; - u32 super_frame_count, x, bits; - int ret; - - ret = - af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy, - fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len, - &temp); - if (ret) - return ret; - if (!temp) { - deb_info("viterbi counter not ready\n"); - return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */ - } - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8, - &temp1); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16, - &temp2); - if (ret) - return ret; - *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; - - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, - &temp1); - if (ret) - return ret; - super_frame_count = ((u32) temp1 << 8) + temp0; - if (super_frame_count == 0) { - deb_info("super frame count 0\n"); - return 102; - } - - /* read fft mode */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, - reg_tpsd_txmod_pos, reg_tpsd_txmod_len, - &temp); - if (ret) - return ret; - if (temp == 0) { - /* 2K */ - x = 1512; - } else if (temp == 1) { - /* 8k */ - x = 6048; - } else { - err("Invalid fft mode"); - return -EINVAL; - } - - /* read modulation mode */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, - reg_tpsd_const_pos, reg_tpsd_const_len, - &temp); - if (ret) - return ret; - switch (temp) { - case 0: /* QPSK */ - bits = 2; - break; - case 1: /* QAM_16 */ - bits = 4; - break; - case 2: /* QAM_64 */ - bits = 6; - break; - default: - err("invalid modulation mode"); - return -EINVAL; - } - *pre_bit_count = super_frame_count * 68 * 4 * x * bits; - deb_info("PRE err count %d frame count %d bit count %d\n", - *pre_err_count, super_frame_count, *pre_bit_count); - return 0; -} - -static int af9005_reset_pre_viterbi(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - - /* set super frame count to 1 */ - ret = - af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, - 1 & 0xff); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, - 1 >> 8); - if (ret) - return ret; - /* reset pre viterbi error count */ - ret = - af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst, - fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len, - 1); - - return ret; -} - -static int af9005_reset_post_viterbi(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - - /* set packet unit */ - ret = - af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, - 10000 & 0xff); - if (ret) - return ret; - ret = - af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, - 10000 >> 8); - if (ret) - return ret; - /* reset post viterbi error count */ - ret = - af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst, - fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len, - 1); - - return ret; -} - -static int af9005_get_statistic(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret, fecavailable; - u64 numerator, denominator; - - deb_info("GET STATISTIC\n"); - ret = af9005_is_fecmon_available(fe, &fecavailable); - if (ret) - return ret; - if (!fecavailable) { - deb_info("fecmon not available\n"); - return 0; - } - - ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count, - &state->pre_vit_bit_count); - if (ret == 0) { - af9005_reset_pre_viterbi(fe); - if (state->pre_vit_bit_count > 0) { - /* according to v 0.0.4 of the dvb api ber should be a multiple - of 10E-9 so we have to multiply the error count by - 10E9=1000000000 */ - numerator = - (u64) state->pre_vit_error_count * (u64) 1000000000; - denominator = (u64) state->pre_vit_bit_count; - state->ber = do_div(numerator, denominator); - } else { - state->ber = 0xffffffff; - } - } - - ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count, - &state->post_vit_bit_count, - &state->abort_count); - if (ret == 0) { - ret = af9005_reset_post_viterbi(fe); - state->unc += state->abort_count; - if (ret) - return ret; - } - return 0; -} - -static int af9005_fe_refresh_state(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - if (time_after(jiffies, state->next_status_check)) { - deb_info("REFRESH STATE\n"); - - /* statistics */ - if (af9005_get_statistic(fe)) - err("get_statistic_failed"); - state->next_status_check = jiffies + 250 * HZ / 1000; - } - return 0; -} - -static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - u8 temp; - int ret; - - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - - *stat = 0; - ret = af9005_read_register_bits(state->d, xd_p_agc_lock, - agc_lock_pos, agc_lock_len, &temp); - if (ret) - return ret; - if (temp) - *stat |= FE_HAS_SIGNAL; - - ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock, - fd_tpsd_lock_pos, fd_tpsd_lock_len, - &temp); - if (ret) - return ret; - if (temp) - *stat |= FE_HAS_CARRIER; - - ret = af9005_read_register_bits(state->d, - xd_r_mp2if_sync_byte_locked, - mp2if_sync_byte_locked_pos, - mp2if_sync_byte_locked_pos, &temp); - if (ret) - return ret; - if (temp) - *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; - if (state->opened) - af9005_led_control(state->d, *stat & FE_HAS_LOCK); - - ret = - af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected, - reg_strong_sginal_detected_pos, - reg_strong_sginal_detected_len, &temp); - if (ret) - return ret; - if (temp != state->strong) { - deb_info("adjust for strong signal %d\n", temp); - state->strong = temp; - } - return 0; -} - -static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - af9005_fe_refresh_state(fe); - *ber = state->ber; - return 0; -} - -static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - af9005_fe_refresh_state(fe); - *unc = state->unc; - return 0; -} - -static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, - u16 * strength) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 if_gain, rf_gain; - - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - ret = - af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain, - &rf_gain); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain, - &if_gain); - if (ret) - return ret; - /* this value has no real meaning, but i don't have the tables that relate - the rf and if gain with the dbm, so I just scale the value */ - *strength = (512 - rf_gain - if_gain) << 7; - return 0; -} - -static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) -{ - /* the snr can be derived from the ber and the modulation - but I don't think this kind of complex calculations belong - in the driver. I may be wrong.... */ - return -ENOSYS; -} - -static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw) -{ - u8 temp0, temp1, temp2, temp3, buf[4]; - int ret; - u32 NS_coeff1_2048Nu; - u32 NS_coeff1_8191Nu; - u32 NS_coeff1_8192Nu; - u32 NS_coeff1_8193Nu; - u32 NS_coeff2_2k; - u32 NS_coeff2_8k; - - switch (bw) { - case 6000000: - NS_coeff1_2048Nu = 0x2ADB6DC; - NS_coeff1_8191Nu = 0xAB7313; - NS_coeff1_8192Nu = 0xAB6DB7; - NS_coeff1_8193Nu = 0xAB685C; - NS_coeff2_2k = 0x156DB6E; - NS_coeff2_8k = 0x55B6DC; - break; - - case 7000000: - NS_coeff1_2048Nu = 0x3200001; - NS_coeff1_8191Nu = 0xC80640; - NS_coeff1_8192Nu = 0xC80000; - NS_coeff1_8193Nu = 0xC7F9C0; - NS_coeff2_2k = 0x1900000; - NS_coeff2_8k = 0x640000; - break; - - case 8000000: - NS_coeff1_2048Nu = 0x3924926; - NS_coeff1_8191Nu = 0xE4996E; - NS_coeff1_8192Nu = 0xE49249; - NS_coeff1_8193Nu = 0xE48B25; - NS_coeff2_2k = 0x1C92493; - NS_coeff2_8k = 0x724925; - break; - default: - err("Invalid bandwidth %d.", bw); - return -EINVAL; - } - - /* - * write NS_coeff1_2048Nu - */ - - temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF); - temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16); - temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - /* cfoe_NS_2k_coeff1_25_24 */ - ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]); - if (ret) - return ret; - - /* cfoe_NS_2k_coeff1_23_16 */ - ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]); - if (ret) - return ret; - - /* cfoe_NS_2k_coeff1_15_8 */ - ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]); - if (ret) - return ret; - - /* cfoe_NS_2k_coeff1_7_0 */ - ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff2_2k - */ - - temp0 = (u8) ((NS_coeff2_2k & 0x0000003F)); - temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6); - temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14); - temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff1_8191Nu - */ - - temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF)); - temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16); - temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff1_8192Nu - */ - - temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF); - temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16); - temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff1_8193Nu - */ - - temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF)); - temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16); - temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff2_8k - */ - - temp0 = (u8) ((NS_coeff2_8k & 0x0000003F)); - temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6); - temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14); - temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]); - return ret; - -} - -static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw) -{ - u8 temp; - switch (bw) { - case 6000000: - temp = 0; - break; - case 7000000: - temp = 1; - break; - case 8000000: - temp = 2; - break; - default: - err("Invalid bandwidth %d.", bw); - return -EINVAL; - } - return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos, - reg_bw_len, temp); -} - -static int af9005_fe_power(struct dvb_frontend *fe, int on) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - u8 temp = on; - int ret; - deb_info("power %s tuner\n", on ? "on" : "off"); - ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); - return ret; -} - -static struct mt2060_config af9005_mt2060_config = { - 0xC0 -}; - -static struct qt1010_config af9005_qt1010_config = { - 0xC4 -}; - -static int af9005_fe_init(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - struct dvb_usb_adapter *adap = fe->dvb->priv; - int ret, i, scriptlen; - u8 temp, temp0 = 0, temp1 = 0, temp2 = 0; - u8 buf[2]; - u16 if1; - - deb_info("in af9005_fe_init\n"); - - /* reset */ - deb_info("reset\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en, - 4, 1, 0x01))) - return ret; - if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0))) - return ret; - /* clear ofdm reset */ - deb_info("clear ofdm reset\n"); - for (i = 0; i < 150; i++) { - if ((ret = - af9005_read_ofdm_register(state->d, - xd_I2C_reg_ofdm_rst, &temp))) - return ret; - if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos)) - break; - msleep(10); - } - if (i == 150) - return -ETIMEDOUT; - - /*FIXME in the dump - write B200 A9 - write xd_g_reg_ofsm_clk 7 - read eepr c6 (2) - read eepr c7 (2) - misc ctrl 3 -> 1 - read eepr ca (6) - write xd_g_reg_ofsm_clk 0 - write B200 a1 - */ - ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07); - if (ret) - return ret; - temp = 0x01; - ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1); - if (ret) - return ret; - - temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos; - if ((ret = - af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, - reg_ofdm_rst_pos, reg_ofdm_rst_len, 1))) - return ret; - ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, - reg_ofdm_rst_pos, reg_ofdm_rst_len, 0); - - if (ret) - return ret; - /* don't know what register aefc is, but this is what the windows driver does */ - ret = af9005_write_ofdm_register(state->d, 0xaefc, 0); - if (ret) - return ret; - - /* set stand alone chip */ - deb_info("set stand alone chip\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone, - reg_dca_stand_alone_pos, - reg_dca_stand_alone_len, 1))) - return ret; - - /* set dca upper & lower chip */ - deb_info("set dca upper & lower chip\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip, - reg_dca_upper_chip_pos, - reg_dca_upper_chip_len, 0))) - return ret; - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip, - reg_dca_lower_chip_pos, - reg_dca_lower_chip_len, 0))) - return ret; - - /* set 2wire master clock to 0x14 (for 60KHz) */ - deb_info("set 2wire master clock to 0x14 (for 60KHz)\n"); - if ((ret = - af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14))) - return ret; - - /* clear dca enable chip */ - deb_info("clear dca enable chip\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_en, - reg_dca_en_pos, reg_dca_en_len, 0))) - return ret; - /* FIXME these are register bits, but I don't know which ones */ - ret = af9005_write_ofdm_register(state->d, 0xa16c, 1); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0); - if (ret) - return ret; - - /* init other parameters: program cfoe and select bandwidth */ - deb_info("program cfoe\n"); - ret = af9005_fe_program_cfoe(state->d, 6000000); - if (ret) - return ret; - /* set read-update bit for modulation */ - deb_info("set read-update bit for modulation\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, - reg_feq_read_update_pos, - reg_feq_read_update_len, 1))) - return ret; - - /* sample code has a set MPEG TS code here - but sniffing reveals that it doesn't do it */ - - /* set read-update bit to 1 for DCA modulation */ - deb_info("set read-update bit 1 for DCA modulation\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, - reg_dca_read_update_pos, - reg_dca_read_update_len, 1))) - return ret; - - /* enable fec monitor */ - deb_info("enable fec monitor\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, - fec_vtb_rsd_mon_en_pos, - fec_vtb_rsd_mon_en_len, 1))) - return ret; - - /* FIXME should be register bits, I don't know which ones */ - ret = af9005_write_ofdm_register(state->d, 0xa601, 0); - - /* set api_retrain_never_freeze */ - deb_info("set api_retrain_never_freeze\n"); - if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01))) - return ret; - - /* load init script */ - deb_info("load init script\n"); - scriptlen = sizeof(script) / sizeof(RegDesc); - for (i = 0; i < scriptlen; i++) { - if ((ret = - af9005_write_register_bits(state->d, script[i].reg, - script[i].pos, - script[i].len, script[i].val))) - return ret; - /* save 3 bytes of original fcw */ - if (script[i].reg == 0xae18) - temp2 = script[i].val; - if (script[i].reg == 0xae19) - temp1 = script[i].val; - if (script[i].reg == 0xae1a) - temp0 = script[i].val; - - /* save original unplug threshold */ - if (script[i].reg == xd_p_reg_unplug_th) - state->original_if_unplug_th = script[i].val; - if (script[i].reg == xd_p_reg_unplug_rf_gain_th) - state->original_rf_unplug_th = script[i].val; - if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th) - state->original_dtop_if_unplug_th = script[i].val; - if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th) - state->original_dtop_rf_unplug_th = script[i].val; - - } - state->original_fcw = - ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0; - - - /* save original TOPs */ - deb_info("save original TOPs\n"); - - /* RF TOP */ - ret = - af9005_read_word_agc(state->d, - xd_p_reg_aagc_rf_top_numerator_9_8, - xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, - &state->original_rf_top); - if (ret) - return ret; - - /* IF TOP */ - ret = - af9005_read_word_agc(state->d, - xd_p_reg_aagc_if_top_numerator_9_8, - xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, - &state->original_if_top); - if (ret) - return ret; - - /* ACI 0 IF TOP */ - ret = - af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, - &state->original_aci0_if_top); - if (ret) - return ret; - - /* ACI 1 IF TOP */ - ret = - af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, - &state->original_aci1_if_top); - if (ret) - return ret; - - /* attach tuner and init */ - if (fe->ops.tuner_ops.release == NULL) { - /* read tuner and board id from eeprom */ - ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2); - if (ret) { - err("Impossible to read EEPROM\n"); - return ret; - } - deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]); - switch (buf[0]) { - case 2: /* MT2060 */ - /* read if1 from eeprom */ - ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2); - if (ret) { - err("Impossible to read EEPROM\n"); - return ret; - } - if1 = (u16) (buf[0] << 8) + buf[1]; - if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap, - &af9005_mt2060_config, if1) == NULL) { - deb_info("MT2060 attach failed\n"); - return -ENODEV; - } - break; - case 3: /* QT1010 */ - case 9: /* QT1010B */ - if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap, - &af9005_qt1010_config) ==NULL) { - deb_info("QT1010 attach failed\n"); - return -ENODEV; - } - break; - default: - err("Unsupported tuner type %d", buf[0]); - return -ENODEV; - } - ret = fe->ops.tuner_ops.init(fe); - if (ret) - return ret; - } - - deb_info("profit!\n"); - return 0; -} - -static int af9005_fe_sleep(struct dvb_frontend *fe) -{ - return af9005_fe_power(fe, 0); -} - -static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - - if (acquire) { - state->opened++; - } else { - - state->opened--; - if (!state->opened) - af9005_led_control(state->d, 0); - } - return 0; -} - -static int af9005_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 temp, temp0, temp1, temp2; - - deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, - fep->bandwidth_hz); - if (fe->ops.tuner_ops.release == NULL) { - err("Tuner not attached"); - return -ENODEV; - } - - deb_info("turn off led\n"); - /* not in the log */ - ret = af9005_led_control(state->d, 0); - if (ret) - return ret; - /* not sure about the bits */ - ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0); - if (ret) - return ret; - - /* set FCW to default value */ - deb_info("set FCW to default value\n"); - temp0 = (u8) (state->original_fcw & 0x000000ff); - temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8); - temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16); - ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xae19, temp1); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xae18, temp2); - if (ret) - return ret; - - /* restore original TOPs */ - deb_info("restore original TOPs\n"); - ret = - af9005_write_word_agc(state->d, - xd_p_reg_aagc_rf_top_numerator_9_8, - xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, - state->original_rf_top); - if (ret) - return ret; - ret = - af9005_write_word_agc(state->d, - xd_p_reg_aagc_if_top_numerator_9_8, - xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, - state->original_if_top); - if (ret) - return ret; - ret = - af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, - state->original_aci0_if_top); - if (ret) - return ret; - ret = - af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, - state->original_aci1_if_top); - if (ret) - return ret; - - /* select bandwidth */ - deb_info("select bandwidth"); - ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz); - if (ret) - return ret; - ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz); - if (ret) - return ret; - - /* clear easy mode flag */ - deb_info("clear easy mode flag\n"); - ret = af9005_write_ofdm_register(state->d, 0xaefd, 0); - if (ret) - return ret; - - /* set unplug threshold to original value */ - deb_info("set unplug threshold to original value\n"); - ret = - af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th, - state->original_if_unplug_th); - if (ret) - return ret; - /* set tuner */ - deb_info("set tuner\n"); - ret = fe->ops.tuner_ops.set_params(fe); - if (ret) - return ret; - - /* trigger ofsm */ - deb_info("trigger ofsm\n"); - temp = 0; - ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1); - if (ret) - return ret; - - /* clear retrain and freeze flag */ - deb_info("clear retrain and freeze flag\n"); - ret = - af9005_write_register_bits(state->d, - xd_p_reg_api_retrain_request, - reg_api_retrain_request_pos, 2, 0); - if (ret) - return ret; - - /* reset pre viterbi and post viterbi registers and statistics */ - af9005_reset_pre_viterbi(fe); - af9005_reset_post_viterbi(fe); - state->pre_vit_error_count = 0; - state->pre_vit_bit_count = 0; - state->ber = 0; - state->post_vit_error_count = 0; - /* state->unc = 0; commented out since it should be ever increasing */ - state->abort_count = 0; - - state->next_status_check = jiffies; - state->strong = -1; - - return 0; -} - -static int af9005_fe_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 temp; - - /* mode */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, - reg_tpsd_const_pos, reg_tpsd_const_len, - &temp); - if (ret) - return ret; - deb_info("===== fe_get_frontend_legacy = =============\n"); - deb_info("CONSTELLATION "); - switch (temp) { - case 0: - fep->modulation = QPSK; - deb_info("QPSK\n"); - break; - case 1: - fep->modulation = QAM_16; - deb_info("QAM_16\n"); - break; - case 2: - fep->modulation = QAM_64; - deb_info("QAM_64\n"); - break; - } - - /* tps hierarchy and alpha value */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier, - reg_tpsd_hier_pos, reg_tpsd_hier_len, - &temp); - if (ret) - return ret; - deb_info("HIERARCHY "); - switch (temp) { - case 0: - fep->hierarchy = HIERARCHY_NONE; - deb_info("NONE\n"); - break; - case 1: - fep->hierarchy = HIERARCHY_1; - deb_info("1\n"); - break; - case 2: - fep->hierarchy = HIERARCHY_2; - deb_info("2\n"); - break; - case 3: - fep->hierarchy = HIERARCHY_4; - deb_info("4\n"); - break; - } - - /* high/low priority */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_dec_pri, - reg_dec_pri_pos, reg_dec_pri_len, &temp); - if (ret) - return ret; - /* if temp is set = high priority */ - deb_info("PRIORITY %s\n", temp ? "high" : "low"); - - /* high coderate */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr, - reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len, - &temp); - if (ret) - return ret; - deb_info("CODERATE HP "); - switch (temp) { - case 0: - fep->code_rate_HP = FEC_1_2; - deb_info("FEC_1_2\n"); - break; - case 1: - fep->code_rate_HP = FEC_2_3; - deb_info("FEC_2_3\n"); - break; - case 2: - fep->code_rate_HP = FEC_3_4; - deb_info("FEC_3_4\n"); - break; - case 3: - fep->code_rate_HP = FEC_5_6; - deb_info("FEC_5_6\n"); - break; - case 4: - fep->code_rate_HP = FEC_7_8; - deb_info("FEC_7_8\n"); - break; - } - - /* low coderate */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr, - reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len, - &temp); - if (ret) - return ret; - deb_info("CODERATE LP "); - switch (temp) { - case 0: - fep->code_rate_LP = FEC_1_2; - deb_info("FEC_1_2\n"); - break; - case 1: - fep->code_rate_LP = FEC_2_3; - deb_info("FEC_2_3\n"); - break; - case 2: - fep->code_rate_LP = FEC_3_4; - deb_info("FEC_3_4\n"); - break; - case 3: - fep->code_rate_LP = FEC_5_6; - deb_info("FEC_5_6\n"); - break; - case 4: - fep->code_rate_LP = FEC_7_8; - deb_info("FEC_7_8\n"); - break; - } - - /* guard interval */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi, - reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp); - if (ret) - return ret; - deb_info("GUARD INTERVAL "); - switch (temp) { - case 0: - fep->guard_interval = GUARD_INTERVAL_1_32; - deb_info("1_32\n"); - break; - case 1: - fep->guard_interval = GUARD_INTERVAL_1_16; - deb_info("1_16\n"); - break; - case 2: - fep->guard_interval = GUARD_INTERVAL_1_8; - deb_info("1_8\n"); - break; - case 3: - fep->guard_interval = GUARD_INTERVAL_1_4; - deb_info("1_4\n"); - break; - } - - /* fft */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, - reg_tpsd_txmod_pos, reg_tpsd_txmod_len, - &temp); - if (ret) - return ret; - deb_info("TRANSMISSION MODE "); - switch (temp) { - case 0: - fep->transmission_mode = TRANSMISSION_MODE_2K; - deb_info("2K\n"); - break; - case 1: - fep->transmission_mode = TRANSMISSION_MODE_8K; - deb_info("8K\n"); - break; - } - - /* bandwidth */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos, - reg_bw_len, &temp); - deb_info("BANDWIDTH "); - switch (temp) { - case 0: - fep->bandwidth_hz = 6000000; - deb_info("6\n"); - break; - case 1: - fep->bandwidth_hz = 7000000; - deb_info("7\n"); - break; - case 2: - fep->bandwidth_hz = 8000000; - deb_info("8\n"); - break; - } - return 0; -} - -static void af9005_fe_release(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = - (struct af9005_fe_state *)fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops af9005_fe_ops; - -struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) -{ - struct af9005_fe_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL); - if (state == NULL) - goto error; - - deb_info("attaching frontend af9005\n"); - - state->d = d; - state->opened = 0; - - memcpy(&state->frontend.ops, &af9005_fe_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; - error: - return NULL; -} - -static struct dvb_frontend_ops af9005_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "AF9005 USB DVB-T", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = af9005_fe_release, - - .init = af9005_fe_init, - .sleep = af9005_fe_sleep, - .ts_bus_ctrl = af9005_ts_bus_ctrl, - - .set_frontend = af9005_fe_set_frontend, - .get_frontend = af9005_fe_get_frontend, - - .read_status = af9005_fe_read_status, - .read_ber = af9005_fe_read_ber, - .read_signal_strength = af9005_fe_read_signal_strength, - .read_snr = af9005_fe_read_snr, - .read_ucblocks = af9005_fe_read_unc_blocks, -}; diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c deleted file mode 100644 index 7e3961d0db6..00000000000 --- a/drivers/media/dvb/dvb-usb/af9005-remote.c +++ /dev/null @@ -1,157 +0,0 @@ -/* DVB USB compliant Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Standard remote decode function - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "af9005.h" -/* debug */ -static int dvb_usb_af9005_remote_debug; -module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); -MODULE_PARM_DESC(debug, - "enable (1) or disable (0) debug messages." - DVB_USB_DEBUG_STATUS); - -#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args) - -struct rc_map_table rc_map_af9005_table[] = { - - {0x01b7, KEY_POWER}, - {0x01a7, KEY_VOLUMEUP}, - {0x0187, KEY_CHANNELUP}, - {0x017f, KEY_MUTE}, - {0x01bf, KEY_VOLUMEDOWN}, - {0x013f, KEY_CHANNELDOWN}, - {0x01df, KEY_1}, - {0x015f, KEY_2}, - {0x019f, KEY_3}, - {0x011f, KEY_4}, - {0x01ef, KEY_5}, - {0x016f, KEY_6}, - {0x01af, KEY_7}, - {0x0127, KEY_8}, - {0x0107, KEY_9}, - {0x01cf, KEY_ZOOM}, - {0x014f, KEY_0}, - {0x018f, KEY_GOTO}, /* marked jump on the remote */ - - {0x00bd, KEY_POWER}, - {0x007d, KEY_VOLUMEUP}, - {0x00fd, KEY_CHANNELUP}, - {0x009d, KEY_MUTE}, - {0x005d, KEY_VOLUMEDOWN}, - {0x00dd, KEY_CHANNELDOWN}, - {0x00ad, KEY_1}, - {0x006d, KEY_2}, - {0x00ed, KEY_3}, - {0x008d, KEY_4}, - {0x004d, KEY_5}, - {0x00cd, KEY_6}, - {0x00b5, KEY_7}, - {0x0075, KEY_8}, - {0x00f5, KEY_9}, - {0x0095, KEY_ZOOM}, - {0x0055, KEY_0}, - {0x00d5, KEY_GOTO}, /* marked jump on the remote */ -}; - -int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table); - -static int repeatable_keys[] = { - KEY_VOLUMEUP, - KEY_VOLUMEDOWN, - KEY_CHANNELUP, - KEY_CHANNELDOWN -}; - -int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event, - int *state) -{ - u16 mark, space; - u32 result; - u8 cust, dat, invdat; - int i; - - if (len >= 6) { - mark = (u16) (data[0] << 8) + data[1]; - space = (u16) (data[2] << 8) + data[3]; - if (space * 3 < mark) { - for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { - if (d->last_event == repeatable_keys[i]) { - *state = REMOTE_KEY_REPEAT; - *event = d->last_event; - deb_decode("repeat key, event %x\n", - *event); - return 0; - } - } - deb_decode("repeated key ignored (non repeatable)\n"); - return 0; - } else if (len >= 33 * 4) { /*32 bits + start code */ - result = 0; - for (i = 4; i < 4 + 32 * 4; i += 4) { - result <<= 1; - mark = (u16) (data[i] << 8) + data[i + 1]; - mark >>= 1; - space = (u16) (data[i + 2] << 8) + data[i + 3]; - space >>= 1; - if (mark * 2 > space) - result += 1; - } - deb_decode("key pressed, raw value %x\n", result); - if ((result & 0xff000000) != 0xfe000000) { - deb_decode - ("doesn't start with 0xfe, ignored\n"); - return 0; - } - cust = (result >> 16) & 0xff; - dat = (result >> 8) & 0xff; - invdat = (~result) & 0xff; - if (dat != invdat) { - deb_decode("code != inverted code\n"); - return 0; - } - for (i = 0; i < rc_map_af9005_table_size; i++) { - if (rc5_custom(&rc_map_af9005_table[i]) == cust - && rc5_data(&rc_map_af9005_table[i]) == dat) { - *event = rc_map_af9005_table[i].keycode; - *state = REMOTE_KEY_PRESSED; - deb_decode - ("key pressed, event %x\n", *event); - return 0; - } - } - deb_decode("not found in table\n"); - } - } - return 0; -} - -EXPORT_SYMBOL(rc_map_af9005_table); -EXPORT_SYMBOL(rc_map_af9005_table_size); -EXPORT_SYMBOL(af9005_rc_decode); - -MODULE_AUTHOR("Luca Olivetti "); -MODULE_DESCRIPTION - ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h deleted file mode 100644 index 4d69045426d..00000000000 --- a/drivers/media/dvb/dvb-usb/af9005-script.h +++ /dev/null @@ -1,203 +0,0 @@ -/* -File automatically generated by createinit.py using data -extracted from AF05BDA.sys (windows driver): - -dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110 -python createinit.py > af9005-script.h - -*/ - -typedef struct { - u16 reg; - u8 pos; - u8 len; - u8 val; -} RegDesc; - -static RegDesc script[] = { - {0xa180, 0x0, 0x8, 0xa}, - {0xa181, 0x0, 0x8, 0xd7}, - {0xa182, 0x0, 0x8, 0xa3}, - {0xa0a0, 0x0, 0x8, 0x0}, - {0xa0a1, 0x0, 0x5, 0x0}, - {0xa0a1, 0x5, 0x1, 0x1}, - {0xa0c0, 0x0, 0x4, 0x1}, - {0xa20e, 0x4, 0x4, 0xa}, - {0xa20f, 0x0, 0x8, 0x40}, - {0xa210, 0x0, 0x8, 0x8}, - {0xa32a, 0x0, 0x4, 0xa}, - {0xa32c, 0x0, 0x8, 0x20}, - {0xa32b, 0x0, 0x8, 0x15}, - {0xa1a0, 0x1, 0x1, 0x1}, - {0xa000, 0x0, 0x1, 0x1}, - {0xa000, 0x1, 0x1, 0x0}, - {0xa001, 0x1, 0x1, 0x1}, - {0xa001, 0x0, 0x1, 0x0}, - {0xa001, 0x5, 0x1, 0x0}, - {0xa00e, 0x0, 0x5, 0x10}, - {0xa00f, 0x0, 0x3, 0x4}, - {0xa00f, 0x3, 0x3, 0x5}, - {0xa010, 0x0, 0x3, 0x4}, - {0xa010, 0x3, 0x3, 0x5}, - {0xa016, 0x4, 0x4, 0x3}, - {0xa01f, 0x0, 0x6, 0xa}, - {0xa020, 0x0, 0x6, 0xa}, - {0xa2bc, 0x0, 0x1, 0x1}, - {0xa2bc, 0x5, 0x1, 0x1}, - {0xa015, 0x0, 0x8, 0x50}, - {0xa016, 0x0, 0x1, 0x0}, - {0xa02a, 0x0, 0x8, 0x50}, - {0xa029, 0x0, 0x8, 0x4b}, - {0xa614, 0x0, 0x8, 0x46}, - {0xa002, 0x0, 0x5, 0x19}, - {0xa003, 0x0, 0x5, 0x1a}, - {0xa004, 0x0, 0x5, 0x19}, - {0xa005, 0x0, 0x5, 0x1a}, - {0xa008, 0x0, 0x8, 0x69}, - {0xa009, 0x0, 0x2, 0x2}, - {0xae1b, 0x0, 0x8, 0x69}, - {0xae1c, 0x0, 0x8, 0x2}, - {0xae1d, 0x0, 0x8, 0x2a}, - {0xa022, 0x0, 0x8, 0xaa}, - {0xa006, 0x0, 0x8, 0xc8}, - {0xa007, 0x0, 0x2, 0x0}, - {0xa00c, 0x0, 0x8, 0xba}, - {0xa00d, 0x0, 0x2, 0x2}, - {0xa608, 0x0, 0x8, 0xba}, - {0xa60e, 0x0, 0x2, 0x2}, - {0xa609, 0x0, 0x8, 0x80}, - {0xa60e, 0x2, 0x2, 0x3}, - {0xa00a, 0x0, 0x8, 0xb6}, - {0xa00b, 0x0, 0x2, 0x0}, - {0xa011, 0x0, 0x8, 0xb9}, - {0xa012, 0x0, 0x2, 0x0}, - {0xa013, 0x0, 0x8, 0xbd}, - {0xa014, 0x0, 0x2, 0x2}, - {0xa366, 0x0, 0x1, 0x1}, - {0xa2bc, 0x3, 0x1, 0x0}, - {0xa2bd, 0x0, 0x8, 0xa}, - {0xa2be, 0x0, 0x8, 0x14}, - {0xa2bf, 0x0, 0x8, 0x8}, - {0xa60a, 0x0, 0x8, 0xbd}, - {0xa60e, 0x4, 0x2, 0x2}, - {0xa60b, 0x0, 0x8, 0x86}, - {0xa60e, 0x6, 0x2, 0x3}, - {0xa001, 0x2, 0x2, 0x1}, - {0xa1c7, 0x0, 0x8, 0xf5}, - {0xa03d, 0x0, 0x8, 0xb1}, - {0xa616, 0x0, 0x8, 0xff}, - {0xa617, 0x0, 0x8, 0xad}, - {0xa618, 0x0, 0x8, 0xad}, - {0xa61e, 0x3, 0x1, 0x1}, - {0xae1a, 0x0, 0x8, 0x0}, - {0xae19, 0x0, 0x8, 0xc8}, - {0xae18, 0x0, 0x8, 0x61}, - {0xa140, 0x0, 0x8, 0x0}, - {0xa141, 0x0, 0x8, 0xc8}, - {0xa142, 0x0, 0x7, 0x61}, - {0xa023, 0x0, 0x8, 0xff}, - {0xa021, 0x0, 0x8, 0xad}, - {0xa026, 0x0, 0x1, 0x0}, - {0xa024, 0x0, 0x8, 0xff}, - {0xa025, 0x0, 0x8, 0xff}, - {0xa1c8, 0x0, 0x8, 0xf}, - {0xa2bc, 0x1, 0x1, 0x0}, - {0xa60c, 0x0, 0x4, 0x5}, - {0xa60c, 0x4, 0x4, 0x6}, - {0xa60d, 0x0, 0x8, 0xa}, - {0xa371, 0x0, 0x1, 0x1}, - {0xa366, 0x1, 0x3, 0x7}, - {0xa338, 0x0, 0x8, 0x10}, - {0xa339, 0x0, 0x6, 0x7}, - {0xa33a, 0x0, 0x6, 0x1f}, - {0xa33b, 0x0, 0x8, 0xf6}, - {0xa33c, 0x3, 0x5, 0x4}, - {0xa33d, 0x4, 0x4, 0x0}, - {0xa33d, 0x1, 0x1, 0x1}, - {0xa33d, 0x2, 0x1, 0x1}, - {0xa33d, 0x3, 0x1, 0x1}, - {0xa16d, 0x0, 0x4, 0xf}, - {0xa161, 0x0, 0x5, 0x5}, - {0xa162, 0x0, 0x4, 0x5}, - {0xa165, 0x0, 0x8, 0xff}, - {0xa166, 0x0, 0x8, 0x9c}, - {0xa2c3, 0x0, 0x4, 0x5}, - {0xa61a, 0x0, 0x6, 0xf}, - {0xb200, 0x0, 0x8, 0xa1}, - {0xb201, 0x0, 0x8, 0x7}, - {0xa093, 0x0, 0x1, 0x0}, - {0xa093, 0x1, 0x5, 0xf}, - {0xa094, 0x0, 0x8, 0xff}, - {0xa095, 0x0, 0x8, 0xf}, - {0xa080, 0x2, 0x5, 0x3}, - {0xa081, 0x0, 0x4, 0x0}, - {0xa081, 0x4, 0x4, 0x9}, - {0xa082, 0x0, 0x5, 0x1f}, - {0xa08d, 0x0, 0x8, 0x1}, - {0xa083, 0x0, 0x8, 0x32}, - {0xa084, 0x0, 0x1, 0x0}, - {0xa08e, 0x0, 0x8, 0x3}, - {0xa085, 0x0, 0x8, 0x32}, - {0xa086, 0x0, 0x3, 0x0}, - {0xa087, 0x0, 0x8, 0x6e}, - {0xa088, 0x0, 0x5, 0x15}, - {0xa089, 0x0, 0x8, 0x0}, - {0xa08a, 0x0, 0x5, 0x19}, - {0xa08b, 0x0, 0x8, 0x92}, - {0xa08c, 0x0, 0x5, 0x1c}, - {0xa120, 0x0, 0x8, 0x0}, - {0xa121, 0x0, 0x5, 0x10}, - {0xa122, 0x0, 0x8, 0x0}, - {0xa123, 0x0, 0x7, 0x40}, - {0xa123, 0x7, 0x1, 0x0}, - {0xa124, 0x0, 0x8, 0x13}, - {0xa125, 0x0, 0x7, 0x10}, - {0xa1c0, 0x0, 0x8, 0x0}, - {0xa1c1, 0x0, 0x5, 0x4}, - {0xa1c2, 0x0, 0x8, 0x0}, - {0xa1c3, 0x0, 0x5, 0x10}, - {0xa1c3, 0x5, 0x3, 0x0}, - {0xa1c4, 0x0, 0x6, 0x0}, - {0xa1c5, 0x0, 0x7, 0x10}, - {0xa100, 0x0, 0x8, 0x0}, - {0xa101, 0x0, 0x5, 0x10}, - {0xa102, 0x0, 0x8, 0x0}, - {0xa103, 0x0, 0x7, 0x40}, - {0xa103, 0x7, 0x1, 0x0}, - {0xa104, 0x0, 0x8, 0x18}, - {0xa105, 0x0, 0x7, 0xa}, - {0xa106, 0x0, 0x8, 0x20}, - {0xa107, 0x0, 0x8, 0x40}, - {0xa108, 0x0, 0x4, 0x0}, - {0xa38c, 0x0, 0x8, 0xfc}, - {0xa38d, 0x0, 0x8, 0x0}, - {0xa38e, 0x0, 0x8, 0x7e}, - {0xa38f, 0x0, 0x8, 0x0}, - {0xa390, 0x0, 0x8, 0x2f}, - {0xa60f, 0x5, 0x1, 0x1}, - {0xa170, 0x0, 0x8, 0xdc}, - {0xa171, 0x0, 0x2, 0x0}, - {0xa2ae, 0x0, 0x1, 0x1}, - {0xa2ae, 0x1, 0x1, 0x1}, - {0xa392, 0x0, 0x1, 0x1}, - {0xa391, 0x2, 0x1, 0x0}, - {0xabc1, 0x0, 0x8, 0xff}, - {0xabc2, 0x0, 0x8, 0x0}, - {0xabc8, 0x0, 0x8, 0x8}, - {0xabca, 0x0, 0x8, 0x10}, - {0xabcb, 0x0, 0x1, 0x0}, - {0xabc3, 0x5, 0x3, 0x7}, - {0xabc0, 0x6, 0x1, 0x0}, - {0xabc0, 0x4, 0x2, 0x0}, - {0xa344, 0x4, 0x4, 0x1}, - {0xabc0, 0x7, 0x1, 0x1}, - {0xabc0, 0x2, 0x1, 0x1}, - {0xa345, 0x0, 0x8, 0x66}, - {0xa346, 0x0, 0x8, 0x66}, - {0xa347, 0x0, 0x4, 0x0}, - {0xa343, 0x0, 0x4, 0xa}, - {0xa347, 0x4, 0x4, 0x2}, - {0xa348, 0x0, 0x4, 0xc}, - {0xa348, 0x4, 0x4, 0x7}, - {0xa349, 0x0, 0x6, 0x2}, -}; diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c deleted file mode 100644 index af176b6ce73..00000000000 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ /dev/null @@ -1,1117 +0,0 @@ -/* DVB USB compliant Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "af9005.h" - -/* debug */ -int dvb_usb_af9005_debug; -module_param_named(debug, dvb_usb_af9005_debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." - DVB_USB_DEBUG_STATUS); -/* enable obnoxious led */ -bool dvb_usb_af9005_led = 1; -module_param_named(led, dvb_usb_af9005_led, bool, 0644); -MODULE_PARM_DESC(led, "enable led (default: 1)."); - -/* eeprom dump */ -static int dvb_usb_af9005_dump_eeprom; -module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); -MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* remote control decoder */ -static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, - u32 *event, int *state); -static void *rc_keys; -static int *rc_keys_size; - -u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; - -struct af9005_device_state { - u8 sequence; - int led_state; -}; - -static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, - int readwrite, int type, u8 * values, int len) -{ - struct af9005_device_state *st = d->priv; - u8 obuf[16] = { 0 }; - u8 ibuf[17] = { 0 }; - u8 command; - int i; - int ret; - - if (len < 1) { - err("generic read/write, less than 1 byte. Makes no sense."); - return -EINVAL; - } - if (len > 8) { - err("generic read/write, more than 8 bytes. Not supported."); - return -EINVAL; - } - - obuf[0] = 14; /* rest of buffer length low */ - obuf[1] = 0; /* rest of buffer length high */ - - obuf[2] = AF9005_REGISTER_RW; /* register operation */ - obuf[3] = 12; /* rest of buffer length */ - - obuf[4] = st->sequence++; /* sequence number */ - - obuf[5] = (u8) (reg >> 8); /* register address */ - obuf[6] = (u8) (reg & 0xff); - - if (type == AF9005_OFDM_REG) { - command = AF9005_CMD_OFDM_REG; - } else { - command = AF9005_CMD_TUNER; - } - - if (len > 1) - command |= - AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3; - command |= readwrite; - if (readwrite == AF9005_CMD_WRITE) - for (i = 0; i < len; i++) - obuf[8 + i] = values[i]; - else if (type == AF9005_TUNER_REG) - /* read command for tuner, the first byte contains the i2c address */ - obuf[8] = values[0]; - obuf[7] = command; - - ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0); - if (ret) - return ret; - - /* sanity check */ - if (ibuf[2] != AF9005_REGISTER_RW_ACK) { - err("generic read/write, wrong reply code."); - return -EIO; - } - if (ibuf[3] != 0x0d) { - err("generic read/write, wrong length in reply."); - return -EIO; - } - if (ibuf[4] != obuf[4]) { - err("generic read/write, wrong sequence in reply."); - return -EIO; - } - /* - Windows driver doesn't check these fields, in fact sometimes - the register in the reply is different that what has been sent - - if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) { - err("generic read/write, wrong register in reply."); - return -EIO; - } - if (ibuf[7] != command) { - err("generic read/write wrong command in reply."); - return -EIO; - } - */ - if (ibuf[16] != 0x01) { - err("generic read/write wrong status code in reply."); - return -EIO; - } - if (readwrite == AF9005_CMD_READ) - for (i = 0; i < len; i++) - values[i] = ibuf[8 + i]; - - return 0; - -} - -int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value) -{ - int ret; - deb_reg("read register %x ", reg); - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_READ, AF9005_OFDM_REG, - value, 1); - if (ret) - deb_reg("failed\n"); - else - deb_reg("value %x\n", *value); - return ret; -} - -int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len) -{ - int ret; - deb_reg("read %d registers %x ", len, reg); - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_READ, AF9005_OFDM_REG, - values, len); - if (ret) - deb_reg("failed\n"); - else - debug_dump(values, len, deb_reg); - return ret; -} - -int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value) -{ - int ret; - u8 temp = value; - deb_reg("write register %x value %x ", reg, value); - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_WRITE, AF9005_OFDM_REG, - &temp, 1); - if (ret) - deb_reg("failed\n"); - else - deb_reg("ok\n"); - return ret; -} - -int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len) -{ - int ret; - deb_reg("write %d registers %x values ", len, reg); - debug_dump(values, len, deb_reg); - - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_WRITE, AF9005_OFDM_REG, - values, len); - if (ret) - deb_reg("failed\n"); - else - deb_reg("ok\n"); - return ret; -} - -int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, - u8 len, u8 * value) -{ - u8 temp; - int ret; - deb_reg("read bits %x %x %x", reg, pos, len); - ret = af9005_read_ofdm_register(d, reg, &temp); - if (ret) { - deb_reg(" failed\n"); - return ret; - } - *value = (temp >> pos) & regmask[len - 1]; - deb_reg(" value %x\n", *value); - return 0; - -} - -int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, - u8 len, u8 value) -{ - u8 temp, mask; - int ret; - deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value); - if (pos == 0 && len == 8) - return af9005_write_ofdm_register(d, reg, value); - ret = af9005_read_ofdm_register(d, reg, &temp); - if (ret) - return ret; - mask = regmask[len - 1] << pos; - temp = (temp & ~mask) | ((value << pos) & mask); - return af9005_write_ofdm_register(d, reg, temp); - -} - -static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d, - u16 reg, u8 * values, int len) -{ - return af9005_generic_read_write(d, reg, - AF9005_CMD_READ, AF9005_TUNER_REG, - values, len); -} - -static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d, - u16 reg, u8 * values, int len) -{ - return af9005_generic_read_write(d, reg, - AF9005_CMD_WRITE, - AF9005_TUNER_REG, values, len); -} - -int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len) -{ - /* don't let the name of this function mislead you: it's just used - as an interface from the firmware to the i2c bus. The actual - i2c addresses are contained in the data */ - int ret, i, done = 0, fail = 0; - u8 temp; - ret = af9005_usb_write_tuner_registers(d, reg, values, len); - if (ret) - return ret; - if (reg != 0xffff) { - /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */ - for (i = 0; i < 200; i++) { - ret = - af9005_read_ofdm_register(d, - xd_I2C_i2c_m_status_wdat_done, - &temp); - if (ret) - return ret; - done = temp & (regmask[i2c_m_status_wdat_done_len - 1] - << i2c_m_status_wdat_done_pos); - if (done) - break; - fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1] - << i2c_m_status_wdat_fail_pos); - if (fail) - break; - msleep(50); - } - if (i == 200) - return -ETIMEDOUT; - if (fail) { - /* clear write fail bit */ - af9005_write_register_bits(d, - xd_I2C_i2c_m_status_wdat_fail, - i2c_m_status_wdat_fail_pos, - i2c_m_status_wdat_fail_len, - 1); - return -EIO; - } - /* clear write done bit */ - ret = - af9005_write_register_bits(d, - xd_I2C_i2c_m_status_wdat_fail, - i2c_m_status_wdat_done_pos, - i2c_m_status_wdat_done_len, 1); - if (ret) - return ret; - } - return 0; -} - -int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr, - u8 * values, int len) -{ - /* don't let the name of this function mislead you: it's just used - as an interface from the firmware to the i2c bus. The actual - i2c addresses are contained in the data */ - int ret, i; - u8 temp, buf[2]; - - buf[0] = addr; /* tuner i2c address */ - buf[1] = values[0]; /* tuner register */ - - values[0] = addr + 0x01; /* i2c read address */ - - if (reg == APO_REG_I2C_RW_SILICON_TUNER) { - /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */ - ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2); - if (ret) - return ret; - } - - /* send read command to ofsm */ - ret = af9005_usb_read_tuner_registers(d, reg, values, 1); - if (ret) - return ret; - - /* check if read done */ - for (i = 0; i < 200; i++) { - ret = af9005_read_ofdm_register(d, 0xa408, &temp); - if (ret) - return ret; - if (temp & 0x01) - break; - msleep(50); - } - if (i == 200) - return -ETIMEDOUT; - - /* clear read done bit (by writing 1) */ - ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1); - if (ret) - return ret; - - /* get read data (available from 0xa400) */ - for (i = 0; i < len; i++) { - ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp); - if (ret) - return ret; - values[i] = temp; - } - return 0; -} - -static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg, - u8 * data, int len) -{ - int ret, i; - u8 buf[3]; - deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr, - reg, len); - debug_dump(data, len, deb_i2c); - - for (i = 0; i < len; i++) { - buf[0] = i2caddr; - buf[1] = reg + (u8) i; - buf[2] = data[i]; - ret = - af9005_write_tuner_registers(d, - APO_REG_I2C_RW_SILICON_TUNER, - buf, 3); - if (ret) { - deb_i2c("i2c_write failed\n"); - return ret; - } - } - deb_i2c("i2c_write ok\n"); - return 0; -} - -static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg, - u8 * data, int len) -{ - int ret, i; - u8 temp; - deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len); - for (i = 0; i < len; i++) { - temp = reg + i; - ret = - af9005_read_tuner_registers(d, - APO_REG_I2C_RW_SILICON_TUNER, - i2caddr, &temp, 1); - if (ret) { - deb_i2c("i2c_read failed\n"); - return ret; - } - data[i] = temp; - } - deb_i2c("i2c data read: "); - debug_dump(data, len, deb_i2c); - return 0; -} - -static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - /* only implements what the mt2060 module does, don't know how - to make it really generic */ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret; - u8 reg, addr; - u8 *value; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - if (num == 2) { - /* reads a single register */ - reg = *msg[0].buf; - addr = msg[0].addr; - value = msg[1].buf; - ret = af9005_i2c_read(d, addr, reg, value, 1); - if (ret == 0) - ret = 2; - } else { - /* write one or more registers */ - reg = msg[0].buf[0]; - addr = msg[0].addr; - value = &msg[0].buf[1]; - ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1); - if (ret == 0) - ret = 1; - } - - mutex_unlock(&d->i2c_mutex); - return ret; -} - -static u32 af9005_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9005_i2c_algo = { - .master_xfer = af9005_i2c_xfer, - .functionality = af9005_i2c_func, -}; - -int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf, - int wlen, u8 * rbuf, int rlen) -{ - struct af9005_device_state *st = d->priv; - - int ret, i, packet_len; - u8 buf[64]; - u8 ibuf[64]; - - if (wlen < 0) { - err("send command, wlen less than 0 bytes. Makes no sense."); - return -EINVAL; - } - if (wlen > 54) { - err("send command, wlen more than 54 bytes. Not supported."); - return -EINVAL; - } - if (rlen > 54) { - err("send command, rlen more than 54 bytes. Not supported."); - return -EINVAL; - } - packet_len = wlen + 5; - buf[0] = (u8) (packet_len & 0xff); - buf[1] = (u8) ((packet_len & 0xff00) >> 8); - - buf[2] = 0x26; /* packet type */ - buf[3] = wlen + 3; - buf[4] = st->sequence++; - buf[5] = command; - buf[6] = wlen; - for (i = 0; i < wlen; i++) - buf[7 + i] = wbuf[i]; - ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0); - if (ret) - return ret; - if (ibuf[2] != 0x27) { - err("send command, wrong reply code."); - return -EIO; - } - if (ibuf[4] != buf[4]) { - err("send command, wrong sequence in reply."); - return -EIO; - } - if (ibuf[5] != 0x01) { - err("send command, wrong status code in reply."); - return -EIO; - } - if (ibuf[6] != rlen) { - err("send command, invalid data length in reply."); - return -EIO; - } - for (i = 0; i < rlen; i++) - rbuf[i] = ibuf[i + 7]; - return 0; -} - -int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values, - int len) -{ - struct af9005_device_state *st = d->priv; - u8 obuf[16], ibuf[14]; - int ret, i; - - memset(obuf, 0, sizeof(obuf)); - memset(ibuf, 0, sizeof(ibuf)); - - obuf[0] = 14; /* length of rest of packet low */ - obuf[1] = 0; /* length of rest of packer high */ - - obuf[2] = 0x2a; /* read/write eeprom */ - - obuf[3] = 12; /* size */ - - obuf[4] = st->sequence++; - - obuf[5] = 0; /* read */ - - obuf[6] = len; - obuf[7] = address; - ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0); - if (ret) - return ret; - if (ibuf[2] != 0x2b) { - err("Read eeprom, invalid reply code"); - return -EIO; - } - if (ibuf[3] != 10) { - err("Read eeprom, invalid reply length"); - return -EIO; - } - if (ibuf[4] != obuf[4]) { - err("Read eeprom, wrong sequence in reply "); - return -EIO; - } - if (ibuf[5] != 1) { - err("Read eeprom, wrong status in reply "); - return -EIO; - } - for (i = 0; i < len; i++) { - values[i] = ibuf[6 + i]; - } - return 0; -} - -static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) -{ - u8 buf[FW_BULKOUT_SIZE + 2]; - u16 checksum; - int act_len, i, ret; - memset(buf, 0, sizeof(buf)); - buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); - buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); - switch (type) { - case FW_CONFIG: - buf[2] = 0x11; - buf[3] = 0x04; - buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ - buf[5] = 0x03; - checksum = buf[4] + buf[5]; - buf[6] = (u8) ((checksum >> 8) & 0xff); - buf[7] = (u8) (checksum & 0xff); - break; - case FW_CONFIRM: - buf[2] = 0x11; - buf[3] = 0x04; - buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ - buf[5] = 0x01; - checksum = buf[4] + buf[5]; - buf[6] = (u8) ((checksum >> 8) & 0xff); - buf[7] = (u8) (checksum & 0xff); - break; - case FW_BOOT: - buf[2] = 0x10; - buf[3] = 0x08; - buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ - buf[5] = 0x97; - buf[6] = 0xaa; - buf[7] = 0x55; - buf[8] = 0xa5; - buf[9] = 0x5a; - checksum = 0; - for (i = 4; i <= 9; i++) - checksum += buf[i]; - buf[10] = (u8) ((checksum >> 8) & 0xff); - buf[11] = (u8) (checksum & 0xff); - break; - default: - err("boot packet invalid boot packet type"); - return -EINVAL; - } - deb_fw(">>> "); - debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); - - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x02), - buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); - if (ret) - err("boot packet bulk message failed: %d (%d/%d)", ret, - FW_BULKOUT_SIZE + 2, act_len); - else - ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; - if (ret) - return ret; - memset(buf, 0, 9); - ret = usb_bulk_msg(udev, - usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); - if (ret) { - err("boot packet recv bulk message failed: %d", ret); - return ret; - } - deb_fw("<<< "); - debug_dump(buf, act_len, deb_fw); - checksum = 0; - switch (type) { - case FW_CONFIG: - if (buf[2] != 0x11) { - err("boot bad config header."); - return -EIO; - } - if (buf[3] != 0x05) { - err("boot bad config size."); - return -EIO; - } - if (buf[4] != 0x00) { - err("boot bad config sequence."); - return -EIO; - } - if (buf[5] != 0x04) { - err("boot bad config subtype."); - return -EIO; - } - for (i = 4; i <= 6; i++) - checksum += buf[i]; - if (buf[7] * 256 + buf[8] != checksum) { - err("boot bad config checksum."); - return -EIO; - } - *reply = buf[6]; - break; - case FW_CONFIRM: - if (buf[2] != 0x11) { - err("boot bad confirm header."); - return -EIO; - } - if (buf[3] != 0x05) { - err("boot bad confirm size."); - return -EIO; - } - if (buf[4] != 0x00) { - err("boot bad confirm sequence."); - return -EIO; - } - if (buf[5] != 0x02) { - err("boot bad confirm subtype."); - return -EIO; - } - for (i = 4; i <= 6; i++) - checksum += buf[i]; - if (buf[7] * 256 + buf[8] != checksum) { - err("boot bad confirm checksum."); - return -EIO; - } - *reply = buf[6]; - break; - case FW_BOOT: - if (buf[2] != 0x10) { - err("boot bad boot header."); - return -EIO; - } - if (buf[3] != 0x05) { - err("boot bad boot size."); - return -EIO; - } - if (buf[4] != 0x00) { - err("boot bad boot sequence."); - return -EIO; - } - if (buf[5] != 0x01) { - err("boot bad boot pattern 01."); - return -EIO; - } - if (buf[6] != 0x10) { - err("boot bad boot pattern 10."); - return -EIO; - } - for (i = 4; i <= 6; i++) - checksum += buf[i]; - if (buf[7] * 256 + buf[8] != checksum) { - err("boot bad boot checksum."); - return -EIO; - } - break; - - } - - return 0; -} - -static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) -{ - int i, packets, ret, act_len; - - u8 buf[FW_BULKOUT_SIZE + 2]; - u8 reply; - - ret = af9005_boot_packet(udev, FW_CONFIG, &reply); - if (ret) - return ret; - if (reply != 0x01) { - err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); - return -EIO; - } - packets = fw->size / FW_BULKOUT_SIZE; - buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); - buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); - for (i = 0; i < packets; i++) { - memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, - FW_BULKOUT_SIZE); - deb_fw(">>> "); - debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x02), - buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); - if (ret) { - err("firmware download failed at packet %d with code %d", i, ret); - return ret; - } - } - ret = af9005_boot_packet(udev, FW_CONFIRM, &reply); - if (ret) - return ret; - if (reply != (u8) (packets & 0xff)) { - err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); - return -EIO; - } - ret = af9005_boot_packet(udev, FW_BOOT, &reply); - if (ret) - return ret; - ret = af9005_boot_packet(udev, FW_CONFIG, &reply); - if (ret) - return ret; - if (reply != 0x02) { - err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); - return -EIO; - } - - return 0; - -} - -int af9005_led_control(struct dvb_usb_device *d, int onoff) -{ - struct af9005_device_state *st = d->priv; - int temp, ret; - - if (onoff && dvb_usb_af9005_led) - temp = 1; - else - temp = 0; - if (st->led_state != temp) { - ret = - af9005_write_register_bits(d, xd_p_reg_top_locken1, - reg_top_locken1_pos, - reg_top_locken1_len, temp); - if (ret) - return ret; - ret = - af9005_write_register_bits(d, xd_p_reg_top_lock1, - reg_top_lock1_pos, - reg_top_lock1_len, temp); - if (ret) - return ret; - st->led_state = temp; - } - return 0; -} - -static int af9005_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 buf[8]; - int i; - - /* without these calls the first commands after downloading - the firmware fail. I put these calls here to simulate - what it is done in dvb-usb-init.c. - */ - struct usb_device *udev = adap->dev->udev; - usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); - if (dvb_usb_af9005_dump_eeprom) { - printk("EEPROM DUMP\n"); - for (i = 0; i < 255; i += 8) { - af9005_read_eeprom(adap->dev, i, buf, 8); - printk("ADDR %x ", i); - debug_dump(buf, 8, printk); - } - } - adap->fe_adap[0].fe = af9005_fe_attach(adap->dev); - return 0; -} - -static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) -{ - struct af9005_device_state *st = d->priv; - int ret, len; - - u8 obuf[5]; - u8 ibuf[256]; - - *state = REMOTE_NO_KEY_PRESSED; - if (rc_decode == NULL) { - /* it shouldn't never come here */ - return 0; - } - /* deb_info("rc_query\n"); */ - obuf[0] = 3; /* rest of packet length low */ - obuf[1] = 0; /* rest of packet lentgh high */ - obuf[2] = 0x40; /* read remote */ - obuf[3] = 1; /* rest of packet length */ - obuf[4] = st->sequence++; /* sequence number */ - ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0); - if (ret) { - err("rc query failed"); - return ret; - } - if (ibuf[2] != 0x41) { - err("rc query bad header."); - return -EIO; - } - if (ibuf[4] != obuf[4]) { - err("rc query bad sequence."); - return -EIO; - } - len = ibuf[5]; - if (len > 246) { - err("rc query invalid length"); - return -EIO; - } - if (len > 0) { - deb_rc("rc data (%d) ", len); - debug_dump((ibuf + 6), len, deb_rc); - ret = rc_decode(d, &ibuf[6], len, event, state); - if (ret) { - err("rc_decode failed"); - return ret; - } else { - deb_rc("rc_decode state %x event %x\n", *state, *event); - if (*state == REMOTE_KEY_REPEAT) - *event = d->last_event; - } - } - return 0; -} - -static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - - return 0; -} - -static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - deb_info("pid filter control onoff %d\n", onoff); - if (onoff) { - ret = - af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); - if (ret) - return ret; - ret = - af9005_write_register_bits(adap->dev, - XD_MP2IF_DMX_CTRL, 1, 1, 1); - if (ret) - return ret; - ret = - af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); - } else - ret = - af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); - if (ret) - return ret; - deb_info("pid filter control ok\n"); - return 0; -} - -static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, - u16 pid, int onoff) -{ - u8 cmd = index & 0x1f; - int ret; - deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, - pid, onoff); - if (onoff) { - /* cannot use it as pid_filter_ctrl since it has to be done - before setting the first pid */ - if (adap->feedcount == 1) { - deb_info("first pid set, enable pid table\n"); - ret = af9005_pid_filter_control(adap, onoff); - if (ret) - return ret; - } - ret = - af9005_write_ofdm_register(adap->dev, - XD_MP2IF_PID_DATA_L, - (u8) (pid & 0xff)); - if (ret) - return ret; - ret = - af9005_write_ofdm_register(adap->dev, - XD_MP2IF_PID_DATA_H, - (u8) (pid >> 8)); - if (ret) - return ret; - cmd |= 0x20 | 0x40; - } else { - if (adap->feedcount == 0) { - deb_info("last pid unset, disable pid table\n"); - ret = af9005_pid_filter_control(adap, onoff); - if (ret) - return ret; - } - } - ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); - if (ret) - return ret; - deb_info("set pid ok\n"); - return 0; -} - -static int af9005_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int ret; - u8 reply; - ret = af9005_boot_packet(udev, FW_CONFIG, &reply); - if (ret) - return ret; - deb_info("result of FW_CONFIG in identify state %d\n", reply); - if (reply == 0x01) - *cold = 1; - else if (reply == 0x02) - *cold = 0; - else - return -EIO; - deb_info("Identify state cold = %d\n", *cold); - return 0; -} - -static struct dvb_usb_device_properties af9005_properties; - -static int af9005_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &af9005_properties, - THIS_MODULE, NULL, adapter_nr); -} - -enum af9005_usb_table_entry { - AFATECH_AF9005, - TERRATEC_AF9005, - ANSONIC_AF9005, -}; - -static struct usb_device_id af9005_usb_table[] = { - [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH, - USB_PID_AFATECH_AF9005)}, - [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_USB_XE)}, - [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC, - USB_PID_ANSONIC_DVBT_USB)}, - { } -}; - -MODULE_DEVICE_TABLE(usb, af9005_usb_table); - -static struct dvb_usb_device_properties af9005_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "af9005.fw", - .download_firmware = af9005_download_firmware, - .no_reconnect = 1, - - .size_of_priv = sizeof(struct af9005_device_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = - DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = af9005_pid_filter, - /* .pid_filter_ctrl = af9005_pid_filter_control, */ - .frontend_attach = af9005_frontend_attach, - /* .tuner_attach = af9005_tuner_attach, */ - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 4096, /* actual size seen is 3948 */ - } - } - }, - }}, - } - }, - .power_ctrl = af9005_power_ctrl, - .identify_state = af9005_identify_state, - - .i2c_algo = &af9005_i2c_algo, - - .rc.legacy = { - .rc_interval = 200, - .rc_map_table = NULL, - .rc_map_size = 0, - .rc_query = af9005_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 2, - .generic_bulk_ctrl_endpoint_response = 1, - - .num_device_descs = 3, - .devices = { - {.name = "Afatech DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL}, - .warm_ids = {NULL}, - }, - {.name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL}, - .warm_ids = {NULL}, - }, - {.name = "Ansonic DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL}, - .warm_ids = {NULL}, - }, - {NULL}, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver af9005_usb_driver = { - .name = "dvb_usb_af9005", - .probe = af9005_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = af9005_usb_table, -}; - -/* module stuff */ -static int __init af9005_usb_module_init(void) -{ - int result; - if ((result = usb_register(&af9005_usb_driver))) { - err("usb_register failed. (%d)", result); - return result; - } - rc_decode = symbol_request(af9005_rc_decode); - rc_keys = symbol_request(rc_map_af9005_table); - rc_keys_size = symbol_request(rc_map_af9005_table_size); - if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { - err("af9005_rc_decode function not found, disabling remote"); - af9005_properties.rc.legacy.rc_query = NULL; - } else { - af9005_properties.rc.legacy.rc_map_table = rc_keys; - af9005_properties.rc.legacy.rc_map_size = *rc_keys_size; - } - - return 0; -} - -static void __exit af9005_usb_module_exit(void) -{ - /* release rc decode symbols */ - if (rc_decode != NULL) - symbol_put(af9005_rc_decode); - if (rc_keys != NULL) - symbol_put(rc_map_af9005_table); - if (rc_keys_size != NULL) - symbol_put(rc_map_af9005_table_size); - /* deregister this driver from the USB subsystem */ - usb_deregister(&af9005_usb_driver); -} - -module_init(af9005_usb_module_init); -module_exit(af9005_usb_module_exit); - -MODULE_AUTHOR("Luca Olivetti "); -MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h deleted file mode 100644 index 6a2bf3de845..00000000000 --- a/drivers/media/dvb/dvb-usb/af9005.h +++ /dev/null @@ -1,3496 +0,0 @@ -/* Common header-file of the Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_AF9005_H_ -#define _DVB_USB_AF9005_H_ - -#define DVB_USB_LOG_PREFIX "af9005" -#include "dvb-usb.h" - -extern int dvb_usb_af9005_debug; -#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args) -#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args) -#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) -#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) - -extern bool dvb_usb_af9005_led; - -/* firmware */ -#define FW_BULKOUT_SIZE 250 -enum { - FW_CONFIG, - FW_CONFIRM, - FW_BOOT -}; - -/* af9005 commands */ -#define AF9005_OFDM_REG 0 -#define AF9005_TUNER_REG 1 - -#define AF9005_REGISTER_RW 0x20 -#define AF9005_REGISTER_RW_ACK 0x21 - -#define AF9005_CMD_OFDM_REG 0x00 -#define AF9005_CMD_TUNER 0x80 -#define AF9005_CMD_BURST 0x02 -#define AF9005_CMD_AUTOINC 0x04 -#define AF9005_CMD_READ 0x00 -#define AF9005_CMD_WRITE 0x01 - -/* af9005 registers */ -#define APO_REG_RESET 0xAEFF - -#define APO_REG_I2C_RW_CAN_TUNER 0xF000 -#define APO_REG_I2C_RW_SILICON_TUNER 0xF001 -#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */ -#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */ - -/*********************************************************************** - * Apollo Registers from VLSI * - ***********************************************************************/ -#define xd_p_reg_aagc_inverted_agc 0xA000 -#define reg_aagc_inverted_agc_pos 0 -#define reg_aagc_inverted_agc_len 1 -#define reg_aagc_inverted_agc_lsb 0 -#define xd_p_reg_aagc_sign_only 0xA000 -#define reg_aagc_sign_only_pos 1 -#define reg_aagc_sign_only_len 1 -#define reg_aagc_sign_only_lsb 0 -#define xd_p_reg_aagc_slow_adc_en 0xA000 -#define reg_aagc_slow_adc_en_pos 2 -#define reg_aagc_slow_adc_en_len 1 -#define reg_aagc_slow_adc_en_lsb 0 -#define xd_p_reg_aagc_slow_adc_scale 0xA000 -#define reg_aagc_slow_adc_scale_pos 3 -#define reg_aagc_slow_adc_scale_len 5 -#define reg_aagc_slow_adc_scale_lsb 0 -#define xd_p_reg_aagc_check_slow_adc_lock 0xA001 -#define reg_aagc_check_slow_adc_lock_pos 0 -#define reg_aagc_check_slow_adc_lock_len 1 -#define reg_aagc_check_slow_adc_lock_lsb 0 -#define xd_p_reg_aagc_init_control 0xA001 -#define reg_aagc_init_control_pos 1 -#define reg_aagc_init_control_len 1 -#define reg_aagc_init_control_lsb 0 -#define xd_p_reg_aagc_total_gain_sel 0xA001 -#define reg_aagc_total_gain_sel_pos 2 -#define reg_aagc_total_gain_sel_len 2 -#define reg_aagc_total_gain_sel_lsb 0 -#define xd_p_reg_aagc_out_inv 0xA001 -#define reg_aagc_out_inv_pos 5 -#define reg_aagc_out_inv_len 1 -#define reg_aagc_out_inv_lsb 0 -#define xd_p_reg_aagc_int_en 0xA001 -#define reg_aagc_int_en_pos 6 -#define reg_aagc_int_en_len 1 -#define reg_aagc_int_en_lsb 0 -#define xd_p_reg_aagc_lock_change_flag 0xA001 -#define reg_aagc_lock_change_flag_pos 7 -#define reg_aagc_lock_change_flag_len 1 -#define reg_aagc_lock_change_flag_lsb 0 -#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002 -#define reg_aagc_rf_loop_bw_scale_acquire_pos 0 -#define reg_aagc_rf_loop_bw_scale_acquire_len 5 -#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0 -#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003 -#define reg_aagc_rf_loop_bw_scale_track_pos 0 -#define reg_aagc_rf_loop_bw_scale_track_len 5 -#define reg_aagc_rf_loop_bw_scale_track_lsb 0 -#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004 -#define reg_aagc_if_loop_bw_scale_acquire_pos 0 -#define reg_aagc_if_loop_bw_scale_acquire_len 5 -#define reg_aagc_if_loop_bw_scale_acquire_lsb 0 -#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005 -#define reg_aagc_if_loop_bw_scale_track_pos 0 -#define reg_aagc_if_loop_bw_scale_track_len 5 -#define reg_aagc_if_loop_bw_scale_track_lsb 0 -#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006 -#define reg_aagc_max_rf_agc_7_0_pos 0 -#define reg_aagc_max_rf_agc_7_0_len 8 -#define reg_aagc_max_rf_agc_7_0_lsb 0 -#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007 -#define reg_aagc_max_rf_agc_9_8_pos 0 -#define reg_aagc_max_rf_agc_9_8_len 2 -#define reg_aagc_max_rf_agc_9_8_lsb 8 -#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008 -#define reg_aagc_min_rf_agc_7_0_pos 0 -#define reg_aagc_min_rf_agc_7_0_len 8 -#define reg_aagc_min_rf_agc_7_0_lsb 0 -#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009 -#define reg_aagc_min_rf_agc_9_8_pos 0 -#define reg_aagc_min_rf_agc_9_8_len 2 -#define reg_aagc_min_rf_agc_9_8_lsb 8 -#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A -#define reg_aagc_max_if_agc_7_0_pos 0 -#define reg_aagc_max_if_agc_7_0_len 8 -#define reg_aagc_max_if_agc_7_0_lsb 0 -#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B -#define reg_aagc_max_if_agc_9_8_pos 0 -#define reg_aagc_max_if_agc_9_8_len 2 -#define reg_aagc_max_if_agc_9_8_lsb 8 -#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C -#define reg_aagc_min_if_agc_7_0_pos 0 -#define reg_aagc_min_if_agc_7_0_len 8 -#define reg_aagc_min_if_agc_7_0_lsb 0 -#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D -#define reg_aagc_min_if_agc_9_8_pos 0 -#define reg_aagc_min_if_agc_9_8_len 2 -#define reg_aagc_min_if_agc_9_8_lsb 8 -#define xd_p_reg_aagc_lock_sample_scale 0xA00E -#define reg_aagc_lock_sample_scale_pos 0 -#define reg_aagc_lock_sample_scale_len 5 -#define reg_aagc_lock_sample_scale_lsb 0 -#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F -#define reg_aagc_rf_agc_lock_scale_acquire_pos 0 -#define reg_aagc_rf_agc_lock_scale_acquire_len 3 -#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0 -#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F -#define reg_aagc_rf_agc_lock_scale_track_pos 3 -#define reg_aagc_rf_agc_lock_scale_track_len 3 -#define reg_aagc_rf_agc_lock_scale_track_lsb 0 -#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010 -#define reg_aagc_if_agc_lock_scale_acquire_pos 0 -#define reg_aagc_if_agc_lock_scale_acquire_len 3 -#define reg_aagc_if_agc_lock_scale_acquire_lsb 0 -#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010 -#define reg_aagc_if_agc_lock_scale_track_pos 3 -#define reg_aagc_if_agc_lock_scale_track_len 3 -#define reg_aagc_if_agc_lock_scale_track_lsb 0 -#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011 -#define reg_aagc_rf_top_numerator_7_0_pos 0 -#define reg_aagc_rf_top_numerator_7_0_len 8 -#define reg_aagc_rf_top_numerator_7_0_lsb 0 -#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012 -#define reg_aagc_rf_top_numerator_9_8_pos 0 -#define reg_aagc_rf_top_numerator_9_8_len 2 -#define reg_aagc_rf_top_numerator_9_8_lsb 8 -#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013 -#define reg_aagc_if_top_numerator_7_0_pos 0 -#define reg_aagc_if_top_numerator_7_0_len 8 -#define reg_aagc_if_top_numerator_7_0_lsb 0 -#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014 -#define reg_aagc_if_top_numerator_9_8_pos 0 -#define reg_aagc_if_top_numerator_9_8_len 2 -#define reg_aagc_if_top_numerator_9_8_lsb 8 -#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015 -#define reg_aagc_adc_out_desired_7_0_pos 0 -#define reg_aagc_adc_out_desired_7_0_len 8 -#define reg_aagc_adc_out_desired_7_0_lsb 0 -#define xd_p_reg_aagc_adc_out_desired_8 0xA016 -#define reg_aagc_adc_out_desired_8_pos 0 -#define reg_aagc_adc_out_desired_8_len 1 -#define reg_aagc_adc_out_desired_8_lsb 0 -#define xd_p_reg_aagc_fixed_gain 0xA016 -#define reg_aagc_fixed_gain_pos 3 -#define reg_aagc_fixed_gain_len 1 -#define reg_aagc_fixed_gain_lsb 0 -#define xd_p_reg_aagc_lock_count_th 0xA016 -#define reg_aagc_lock_count_th_pos 4 -#define reg_aagc_lock_count_th_len 4 -#define reg_aagc_lock_count_th_lsb 0 -#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017 -#define reg_aagc_fixed_rf_agc_control_7_0_pos 0 -#define reg_aagc_fixed_rf_agc_control_7_0_len 8 -#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0 -#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018 -#define reg_aagc_fixed_rf_agc_control_15_8_pos 0 -#define reg_aagc_fixed_rf_agc_control_15_8_len 8 -#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8 -#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019 -#define reg_aagc_fixed_rf_agc_control_23_16_pos 0 -#define reg_aagc_fixed_rf_agc_control_23_16_len 8 -#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16 -#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A -#define reg_aagc_fixed_rf_agc_control_30_24_pos 0 -#define reg_aagc_fixed_rf_agc_control_30_24_len 7 -#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24 -#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B -#define reg_aagc_fixed_if_agc_control_7_0_pos 0 -#define reg_aagc_fixed_if_agc_control_7_0_len 8 -#define reg_aagc_fixed_if_agc_control_7_0_lsb 0 -#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C -#define reg_aagc_fixed_if_agc_control_15_8_pos 0 -#define reg_aagc_fixed_if_agc_control_15_8_len 8 -#define reg_aagc_fixed_if_agc_control_15_8_lsb 8 -#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D -#define reg_aagc_fixed_if_agc_control_23_16_pos 0 -#define reg_aagc_fixed_if_agc_control_23_16_len 8 -#define reg_aagc_fixed_if_agc_control_23_16_lsb 16 -#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E -#define reg_aagc_fixed_if_agc_control_30_24_pos 0 -#define reg_aagc_fixed_if_agc_control_30_24_len 7 -#define reg_aagc_fixed_if_agc_control_30_24_lsb 24 -#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F -#define reg_aagc_rf_agc_unlock_numerator_pos 0 -#define reg_aagc_rf_agc_unlock_numerator_len 6 -#define reg_aagc_rf_agc_unlock_numerator_lsb 0 -#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020 -#define reg_aagc_if_agc_unlock_numerator_pos 0 -#define reg_aagc_if_agc_unlock_numerator_len 6 -#define reg_aagc_if_agc_unlock_numerator_lsb 0 -#define xd_p_reg_unplug_th 0xA021 -#define reg_unplug_th_pos 0 -#define reg_unplug_th_len 8 -#define reg_aagc_rf_x0_lsb 0 -#define xd_p_reg_weak_signal_rfagc_thr 0xA022 -#define reg_weak_signal_rfagc_thr_pos 0 -#define reg_weak_signal_rfagc_thr_len 8 -#define reg_weak_signal_rfagc_thr_lsb 0 -#define xd_p_reg_unplug_rf_gain_th 0xA023 -#define reg_unplug_rf_gain_th_pos 0 -#define reg_unplug_rf_gain_th_len 8 -#define reg_unplug_rf_gain_th_lsb 0 -#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024 -#define reg_unplug_dtop_rf_gain_th_pos 0 -#define reg_unplug_dtop_rf_gain_th_len 8 -#define reg_unplug_dtop_rf_gain_th_lsb 0 -#define xd_p_reg_unplug_dtop_if_gain_th 0xA025 -#define reg_unplug_dtop_if_gain_th_pos 0 -#define reg_unplug_dtop_if_gain_th_len 8 -#define reg_unplug_dtop_if_gain_th_lsb 0 -#define xd_p_reg_top_recover_at_unplug_en 0xA026 -#define reg_top_recover_at_unplug_en_pos 0 -#define reg_top_recover_at_unplug_en_len 1 -#define reg_top_recover_at_unplug_en_lsb 0 -#define xd_p_reg_aagc_rf_x6 0xA027 -#define reg_aagc_rf_x6_pos 0 -#define reg_aagc_rf_x6_len 8 -#define reg_aagc_rf_x6_lsb 0 -#define xd_p_reg_aagc_rf_x7 0xA028 -#define reg_aagc_rf_x7_pos 0 -#define reg_aagc_rf_x7_len 8 -#define reg_aagc_rf_x7_lsb 0 -#define xd_p_reg_aagc_rf_x8 0xA029 -#define reg_aagc_rf_x8_pos 0 -#define reg_aagc_rf_x8_len 8 -#define reg_aagc_rf_x8_lsb 0 -#define xd_p_reg_aagc_rf_x9 0xA02A -#define reg_aagc_rf_x9_pos 0 -#define reg_aagc_rf_x9_len 8 -#define reg_aagc_rf_x9_lsb 0 -#define xd_p_reg_aagc_rf_x10 0xA02B -#define reg_aagc_rf_x10_pos 0 -#define reg_aagc_rf_x10_len 8 -#define reg_aagc_rf_x10_lsb 0 -#define xd_p_reg_aagc_rf_x11 0xA02C -#define reg_aagc_rf_x11_pos 0 -#define reg_aagc_rf_x11_len 8 -#define reg_aagc_rf_x11_lsb 0 -#define xd_p_reg_aagc_rf_x12 0xA02D -#define reg_aagc_rf_x12_pos 0 -#define reg_aagc_rf_x12_len 8 -#define reg_aagc_rf_x12_lsb 0 -#define xd_p_reg_aagc_rf_x13 0xA02E -#define reg_aagc_rf_x13_pos 0 -#define reg_aagc_rf_x13_len 8 -#define reg_aagc_rf_x13_lsb 0 -#define xd_p_reg_aagc_if_x0 0xA02F -#define reg_aagc_if_x0_pos 0 -#define reg_aagc_if_x0_len 8 -#define reg_aagc_if_x0_lsb 0 -#define xd_p_reg_aagc_if_x1 0xA030 -#define reg_aagc_if_x1_pos 0 -#define reg_aagc_if_x1_len 8 -#define reg_aagc_if_x1_lsb 0 -#define xd_p_reg_aagc_if_x2 0xA031 -#define reg_aagc_if_x2_pos 0 -#define reg_aagc_if_x2_len 8 -#define reg_aagc_if_x2_lsb 0 -#define xd_p_reg_aagc_if_x3 0xA032 -#define reg_aagc_if_x3_pos 0 -#define reg_aagc_if_x3_len 8 -#define reg_aagc_if_x3_lsb 0 -#define xd_p_reg_aagc_if_x4 0xA033 -#define reg_aagc_if_x4_pos 0 -#define reg_aagc_if_x4_len 8 -#define reg_aagc_if_x4_lsb 0 -#define xd_p_reg_aagc_if_x5 0xA034 -#define reg_aagc_if_x5_pos 0 -#define reg_aagc_if_x5_len 8 -#define reg_aagc_if_x5_lsb 0 -#define xd_p_reg_aagc_if_x6 0xA035 -#define reg_aagc_if_x6_pos 0 -#define reg_aagc_if_x6_len 8 -#define reg_aagc_if_x6_lsb 0 -#define xd_p_reg_aagc_if_x7 0xA036 -#define reg_aagc_if_x7_pos 0 -#define reg_aagc_if_x7_len 8 -#define reg_aagc_if_x7_lsb 0 -#define xd_p_reg_aagc_if_x8 0xA037 -#define reg_aagc_if_x8_pos 0 -#define reg_aagc_if_x8_len 8 -#define reg_aagc_if_x8_lsb 0 -#define xd_p_reg_aagc_if_x9 0xA038 -#define reg_aagc_if_x9_pos 0 -#define reg_aagc_if_x9_len 8 -#define reg_aagc_if_x9_lsb 0 -#define xd_p_reg_aagc_if_x10 0xA039 -#define reg_aagc_if_x10_pos 0 -#define reg_aagc_if_x10_len 8 -#define reg_aagc_if_x10_lsb 0 -#define xd_p_reg_aagc_if_x11 0xA03A -#define reg_aagc_if_x11_pos 0 -#define reg_aagc_if_x11_len 8 -#define reg_aagc_if_x11_lsb 0 -#define xd_p_reg_aagc_if_x12 0xA03B -#define reg_aagc_if_x12_pos 0 -#define reg_aagc_if_x12_len 8 -#define reg_aagc_if_x12_lsb 0 -#define xd_p_reg_aagc_if_x13 0xA03C -#define reg_aagc_if_x13_pos 0 -#define reg_aagc_if_x13_len 8 -#define reg_aagc_if_x13_lsb 0 -#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D -#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0 -#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8 -#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0 -#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E -#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0 -#define reg_aagc_min_if_ctl_8bit_for_dca_len 8 -#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0 -#define xd_r_reg_aagc_total_gain_7_0 0xA070 -#define reg_aagc_total_gain_7_0_pos 0 -#define reg_aagc_total_gain_7_0_len 8 -#define reg_aagc_total_gain_7_0_lsb 0 -#define xd_r_reg_aagc_total_gain_15_8 0xA071 -#define reg_aagc_total_gain_15_8_pos 0 -#define reg_aagc_total_gain_15_8_len 8 -#define reg_aagc_total_gain_15_8_lsb 8 -#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074 -#define reg_aagc_in_sat_cnt_7_0_pos 0 -#define reg_aagc_in_sat_cnt_7_0_len 8 -#define reg_aagc_in_sat_cnt_7_0_lsb 0 -#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075 -#define reg_aagc_in_sat_cnt_15_8_pos 0 -#define reg_aagc_in_sat_cnt_15_8_len 8 -#define reg_aagc_in_sat_cnt_15_8_lsb 8 -#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076 -#define reg_aagc_in_sat_cnt_23_16_pos 0 -#define reg_aagc_in_sat_cnt_23_16_len 8 -#define reg_aagc_in_sat_cnt_23_16_lsb 16 -#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077 -#define reg_aagc_in_sat_cnt_31_24_pos 0 -#define reg_aagc_in_sat_cnt_31_24_len 8 -#define reg_aagc_in_sat_cnt_31_24_lsb 24 -#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078 -#define reg_aagc_digital_rf_volt_7_0_pos 0 -#define reg_aagc_digital_rf_volt_7_0_len 8 -#define reg_aagc_digital_rf_volt_7_0_lsb 0 -#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079 -#define reg_aagc_digital_rf_volt_9_8_pos 0 -#define reg_aagc_digital_rf_volt_9_8_len 2 -#define reg_aagc_digital_rf_volt_9_8_lsb 8 -#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A -#define reg_aagc_digital_if_volt_7_0_pos 0 -#define reg_aagc_digital_if_volt_7_0_len 8 -#define reg_aagc_digital_if_volt_7_0_lsb 0 -#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B -#define reg_aagc_digital_if_volt_9_8_pos 0 -#define reg_aagc_digital_if_volt_9_8_len 2 -#define reg_aagc_digital_if_volt_9_8_lsb 8 -#define xd_r_reg_aagc_rf_gain 0xA07C -#define reg_aagc_rf_gain_pos 0 -#define reg_aagc_rf_gain_len 8 -#define reg_aagc_rf_gain_lsb 0 -#define xd_r_reg_aagc_if_gain 0xA07D -#define reg_aagc_if_gain_pos 0 -#define reg_aagc_if_gain_len 8 -#define reg_aagc_if_gain_lsb 0 -#define xd_p_tinr_imp_indicator 0xA080 -#define tinr_imp_indicator_pos 0 -#define tinr_imp_indicator_len 2 -#define tinr_imp_indicator_lsb 0 -#define xd_p_reg_tinr_fifo_size 0xA080 -#define reg_tinr_fifo_size_pos 2 -#define reg_tinr_fifo_size_len 5 -#define reg_tinr_fifo_size_lsb 0 -#define xd_p_reg_tinr_saturation_cnt_th 0xA081 -#define reg_tinr_saturation_cnt_th_pos 0 -#define reg_tinr_saturation_cnt_th_len 4 -#define reg_tinr_saturation_cnt_th_lsb 0 -#define xd_p_reg_tinr_saturation_th_3_0 0xA081 -#define reg_tinr_saturation_th_3_0_pos 4 -#define reg_tinr_saturation_th_3_0_len 4 -#define reg_tinr_saturation_th_3_0_lsb 0 -#define xd_p_reg_tinr_saturation_th_8_4 0xA082 -#define reg_tinr_saturation_th_8_4_pos 0 -#define reg_tinr_saturation_th_8_4_len 5 -#define reg_tinr_saturation_th_8_4_lsb 4 -#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083 -#define reg_tinr_imp_duration_th_2k_7_0_pos 0 -#define reg_tinr_imp_duration_th_2k_7_0_len 8 -#define reg_tinr_imp_duration_th_2k_7_0_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084 -#define reg_tinr_imp_duration_th_2k_8_pos 0 -#define reg_tinr_imp_duration_th_2k_8_len 1 -#define reg_tinr_imp_duration_th_2k_8_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085 -#define reg_tinr_imp_duration_th_8k_7_0_pos 0 -#define reg_tinr_imp_duration_th_8k_7_0_len 8 -#define reg_tinr_imp_duration_th_8k_7_0_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086 -#define reg_tinr_imp_duration_th_8k_10_8_pos 0 -#define reg_tinr_imp_duration_th_8k_10_8_len 3 -#define reg_tinr_imp_duration_th_8k_10_8_lsb 8 -#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087 -#define reg_tinr_freq_ratio_6m_7_0_pos 0 -#define reg_tinr_freq_ratio_6m_7_0_len 8 -#define reg_tinr_freq_ratio_6m_7_0_lsb 0 -#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088 -#define reg_tinr_freq_ratio_6m_12_8_pos 0 -#define reg_tinr_freq_ratio_6m_12_8_len 5 -#define reg_tinr_freq_ratio_6m_12_8_lsb 8 -#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089 -#define reg_tinr_freq_ratio_7m_7_0_pos 0 -#define reg_tinr_freq_ratio_7m_7_0_len 8 -#define reg_tinr_freq_ratio_7m_7_0_lsb 0 -#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A -#define reg_tinr_freq_ratio_7m_12_8_pos 0 -#define reg_tinr_freq_ratio_7m_12_8_len 5 -#define reg_tinr_freq_ratio_7m_12_8_lsb 8 -#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B -#define reg_tinr_freq_ratio_8m_7_0_pos 0 -#define reg_tinr_freq_ratio_8m_7_0_len 8 -#define reg_tinr_freq_ratio_8m_7_0_lsb 0 -#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C -#define reg_tinr_freq_ratio_8m_12_8_pos 0 -#define reg_tinr_freq_ratio_8m_12_8_len 5 -#define reg_tinr_freq_ratio_8m_12_8_lsb 8 -#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D -#define reg_tinr_imp_duration_th_low_2k_pos 0 -#define reg_tinr_imp_duration_th_low_2k_len 8 -#define reg_tinr_imp_duration_th_low_2k_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E -#define reg_tinr_imp_duration_th_low_8k_pos 0 -#define reg_tinr_imp_duration_th_low_8k_len 8 -#define reg_tinr_imp_duration_th_low_8k_lsb 0 -#define xd_r_reg_tinr_counter_7_0 0xA090 -#define reg_tinr_counter_7_0_pos 0 -#define reg_tinr_counter_7_0_len 8 -#define reg_tinr_counter_7_0_lsb 0 -#define xd_r_reg_tinr_counter_15_8 0xA091 -#define reg_tinr_counter_15_8_pos 0 -#define reg_tinr_counter_15_8_len 8 -#define reg_tinr_counter_15_8_lsb 8 -#define xd_p_reg_tinr_adative_tinr_en 0xA093 -#define reg_tinr_adative_tinr_en_pos 0 -#define reg_tinr_adative_tinr_en_len 1 -#define reg_tinr_adative_tinr_en_lsb 0 -#define xd_p_reg_tinr_peak_fifo_size 0xA093 -#define reg_tinr_peak_fifo_size_pos 1 -#define reg_tinr_peak_fifo_size_len 5 -#define reg_tinr_peak_fifo_size_lsb 0 -#define xd_p_reg_tinr_counter_rst 0xA093 -#define reg_tinr_counter_rst_pos 6 -#define reg_tinr_counter_rst_len 1 -#define reg_tinr_counter_rst_lsb 0 -#define xd_p_reg_tinr_search_period_7_0 0xA094 -#define reg_tinr_search_period_7_0_pos 0 -#define reg_tinr_search_period_7_0_len 8 -#define reg_tinr_search_period_7_0_lsb 0 -#define xd_p_reg_tinr_search_period_15_8 0xA095 -#define reg_tinr_search_period_15_8_pos 0 -#define reg_tinr_search_period_15_8_len 8 -#define reg_tinr_search_period_15_8_lsb 8 -#define xd_p_reg_ccifs_fcw_7_0 0xA0A0 -#define reg_ccifs_fcw_7_0_pos 0 -#define reg_ccifs_fcw_7_0_len 8 -#define reg_ccifs_fcw_7_0_lsb 0 -#define xd_p_reg_ccifs_fcw_12_8 0xA0A1 -#define reg_ccifs_fcw_12_8_pos 0 -#define reg_ccifs_fcw_12_8_len 5 -#define reg_ccifs_fcw_12_8_lsb 8 -#define xd_p_reg_ccifs_spec_inv 0xA0A1 -#define reg_ccifs_spec_inv_pos 5 -#define reg_ccifs_spec_inv_len 1 -#define reg_ccifs_spec_inv_lsb 0 -#define xd_p_reg_gp_trigger 0xA0A2 -#define reg_gp_trigger_pos 0 -#define reg_gp_trigger_len 1 -#define reg_gp_trigger_lsb 0 -#define xd_p_reg_trigger_sel 0xA0A2 -#define reg_trigger_sel_pos 1 -#define reg_trigger_sel_len 2 -#define reg_trigger_sel_lsb 0 -#define xd_p_reg_debug_ofdm 0xA0A2 -#define reg_debug_ofdm_pos 3 -#define reg_debug_ofdm_len 2 -#define reg_debug_ofdm_lsb 0 -#define xd_p_reg_trigger_module_sel 0xA0A3 -#define reg_trigger_module_sel_pos 0 -#define reg_trigger_module_sel_len 6 -#define reg_trigger_module_sel_lsb 0 -#define xd_p_reg_trigger_set_sel 0xA0A4 -#define reg_trigger_set_sel_pos 0 -#define reg_trigger_set_sel_len 6 -#define reg_trigger_set_sel_lsb 0 -#define xd_p_reg_fw_int_mask_n 0xA0A4 -#define reg_fw_int_mask_n_pos 6 -#define reg_fw_int_mask_n_len 1 -#define reg_fw_int_mask_n_lsb 0 -#define xd_p_reg_debug_group 0xA0A5 -#define reg_debug_group_pos 0 -#define reg_debug_group_len 4 -#define reg_debug_group_lsb 0 -#define xd_p_reg_odbg_clk_sel 0xA0A5 -#define reg_odbg_clk_sel_pos 4 -#define reg_odbg_clk_sel_len 2 -#define reg_odbg_clk_sel_lsb 0 -#define xd_p_reg_ccif_sc 0xA0C0 -#define reg_ccif_sc_pos 0 -#define reg_ccif_sc_len 4 -#define reg_ccif_sc_lsb 0 -#define xd_r_reg_ccif_saturate 0xA0C1 -#define reg_ccif_saturate_pos 0 -#define reg_ccif_saturate_len 2 -#define reg_ccif_saturate_lsb 0 -#define xd_r_reg_antif_saturate 0xA0C1 -#define reg_antif_saturate_pos 2 -#define reg_antif_saturate_len 4 -#define reg_antif_saturate_lsb 0 -#define xd_r_reg_acif_saturate 0xA0C2 -#define reg_acif_saturate_pos 0 -#define reg_acif_saturate_len 8 -#define reg_acif_saturate_lsb 0 -#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8 -#define reg_tmr_timer0_threshold_7_0_pos 0 -#define reg_tmr_timer0_threshold_7_0_len 8 -#define reg_tmr_timer0_threshold_7_0_lsb 0 -#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9 -#define reg_tmr_timer0_threshold_15_8_pos 0 -#define reg_tmr_timer0_threshold_15_8_len 8 -#define reg_tmr_timer0_threshold_15_8_lsb 8 -#define xd_p_reg_tmr_timer0_enable 0xA0CA -#define reg_tmr_timer0_enable_pos 0 -#define reg_tmr_timer0_enable_len 1 -#define reg_tmr_timer0_enable_lsb 0 -#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA -#define reg_tmr_timer0_clk_sel_pos 1 -#define reg_tmr_timer0_clk_sel_len 1 -#define reg_tmr_timer0_clk_sel_lsb 0 -#define xd_p_reg_tmr_timer0_int 0xA0CA -#define reg_tmr_timer0_int_pos 2 -#define reg_tmr_timer0_int_len 1 -#define reg_tmr_timer0_int_lsb 0 -#define xd_p_reg_tmr_timer0_rst 0xA0CA -#define reg_tmr_timer0_rst_pos 3 -#define reg_tmr_timer0_rst_len 1 -#define reg_tmr_timer0_rst_lsb 0 -#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB -#define reg_tmr_timer0_count_7_0_pos 0 -#define reg_tmr_timer0_count_7_0_len 8 -#define reg_tmr_timer0_count_7_0_lsb 0 -#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC -#define reg_tmr_timer0_count_15_8_pos 0 -#define reg_tmr_timer0_count_15_8_len 8 -#define reg_tmr_timer0_count_15_8_lsb 8 -#define xd_p_reg_suspend 0xA0CD -#define reg_suspend_pos 0 -#define reg_suspend_len 1 -#define reg_suspend_lsb 0 -#define xd_p_reg_suspend_rdy 0xA0CD -#define reg_suspend_rdy_pos 1 -#define reg_suspend_rdy_len 1 -#define reg_suspend_rdy_lsb 0 -#define xd_p_reg_resume 0xA0CD -#define reg_resume_pos 2 -#define reg_resume_len 1 -#define reg_resume_lsb 0 -#define xd_p_reg_resume_rdy 0xA0CD -#define reg_resume_rdy_pos 3 -#define reg_resume_rdy_len 1 -#define reg_resume_rdy_lsb 0 -#define xd_p_reg_fmf 0xA0CE -#define reg_fmf_pos 0 -#define reg_fmf_len 8 -#define reg_fmf_lsb 0 -#define xd_p_ccid_accumulate_num_2k_7_0 0xA100 -#define ccid_accumulate_num_2k_7_0_pos 0 -#define ccid_accumulate_num_2k_7_0_len 8 -#define ccid_accumulate_num_2k_7_0_lsb 0 -#define xd_p_ccid_accumulate_num_2k_12_8 0xA101 -#define ccid_accumulate_num_2k_12_8_pos 0 -#define ccid_accumulate_num_2k_12_8_len 5 -#define ccid_accumulate_num_2k_12_8_lsb 8 -#define xd_p_ccid_accumulate_num_8k_7_0 0xA102 -#define ccid_accumulate_num_8k_7_0_pos 0 -#define ccid_accumulate_num_8k_7_0_len 8 -#define ccid_accumulate_num_8k_7_0_lsb 0 -#define xd_p_ccid_accumulate_num_8k_14_8 0xA103 -#define ccid_accumulate_num_8k_14_8_pos 0 -#define ccid_accumulate_num_8k_14_8_len 7 -#define ccid_accumulate_num_8k_14_8_lsb 8 -#define xd_p_ccid_desired_level_0 0xA103 -#define ccid_desired_level_0_pos 7 -#define ccid_desired_level_0_len 1 -#define ccid_desired_level_0_lsb 0 -#define xd_p_ccid_desired_level_8_1 0xA104 -#define ccid_desired_level_8_1_pos 0 -#define ccid_desired_level_8_1_len 8 -#define ccid_desired_level_8_1_lsb 1 -#define xd_p_ccid_apply_delay 0xA105 -#define ccid_apply_delay_pos 0 -#define ccid_apply_delay_len 7 -#define ccid_apply_delay_lsb 0 -#define xd_p_ccid_CCID_Threshold1 0xA106 -#define ccid_CCID_Threshold1_pos 0 -#define ccid_CCID_Threshold1_len 8 -#define ccid_CCID_Threshold1_lsb 0 -#define xd_p_ccid_CCID_Threshold2 0xA107 -#define ccid_CCID_Threshold2_pos 0 -#define ccid_CCID_Threshold2_len 8 -#define ccid_CCID_Threshold2_lsb 0 -#define xd_p_reg_ccid_gain_scale 0xA108 -#define reg_ccid_gain_scale_pos 0 -#define reg_ccid_gain_scale_len 4 -#define reg_ccid_gain_scale_lsb 0 -#define xd_p_reg_ccid2_passband_gain_set 0xA108 -#define reg_ccid2_passband_gain_set_pos 4 -#define reg_ccid2_passband_gain_set_len 4 -#define reg_ccid2_passband_gain_set_lsb 0 -#define xd_r_ccid_multiplier_7_0 0xA109 -#define ccid_multiplier_7_0_pos 0 -#define ccid_multiplier_7_0_len 8 -#define ccid_multiplier_7_0_lsb 0 -#define xd_r_ccid_multiplier_15_8 0xA10A -#define ccid_multiplier_15_8_pos 0 -#define ccid_multiplier_15_8_len 8 -#define ccid_multiplier_15_8_lsb 8 -#define xd_r_ccid_right_shift_bits 0xA10B -#define ccid_right_shift_bits_pos 0 -#define ccid_right_shift_bits_len 4 -#define ccid_right_shift_bits_lsb 0 -#define xd_r_reg_ccid_sx_7_0 0xA10C -#define reg_ccid_sx_7_0_pos 0 -#define reg_ccid_sx_7_0_len 8 -#define reg_ccid_sx_7_0_lsb 0 -#define xd_r_reg_ccid_sx_15_8 0xA10D -#define reg_ccid_sx_15_8_pos 0 -#define reg_ccid_sx_15_8_len 8 -#define reg_ccid_sx_15_8_lsb 8 -#define xd_r_reg_ccid_sx_21_16 0xA10E -#define reg_ccid_sx_21_16_pos 0 -#define reg_ccid_sx_21_16_len 6 -#define reg_ccid_sx_21_16_lsb 16 -#define xd_r_reg_ccid_sy_7_0 0xA110 -#define reg_ccid_sy_7_0_pos 0 -#define reg_ccid_sy_7_0_len 8 -#define reg_ccid_sy_7_0_lsb 0 -#define xd_r_reg_ccid_sy_15_8 0xA111 -#define reg_ccid_sy_15_8_pos 0 -#define reg_ccid_sy_15_8_len 8 -#define reg_ccid_sy_15_8_lsb 8 -#define xd_r_reg_ccid_sy_23_16 0xA112 -#define reg_ccid_sy_23_16_pos 0 -#define reg_ccid_sy_23_16_len 8 -#define reg_ccid_sy_23_16_lsb 16 -#define xd_r_reg_ccid2_sz_7_0 0xA114 -#define reg_ccid2_sz_7_0_pos 0 -#define reg_ccid2_sz_7_0_len 8 -#define reg_ccid2_sz_7_0_lsb 0 -#define xd_r_reg_ccid2_sz_15_8 0xA115 -#define reg_ccid2_sz_15_8_pos 0 -#define reg_ccid2_sz_15_8_len 8 -#define reg_ccid2_sz_15_8_lsb 8 -#define xd_r_reg_ccid2_sz_23_16 0xA116 -#define reg_ccid2_sz_23_16_pos 0 -#define reg_ccid2_sz_23_16_len 8 -#define reg_ccid2_sz_23_16_lsb 16 -#define xd_r_reg_ccid2_sz_25_24 0xA117 -#define reg_ccid2_sz_25_24_pos 0 -#define reg_ccid2_sz_25_24_len 2 -#define reg_ccid2_sz_25_24_lsb 24 -#define xd_r_reg_ccid2_sy_7_0 0xA118 -#define reg_ccid2_sy_7_0_pos 0 -#define reg_ccid2_sy_7_0_len 8 -#define reg_ccid2_sy_7_0_lsb 0 -#define xd_r_reg_ccid2_sy_15_8 0xA119 -#define reg_ccid2_sy_15_8_pos 0 -#define reg_ccid2_sy_15_8_len 8 -#define reg_ccid2_sy_15_8_lsb 8 -#define xd_r_reg_ccid2_sy_23_16 0xA11A -#define reg_ccid2_sy_23_16_pos 0 -#define reg_ccid2_sy_23_16_len 8 -#define reg_ccid2_sy_23_16_lsb 16 -#define xd_r_reg_ccid2_sy_25_24 0xA11B -#define reg_ccid2_sy_25_24_pos 0 -#define reg_ccid2_sy_25_24_len 2 -#define reg_ccid2_sy_25_24_lsb 24 -#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120 -#define dagc1_accumulate_num_2k_7_0_pos 0 -#define dagc1_accumulate_num_2k_7_0_len 8 -#define dagc1_accumulate_num_2k_7_0_lsb 0 -#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121 -#define dagc1_accumulate_num_2k_12_8_pos 0 -#define dagc1_accumulate_num_2k_12_8_len 5 -#define dagc1_accumulate_num_2k_12_8_lsb 8 -#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122 -#define dagc1_accumulate_num_8k_7_0_pos 0 -#define dagc1_accumulate_num_8k_7_0_len 8 -#define dagc1_accumulate_num_8k_7_0_lsb 0 -#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123 -#define dagc1_accumulate_num_8k_14_8_pos 0 -#define dagc1_accumulate_num_8k_14_8_len 7 -#define dagc1_accumulate_num_8k_14_8_lsb 8 -#define xd_p_dagc1_desired_level_0 0xA123 -#define dagc1_desired_level_0_pos 7 -#define dagc1_desired_level_0_len 1 -#define dagc1_desired_level_0_lsb 0 -#define xd_p_dagc1_desired_level_8_1 0xA124 -#define dagc1_desired_level_8_1_pos 0 -#define dagc1_desired_level_8_1_len 8 -#define dagc1_desired_level_8_1_lsb 1 -#define xd_p_dagc1_apply_delay 0xA125 -#define dagc1_apply_delay_pos 0 -#define dagc1_apply_delay_len 7 -#define dagc1_apply_delay_lsb 0 -#define xd_p_dagc1_bypass_scale_ctl 0xA126 -#define dagc1_bypass_scale_ctl_pos 0 -#define dagc1_bypass_scale_ctl_len 2 -#define dagc1_bypass_scale_ctl_lsb 0 -#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127 -#define reg_dagc1_in_sat_cnt_7_0_pos 0 -#define reg_dagc1_in_sat_cnt_7_0_len 8 -#define reg_dagc1_in_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128 -#define reg_dagc1_in_sat_cnt_15_8_pos 0 -#define reg_dagc1_in_sat_cnt_15_8_len 8 -#define reg_dagc1_in_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129 -#define reg_dagc1_in_sat_cnt_23_16_pos 0 -#define reg_dagc1_in_sat_cnt_23_16_len 8 -#define reg_dagc1_in_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A -#define reg_dagc1_in_sat_cnt_31_24_pos 0 -#define reg_dagc1_in_sat_cnt_31_24_len 8 -#define reg_dagc1_in_sat_cnt_31_24_lsb 24 -#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B -#define reg_dagc1_out_sat_cnt_7_0_pos 0 -#define reg_dagc1_out_sat_cnt_7_0_len 8 -#define reg_dagc1_out_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C -#define reg_dagc1_out_sat_cnt_15_8_pos 0 -#define reg_dagc1_out_sat_cnt_15_8_len 8 -#define reg_dagc1_out_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D -#define reg_dagc1_out_sat_cnt_23_16_pos 0 -#define reg_dagc1_out_sat_cnt_23_16_len 8 -#define reg_dagc1_out_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E -#define reg_dagc1_out_sat_cnt_31_24_pos 0 -#define reg_dagc1_out_sat_cnt_31_24_len 8 -#define reg_dagc1_out_sat_cnt_31_24_lsb 24 -#define xd_r_dagc1_multiplier_7_0 0xA136 -#define dagc1_multiplier_7_0_pos 0 -#define dagc1_multiplier_7_0_len 8 -#define dagc1_multiplier_7_0_lsb 0 -#define xd_r_dagc1_multiplier_15_8 0xA137 -#define dagc1_multiplier_15_8_pos 0 -#define dagc1_multiplier_15_8_len 8 -#define dagc1_multiplier_15_8_lsb 8 -#define xd_r_dagc1_right_shift_bits 0xA138 -#define dagc1_right_shift_bits_pos 0 -#define dagc1_right_shift_bits_len 4 -#define dagc1_right_shift_bits_lsb 0 -#define xd_p_reg_bfs_fcw_7_0 0xA140 -#define reg_bfs_fcw_7_0_pos 0 -#define reg_bfs_fcw_7_0_len 8 -#define reg_bfs_fcw_7_0_lsb 0 -#define xd_p_reg_bfs_fcw_15_8 0xA141 -#define reg_bfs_fcw_15_8_pos 0 -#define reg_bfs_fcw_15_8_len 8 -#define reg_bfs_fcw_15_8_lsb 8 -#define xd_p_reg_bfs_fcw_22_16 0xA142 -#define reg_bfs_fcw_22_16_pos 0 -#define reg_bfs_fcw_22_16_len 7 -#define reg_bfs_fcw_22_16_lsb 16 -#define xd_p_reg_antif_sf_7_0 0xA144 -#define reg_antif_sf_7_0_pos 0 -#define reg_antif_sf_7_0_len 8 -#define reg_antif_sf_7_0_lsb 0 -#define xd_p_reg_antif_sf_11_8 0xA145 -#define reg_antif_sf_11_8_pos 0 -#define reg_antif_sf_11_8_len 4 -#define reg_antif_sf_11_8_lsb 8 -#define xd_r_bfs_fcw_q_7_0 0xA150 -#define bfs_fcw_q_7_0_pos 0 -#define bfs_fcw_q_7_0_len 8 -#define bfs_fcw_q_7_0_lsb 0 -#define xd_r_bfs_fcw_q_15_8 0xA151 -#define bfs_fcw_q_15_8_pos 0 -#define bfs_fcw_q_15_8_len 8 -#define bfs_fcw_q_15_8_lsb 8 -#define xd_r_bfs_fcw_q_22_16 0xA152 -#define bfs_fcw_q_22_16_pos 0 -#define bfs_fcw_q_22_16_len 7 -#define bfs_fcw_q_22_16_lsb 16 -#define xd_p_reg_dca_enu 0xA160 -#define reg_dca_enu_pos 0 -#define reg_dca_enu_len 1 -#define reg_dca_enu_lsb 0 -#define xd_p_reg_dca_enl 0xA160 -#define reg_dca_enl_pos 1 -#define reg_dca_enl_len 1 -#define reg_dca_enl_lsb 0 -#define xd_p_reg_dca_lower_chip 0xA160 -#define reg_dca_lower_chip_pos 2 -#define reg_dca_lower_chip_len 1 -#define reg_dca_lower_chip_lsb 0 -#define xd_p_reg_dca_upper_chip 0xA160 -#define reg_dca_upper_chip_pos 3 -#define reg_dca_upper_chip_len 1 -#define reg_dca_upper_chip_lsb 0 -#define xd_p_reg_dca_platch 0xA160 -#define reg_dca_platch_pos 4 -#define reg_dca_platch_len 1 -#define reg_dca_platch_lsb 0 -#define xd_p_reg_dca_th 0xA161 -#define reg_dca_th_pos 0 -#define reg_dca_th_len 5 -#define reg_dca_th_lsb 0 -#define xd_p_reg_dca_scale 0xA162 -#define reg_dca_scale_pos 0 -#define reg_dca_scale_len 4 -#define reg_dca_scale_lsb 0 -#define xd_p_reg_dca_tone_7_0 0xA163 -#define reg_dca_tone_7_0_pos 0 -#define reg_dca_tone_7_0_len 8 -#define reg_dca_tone_7_0_lsb 0 -#define xd_p_reg_dca_tone_12_8 0xA164 -#define reg_dca_tone_12_8_pos 0 -#define reg_dca_tone_12_8_len 5 -#define reg_dca_tone_12_8_lsb 8 -#define xd_p_reg_dca_time_7_0 0xA165 -#define reg_dca_time_7_0_pos 0 -#define reg_dca_time_7_0_len 8 -#define reg_dca_time_7_0_lsb 0 -#define xd_p_reg_dca_time_15_8 0xA166 -#define reg_dca_time_15_8_pos 0 -#define reg_dca_time_15_8_len 8 -#define reg_dca_time_15_8_lsb 8 -#define xd_r_dcasm 0xA167 -#define dcasm_pos 0 -#define dcasm_len 3 -#define dcasm_lsb 0 -#define xd_p_reg_qnt_valuew_7_0 0xA168 -#define reg_qnt_valuew_7_0_pos 0 -#define reg_qnt_valuew_7_0_len 8 -#define reg_qnt_valuew_7_0_lsb 0 -#define xd_p_reg_qnt_valuew_10_8 0xA169 -#define reg_qnt_valuew_10_8_pos 0 -#define reg_qnt_valuew_10_8_len 3 -#define reg_qnt_valuew_10_8_lsb 8 -#define xd_p_dca_sbx_gain_diff_7_0 0xA16A -#define dca_sbx_gain_diff_7_0_pos 0 -#define dca_sbx_gain_diff_7_0_len 8 -#define dca_sbx_gain_diff_7_0_lsb 0 -#define xd_p_dca_sbx_gain_diff_9_8 0xA16B -#define dca_sbx_gain_diff_9_8_pos 0 -#define dca_sbx_gain_diff_9_8_len 2 -#define dca_sbx_gain_diff_9_8_lsb 8 -#define xd_p_reg_dca_stand_alone 0xA16C -#define reg_dca_stand_alone_pos 0 -#define reg_dca_stand_alone_len 1 -#define reg_dca_stand_alone_lsb 0 -#define xd_p_reg_dca_upper_out_en 0xA16C -#define reg_dca_upper_out_en_pos 1 -#define reg_dca_upper_out_en_len 1 -#define reg_dca_upper_out_en_lsb 0 -#define xd_p_reg_dca_rc_en 0xA16C -#define reg_dca_rc_en_pos 2 -#define reg_dca_rc_en_len 1 -#define reg_dca_rc_en_lsb 0 -#define xd_p_reg_dca_retrain_send 0xA16C -#define reg_dca_retrain_send_pos 3 -#define reg_dca_retrain_send_len 1 -#define reg_dca_retrain_send_lsb 0 -#define xd_p_reg_dca_retrain_rec 0xA16C -#define reg_dca_retrain_rec_pos 4 -#define reg_dca_retrain_rec_len 1 -#define reg_dca_retrain_rec_lsb 0 -#define xd_p_reg_dca_api_tpsrdy 0xA16C -#define reg_dca_api_tpsrdy_pos 5 -#define reg_dca_api_tpsrdy_len 1 -#define reg_dca_api_tpsrdy_lsb 0 -#define xd_p_reg_dca_symbol_gap 0xA16D -#define reg_dca_symbol_gap_pos 0 -#define reg_dca_symbol_gap_len 4 -#define reg_dca_symbol_gap_lsb 0 -#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E -#define reg_qnt_nfvaluew_7_0_pos 0 -#define reg_qnt_nfvaluew_7_0_len 8 -#define reg_qnt_nfvaluew_7_0_lsb 0 -#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F -#define reg_qnt_nfvaluew_10_8_pos 0 -#define reg_qnt_nfvaluew_10_8_len 3 -#define reg_qnt_nfvaluew_10_8_lsb 8 -#define xd_p_reg_qnt_flatness_thr_7_0 0xA170 -#define reg_qnt_flatness_thr_7_0_pos 0 -#define reg_qnt_flatness_thr_7_0_len 8 -#define reg_qnt_flatness_thr_7_0_lsb 0 -#define xd_p_reg_qnt_flatness_thr_9_8 0xA171 -#define reg_qnt_flatness_thr_9_8_pos 0 -#define reg_qnt_flatness_thr_9_8_len 2 -#define reg_qnt_flatness_thr_9_8_lsb 8 -#define xd_p_reg_dca_tone_idx_5_0 0xA171 -#define reg_dca_tone_idx_5_0_pos 2 -#define reg_dca_tone_idx_5_0_len 6 -#define reg_dca_tone_idx_5_0_lsb 0 -#define xd_p_reg_dca_tone_idx_12_6 0xA172 -#define reg_dca_tone_idx_12_6_pos 0 -#define reg_dca_tone_idx_12_6_len 7 -#define reg_dca_tone_idx_12_6_lsb 6 -#define xd_p_reg_dca_data_vld 0xA173 -#define reg_dca_data_vld_pos 0 -#define reg_dca_data_vld_len 1 -#define reg_dca_data_vld_lsb 0 -#define xd_p_reg_dca_read_update 0xA173 -#define reg_dca_read_update_pos 1 -#define reg_dca_read_update_len 1 -#define reg_dca_read_update_lsb 0 -#define xd_r_reg_dca_data_re_5_0 0xA173 -#define reg_dca_data_re_5_0_pos 2 -#define reg_dca_data_re_5_0_len 6 -#define reg_dca_data_re_5_0_lsb 0 -#define xd_r_reg_dca_data_re_10_6 0xA174 -#define reg_dca_data_re_10_6_pos 0 -#define reg_dca_data_re_10_6_len 5 -#define reg_dca_data_re_10_6_lsb 6 -#define xd_r_reg_dca_data_im_7_0 0xA175 -#define reg_dca_data_im_7_0_pos 0 -#define reg_dca_data_im_7_0_len 8 -#define reg_dca_data_im_7_0_lsb 0 -#define xd_r_reg_dca_data_im_10_8 0xA176 -#define reg_dca_data_im_10_8_pos 0 -#define reg_dca_data_im_10_8_len 3 -#define reg_dca_data_im_10_8_lsb 8 -#define xd_r_reg_dca_data_h2_7_0 0xA178 -#define reg_dca_data_h2_7_0_pos 0 -#define reg_dca_data_h2_7_0_len 8 -#define reg_dca_data_h2_7_0_lsb 0 -#define xd_r_reg_dca_data_h2_9_8 0xA179 -#define reg_dca_data_h2_9_8_pos 0 -#define reg_dca_data_h2_9_8_len 2 -#define reg_dca_data_h2_9_8_lsb 8 -#define xd_p_reg_f_adc_7_0 0xA180 -#define reg_f_adc_7_0_pos 0 -#define reg_f_adc_7_0_len 8 -#define reg_f_adc_7_0_lsb 0 -#define xd_p_reg_f_adc_15_8 0xA181 -#define reg_f_adc_15_8_pos 0 -#define reg_f_adc_15_8_len 8 -#define reg_f_adc_15_8_lsb 8 -#define xd_p_reg_f_adc_23_16 0xA182 -#define reg_f_adc_23_16_pos 0 -#define reg_f_adc_23_16_len 8 -#define reg_f_adc_23_16_lsb 16 -#define xd_r_intp_mu_7_0 0xA190 -#define intp_mu_7_0_pos 0 -#define intp_mu_7_0_len 8 -#define intp_mu_7_0_lsb 0 -#define xd_r_intp_mu_15_8 0xA191 -#define intp_mu_15_8_pos 0 -#define intp_mu_15_8_len 8 -#define intp_mu_15_8_lsb 8 -#define xd_r_intp_mu_19_16 0xA192 -#define intp_mu_19_16_pos 0 -#define intp_mu_19_16_len 4 -#define intp_mu_19_16_lsb 16 -#define xd_p_reg_agc_rst 0xA1A0 -#define reg_agc_rst_pos 0 -#define reg_agc_rst_len 1 -#define reg_agc_rst_lsb 0 -#define xd_p_rf_agc_en 0xA1A0 -#define rf_agc_en_pos 1 -#define rf_agc_en_len 1 -#define rf_agc_en_lsb 0 -#define xd_p_rf_agc_dis 0xA1A0 -#define rf_agc_dis_pos 2 -#define rf_agc_dis_len 1 -#define rf_agc_dis_lsb 0 -#define xd_p_if_agc_rst 0xA1A0 -#define if_agc_rst_pos 3 -#define if_agc_rst_len 1 -#define if_agc_rst_lsb 0 -#define xd_p_if_agc_en 0xA1A0 -#define if_agc_en_pos 4 -#define if_agc_en_len 1 -#define if_agc_en_lsb 0 -#define xd_p_if_agc_dis 0xA1A0 -#define if_agc_dis_pos 5 -#define if_agc_dis_len 1 -#define if_agc_dis_lsb 0 -#define xd_p_agc_lock 0xA1A0 -#define agc_lock_pos 6 -#define agc_lock_len 1 -#define agc_lock_lsb 0 -#define xd_p_reg_tinr_rst 0xA1A1 -#define reg_tinr_rst_pos 0 -#define reg_tinr_rst_len 1 -#define reg_tinr_rst_lsb 0 -#define xd_p_reg_tinr_en 0xA1A1 -#define reg_tinr_en_pos 1 -#define reg_tinr_en_len 1 -#define reg_tinr_en_lsb 0 -#define xd_p_reg_ccifs_en 0xA1A2 -#define reg_ccifs_en_pos 0 -#define reg_ccifs_en_len 1 -#define reg_ccifs_en_lsb 0 -#define xd_p_reg_ccifs_dis 0xA1A2 -#define reg_ccifs_dis_pos 1 -#define reg_ccifs_dis_len 1 -#define reg_ccifs_dis_lsb 0 -#define xd_p_reg_ccifs_rst 0xA1A2 -#define reg_ccifs_rst_pos 2 -#define reg_ccifs_rst_len 1 -#define reg_ccifs_rst_lsb 0 -#define xd_p_reg_ccifs_byp 0xA1A2 -#define reg_ccifs_byp_pos 3 -#define reg_ccifs_byp_len 1 -#define reg_ccifs_byp_lsb 0 -#define xd_p_reg_ccif_en 0xA1A3 -#define reg_ccif_en_pos 0 -#define reg_ccif_en_len 1 -#define reg_ccif_en_lsb 0 -#define xd_p_reg_ccif_dis 0xA1A3 -#define reg_ccif_dis_pos 1 -#define reg_ccif_dis_len 1 -#define reg_ccif_dis_lsb 0 -#define xd_p_reg_ccif_rst 0xA1A3 -#define reg_ccif_rst_pos 2 -#define reg_ccif_rst_len 1 -#define reg_ccif_rst_lsb 0 -#define xd_p_reg_ccif_byp 0xA1A3 -#define reg_ccif_byp_pos 3 -#define reg_ccif_byp_len 1 -#define reg_ccif_byp_lsb 0 -#define xd_p_dagc1_rst 0xA1A4 -#define dagc1_rst_pos 0 -#define dagc1_rst_len 1 -#define dagc1_rst_lsb 0 -#define xd_p_dagc1_en 0xA1A4 -#define dagc1_en_pos 1 -#define dagc1_en_len 1 -#define dagc1_en_lsb 0 -#define xd_p_dagc1_mode 0xA1A4 -#define dagc1_mode_pos 2 -#define dagc1_mode_len 2 -#define dagc1_mode_lsb 0 -#define xd_p_dagc1_done 0xA1A4 -#define dagc1_done_pos 4 -#define dagc1_done_len 1 -#define dagc1_done_lsb 0 -#define xd_p_ccid_rst 0xA1A5 -#define ccid_rst_pos 0 -#define ccid_rst_len 1 -#define ccid_rst_lsb 0 -#define xd_p_ccid_en 0xA1A5 -#define ccid_en_pos 1 -#define ccid_en_len 1 -#define ccid_en_lsb 0 -#define xd_p_ccid_mode 0xA1A5 -#define ccid_mode_pos 2 -#define ccid_mode_len 2 -#define ccid_mode_lsb 0 -#define xd_p_ccid_done 0xA1A5 -#define ccid_done_pos 4 -#define ccid_done_len 1 -#define ccid_done_lsb 0 -#define xd_r_ccid_deted 0xA1A5 -#define ccid_deted_pos 5 -#define ccid_deted_len 1 -#define ccid_deted_lsb 0 -#define xd_p_ccid2_en 0xA1A5 -#define ccid2_en_pos 6 -#define ccid2_en_len 1 -#define ccid2_en_lsb 0 -#define xd_p_ccid2_done 0xA1A5 -#define ccid2_done_pos 7 -#define ccid2_done_len 1 -#define ccid2_done_lsb 0 -#define xd_p_reg_bfs_en 0xA1A6 -#define reg_bfs_en_pos 0 -#define reg_bfs_en_len 1 -#define reg_bfs_en_lsb 0 -#define xd_p_reg_bfs_dis 0xA1A6 -#define reg_bfs_dis_pos 1 -#define reg_bfs_dis_len 1 -#define reg_bfs_dis_lsb 0 -#define xd_p_reg_bfs_rst 0xA1A6 -#define reg_bfs_rst_pos 2 -#define reg_bfs_rst_len 1 -#define reg_bfs_rst_lsb 0 -#define xd_p_reg_bfs_byp 0xA1A6 -#define reg_bfs_byp_pos 3 -#define reg_bfs_byp_len 1 -#define reg_bfs_byp_lsb 0 -#define xd_p_reg_antif_en 0xA1A7 -#define reg_antif_en_pos 0 -#define reg_antif_en_len 1 -#define reg_antif_en_lsb 0 -#define xd_p_reg_antif_dis 0xA1A7 -#define reg_antif_dis_pos 1 -#define reg_antif_dis_len 1 -#define reg_antif_dis_lsb 0 -#define xd_p_reg_antif_rst 0xA1A7 -#define reg_antif_rst_pos 2 -#define reg_antif_rst_len 1 -#define reg_antif_rst_lsb 0 -#define xd_p_reg_antif_byp 0xA1A7 -#define reg_antif_byp_pos 3 -#define reg_antif_byp_len 1 -#define reg_antif_byp_lsb 0 -#define xd_p_intp_en 0xA1A8 -#define intp_en_pos 0 -#define intp_en_len 1 -#define intp_en_lsb 0 -#define xd_p_intp_dis 0xA1A8 -#define intp_dis_pos 1 -#define intp_dis_len 1 -#define intp_dis_lsb 0 -#define xd_p_intp_rst 0xA1A8 -#define intp_rst_pos 2 -#define intp_rst_len 1 -#define intp_rst_lsb 0 -#define xd_p_intp_byp 0xA1A8 -#define intp_byp_pos 3 -#define intp_byp_len 1 -#define intp_byp_lsb 0 -#define xd_p_reg_acif_en 0xA1A9 -#define reg_acif_en_pos 0 -#define reg_acif_en_len 1 -#define reg_acif_en_lsb 0 -#define xd_p_reg_acif_dis 0xA1A9 -#define reg_acif_dis_pos 1 -#define reg_acif_dis_len 1 -#define reg_acif_dis_lsb 0 -#define xd_p_reg_acif_rst 0xA1A9 -#define reg_acif_rst_pos 2 -#define reg_acif_rst_len 1 -#define reg_acif_rst_lsb 0 -#define xd_p_reg_acif_byp 0xA1A9 -#define reg_acif_byp_pos 3 -#define reg_acif_byp_len 1 -#define reg_acif_byp_lsb 0 -#define xd_p_reg_acif_sync_mode 0xA1A9 -#define reg_acif_sync_mode_pos 4 -#define reg_acif_sync_mode_len 1 -#define reg_acif_sync_mode_lsb 0 -#define xd_p_dagc2_rst 0xA1AA -#define dagc2_rst_pos 0 -#define dagc2_rst_len 1 -#define dagc2_rst_lsb 0 -#define xd_p_dagc2_en 0xA1AA -#define dagc2_en_pos 1 -#define dagc2_en_len 1 -#define dagc2_en_lsb 0 -#define xd_p_dagc2_mode 0xA1AA -#define dagc2_mode_pos 2 -#define dagc2_mode_len 2 -#define dagc2_mode_lsb 0 -#define xd_p_dagc2_done 0xA1AA -#define dagc2_done_pos 4 -#define dagc2_done_len 1 -#define dagc2_done_lsb 0 -#define xd_p_reg_dca_en 0xA1AB -#define reg_dca_en_pos 0 -#define reg_dca_en_len 1 -#define reg_dca_en_lsb 0 -#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0 -#define dagc2_accumulate_num_2k_7_0_pos 0 -#define dagc2_accumulate_num_2k_7_0_len 8 -#define dagc2_accumulate_num_2k_7_0_lsb 0 -#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1 -#define dagc2_accumulate_num_2k_12_8_pos 0 -#define dagc2_accumulate_num_2k_12_8_len 5 -#define dagc2_accumulate_num_2k_12_8_lsb 8 -#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2 -#define dagc2_accumulate_num_8k_7_0_pos 0 -#define dagc2_accumulate_num_8k_7_0_len 8 -#define dagc2_accumulate_num_8k_7_0_lsb 0 -#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3 -#define dagc2_accumulate_num_8k_12_8_pos 0 -#define dagc2_accumulate_num_8k_12_8_len 5 -#define dagc2_accumulate_num_8k_12_8_lsb 8 -#define xd_p_dagc2_desired_level_2_0 0xA1C3 -#define dagc2_desired_level_2_0_pos 5 -#define dagc2_desired_level_2_0_len 3 -#define dagc2_desired_level_2_0_lsb 0 -#define xd_p_dagc2_desired_level_8_3 0xA1C4 -#define dagc2_desired_level_8_3_pos 0 -#define dagc2_desired_level_8_3_len 6 -#define dagc2_desired_level_8_3_lsb 3 -#define xd_p_dagc2_apply_delay 0xA1C5 -#define dagc2_apply_delay_pos 0 -#define dagc2_apply_delay_len 7 -#define dagc2_apply_delay_lsb 0 -#define xd_p_dagc2_bypass_scale_ctl 0xA1C6 -#define dagc2_bypass_scale_ctl_pos 0 -#define dagc2_bypass_scale_ctl_len 3 -#define dagc2_bypass_scale_ctl_lsb 0 -#define xd_p_dagc2_programmable_shift1 0xA1C7 -#define dagc2_programmable_shift1_pos 0 -#define dagc2_programmable_shift1_len 8 -#define dagc2_programmable_shift1_lsb 0 -#define xd_p_dagc2_programmable_shift2 0xA1C8 -#define dagc2_programmable_shift2_pos 0 -#define dagc2_programmable_shift2_len 8 -#define dagc2_programmable_shift2_lsb 0 -#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9 -#define reg_dagc2_in_sat_cnt_7_0_pos 0 -#define reg_dagc2_in_sat_cnt_7_0_len 8 -#define reg_dagc2_in_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA -#define reg_dagc2_in_sat_cnt_15_8_pos 0 -#define reg_dagc2_in_sat_cnt_15_8_len 8 -#define reg_dagc2_in_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB -#define reg_dagc2_in_sat_cnt_23_16_pos 0 -#define reg_dagc2_in_sat_cnt_23_16_len 8 -#define reg_dagc2_in_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC -#define reg_dagc2_in_sat_cnt_31_24_pos 0 -#define reg_dagc2_in_sat_cnt_31_24_len 8 -#define reg_dagc2_in_sat_cnt_31_24_lsb 24 -#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD -#define reg_dagc2_out_sat_cnt_7_0_pos 0 -#define reg_dagc2_out_sat_cnt_7_0_len 8 -#define reg_dagc2_out_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE -#define reg_dagc2_out_sat_cnt_15_8_pos 0 -#define reg_dagc2_out_sat_cnt_15_8_len 8 -#define reg_dagc2_out_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF -#define reg_dagc2_out_sat_cnt_23_16_pos 0 -#define reg_dagc2_out_sat_cnt_23_16_len 8 -#define reg_dagc2_out_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0 -#define reg_dagc2_out_sat_cnt_31_24_pos 0 -#define reg_dagc2_out_sat_cnt_31_24_len 8 -#define reg_dagc2_out_sat_cnt_31_24_lsb 24 -#define xd_r_dagc2_multiplier_7_0 0xA1D6 -#define dagc2_multiplier_7_0_pos 0 -#define dagc2_multiplier_7_0_len 8 -#define dagc2_multiplier_7_0_lsb 0 -#define xd_r_dagc2_multiplier_15_8 0xA1D7 -#define dagc2_multiplier_15_8_pos 0 -#define dagc2_multiplier_15_8_len 8 -#define dagc2_multiplier_15_8_lsb 8 -#define xd_r_dagc2_right_shift_bits 0xA1D8 -#define dagc2_right_shift_bits_pos 0 -#define dagc2_right_shift_bits_len 4 -#define dagc2_right_shift_bits_lsb 0 -#define xd_p_cfoe_NS_coeff1_7_0 0xA200 -#define cfoe_NS_coeff1_7_0_pos 0 -#define cfoe_NS_coeff1_7_0_len 8 -#define cfoe_NS_coeff1_7_0_lsb 0 -#define xd_p_cfoe_NS_coeff1_15_8 0xA201 -#define cfoe_NS_coeff1_15_8_pos 0 -#define cfoe_NS_coeff1_15_8_len 8 -#define cfoe_NS_coeff1_15_8_lsb 8 -#define xd_p_cfoe_NS_coeff1_23_16 0xA202 -#define cfoe_NS_coeff1_23_16_pos 0 -#define cfoe_NS_coeff1_23_16_len 8 -#define cfoe_NS_coeff1_23_16_lsb 16 -#define xd_p_cfoe_NS_coeff1_25_24 0xA203 -#define cfoe_NS_coeff1_25_24_pos 0 -#define cfoe_NS_coeff1_25_24_len 2 -#define cfoe_NS_coeff1_25_24_lsb 24 -#define xd_p_cfoe_NS_coeff2_5_0 0xA203 -#define cfoe_NS_coeff2_5_0_pos 2 -#define cfoe_NS_coeff2_5_0_len 6 -#define cfoe_NS_coeff2_5_0_lsb 0 -#define xd_p_cfoe_NS_coeff2_13_6 0xA204 -#define cfoe_NS_coeff2_13_6_pos 0 -#define cfoe_NS_coeff2_13_6_len 8 -#define cfoe_NS_coeff2_13_6_lsb 6 -#define xd_p_cfoe_NS_coeff2_21_14 0xA205 -#define cfoe_NS_coeff2_21_14_pos 0 -#define cfoe_NS_coeff2_21_14_len 8 -#define cfoe_NS_coeff2_21_14_lsb 14 -#define xd_p_cfoe_NS_coeff2_24_22 0xA206 -#define cfoe_NS_coeff2_24_22_pos 0 -#define cfoe_NS_coeff2_24_22_len 3 -#define cfoe_NS_coeff2_24_22_lsb 22 -#define xd_p_cfoe_lf_c1_4_0 0xA206 -#define cfoe_lf_c1_4_0_pos 3 -#define cfoe_lf_c1_4_0_len 5 -#define cfoe_lf_c1_4_0_lsb 0 -#define xd_p_cfoe_lf_c1_12_5 0xA207 -#define cfoe_lf_c1_12_5_pos 0 -#define cfoe_lf_c1_12_5_len 8 -#define cfoe_lf_c1_12_5_lsb 5 -#define xd_p_cfoe_lf_c1_20_13 0xA208 -#define cfoe_lf_c1_20_13_pos 0 -#define cfoe_lf_c1_20_13_len 8 -#define cfoe_lf_c1_20_13_lsb 13 -#define xd_p_cfoe_lf_c1_25_21 0xA209 -#define cfoe_lf_c1_25_21_pos 0 -#define cfoe_lf_c1_25_21_len 5 -#define cfoe_lf_c1_25_21_lsb 21 -#define xd_p_cfoe_lf_c2_2_0 0xA209 -#define cfoe_lf_c2_2_0_pos 5 -#define cfoe_lf_c2_2_0_len 3 -#define cfoe_lf_c2_2_0_lsb 0 -#define xd_p_cfoe_lf_c2_10_3 0xA20A -#define cfoe_lf_c2_10_3_pos 0 -#define cfoe_lf_c2_10_3_len 8 -#define cfoe_lf_c2_10_3_lsb 3 -#define xd_p_cfoe_lf_c2_18_11 0xA20B -#define cfoe_lf_c2_18_11_pos 0 -#define cfoe_lf_c2_18_11_len 8 -#define cfoe_lf_c2_18_11_lsb 11 -#define xd_p_cfoe_lf_c2_25_19 0xA20C -#define cfoe_lf_c2_25_19_pos 0 -#define cfoe_lf_c2_25_19_len 7 -#define cfoe_lf_c2_25_19_lsb 19 -#define xd_p_cfoe_ifod_7_0 0xA20D -#define cfoe_ifod_7_0_pos 0 -#define cfoe_ifod_7_0_len 8 -#define cfoe_ifod_7_0_lsb 0 -#define xd_p_cfoe_ifod_10_8 0xA20E -#define cfoe_ifod_10_8_pos 0 -#define cfoe_ifod_10_8_len 3 -#define cfoe_ifod_10_8_lsb 8 -#define xd_p_cfoe_Divg_ctr_th 0xA20E -#define cfoe_Divg_ctr_th_pos 4 -#define cfoe_Divg_ctr_th_len 4 -#define cfoe_Divg_ctr_th_lsb 0 -#define xd_p_cfoe_FOT_divg_th 0xA20F -#define cfoe_FOT_divg_th_pos 0 -#define cfoe_FOT_divg_th_len 8 -#define cfoe_FOT_divg_th_lsb 0 -#define xd_p_cfoe_FOT_cnvg_th 0xA210 -#define cfoe_FOT_cnvg_th_pos 0 -#define cfoe_FOT_cnvg_th_len 8 -#define cfoe_FOT_cnvg_th_lsb 0 -#define xd_p_reg_cfoe_offset_7_0 0xA211 -#define reg_cfoe_offset_7_0_pos 0 -#define reg_cfoe_offset_7_0_len 8 -#define reg_cfoe_offset_7_0_lsb 0 -#define xd_p_reg_cfoe_offset_9_8 0xA212 -#define reg_cfoe_offset_9_8_pos 0 -#define reg_cfoe_offset_9_8_len 2 -#define reg_cfoe_offset_9_8_lsb 8 -#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212 -#define reg_cfoe_ifoe_sign_corr_pos 2 -#define reg_cfoe_ifoe_sign_corr_len 1 -#define reg_cfoe_ifoe_sign_corr_lsb 0 -#define xd_r_cfoe_fot_LF_output_7_0 0xA218 -#define cfoe_fot_LF_output_7_0_pos 0 -#define cfoe_fot_LF_output_7_0_len 8 -#define cfoe_fot_LF_output_7_0_lsb 0 -#define xd_r_cfoe_fot_LF_output_15_8 0xA219 -#define cfoe_fot_LF_output_15_8_pos 0 -#define cfoe_fot_LF_output_15_8_len 8 -#define cfoe_fot_LF_output_15_8_lsb 8 -#define xd_r_cfoe_ifo_metric_7_0 0xA21A -#define cfoe_ifo_metric_7_0_pos 0 -#define cfoe_ifo_metric_7_0_len 8 -#define cfoe_ifo_metric_7_0_lsb 0 -#define xd_r_cfoe_ifo_metric_15_8 0xA21B -#define cfoe_ifo_metric_15_8_pos 0 -#define cfoe_ifo_metric_15_8_len 8 -#define cfoe_ifo_metric_15_8_lsb 8 -#define xd_r_cfoe_ifo_metric_23_16 0xA21C -#define cfoe_ifo_metric_23_16_pos 0 -#define cfoe_ifo_metric_23_16_len 8 -#define cfoe_ifo_metric_23_16_lsb 16 -#define xd_p_ste_Nu 0xA220 -#define ste_Nu_pos 0 -#define ste_Nu_len 2 -#define ste_Nu_lsb 0 -#define xd_p_ste_GI 0xA220 -#define ste_GI_pos 2 -#define ste_GI_len 3 -#define ste_GI_lsb 0 -#define xd_p_ste_symbol_num 0xA221 -#define ste_symbol_num_pos 0 -#define ste_symbol_num_len 2 -#define ste_symbol_num_lsb 0 -#define xd_p_ste_sample_num 0xA221 -#define ste_sample_num_pos 2 -#define ste_sample_num_len 2 -#define ste_sample_num_lsb 0 -#define xd_p_reg_ste_buf_en 0xA221 -#define reg_ste_buf_en_pos 7 -#define reg_ste_buf_en_len 1 -#define reg_ste_buf_en_lsb 0 -#define xd_p_ste_FFT_offset_7_0 0xA222 -#define ste_FFT_offset_7_0_pos 0 -#define ste_FFT_offset_7_0_len 8 -#define ste_FFT_offset_7_0_lsb 0 -#define xd_p_ste_FFT_offset_11_8 0xA223 -#define ste_FFT_offset_11_8_pos 0 -#define ste_FFT_offset_11_8_len 4 -#define ste_FFT_offset_11_8_lsb 8 -#define xd_p_reg_ste_tstmod 0xA223 -#define reg_ste_tstmod_pos 5 -#define reg_ste_tstmod_len 1 -#define reg_ste_tstmod_lsb 0 -#define xd_p_ste_adv_start_7_0 0xA224 -#define ste_adv_start_7_0_pos 0 -#define ste_adv_start_7_0_len 8 -#define ste_adv_start_7_0_lsb 0 -#define xd_p_ste_adv_start_10_8 0xA225 -#define ste_adv_start_10_8_pos 0 -#define ste_adv_start_10_8_len 3 -#define ste_adv_start_10_8_lsb 8 -#define xd_p_ste_adv_stop 0xA226 -#define ste_adv_stop_pos 0 -#define ste_adv_stop_len 8 -#define ste_adv_stop_lsb 0 -#define xd_r_ste_P_value_7_0 0xA228 -#define ste_P_value_7_0_pos 0 -#define ste_P_value_7_0_len 8 -#define ste_P_value_7_0_lsb 0 -#define xd_r_ste_P_value_10_8 0xA229 -#define ste_P_value_10_8_pos 0 -#define ste_P_value_10_8_len 3 -#define ste_P_value_10_8_lsb 8 -#define xd_r_ste_M_value_7_0 0xA22A -#define ste_M_value_7_0_pos 0 -#define ste_M_value_7_0_len 8 -#define ste_M_value_7_0_lsb 0 -#define xd_r_ste_M_value_10_8 0xA22B -#define ste_M_value_10_8_pos 0 -#define ste_M_value_10_8_len 3 -#define ste_M_value_10_8_lsb 8 -#define xd_r_ste_H1 0xA22C -#define ste_H1_pos 0 -#define ste_H1_len 7 -#define ste_H1_lsb 0 -#define xd_r_ste_H2 0xA22D -#define ste_H2_pos 0 -#define ste_H2_len 7 -#define ste_H2_lsb 0 -#define xd_r_ste_H3 0xA22E -#define ste_H3_pos 0 -#define ste_H3_len 7 -#define ste_H3_lsb 0 -#define xd_r_ste_H4 0xA22F -#define ste_H4_pos 0 -#define ste_H4_len 7 -#define ste_H4_lsb 0 -#define xd_r_ste_Corr_value_I_7_0 0xA230 -#define ste_Corr_value_I_7_0_pos 0 -#define ste_Corr_value_I_7_0_len 8 -#define ste_Corr_value_I_7_0_lsb 0 -#define xd_r_ste_Corr_value_I_15_8 0xA231 -#define ste_Corr_value_I_15_8_pos 0 -#define ste_Corr_value_I_15_8_len 8 -#define ste_Corr_value_I_15_8_lsb 8 -#define xd_r_ste_Corr_value_I_23_16 0xA232 -#define ste_Corr_value_I_23_16_pos 0 -#define ste_Corr_value_I_23_16_len 8 -#define ste_Corr_value_I_23_16_lsb 16 -#define xd_r_ste_Corr_value_I_27_24 0xA233 -#define ste_Corr_value_I_27_24_pos 0 -#define ste_Corr_value_I_27_24_len 4 -#define ste_Corr_value_I_27_24_lsb 24 -#define xd_r_ste_Corr_value_Q_7_0 0xA234 -#define ste_Corr_value_Q_7_0_pos 0 -#define ste_Corr_value_Q_7_0_len 8 -#define ste_Corr_value_Q_7_0_lsb 0 -#define xd_r_ste_Corr_value_Q_15_8 0xA235 -#define ste_Corr_value_Q_15_8_pos 0 -#define ste_Corr_value_Q_15_8_len 8 -#define ste_Corr_value_Q_15_8_lsb 8 -#define xd_r_ste_Corr_value_Q_23_16 0xA236 -#define ste_Corr_value_Q_23_16_pos 0 -#define ste_Corr_value_Q_23_16_len 8 -#define ste_Corr_value_Q_23_16_lsb 16 -#define xd_r_ste_Corr_value_Q_27_24 0xA237 -#define ste_Corr_value_Q_27_24_pos 0 -#define ste_Corr_value_Q_27_24_len 4 -#define ste_Corr_value_Q_27_24_lsb 24 -#define xd_r_ste_J_num_7_0 0xA238 -#define ste_J_num_7_0_pos 0 -#define ste_J_num_7_0_len 8 -#define ste_J_num_7_0_lsb 0 -#define xd_r_ste_J_num_15_8 0xA239 -#define ste_J_num_15_8_pos 0 -#define ste_J_num_15_8_len 8 -#define ste_J_num_15_8_lsb 8 -#define xd_r_ste_J_num_23_16 0xA23A -#define ste_J_num_23_16_pos 0 -#define ste_J_num_23_16_len 8 -#define ste_J_num_23_16_lsb 16 -#define xd_r_ste_J_num_31_24 0xA23B -#define ste_J_num_31_24_pos 0 -#define ste_J_num_31_24_len 8 -#define ste_J_num_31_24_lsb 24 -#define xd_r_ste_J_den_7_0 0xA23C -#define ste_J_den_7_0_pos 0 -#define ste_J_den_7_0_len 8 -#define ste_J_den_7_0_lsb 0 -#define xd_r_ste_J_den_15_8 0xA23D -#define ste_J_den_15_8_pos 0 -#define ste_J_den_15_8_len 8 -#define ste_J_den_15_8_lsb 8 -#define xd_r_ste_J_den_18_16 0xA23E -#define ste_J_den_18_16_pos 0 -#define ste_J_den_18_16_len 3 -#define ste_J_den_18_16_lsb 16 -#define xd_r_ste_Beacon_Indicator 0xA23E -#define ste_Beacon_Indicator_pos 4 -#define ste_Beacon_Indicator_len 1 -#define ste_Beacon_Indicator_lsb 0 -#define xd_r_tpsd_Frame_Num 0xA250 -#define tpsd_Frame_Num_pos 0 -#define tpsd_Frame_Num_len 2 -#define tpsd_Frame_Num_lsb 0 -#define xd_r_tpsd_Constel 0xA250 -#define tpsd_Constel_pos 2 -#define tpsd_Constel_len 2 -#define tpsd_Constel_lsb 0 -#define xd_r_tpsd_GI 0xA250 -#define tpsd_GI_pos 4 -#define tpsd_GI_len 2 -#define tpsd_GI_lsb 0 -#define xd_r_tpsd_Mode 0xA250 -#define tpsd_Mode_pos 6 -#define tpsd_Mode_len 2 -#define tpsd_Mode_lsb 0 -#define xd_r_tpsd_CR_HP 0xA251 -#define tpsd_CR_HP_pos 0 -#define tpsd_CR_HP_len 3 -#define tpsd_CR_HP_lsb 0 -#define xd_r_tpsd_CR_LP 0xA251 -#define tpsd_CR_LP_pos 3 -#define tpsd_CR_LP_len 3 -#define tpsd_CR_LP_lsb 0 -#define xd_r_tpsd_Hie 0xA252 -#define tpsd_Hie_pos 0 -#define tpsd_Hie_len 3 -#define tpsd_Hie_lsb 0 -#define xd_r_tpsd_Res_Bits 0xA252 -#define tpsd_Res_Bits_pos 3 -#define tpsd_Res_Bits_len 5 -#define tpsd_Res_Bits_lsb 0 -#define xd_r_tpsd_Res_Bits_0 0xA253 -#define tpsd_Res_Bits_0_pos 0 -#define tpsd_Res_Bits_0_len 1 -#define tpsd_Res_Bits_0_lsb 0 -#define xd_r_tpsd_LengthInd 0xA253 -#define tpsd_LengthInd_pos 1 -#define tpsd_LengthInd_len 6 -#define tpsd_LengthInd_lsb 0 -#define xd_r_tpsd_Cell_Id_7_0 0xA254 -#define tpsd_Cell_Id_7_0_pos 0 -#define tpsd_Cell_Id_7_0_len 8 -#define tpsd_Cell_Id_7_0_lsb 0 -#define xd_r_tpsd_Cell_Id_15_8 0xA255 -#define tpsd_Cell_Id_15_8_pos 0 -#define tpsd_Cell_Id_15_8_len 8 -#define tpsd_Cell_Id_15_8_lsb 0 -#define xd_p_reg_fft_mask_tone0_7_0 0xA260 -#define reg_fft_mask_tone0_7_0_pos 0 -#define reg_fft_mask_tone0_7_0_len 8 -#define reg_fft_mask_tone0_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone0_12_8 0xA261 -#define reg_fft_mask_tone0_12_8_pos 0 -#define reg_fft_mask_tone0_12_8_len 5 -#define reg_fft_mask_tone0_12_8_lsb 8 -#define xd_p_reg_fft_mask_tone1_7_0 0xA262 -#define reg_fft_mask_tone1_7_0_pos 0 -#define reg_fft_mask_tone1_7_0_len 8 -#define reg_fft_mask_tone1_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone1_12_8 0xA263 -#define reg_fft_mask_tone1_12_8_pos 0 -#define reg_fft_mask_tone1_12_8_len 5 -#define reg_fft_mask_tone1_12_8_lsb 8 -#define xd_p_reg_fft_mask_tone2_7_0 0xA264 -#define reg_fft_mask_tone2_7_0_pos 0 -#define reg_fft_mask_tone2_7_0_len 8 -#define reg_fft_mask_tone2_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone2_12_8 0xA265 -#define reg_fft_mask_tone2_12_8_pos 0 -#define reg_fft_mask_tone2_12_8_len 5 -#define reg_fft_mask_tone2_12_8_lsb 8 -#define xd_p_reg_fft_mask_tone3_7_0 0xA266 -#define reg_fft_mask_tone3_7_0_pos 0 -#define reg_fft_mask_tone3_7_0_len 8 -#define reg_fft_mask_tone3_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone3_12_8 0xA267 -#define reg_fft_mask_tone3_12_8_pos 0 -#define reg_fft_mask_tone3_12_8_len 5 -#define reg_fft_mask_tone3_12_8_lsb 8 -#define xd_p_reg_fft_mask_from0_7_0 0xA268 -#define reg_fft_mask_from0_7_0_pos 0 -#define reg_fft_mask_from0_7_0_len 8 -#define reg_fft_mask_from0_7_0_lsb 0 -#define xd_p_reg_fft_mask_from0_12_8 0xA269 -#define reg_fft_mask_from0_12_8_pos 0 -#define reg_fft_mask_from0_12_8_len 5 -#define reg_fft_mask_from0_12_8_lsb 8 -#define xd_p_reg_fft_mask_to0_7_0 0xA26A -#define reg_fft_mask_to0_7_0_pos 0 -#define reg_fft_mask_to0_7_0_len 8 -#define reg_fft_mask_to0_7_0_lsb 0 -#define xd_p_reg_fft_mask_to0_12_8 0xA26B -#define reg_fft_mask_to0_12_8_pos 0 -#define reg_fft_mask_to0_12_8_len 5 -#define reg_fft_mask_to0_12_8_lsb 8 -#define xd_p_reg_fft_mask_from1_7_0 0xA26C -#define reg_fft_mask_from1_7_0_pos 0 -#define reg_fft_mask_from1_7_0_len 8 -#define reg_fft_mask_from1_7_0_lsb 0 -#define xd_p_reg_fft_mask_from1_12_8 0xA26D -#define reg_fft_mask_from1_12_8_pos 0 -#define reg_fft_mask_from1_12_8_len 5 -#define reg_fft_mask_from1_12_8_lsb 8 -#define xd_p_reg_fft_mask_to1_7_0 0xA26E -#define reg_fft_mask_to1_7_0_pos 0 -#define reg_fft_mask_to1_7_0_len 8 -#define reg_fft_mask_to1_7_0_lsb 0 -#define xd_p_reg_fft_mask_to1_12_8 0xA26F -#define reg_fft_mask_to1_12_8_pos 0 -#define reg_fft_mask_to1_12_8_len 5 -#define reg_fft_mask_to1_12_8_lsb 8 -#define xd_p_reg_cge_idx0_7_0 0xA280 -#define reg_cge_idx0_7_0_pos 0 -#define reg_cge_idx0_7_0_len 8 -#define reg_cge_idx0_7_0_lsb 0 -#define xd_p_reg_cge_idx0_12_8 0xA281 -#define reg_cge_idx0_12_8_pos 0 -#define reg_cge_idx0_12_8_len 5 -#define reg_cge_idx0_12_8_lsb 8 -#define xd_p_reg_cge_idx1_7_0 0xA282 -#define reg_cge_idx1_7_0_pos 0 -#define reg_cge_idx1_7_0_len 8 -#define reg_cge_idx1_7_0_lsb 0 -#define xd_p_reg_cge_idx1_12_8 0xA283 -#define reg_cge_idx1_12_8_pos 0 -#define reg_cge_idx1_12_8_len 5 -#define reg_cge_idx1_12_8_lsb 8 -#define xd_p_reg_cge_idx2_7_0 0xA284 -#define reg_cge_idx2_7_0_pos 0 -#define reg_cge_idx2_7_0_len 8 -#define reg_cge_idx2_7_0_lsb 0 -#define xd_p_reg_cge_idx2_12_8 0xA285 -#define reg_cge_idx2_12_8_pos 0 -#define reg_cge_idx2_12_8_len 5 -#define reg_cge_idx2_12_8_lsb 8 -#define xd_p_reg_cge_idx3_7_0 0xA286 -#define reg_cge_idx3_7_0_pos 0 -#define reg_cge_idx3_7_0_len 8 -#define reg_cge_idx3_7_0_lsb 0 -#define xd_p_reg_cge_idx3_12_8 0xA287 -#define reg_cge_idx3_12_8_pos 0 -#define reg_cge_idx3_12_8_len 5 -#define reg_cge_idx3_12_8_lsb 8 -#define xd_p_reg_cge_idx4_7_0 0xA288 -#define reg_cge_idx4_7_0_pos 0 -#define reg_cge_idx4_7_0_len 8 -#define reg_cge_idx4_7_0_lsb 0 -#define xd_p_reg_cge_idx4_12_8 0xA289 -#define reg_cge_idx4_12_8_pos 0 -#define reg_cge_idx4_12_8_len 5 -#define reg_cge_idx4_12_8_lsb 8 -#define xd_p_reg_cge_idx5_7_0 0xA28A -#define reg_cge_idx5_7_0_pos 0 -#define reg_cge_idx5_7_0_len 8 -#define reg_cge_idx5_7_0_lsb 0 -#define xd_p_reg_cge_idx5_12_8 0xA28B -#define reg_cge_idx5_12_8_pos 0 -#define reg_cge_idx5_12_8_len 5 -#define reg_cge_idx5_12_8_lsb 8 -#define xd_p_reg_cge_idx6_7_0 0xA28C -#define reg_cge_idx6_7_0_pos 0 -#define reg_cge_idx6_7_0_len 8 -#define reg_cge_idx6_7_0_lsb 0 -#define xd_p_reg_cge_idx6_12_8 0xA28D -#define reg_cge_idx6_12_8_pos 0 -#define reg_cge_idx6_12_8_len 5 -#define reg_cge_idx6_12_8_lsb 8 -#define xd_p_reg_cge_idx7_7_0 0xA28E -#define reg_cge_idx7_7_0_pos 0 -#define reg_cge_idx7_7_0_len 8 -#define reg_cge_idx7_7_0_lsb 0 -#define xd_p_reg_cge_idx7_12_8 0xA28F -#define reg_cge_idx7_12_8_pos 0 -#define reg_cge_idx7_12_8_len 5 -#define reg_cge_idx7_12_8_lsb 8 -#define xd_p_reg_cge_idx8_7_0 0xA290 -#define reg_cge_idx8_7_0_pos 0 -#define reg_cge_idx8_7_0_len 8 -#define reg_cge_idx8_7_0_lsb 0 -#define xd_p_reg_cge_idx8_12_8 0xA291 -#define reg_cge_idx8_12_8_pos 0 -#define reg_cge_idx8_12_8_len 5 -#define reg_cge_idx8_12_8_lsb 8 -#define xd_p_reg_cge_idx9_7_0 0xA292 -#define reg_cge_idx9_7_0_pos 0 -#define reg_cge_idx9_7_0_len 8 -#define reg_cge_idx9_7_0_lsb 0 -#define xd_p_reg_cge_idx9_12_8 0xA293 -#define reg_cge_idx9_12_8_pos 0 -#define reg_cge_idx9_12_8_len 5 -#define reg_cge_idx9_12_8_lsb 8 -#define xd_p_reg_cge_idx10_7_0 0xA294 -#define reg_cge_idx10_7_0_pos 0 -#define reg_cge_idx10_7_0_len 8 -#define reg_cge_idx10_7_0_lsb 0 -#define xd_p_reg_cge_idx10_12_8 0xA295 -#define reg_cge_idx10_12_8_pos 0 -#define reg_cge_idx10_12_8_len 5 -#define reg_cge_idx10_12_8_lsb 8 -#define xd_p_reg_cge_idx11_7_0 0xA296 -#define reg_cge_idx11_7_0_pos 0 -#define reg_cge_idx11_7_0_len 8 -#define reg_cge_idx11_7_0_lsb 0 -#define xd_p_reg_cge_idx11_12_8 0xA297 -#define reg_cge_idx11_12_8_pos 0 -#define reg_cge_idx11_12_8_len 5 -#define reg_cge_idx11_12_8_lsb 8 -#define xd_p_reg_cge_idx12_7_0 0xA298 -#define reg_cge_idx12_7_0_pos 0 -#define reg_cge_idx12_7_0_len 8 -#define reg_cge_idx12_7_0_lsb 0 -#define xd_p_reg_cge_idx12_12_8 0xA299 -#define reg_cge_idx12_12_8_pos 0 -#define reg_cge_idx12_12_8_len 5 -#define reg_cge_idx12_12_8_lsb 8 -#define xd_p_reg_cge_idx13_7_0 0xA29A -#define reg_cge_idx13_7_0_pos 0 -#define reg_cge_idx13_7_0_len 8 -#define reg_cge_idx13_7_0_lsb 0 -#define xd_p_reg_cge_idx13_12_8 0xA29B -#define reg_cge_idx13_12_8_pos 0 -#define reg_cge_idx13_12_8_len 5 -#define reg_cge_idx13_12_8_lsb 8 -#define xd_p_reg_cge_idx14_7_0 0xA29C -#define reg_cge_idx14_7_0_pos 0 -#define reg_cge_idx14_7_0_len 8 -#define reg_cge_idx14_7_0_lsb 0 -#define xd_p_reg_cge_idx14_12_8 0xA29D -#define reg_cge_idx14_12_8_pos 0 -#define reg_cge_idx14_12_8_len 5 -#define reg_cge_idx14_12_8_lsb 8 -#define xd_p_reg_cge_idx15_7_0 0xA29E -#define reg_cge_idx15_7_0_pos 0 -#define reg_cge_idx15_7_0_len 8 -#define reg_cge_idx15_7_0_lsb 0 -#define xd_p_reg_cge_idx15_12_8 0xA29F -#define reg_cge_idx15_12_8_pos 0 -#define reg_cge_idx15_12_8_len 5 -#define reg_cge_idx15_12_8_lsb 8 -#define xd_r_reg_fft_crc 0xA2A8 -#define reg_fft_crc_pos 0 -#define reg_fft_crc_len 8 -#define reg_fft_crc_lsb 0 -#define xd_p_fd_fft_shift_max 0xA2A9 -#define fd_fft_shift_max_pos 0 -#define fd_fft_shift_max_len 4 -#define fd_fft_shift_max_lsb 0 -#define xd_r_fd_fft_shift 0xA2A9 -#define fd_fft_shift_pos 4 -#define fd_fft_shift_len 4 -#define fd_fft_shift_lsb 0 -#define xd_r_fd_fft_frame_num 0xA2AA -#define fd_fft_frame_num_pos 0 -#define fd_fft_frame_num_len 2 -#define fd_fft_frame_num_lsb 0 -#define xd_r_fd_fft_symbol_count 0xA2AB -#define fd_fft_symbol_count_pos 0 -#define fd_fft_symbol_count_len 7 -#define fd_fft_symbol_count_lsb 0 -#define xd_r_reg_fft_idx_max_7_0 0xA2AC -#define reg_fft_idx_max_7_0_pos 0 -#define reg_fft_idx_max_7_0_len 8 -#define reg_fft_idx_max_7_0_lsb 0 -#define xd_r_reg_fft_idx_max_12_8 0xA2AD -#define reg_fft_idx_max_12_8_pos 0 -#define reg_fft_idx_max_12_8_len 5 -#define reg_fft_idx_max_12_8_lsb 8 -#define xd_p_reg_cge_program 0xA2AE -#define reg_cge_program_pos 0 -#define reg_cge_program_len 1 -#define reg_cge_program_lsb 0 -#define xd_p_reg_cge_fixed 0xA2AE -#define reg_cge_fixed_pos 1 -#define reg_cge_fixed_len 1 -#define reg_cge_fixed_lsb 0 -#define xd_p_reg_fft_rotate_en 0xA2AE -#define reg_fft_rotate_en_pos 2 -#define reg_fft_rotate_en_len 1 -#define reg_fft_rotate_en_lsb 0 -#define xd_p_reg_fft_rotate_base_4_0 0xA2AE -#define reg_fft_rotate_base_4_0_pos 3 -#define reg_fft_rotate_base_4_0_len 5 -#define reg_fft_rotate_base_4_0_lsb 0 -#define xd_p_reg_fft_rotate_base_12_5 0xA2AF -#define reg_fft_rotate_base_12_5_pos 0 -#define reg_fft_rotate_base_12_5_len 8 -#define reg_fft_rotate_base_12_5_lsb 5 -#define xd_p_reg_gp_trigger_fd 0xA2B8 -#define reg_gp_trigger_fd_pos 0 -#define reg_gp_trigger_fd_len 1 -#define reg_gp_trigger_fd_lsb 0 -#define xd_p_reg_trigger_sel_fd 0xA2B8 -#define reg_trigger_sel_fd_pos 1 -#define reg_trigger_sel_fd_len 2 -#define reg_trigger_sel_fd_lsb 0 -#define xd_p_reg_trigger_module_sel_fd 0xA2B9 -#define reg_trigger_module_sel_fd_pos 0 -#define reg_trigger_module_sel_fd_len 6 -#define reg_trigger_module_sel_fd_lsb 0 -#define xd_p_reg_trigger_set_sel_fd 0xA2BA -#define reg_trigger_set_sel_fd_pos 0 -#define reg_trigger_set_sel_fd_len 6 -#define reg_trigger_set_sel_fd_lsb 0 -#define xd_p_reg_fd_noname_7_0 0xA2BC -#define reg_fd_noname_7_0_pos 0 -#define reg_fd_noname_7_0_len 8 -#define reg_fd_noname_7_0_lsb 0 -#define xd_p_reg_fd_noname_15_8 0xA2BD -#define reg_fd_noname_15_8_pos 0 -#define reg_fd_noname_15_8_len 8 -#define reg_fd_noname_15_8_lsb 8 -#define xd_p_reg_fd_noname_23_16 0xA2BE -#define reg_fd_noname_23_16_pos 0 -#define reg_fd_noname_23_16_len 8 -#define reg_fd_noname_23_16_lsb 16 -#define xd_p_reg_fd_noname_31_24 0xA2BF -#define reg_fd_noname_31_24_pos 0 -#define reg_fd_noname_31_24_len 8 -#define reg_fd_noname_31_24_lsb 24 -#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0 -#define fd_fpcc_cp_corr_signn_pos 0 -#define fd_fpcc_cp_corr_signn_len 8 -#define fd_fpcc_cp_corr_signn_lsb 0 -#define xd_p_reg_feq_s1 0xA2C1 -#define reg_feq_s1_pos 0 -#define reg_feq_s1_len 5 -#define reg_feq_s1_lsb 0 -#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2 -#define fd_fpcc_cp_corr_tone_th_pos 0 -#define fd_fpcc_cp_corr_tone_th_len 6 -#define fd_fpcc_cp_corr_tone_th_lsb 0 -#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3 -#define fd_fpcc_cp_corr_symbol_log_th_pos 0 -#define fd_fpcc_cp_corr_symbol_log_th_len 4 -#define fd_fpcc_cp_corr_symbol_log_th_lsb 0 -#define xd_p_fd_fpcc_cp_corr_int 0xA2C4 -#define fd_fpcc_cp_corr_int_pos 0 -#define fd_fpcc_cp_corr_int_len 1 -#define fd_fpcc_cp_corr_int_lsb 0 -#define xd_p_reg_sfoe_ns_7_0 0xA320 -#define reg_sfoe_ns_7_0_pos 0 -#define reg_sfoe_ns_7_0_len 8 -#define reg_sfoe_ns_7_0_lsb 0 -#define xd_p_reg_sfoe_ns_14_8 0xA321 -#define reg_sfoe_ns_14_8_pos 0 -#define reg_sfoe_ns_14_8_len 7 -#define reg_sfoe_ns_14_8_lsb 8 -#define xd_p_reg_sfoe_c1_7_0 0xA322 -#define reg_sfoe_c1_7_0_pos 0 -#define reg_sfoe_c1_7_0_len 8 -#define reg_sfoe_c1_7_0_lsb 0 -#define xd_p_reg_sfoe_c1_15_8 0xA323 -#define reg_sfoe_c1_15_8_pos 0 -#define reg_sfoe_c1_15_8_len 8 -#define reg_sfoe_c1_15_8_lsb 8 -#define xd_p_reg_sfoe_c1_17_16 0xA324 -#define reg_sfoe_c1_17_16_pos 0 -#define reg_sfoe_c1_17_16_len 2 -#define reg_sfoe_c1_17_16_lsb 16 -#define xd_p_reg_sfoe_c2_7_0 0xA325 -#define reg_sfoe_c2_7_0_pos 0 -#define reg_sfoe_c2_7_0_len 8 -#define reg_sfoe_c2_7_0_lsb 0 -#define xd_p_reg_sfoe_c2_15_8 0xA326 -#define reg_sfoe_c2_15_8_pos 0 -#define reg_sfoe_c2_15_8_len 8 -#define reg_sfoe_c2_15_8_lsb 8 -#define xd_p_reg_sfoe_c2_17_16 0xA327 -#define reg_sfoe_c2_17_16_pos 0 -#define reg_sfoe_c2_17_16_len 2 -#define reg_sfoe_c2_17_16_lsb 16 -#define xd_r_reg_sfoe_out_9_2 0xA328 -#define reg_sfoe_out_9_2_pos 0 -#define reg_sfoe_out_9_2_len 8 -#define reg_sfoe_out_9_2_lsb 0 -#define xd_r_reg_sfoe_out_1_0 0xA329 -#define reg_sfoe_out_1_0_pos 0 -#define reg_sfoe_out_1_0_len 2 -#define reg_sfoe_out_1_0_lsb 0 -#define xd_p_reg_sfoe_lm_counter_th 0xA32A -#define reg_sfoe_lm_counter_th_pos 0 -#define reg_sfoe_lm_counter_th_len 4 -#define reg_sfoe_lm_counter_th_lsb 0 -#define xd_p_reg_sfoe_convg_th 0xA32B -#define reg_sfoe_convg_th_pos 0 -#define reg_sfoe_convg_th_len 8 -#define reg_sfoe_convg_th_lsb 0 -#define xd_p_reg_sfoe_divg_th 0xA32C -#define reg_sfoe_divg_th_pos 0 -#define reg_sfoe_divg_th_len 8 -#define reg_sfoe_divg_th_lsb 0 -#define xd_p_fd_tpsd_en 0xA330 -#define fd_tpsd_en_pos 0 -#define fd_tpsd_en_len 1 -#define fd_tpsd_en_lsb 0 -#define xd_p_fd_tpsd_dis 0xA330 -#define fd_tpsd_dis_pos 1 -#define fd_tpsd_dis_len 1 -#define fd_tpsd_dis_lsb 0 -#define xd_p_fd_tpsd_rst 0xA330 -#define fd_tpsd_rst_pos 2 -#define fd_tpsd_rst_len 1 -#define fd_tpsd_rst_lsb 0 -#define xd_p_fd_tpsd_lock 0xA330 -#define fd_tpsd_lock_pos 3 -#define fd_tpsd_lock_len 1 -#define fd_tpsd_lock_lsb 0 -#define xd_r_fd_tpsd_s19 0xA330 -#define fd_tpsd_s19_pos 4 -#define fd_tpsd_s19_len 1 -#define fd_tpsd_s19_lsb 0 -#define xd_r_fd_tpsd_s17 0xA330 -#define fd_tpsd_s17_pos 5 -#define fd_tpsd_s17_len 1 -#define fd_tpsd_s17_lsb 0 -#define xd_p_fd_sfr_ste_en 0xA331 -#define fd_sfr_ste_en_pos 0 -#define fd_sfr_ste_en_len 1 -#define fd_sfr_ste_en_lsb 0 -#define xd_p_fd_sfr_ste_dis 0xA331 -#define fd_sfr_ste_dis_pos 1 -#define fd_sfr_ste_dis_len 1 -#define fd_sfr_ste_dis_lsb 0 -#define xd_p_fd_sfr_ste_rst 0xA331 -#define fd_sfr_ste_rst_pos 2 -#define fd_sfr_ste_rst_len 1 -#define fd_sfr_ste_rst_lsb 0 -#define xd_p_fd_sfr_ste_mode 0xA331 -#define fd_sfr_ste_mode_pos 3 -#define fd_sfr_ste_mode_len 1 -#define fd_sfr_ste_mode_lsb 0 -#define xd_p_fd_sfr_ste_done 0xA331 -#define fd_sfr_ste_done_pos 4 -#define fd_sfr_ste_done_len 1 -#define fd_sfr_ste_done_lsb 0 -#define xd_p_reg_cfoe_ffoe_en 0xA332 -#define reg_cfoe_ffoe_en_pos 0 -#define reg_cfoe_ffoe_en_len 1 -#define reg_cfoe_ffoe_en_lsb 0 -#define xd_p_reg_cfoe_ffoe_dis 0xA332 -#define reg_cfoe_ffoe_dis_pos 1 -#define reg_cfoe_ffoe_dis_len 1 -#define reg_cfoe_ffoe_dis_lsb 0 -#define xd_p_reg_cfoe_ffoe_rst 0xA332 -#define reg_cfoe_ffoe_rst_pos 2 -#define reg_cfoe_ffoe_rst_len 1 -#define reg_cfoe_ffoe_rst_lsb 0 -#define xd_p_reg_cfoe_ifoe_en 0xA332 -#define reg_cfoe_ifoe_en_pos 3 -#define reg_cfoe_ifoe_en_len 1 -#define reg_cfoe_ifoe_en_lsb 0 -#define xd_p_reg_cfoe_ifoe_dis 0xA332 -#define reg_cfoe_ifoe_dis_pos 4 -#define reg_cfoe_ifoe_dis_len 1 -#define reg_cfoe_ifoe_dis_lsb 0 -#define xd_p_reg_cfoe_ifoe_rst 0xA332 -#define reg_cfoe_ifoe_rst_pos 5 -#define reg_cfoe_ifoe_rst_len 1 -#define reg_cfoe_ifoe_rst_lsb 0 -#define xd_p_reg_cfoe_fot_en 0xA332 -#define reg_cfoe_fot_en_pos 6 -#define reg_cfoe_fot_en_len 1 -#define reg_cfoe_fot_en_lsb 0 -#define xd_p_reg_cfoe_fot_lm_en 0xA332 -#define reg_cfoe_fot_lm_en_pos 7 -#define reg_cfoe_fot_lm_en_len 1 -#define reg_cfoe_fot_lm_en_lsb 0 -#define xd_p_reg_cfoe_fot_rst 0xA333 -#define reg_cfoe_fot_rst_pos 0 -#define reg_cfoe_fot_rst_len 1 -#define reg_cfoe_fot_rst_lsb 0 -#define xd_r_fd_cfoe_ffoe_done 0xA333 -#define fd_cfoe_ffoe_done_pos 1 -#define fd_cfoe_ffoe_done_len 1 -#define fd_cfoe_ffoe_done_lsb 0 -#define xd_p_fd_cfoe_metric_vld 0xA333 -#define fd_cfoe_metric_vld_pos 2 -#define fd_cfoe_metric_vld_len 1 -#define fd_cfoe_metric_vld_lsb 0 -#define xd_p_reg_cfoe_ifod_vld 0xA333 -#define reg_cfoe_ifod_vld_pos 3 -#define reg_cfoe_ifod_vld_len 1 -#define reg_cfoe_ifod_vld_lsb 0 -#define xd_r_fd_cfoe_ifoe_done 0xA333 -#define fd_cfoe_ifoe_done_pos 4 -#define fd_cfoe_ifoe_done_len 1 -#define fd_cfoe_ifoe_done_lsb 0 -#define xd_r_fd_cfoe_fot_valid 0xA333 -#define fd_cfoe_fot_valid_pos 5 -#define fd_cfoe_fot_valid_len 1 -#define fd_cfoe_fot_valid_lsb 0 -#define xd_p_reg_cfoe_divg_int 0xA333 -#define reg_cfoe_divg_int_pos 6 -#define reg_cfoe_divg_int_len 1 -#define reg_cfoe_divg_int_lsb 0 -#define xd_r_reg_cfoe_divg_flag 0xA333 -#define reg_cfoe_divg_flag_pos 7 -#define reg_cfoe_divg_flag_len 1 -#define reg_cfoe_divg_flag_lsb 0 -#define xd_p_reg_sfoe_en 0xA334 -#define reg_sfoe_en_pos 0 -#define reg_sfoe_en_len 1 -#define reg_sfoe_en_lsb 0 -#define xd_p_reg_sfoe_dis 0xA334 -#define reg_sfoe_dis_pos 1 -#define reg_sfoe_dis_len 1 -#define reg_sfoe_dis_lsb 0 -#define xd_p_reg_sfoe_rst 0xA334 -#define reg_sfoe_rst_pos 2 -#define reg_sfoe_rst_len 1 -#define reg_sfoe_rst_lsb 0 -#define xd_p_reg_sfoe_vld_int 0xA334 -#define reg_sfoe_vld_int_pos 3 -#define reg_sfoe_vld_int_len 1 -#define reg_sfoe_vld_int_lsb 0 -#define xd_p_reg_sfoe_lm_en 0xA334 -#define reg_sfoe_lm_en_pos 4 -#define reg_sfoe_lm_en_len 1 -#define reg_sfoe_lm_en_lsb 0 -#define xd_p_reg_sfoe_divg_int 0xA334 -#define reg_sfoe_divg_int_pos 5 -#define reg_sfoe_divg_int_len 1 -#define reg_sfoe_divg_int_lsb 0 -#define xd_r_reg_sfoe_divg_flag 0xA334 -#define reg_sfoe_divg_flag_pos 6 -#define reg_sfoe_divg_flag_len 1 -#define reg_sfoe_divg_flag_lsb 0 -#define xd_p_reg_fft_rst 0xA335 -#define reg_fft_rst_pos 0 -#define reg_fft_rst_len 1 -#define reg_fft_rst_lsb 0 -#define xd_p_reg_fft_fast_beacon 0xA335 -#define reg_fft_fast_beacon_pos 1 -#define reg_fft_fast_beacon_len 1 -#define reg_fft_fast_beacon_lsb 0 -#define xd_p_reg_fft_fast_valid 0xA335 -#define reg_fft_fast_valid_pos 2 -#define reg_fft_fast_valid_len 1 -#define reg_fft_fast_valid_lsb 0 -#define xd_p_reg_fft_mask_en 0xA335 -#define reg_fft_mask_en_pos 3 -#define reg_fft_mask_en_len 1 -#define reg_fft_mask_en_lsb 0 -#define xd_p_reg_fft_crc_en 0xA335 -#define reg_fft_crc_en_pos 4 -#define reg_fft_crc_en_len 1 -#define reg_fft_crc_en_lsb 0 -#define xd_p_reg_finr_en 0xA336 -#define reg_finr_en_pos 0 -#define reg_finr_en_len 1 -#define reg_finr_en_lsb 0 -#define xd_p_fd_fste_en 0xA337 -#define fd_fste_en_pos 1 -#define fd_fste_en_len 1 -#define fd_fste_en_lsb 0 -#define xd_p_fd_sqi_tps_level_shift 0xA338 -#define fd_sqi_tps_level_shift_pos 0 -#define fd_sqi_tps_level_shift_len 8 -#define fd_sqi_tps_level_shift_lsb 0 -#define xd_p_fd_pilot_ma_len 0xA339 -#define fd_pilot_ma_len_pos 0 -#define fd_pilot_ma_len_len 6 -#define fd_pilot_ma_len_lsb 0 -#define xd_p_fd_tps_ma_len 0xA33A -#define fd_tps_ma_len_pos 0 -#define fd_tps_ma_len_len 6 -#define fd_tps_ma_len_lsb 0 -#define xd_p_fd_sqi_s3 0xA33B -#define fd_sqi_s3_pos 0 -#define fd_sqi_s3_len 8 -#define fd_sqi_s3_lsb 0 -#define xd_p_fd_sqi_dummy_reg_0 0xA33C -#define fd_sqi_dummy_reg_0_pos 0 -#define fd_sqi_dummy_reg_0_len 1 -#define fd_sqi_dummy_reg_0_lsb 0 -#define xd_p_fd_sqi_debug_sel 0xA33C -#define fd_sqi_debug_sel_pos 1 -#define fd_sqi_debug_sel_len 2 -#define fd_sqi_debug_sel_lsb 0 -#define xd_p_fd_sqi_s2 0xA33C -#define fd_sqi_s2_pos 3 -#define fd_sqi_s2_len 5 -#define fd_sqi_s2_lsb 0 -#define xd_p_fd_sqi_dummy_reg_1 0xA33D -#define fd_sqi_dummy_reg_1_pos 0 -#define fd_sqi_dummy_reg_1_len 1 -#define fd_sqi_dummy_reg_1_lsb 0 -#define xd_p_fd_inr_ignore 0xA33D -#define fd_inr_ignore_pos 1 -#define fd_inr_ignore_len 1 -#define fd_inr_ignore_lsb 0 -#define xd_p_fd_pilot_ignore 0xA33D -#define fd_pilot_ignore_pos 2 -#define fd_pilot_ignore_len 1 -#define fd_pilot_ignore_lsb 0 -#define xd_p_fd_etps_ignore 0xA33D -#define fd_etps_ignore_pos 3 -#define fd_etps_ignore_len 1 -#define fd_etps_ignore_lsb 0 -#define xd_p_fd_sqi_s1 0xA33D -#define fd_sqi_s1_pos 4 -#define fd_sqi_s1_len 4 -#define fd_sqi_s1_lsb 0 -#define xd_p_reg_fste_ehw_7_0 0xA33E -#define reg_fste_ehw_7_0_pos 0 -#define reg_fste_ehw_7_0_len 8 -#define reg_fste_ehw_7_0_lsb 0 -#define xd_p_reg_fste_ehw_9_8 0xA33F -#define reg_fste_ehw_9_8_pos 0 -#define reg_fste_ehw_9_8_len 2 -#define reg_fste_ehw_9_8_lsb 8 -#define xd_p_reg_fste_i_adj_vld 0xA33F -#define reg_fste_i_adj_vld_pos 2 -#define reg_fste_i_adj_vld_len 1 -#define reg_fste_i_adj_vld_lsb 0 -#define xd_p_reg_fste_phase_ini_7_0 0xA340 -#define reg_fste_phase_ini_7_0_pos 0 -#define reg_fste_phase_ini_7_0_len 8 -#define reg_fste_phase_ini_7_0_lsb 0 -#define xd_p_reg_fste_phase_ini_11_8 0xA341 -#define reg_fste_phase_ini_11_8_pos 0 -#define reg_fste_phase_ini_11_8_len 4 -#define reg_fste_phase_ini_11_8_lsb 8 -#define xd_p_reg_fste_phase_inc_3_0 0xA341 -#define reg_fste_phase_inc_3_0_pos 4 -#define reg_fste_phase_inc_3_0_len 4 -#define reg_fste_phase_inc_3_0_lsb 0 -#define xd_p_reg_fste_phase_inc_11_4 0xA342 -#define reg_fste_phase_inc_11_4_pos 0 -#define reg_fste_phase_inc_11_4_len 8 -#define reg_fste_phase_inc_11_4_lsb 4 -#define xd_p_reg_fste_acum_cost_cnt_max 0xA343 -#define reg_fste_acum_cost_cnt_max_pos 0 -#define reg_fste_acum_cost_cnt_max_len 4 -#define reg_fste_acum_cost_cnt_max_lsb 0 -#define xd_p_reg_fste_step_size_std 0xA343 -#define reg_fste_step_size_std_pos 4 -#define reg_fste_step_size_std_len 4 -#define reg_fste_step_size_std_lsb 0 -#define xd_p_reg_fste_step_size_max 0xA344 -#define reg_fste_step_size_max_pos 0 -#define reg_fste_step_size_max_len 4 -#define reg_fste_step_size_max_lsb 0 -#define xd_p_reg_fste_step_size_min 0xA344 -#define reg_fste_step_size_min_pos 4 -#define reg_fste_step_size_min_len 4 -#define reg_fste_step_size_min_lsb 0 -#define xd_p_reg_fste_frac_step_size_7_0 0xA345 -#define reg_fste_frac_step_size_7_0_pos 0 -#define reg_fste_frac_step_size_7_0_len 8 -#define reg_fste_frac_step_size_7_0_lsb 0 -#define xd_p_reg_fste_frac_step_size_15_8 0xA346 -#define reg_fste_frac_step_size_15_8_pos 0 -#define reg_fste_frac_step_size_15_8_len 8 -#define reg_fste_frac_step_size_15_8_lsb 8 -#define xd_p_reg_fste_frac_step_size_19_16 0xA347 -#define reg_fste_frac_step_size_19_16_pos 0 -#define reg_fste_frac_step_size_19_16_len 4 -#define reg_fste_frac_step_size_19_16_lsb 16 -#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347 -#define reg_fste_rpd_dir_cnt_max_pos 4 -#define reg_fste_rpd_dir_cnt_max_len 4 -#define reg_fste_rpd_dir_cnt_max_lsb 0 -#define xd_p_reg_fste_ehs 0xA348 -#define reg_fste_ehs_pos 0 -#define reg_fste_ehs_len 4 -#define reg_fste_ehs_lsb 0 -#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348 -#define reg_fste_frac_cost_cnt_max_3_0_pos 4 -#define reg_fste_frac_cost_cnt_max_3_0_len 4 -#define reg_fste_frac_cost_cnt_max_3_0_lsb 0 -#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349 -#define reg_fste_frac_cost_cnt_max_9_4_pos 0 -#define reg_fste_frac_cost_cnt_max_9_4_len 6 -#define reg_fste_frac_cost_cnt_max_9_4_lsb 4 -#define xd_p_reg_fste_w0_7_0 0xA34A -#define reg_fste_w0_7_0_pos 0 -#define reg_fste_w0_7_0_len 8 -#define reg_fste_w0_7_0_lsb 0 -#define xd_p_reg_fste_w0_11_8 0xA34B -#define reg_fste_w0_11_8_pos 0 -#define reg_fste_w0_11_8_len 4 -#define reg_fste_w0_11_8_lsb 8 -#define xd_p_reg_fste_w1_3_0 0xA34B -#define reg_fste_w1_3_0_pos 4 -#define reg_fste_w1_3_0_len 4 -#define reg_fste_w1_3_0_lsb 0 -#define xd_p_reg_fste_w1_11_4 0xA34C -#define reg_fste_w1_11_4_pos 0 -#define reg_fste_w1_11_4_len 8 -#define reg_fste_w1_11_4_lsb 4 -#define xd_p_reg_fste_w2_7_0 0xA34D -#define reg_fste_w2_7_0_pos 0 -#define reg_fste_w2_7_0_len 8 -#define reg_fste_w2_7_0_lsb 0 -#define xd_p_reg_fste_w2_11_8 0xA34E -#define reg_fste_w2_11_8_pos 0 -#define reg_fste_w2_11_8_len 4 -#define reg_fste_w2_11_8_lsb 8 -#define xd_p_reg_fste_w3_3_0 0xA34E -#define reg_fste_w3_3_0_pos 4 -#define reg_fste_w3_3_0_len 4 -#define reg_fste_w3_3_0_lsb 0 -#define xd_p_reg_fste_w3_11_4 0xA34F -#define reg_fste_w3_11_4_pos 0 -#define reg_fste_w3_11_4_len 8 -#define reg_fste_w3_11_4_lsb 4 -#define xd_p_reg_fste_w4_7_0 0xA350 -#define reg_fste_w4_7_0_pos 0 -#define reg_fste_w4_7_0_len 8 -#define reg_fste_w4_7_0_lsb 0 -#define xd_p_reg_fste_w4_11_8 0xA351 -#define reg_fste_w4_11_8_pos 0 -#define reg_fste_w4_11_8_len 4 -#define reg_fste_w4_11_8_lsb 8 -#define xd_p_reg_fste_w5_3_0 0xA351 -#define reg_fste_w5_3_0_pos 4 -#define reg_fste_w5_3_0_len 4 -#define reg_fste_w5_3_0_lsb 0 -#define xd_p_reg_fste_w5_11_4 0xA352 -#define reg_fste_w5_11_4_pos 0 -#define reg_fste_w5_11_4_len 8 -#define reg_fste_w5_11_4_lsb 4 -#define xd_p_reg_fste_w6_7_0 0xA353 -#define reg_fste_w6_7_0_pos 0 -#define reg_fste_w6_7_0_len 8 -#define reg_fste_w6_7_0_lsb 0 -#define xd_p_reg_fste_w6_11_8 0xA354 -#define reg_fste_w6_11_8_pos 0 -#define reg_fste_w6_11_8_len 4 -#define reg_fste_w6_11_8_lsb 8 -#define xd_p_reg_fste_w7_3_0 0xA354 -#define reg_fste_w7_3_0_pos 4 -#define reg_fste_w7_3_0_len 4 -#define reg_fste_w7_3_0_lsb 0 -#define xd_p_reg_fste_w7_11_4 0xA355 -#define reg_fste_w7_11_4_pos 0 -#define reg_fste_w7_11_4_len 8 -#define reg_fste_w7_11_4_lsb 4 -#define xd_p_reg_fste_w8_7_0 0xA356 -#define reg_fste_w8_7_0_pos 0 -#define reg_fste_w8_7_0_len 8 -#define reg_fste_w8_7_0_lsb 0 -#define xd_p_reg_fste_w8_11_8 0xA357 -#define reg_fste_w8_11_8_pos 0 -#define reg_fste_w8_11_8_len 4 -#define reg_fste_w8_11_8_lsb 8 -#define xd_p_reg_fste_w9_3_0 0xA357 -#define reg_fste_w9_3_0_pos 4 -#define reg_fste_w9_3_0_len 4 -#define reg_fste_w9_3_0_lsb 0 -#define xd_p_reg_fste_w9_11_4 0xA358 -#define reg_fste_w9_11_4_pos 0 -#define reg_fste_w9_11_4_len 8 -#define reg_fste_w9_11_4_lsb 4 -#define xd_p_reg_fste_wa_7_0 0xA359 -#define reg_fste_wa_7_0_pos 0 -#define reg_fste_wa_7_0_len 8 -#define reg_fste_wa_7_0_lsb 0 -#define xd_p_reg_fste_wa_11_8 0xA35A -#define reg_fste_wa_11_8_pos 0 -#define reg_fste_wa_11_8_len 4 -#define reg_fste_wa_11_8_lsb 8 -#define xd_p_reg_fste_wb_3_0 0xA35A -#define reg_fste_wb_3_0_pos 4 -#define reg_fste_wb_3_0_len 4 -#define reg_fste_wb_3_0_lsb 0 -#define xd_p_reg_fste_wb_11_4 0xA35B -#define reg_fste_wb_11_4_pos 0 -#define reg_fste_wb_11_4_len 8 -#define reg_fste_wb_11_4_lsb 4 -#define xd_r_fd_fste_i_adj 0xA35C -#define fd_fste_i_adj_pos 0 -#define fd_fste_i_adj_len 5 -#define fd_fste_i_adj_lsb 0 -#define xd_r_fd_fste_f_adj_7_0 0xA35D -#define fd_fste_f_adj_7_0_pos 0 -#define fd_fste_f_adj_7_0_len 8 -#define fd_fste_f_adj_7_0_lsb 0 -#define xd_r_fd_fste_f_adj_15_8 0xA35E -#define fd_fste_f_adj_15_8_pos 0 -#define fd_fste_f_adj_15_8_len 8 -#define fd_fste_f_adj_15_8_lsb 8 -#define xd_r_fd_fste_f_adj_19_16 0xA35F -#define fd_fste_f_adj_19_16_pos 0 -#define fd_fste_f_adj_19_16_len 4 -#define fd_fste_f_adj_19_16_lsb 16 -#define xd_p_reg_feq_Leak_Bypass 0xA366 -#define reg_feq_Leak_Bypass_pos 0 -#define reg_feq_Leak_Bypass_len 1 -#define reg_feq_Leak_Bypass_lsb 0 -#define xd_p_reg_feq_Leak_Mneg1 0xA366 -#define reg_feq_Leak_Mneg1_pos 1 -#define reg_feq_Leak_Mneg1_len 3 -#define reg_feq_Leak_Mneg1_lsb 0 -#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366 -#define reg_feq_Leak_B_ShiftQ_pos 4 -#define reg_feq_Leak_B_ShiftQ_len 4 -#define reg_feq_Leak_B_ShiftQ_lsb 0 -#define xd_p_reg_feq_Leak_B_Float0 0xA367 -#define reg_feq_Leak_B_Float0_pos 0 -#define reg_feq_Leak_B_Float0_len 8 -#define reg_feq_Leak_B_Float0_lsb 0 -#define xd_p_reg_feq_Leak_B_Float1 0xA368 -#define reg_feq_Leak_B_Float1_pos 0 -#define reg_feq_Leak_B_Float1_len 8 -#define reg_feq_Leak_B_Float1_lsb 0 -#define xd_p_reg_feq_Leak_B_Float2 0xA369 -#define reg_feq_Leak_B_Float2_pos 0 -#define reg_feq_Leak_B_Float2_len 8 -#define reg_feq_Leak_B_Float2_lsb 0 -#define xd_p_reg_feq_Leak_B_Float3 0xA36A -#define reg_feq_Leak_B_Float3_pos 0 -#define reg_feq_Leak_B_Float3_len 8 -#define reg_feq_Leak_B_Float3_lsb 0 -#define xd_p_reg_feq_Leak_B_Float4 0xA36B -#define reg_feq_Leak_B_Float4_pos 0 -#define reg_feq_Leak_B_Float4_len 8 -#define reg_feq_Leak_B_Float4_lsb 0 -#define xd_p_reg_feq_Leak_B_Float5 0xA36C -#define reg_feq_Leak_B_Float5_pos 0 -#define reg_feq_Leak_B_Float5_len 8 -#define reg_feq_Leak_B_Float5_lsb 0 -#define xd_p_reg_feq_Leak_B_Float6 0xA36D -#define reg_feq_Leak_B_Float6_pos 0 -#define reg_feq_Leak_B_Float6_len 8 -#define reg_feq_Leak_B_Float6_lsb 0 -#define xd_p_reg_feq_Leak_B_Float7 0xA36E -#define reg_feq_Leak_B_Float7_pos 0 -#define reg_feq_Leak_B_Float7_len 8 -#define reg_feq_Leak_B_Float7_lsb 0 -#define xd_r_reg_feq_data_h2_7_0 0xA36F -#define reg_feq_data_h2_7_0_pos 0 -#define reg_feq_data_h2_7_0_len 8 -#define reg_feq_data_h2_7_0_lsb 0 -#define xd_r_reg_feq_data_h2_9_8 0xA370 -#define reg_feq_data_h2_9_8_pos 0 -#define reg_feq_data_h2_9_8_len 2 -#define reg_feq_data_h2_9_8_lsb 8 -#define xd_p_reg_feq_leak_use_slice_tps 0xA371 -#define reg_feq_leak_use_slice_tps_pos 0 -#define reg_feq_leak_use_slice_tps_len 1 -#define reg_feq_leak_use_slice_tps_lsb 0 -#define xd_p_reg_feq_read_update 0xA371 -#define reg_feq_read_update_pos 1 -#define reg_feq_read_update_len 1 -#define reg_feq_read_update_lsb 0 -#define xd_p_reg_feq_data_vld 0xA371 -#define reg_feq_data_vld_pos 2 -#define reg_feq_data_vld_len 1 -#define reg_feq_data_vld_lsb 0 -#define xd_p_reg_feq_tone_idx_4_0 0xA371 -#define reg_feq_tone_idx_4_0_pos 3 -#define reg_feq_tone_idx_4_0_len 5 -#define reg_feq_tone_idx_4_0_lsb 0 -#define xd_p_reg_feq_tone_idx_12_5 0xA372 -#define reg_feq_tone_idx_12_5_pos 0 -#define reg_feq_tone_idx_12_5_len 8 -#define reg_feq_tone_idx_12_5_lsb 5 -#define xd_r_reg_feq_data_re_7_0 0xA373 -#define reg_feq_data_re_7_0_pos 0 -#define reg_feq_data_re_7_0_len 8 -#define reg_feq_data_re_7_0_lsb 0 -#define xd_r_reg_feq_data_re_10_8 0xA374 -#define reg_feq_data_re_10_8_pos 0 -#define reg_feq_data_re_10_8_len 3 -#define reg_feq_data_re_10_8_lsb 8 -#define xd_r_reg_feq_data_im_7_0 0xA375 -#define reg_feq_data_im_7_0_pos 0 -#define reg_feq_data_im_7_0_len 8 -#define reg_feq_data_im_7_0_lsb 0 -#define xd_r_reg_feq_data_im_10_8 0xA376 -#define reg_feq_data_im_10_8_pos 0 -#define reg_feq_data_im_10_8_len 3 -#define reg_feq_data_im_10_8_lsb 8 -#define xd_r_reg_feq_y_re 0xA377 -#define reg_feq_y_re_pos 0 -#define reg_feq_y_re_len 8 -#define reg_feq_y_re_lsb 0 -#define xd_r_reg_feq_y_im 0xA378 -#define reg_feq_y_im_pos 0 -#define reg_feq_y_im_len 8 -#define reg_feq_y_im_lsb 0 -#define xd_r_reg_feq_h_re_7_0 0xA379 -#define reg_feq_h_re_7_0_pos 0 -#define reg_feq_h_re_7_0_len 8 -#define reg_feq_h_re_7_0_lsb 0 -#define xd_r_reg_feq_h_re_8 0xA37A -#define reg_feq_h_re_8_pos 0 -#define reg_feq_h_re_8_len 1 -#define reg_feq_h_re_8_lsb 0 -#define xd_r_reg_feq_h_im_7_0 0xA37B -#define reg_feq_h_im_7_0_pos 0 -#define reg_feq_h_im_7_0_len 8 -#define reg_feq_h_im_7_0_lsb 0 -#define xd_r_reg_feq_h_im_8 0xA37C -#define reg_feq_h_im_8_pos 0 -#define reg_feq_h_im_8_len 1 -#define reg_feq_h_im_8_lsb 0 -#define xd_p_fec_super_frm_unit_7_0 0xA380 -#define fec_super_frm_unit_7_0_pos 0 -#define fec_super_frm_unit_7_0_len 8 -#define fec_super_frm_unit_7_0_lsb 0 -#define xd_p_fec_super_frm_unit_15_8 0xA381 -#define fec_super_frm_unit_15_8_pos 0 -#define fec_super_frm_unit_15_8_len 8 -#define fec_super_frm_unit_15_8_lsb 8 -#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382 -#define fec_vtb_err_bit_cnt_7_0_pos 0 -#define fec_vtb_err_bit_cnt_7_0_len 8 -#define fec_vtb_err_bit_cnt_7_0_lsb 0 -#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383 -#define fec_vtb_err_bit_cnt_15_8_pos 0 -#define fec_vtb_err_bit_cnt_15_8_len 8 -#define fec_vtb_err_bit_cnt_15_8_lsb 8 -#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384 -#define fec_vtb_err_bit_cnt_23_16_pos 0 -#define fec_vtb_err_bit_cnt_23_16_len 8 -#define fec_vtb_err_bit_cnt_23_16_lsb 16 -#define xd_p_fec_rsd_packet_unit_7_0 0xA385 -#define fec_rsd_packet_unit_7_0_pos 0 -#define fec_rsd_packet_unit_7_0_len 8 -#define fec_rsd_packet_unit_7_0_lsb 0 -#define xd_p_fec_rsd_packet_unit_15_8 0xA386 -#define fec_rsd_packet_unit_15_8_pos 0 -#define fec_rsd_packet_unit_15_8_len 8 -#define fec_rsd_packet_unit_15_8_lsb 8 -#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387 -#define fec_rsd_bit_err_cnt_7_0_pos 0 -#define fec_rsd_bit_err_cnt_7_0_len 8 -#define fec_rsd_bit_err_cnt_7_0_lsb 0 -#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388 -#define fec_rsd_bit_err_cnt_15_8_pos 0 -#define fec_rsd_bit_err_cnt_15_8_len 8 -#define fec_rsd_bit_err_cnt_15_8_lsb 8 -#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389 -#define fec_rsd_bit_err_cnt_23_16_pos 0 -#define fec_rsd_bit_err_cnt_23_16_len 8 -#define fec_rsd_bit_err_cnt_23_16_lsb 16 -#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A -#define fec_rsd_abort_packet_cnt_7_0_pos 0 -#define fec_rsd_abort_packet_cnt_7_0_len 8 -#define fec_rsd_abort_packet_cnt_7_0_lsb 0 -#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B -#define fec_rsd_abort_packet_cnt_15_8_pos 0 -#define fec_rsd_abort_packet_cnt_15_8_len 8 -#define fec_rsd_abort_packet_cnt_15_8_lsb 8 -#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C -#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0 -#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8 -#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0 -#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D -#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0 -#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8 -#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8 -#define xd_p_fec_RS_TH_1_7_0 0xA38E -#define fec_RS_TH_1_7_0_pos 0 -#define fec_RS_TH_1_7_0_len 8 -#define fec_RS_TH_1_7_0_lsb 0 -#define xd_p_fec_RS_TH_1_15_8 0xA38F -#define fec_RS_TH_1_15_8_pos 0 -#define fec_RS_TH_1_15_8_len 8 -#define fec_RS_TH_1_15_8_lsb 8 -#define xd_p_fec_RS_TH_2 0xA390 -#define fec_RS_TH_2_pos 0 -#define fec_RS_TH_2_len 8 -#define fec_RS_TH_2_lsb 0 -#define xd_p_fec_mon_en 0xA391 -#define fec_mon_en_pos 0 -#define fec_mon_en_len 1 -#define fec_mon_en_lsb 0 -#define xd_p_reg_b8to47 0xA391 -#define reg_b8to47_pos 1 -#define reg_b8to47_len 1 -#define reg_b8to47_lsb 0 -#define xd_p_reg_rsd_sync_rep 0xA391 -#define reg_rsd_sync_rep_pos 2 -#define reg_rsd_sync_rep_len 1 -#define reg_rsd_sync_rep_lsb 0 -#define xd_p_fec_rsd_retrain_rst 0xA391 -#define fec_rsd_retrain_rst_pos 3 -#define fec_rsd_retrain_rst_len 1 -#define fec_rsd_retrain_rst_lsb 0 -#define xd_r_fec_rsd_ber_rdy 0xA391 -#define fec_rsd_ber_rdy_pos 4 -#define fec_rsd_ber_rdy_len 1 -#define fec_rsd_ber_rdy_lsb 0 -#define xd_p_fec_rsd_ber_rst 0xA391 -#define fec_rsd_ber_rst_pos 5 -#define fec_rsd_ber_rst_len 1 -#define fec_rsd_ber_rst_lsb 0 -#define xd_r_fec_vtb_ber_rdy 0xA391 -#define fec_vtb_ber_rdy_pos 6 -#define fec_vtb_ber_rdy_len 1 -#define fec_vtb_ber_rdy_lsb 0 -#define xd_p_fec_vtb_ber_rst 0xA391 -#define fec_vtb_ber_rst_pos 7 -#define fec_vtb_ber_rst_len 1 -#define fec_vtb_ber_rst_lsb 0 -#define xd_p_reg_vtb_clk40en 0xA392 -#define reg_vtb_clk40en_pos 0 -#define reg_vtb_clk40en_len 1 -#define reg_vtb_clk40en_lsb 0 -#define xd_p_fec_vtb_rsd_mon_en 0xA392 -#define fec_vtb_rsd_mon_en_pos 1 -#define fec_vtb_rsd_mon_en_len 1 -#define fec_vtb_rsd_mon_en_lsb 0 -#define xd_p_reg_fec_data_en 0xA392 -#define reg_fec_data_en_pos 2 -#define reg_fec_data_en_len 1 -#define reg_fec_data_en_lsb 0 -#define xd_p_fec_dummy_reg_2 0xA392 -#define fec_dummy_reg_2_pos 3 -#define fec_dummy_reg_2_len 3 -#define fec_dummy_reg_2_lsb 0 -#define xd_p_reg_sync_chk 0xA392 -#define reg_sync_chk_pos 6 -#define reg_sync_chk_len 1 -#define reg_sync_chk_lsb 0 -#define xd_p_fec_rsd_bypass 0xA392 -#define fec_rsd_bypass_pos 7 -#define fec_rsd_bypass_len 1 -#define fec_rsd_bypass_lsb 0 -#define xd_p_fec_sw_rst 0xA393 -#define fec_sw_rst_pos 0 -#define fec_sw_rst_len 1 -#define fec_sw_rst_lsb 0 -#define xd_r_fec_vtb_pm_crc 0xA394 -#define fec_vtb_pm_crc_pos 0 -#define fec_vtb_pm_crc_len 8 -#define fec_vtb_pm_crc_lsb 0 -#define xd_r_fec_vtb_tb_7_crc 0xA395 -#define fec_vtb_tb_7_crc_pos 0 -#define fec_vtb_tb_7_crc_len 8 -#define fec_vtb_tb_7_crc_lsb 0 -#define xd_r_fec_vtb_tb_6_crc 0xA396 -#define fec_vtb_tb_6_crc_pos 0 -#define fec_vtb_tb_6_crc_len 8 -#define fec_vtb_tb_6_crc_lsb 0 -#define xd_r_fec_vtb_tb_5_crc 0xA397 -#define fec_vtb_tb_5_crc_pos 0 -#define fec_vtb_tb_5_crc_len 8 -#define fec_vtb_tb_5_crc_lsb 0 -#define xd_r_fec_vtb_tb_4_crc 0xA398 -#define fec_vtb_tb_4_crc_pos 0 -#define fec_vtb_tb_4_crc_len 8 -#define fec_vtb_tb_4_crc_lsb 0 -#define xd_r_fec_vtb_tb_3_crc 0xA399 -#define fec_vtb_tb_3_crc_pos 0 -#define fec_vtb_tb_3_crc_len 8 -#define fec_vtb_tb_3_crc_lsb 0 -#define xd_r_fec_vtb_tb_2_crc 0xA39A -#define fec_vtb_tb_2_crc_pos 0 -#define fec_vtb_tb_2_crc_len 8 -#define fec_vtb_tb_2_crc_lsb 0 -#define xd_r_fec_vtb_tb_1_crc 0xA39B -#define fec_vtb_tb_1_crc_pos 0 -#define fec_vtb_tb_1_crc_len 8 -#define fec_vtb_tb_1_crc_lsb 0 -#define xd_r_fec_vtb_tb_0_crc 0xA39C -#define fec_vtb_tb_0_crc_pos 0 -#define fec_vtb_tb_0_crc_len 8 -#define fec_vtb_tb_0_crc_lsb 0 -#define xd_r_fec_rsd_bank0_crc 0xA39D -#define fec_rsd_bank0_crc_pos 0 -#define fec_rsd_bank0_crc_len 8 -#define fec_rsd_bank0_crc_lsb 0 -#define xd_r_fec_rsd_bank1_crc 0xA39E -#define fec_rsd_bank1_crc_pos 0 -#define fec_rsd_bank1_crc_len 8 -#define fec_rsd_bank1_crc_lsb 0 -#define xd_r_fec_idi_vtb_crc 0xA39F -#define fec_idi_vtb_crc_pos 0 -#define fec_idi_vtb_crc_len 8 -#define fec_idi_vtb_crc_lsb 0 -#define xd_g_reg_tpsd_txmod 0xA3C0 -#define reg_tpsd_txmod_pos 0 -#define reg_tpsd_txmod_len 2 -#define reg_tpsd_txmod_lsb 0 -#define xd_g_reg_tpsd_gi 0xA3C0 -#define reg_tpsd_gi_pos 2 -#define reg_tpsd_gi_len 2 -#define reg_tpsd_gi_lsb 0 -#define xd_g_reg_tpsd_hier 0xA3C0 -#define reg_tpsd_hier_pos 4 -#define reg_tpsd_hier_len 3 -#define reg_tpsd_hier_lsb 0 -#define xd_g_reg_bw 0xA3C1 -#define reg_bw_pos 2 -#define reg_bw_len 2 -#define reg_bw_lsb 0 -#define xd_g_reg_dec_pri 0xA3C1 -#define reg_dec_pri_pos 4 -#define reg_dec_pri_len 1 -#define reg_dec_pri_lsb 0 -#define xd_g_reg_tpsd_const 0xA3C1 -#define reg_tpsd_const_pos 6 -#define reg_tpsd_const_len 2 -#define reg_tpsd_const_lsb 0 -#define xd_g_reg_tpsd_hpcr 0xA3C2 -#define reg_tpsd_hpcr_pos 0 -#define reg_tpsd_hpcr_len 3 -#define reg_tpsd_hpcr_lsb 0 -#define xd_g_reg_tpsd_lpcr 0xA3C2 -#define reg_tpsd_lpcr_pos 3 -#define reg_tpsd_lpcr_len 3 -#define reg_tpsd_lpcr_lsb 0 -#define xd_g_reg_ofsm_clk 0xA3D0 -#define reg_ofsm_clk_pos 0 -#define reg_ofsm_clk_len 3 -#define reg_ofsm_clk_lsb 0 -#define xd_g_reg_fclk_cfg 0xA3D1 -#define reg_fclk_cfg_pos 0 -#define reg_fclk_cfg_len 1 -#define reg_fclk_cfg_lsb 0 -#define xd_g_reg_fclk_idi 0xA3D1 -#define reg_fclk_idi_pos 1 -#define reg_fclk_idi_len 1 -#define reg_fclk_idi_lsb 0 -#define xd_g_reg_fclk_odi 0xA3D1 -#define reg_fclk_odi_pos 2 -#define reg_fclk_odi_len 1 -#define reg_fclk_odi_lsb 0 -#define xd_g_reg_fclk_rsd 0xA3D1 -#define reg_fclk_rsd_pos 3 -#define reg_fclk_rsd_len 1 -#define reg_fclk_rsd_lsb 0 -#define xd_g_reg_fclk_vtb 0xA3D1 -#define reg_fclk_vtb_pos 4 -#define reg_fclk_vtb_len 1 -#define reg_fclk_vtb_lsb 0 -#define xd_g_reg_fclk_cste 0xA3D1 -#define reg_fclk_cste_pos 5 -#define reg_fclk_cste_len 1 -#define reg_fclk_cste_lsb 0 -#define xd_g_reg_fclk_mp2if 0xA3D1 -#define reg_fclk_mp2if_pos 6 -#define reg_fclk_mp2if_len 1 -#define reg_fclk_mp2if_lsb 0 -#define xd_I2C_i2c_m_slave_addr 0xA400 -#define i2c_m_slave_addr_pos 0 -#define i2c_m_slave_addr_len 8 -#define i2c_m_slave_addr_lsb 0 -#define xd_I2C_i2c_m_data1 0xA401 -#define i2c_m_data1_pos 0 -#define i2c_m_data1_len 8 -#define i2c_m_data1_lsb 0 -#define xd_I2C_i2c_m_data2 0xA402 -#define i2c_m_data2_pos 0 -#define i2c_m_data2_len 8 -#define i2c_m_data2_lsb 0 -#define xd_I2C_i2c_m_data3 0xA403 -#define i2c_m_data3_pos 0 -#define i2c_m_data3_len 8 -#define i2c_m_data3_lsb 0 -#define xd_I2C_i2c_m_data4 0xA404 -#define i2c_m_data4_pos 0 -#define i2c_m_data4_len 8 -#define i2c_m_data4_lsb 0 -#define xd_I2C_i2c_m_data5 0xA405 -#define i2c_m_data5_pos 0 -#define i2c_m_data5_len 8 -#define i2c_m_data5_lsb 0 -#define xd_I2C_i2c_m_data6 0xA406 -#define i2c_m_data6_pos 0 -#define i2c_m_data6_len 8 -#define i2c_m_data6_lsb 0 -#define xd_I2C_i2c_m_data7 0xA407 -#define i2c_m_data7_pos 0 -#define i2c_m_data7_len 8 -#define i2c_m_data7_lsb 0 -#define xd_I2C_i2c_m_data8 0xA408 -#define i2c_m_data8_pos 0 -#define i2c_m_data8_len 8 -#define i2c_m_data8_lsb 0 -#define xd_I2C_i2c_m_data9 0xA409 -#define i2c_m_data9_pos 0 -#define i2c_m_data9_len 8 -#define i2c_m_data9_lsb 0 -#define xd_I2C_i2c_m_data10 0xA40A -#define i2c_m_data10_pos 0 -#define i2c_m_data10_len 8 -#define i2c_m_data10_lsb 0 -#define xd_I2C_i2c_m_data11 0xA40B -#define i2c_m_data11_pos 0 -#define i2c_m_data11_len 8 -#define i2c_m_data11_lsb 0 -#define xd_I2C_i2c_m_cmd_rw 0xA40C -#define i2c_m_cmd_rw_pos 0 -#define i2c_m_cmd_rw_len 1 -#define i2c_m_cmd_rw_lsb 0 -#define xd_I2C_i2c_m_cmd_rwlen 0xA40C -#define i2c_m_cmd_rwlen_pos 3 -#define i2c_m_cmd_rwlen_len 4 -#define i2c_m_cmd_rwlen_lsb 0 -#define xd_I2C_i2c_m_status_cmd_exe 0xA40D -#define i2c_m_status_cmd_exe_pos 0 -#define i2c_m_status_cmd_exe_len 1 -#define i2c_m_status_cmd_exe_lsb 0 -#define xd_I2C_i2c_m_status_wdat_done 0xA40D -#define i2c_m_status_wdat_done_pos 1 -#define i2c_m_status_wdat_done_len 1 -#define i2c_m_status_wdat_done_lsb 0 -#define xd_I2C_i2c_m_status_wdat_fail 0xA40D -#define i2c_m_status_wdat_fail_pos 2 -#define i2c_m_status_wdat_fail_len 1 -#define i2c_m_status_wdat_fail_lsb 0 -#define xd_I2C_i2c_m_period 0xA40E -#define i2c_m_period_pos 0 -#define i2c_m_period_len 8 -#define i2c_m_period_lsb 0 -#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F -#define i2c_m_reg_msb_lsb_pos 0 -#define i2c_m_reg_msb_lsb_len 1 -#define i2c_m_reg_msb_lsb_lsb 0 -#define xd_I2C_reg_ofdm_rst 0xA40F -#define reg_ofdm_rst_pos 1 -#define reg_ofdm_rst_len 1 -#define reg_ofdm_rst_lsb 0 -#define xd_I2C_reg_sample_period_on_tuner 0xA40F -#define reg_sample_period_on_tuner_pos 2 -#define reg_sample_period_on_tuner_len 1 -#define reg_sample_period_on_tuner_lsb 0 -#define xd_I2C_reg_rst_i2c 0xA40F -#define reg_rst_i2c_pos 3 -#define reg_rst_i2c_len 1 -#define reg_rst_i2c_lsb 0 -#define xd_I2C_reg_ofdm_rst_en 0xA40F -#define reg_ofdm_rst_en_pos 4 -#define reg_ofdm_rst_en_len 1 -#define reg_ofdm_rst_en_lsb 0 -#define xd_I2C_reg_tuner_sda_sync_on 0xA40F -#define reg_tuner_sda_sync_on_pos 5 -#define reg_tuner_sda_sync_on_len 1 -#define reg_tuner_sda_sync_on_lsb 0 -#define xd_p_mp2if_data_access_disable_ofsm 0xA500 -#define mp2if_data_access_disable_ofsm_pos 0 -#define mp2if_data_access_disable_ofsm_len 1 -#define mp2if_data_access_disable_ofsm_lsb 0 -#define xd_p_reg_mp2_sw_rst_ofsm 0xA500 -#define reg_mp2_sw_rst_ofsm_pos 1 -#define reg_mp2_sw_rst_ofsm_len 1 -#define reg_mp2_sw_rst_ofsm_lsb 0 -#define xd_p_reg_mp2if_clk_en_ofsm 0xA500 -#define reg_mp2if_clk_en_ofsm_pos 2 -#define reg_mp2if_clk_en_ofsm_len 1 -#define reg_mp2if_clk_en_ofsm_lsb 0 -#define xd_r_mp2if_sync_byte_locked 0xA500 -#define mp2if_sync_byte_locked_pos 3 -#define mp2if_sync_byte_locked_len 1 -#define mp2if_sync_byte_locked_lsb 0 -#define xd_r_mp2if_ts_not_188 0xA500 -#define mp2if_ts_not_188_pos 4 -#define mp2if_ts_not_188_len 1 -#define mp2if_ts_not_188_lsb 0 -#define xd_r_mp2if_psb_empty 0xA500 -#define mp2if_psb_empty_pos 5 -#define mp2if_psb_empty_len 1 -#define mp2if_psb_empty_lsb 0 -#define xd_r_mp2if_psb_overflow 0xA500 -#define mp2if_psb_overflow_pos 6 -#define mp2if_psb_overflow_len 1 -#define mp2if_psb_overflow_lsb 0 -#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500 -#define mp2if_keep_sf_sync_byte_ofsm_pos 7 -#define mp2if_keep_sf_sync_byte_ofsm_len 1 -#define mp2if_keep_sf_sync_byte_ofsm_lsb 0 -#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501 -#define mp2if_psb_mp2if_num_pkt_pos 0 -#define mp2if_psb_mp2if_num_pkt_len 6 -#define mp2if_psb_mp2if_num_pkt_lsb 0 -#define xd_p_reg_mpeg_full_speed_ofsm 0xA501 -#define reg_mpeg_full_speed_ofsm_pos 6 -#define reg_mpeg_full_speed_ofsm_len 1 -#define reg_mpeg_full_speed_ofsm_lsb 0 -#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501 -#define mp2if_mpeg_ser_mode_ofsm_pos 7 -#define mp2if_mpeg_ser_mode_ofsm_len 1 -#define mp2if_mpeg_ser_mode_ofsm_lsb 0 -#define xd_p_reg_sw_mon51 0xA600 -#define reg_sw_mon51_pos 0 -#define reg_sw_mon51_len 8 -#define reg_sw_mon51_lsb 0 -#define xd_p_reg_top_pcsel 0xA601 -#define reg_top_pcsel_pos 0 -#define reg_top_pcsel_len 1 -#define reg_top_pcsel_lsb 0 -#define xd_p_reg_top_rs232 0xA601 -#define reg_top_rs232_pos 1 -#define reg_top_rs232_len 1 -#define reg_top_rs232_lsb 0 -#define xd_p_reg_top_pcout 0xA601 -#define reg_top_pcout_pos 2 -#define reg_top_pcout_len 1 -#define reg_top_pcout_lsb 0 -#define xd_p_reg_top_debug 0xA601 -#define reg_top_debug_pos 3 -#define reg_top_debug_len 1 -#define reg_top_debug_lsb 0 -#define xd_p_reg_top_adcdly 0xA601 -#define reg_top_adcdly_pos 4 -#define reg_top_adcdly_len 2 -#define reg_top_adcdly_lsb 0 -#define xd_p_reg_top_pwrdw 0xA601 -#define reg_top_pwrdw_pos 6 -#define reg_top_pwrdw_len 1 -#define reg_top_pwrdw_lsb 0 -#define xd_p_reg_top_pwrdw_inv 0xA601 -#define reg_top_pwrdw_inv_pos 7 -#define reg_top_pwrdw_inv_len 1 -#define reg_top_pwrdw_inv_lsb 0 -#define xd_p_reg_top_int_inv 0xA602 -#define reg_top_int_inv_pos 0 -#define reg_top_int_inv_len 1 -#define reg_top_int_inv_lsb 0 -#define xd_p_reg_top_dio_sel 0xA602 -#define reg_top_dio_sel_pos 1 -#define reg_top_dio_sel_len 1 -#define reg_top_dio_sel_lsb 0 -#define xd_p_reg_top_gpioon0 0xA603 -#define reg_top_gpioon0_pos 0 -#define reg_top_gpioon0_len 1 -#define reg_top_gpioon0_lsb 0 -#define xd_p_reg_top_gpioon1 0xA603 -#define reg_top_gpioon1_pos 1 -#define reg_top_gpioon1_len 1 -#define reg_top_gpioon1_lsb 0 -#define xd_p_reg_top_gpioon2 0xA603 -#define reg_top_gpioon2_pos 2 -#define reg_top_gpioon2_len 1 -#define reg_top_gpioon2_lsb 0 -#define xd_p_reg_top_gpioon3 0xA603 -#define reg_top_gpioon3_pos 3 -#define reg_top_gpioon3_len 1 -#define reg_top_gpioon3_lsb 0 -#define xd_p_reg_top_lockon1 0xA603 -#define reg_top_lockon1_pos 4 -#define reg_top_lockon1_len 1 -#define reg_top_lockon1_lsb 0 -#define xd_p_reg_top_lockon2 0xA603 -#define reg_top_lockon2_pos 5 -#define reg_top_lockon2_len 1 -#define reg_top_lockon2_lsb 0 -#define xd_p_reg_top_gpioo0 0xA604 -#define reg_top_gpioo0_pos 0 -#define reg_top_gpioo0_len 1 -#define reg_top_gpioo0_lsb 0 -#define xd_p_reg_top_gpioo1 0xA604 -#define reg_top_gpioo1_pos 1 -#define reg_top_gpioo1_len 1 -#define reg_top_gpioo1_lsb 0 -#define xd_p_reg_top_gpioo2 0xA604 -#define reg_top_gpioo2_pos 2 -#define reg_top_gpioo2_len 1 -#define reg_top_gpioo2_lsb 0 -#define xd_p_reg_top_gpioo3 0xA604 -#define reg_top_gpioo3_pos 3 -#define reg_top_gpioo3_len 1 -#define reg_top_gpioo3_lsb 0 -#define xd_p_reg_top_lock1 0xA604 -#define reg_top_lock1_pos 4 -#define reg_top_lock1_len 1 -#define reg_top_lock1_lsb 0 -#define xd_p_reg_top_lock2 0xA604 -#define reg_top_lock2_pos 5 -#define reg_top_lock2_len 1 -#define reg_top_lock2_lsb 0 -#define xd_p_reg_top_gpioen0 0xA605 -#define reg_top_gpioen0_pos 0 -#define reg_top_gpioen0_len 1 -#define reg_top_gpioen0_lsb 0 -#define xd_p_reg_top_gpioen1 0xA605 -#define reg_top_gpioen1_pos 1 -#define reg_top_gpioen1_len 1 -#define reg_top_gpioen1_lsb 0 -#define xd_p_reg_top_gpioen2 0xA605 -#define reg_top_gpioen2_pos 2 -#define reg_top_gpioen2_len 1 -#define reg_top_gpioen2_lsb 0 -#define xd_p_reg_top_gpioen3 0xA605 -#define reg_top_gpioen3_pos 3 -#define reg_top_gpioen3_len 1 -#define reg_top_gpioen3_lsb 0 -#define xd_p_reg_top_locken1 0xA605 -#define reg_top_locken1_pos 4 -#define reg_top_locken1_len 1 -#define reg_top_locken1_lsb 0 -#define xd_p_reg_top_locken2 0xA605 -#define reg_top_locken2_pos 5 -#define reg_top_locken2_len 1 -#define reg_top_locken2_lsb 0 -#define xd_r_reg_top_gpioi0 0xA606 -#define reg_top_gpioi0_pos 0 -#define reg_top_gpioi0_len 1 -#define reg_top_gpioi0_lsb 0 -#define xd_r_reg_top_gpioi1 0xA606 -#define reg_top_gpioi1_pos 1 -#define reg_top_gpioi1_len 1 -#define reg_top_gpioi1_lsb 0 -#define xd_r_reg_top_gpioi2 0xA606 -#define reg_top_gpioi2_pos 2 -#define reg_top_gpioi2_len 1 -#define reg_top_gpioi2_lsb 0 -#define xd_r_reg_top_gpioi3 0xA606 -#define reg_top_gpioi3_pos 3 -#define reg_top_gpioi3_len 1 -#define reg_top_gpioi3_lsb 0 -#define xd_r_reg_top_locki1 0xA606 -#define reg_top_locki1_pos 4 -#define reg_top_locki1_len 1 -#define reg_top_locki1_lsb 0 -#define xd_r_reg_top_locki2 0xA606 -#define reg_top_locki2_pos 5 -#define reg_top_locki2_len 1 -#define reg_top_locki2_lsb 0 -#define xd_p_reg_dummy_7_0 0xA608 -#define reg_dummy_7_0_pos 0 -#define reg_dummy_7_0_len 8 -#define reg_dummy_7_0_lsb 0 -#define xd_p_reg_dummy_15_8 0xA609 -#define reg_dummy_15_8_pos 0 -#define reg_dummy_15_8_len 8 -#define reg_dummy_15_8_lsb 8 -#define xd_p_reg_dummy_23_16 0xA60A -#define reg_dummy_23_16_pos 0 -#define reg_dummy_23_16_len 8 -#define reg_dummy_23_16_lsb 16 -#define xd_p_reg_dummy_31_24 0xA60B -#define reg_dummy_31_24_pos 0 -#define reg_dummy_31_24_len 8 -#define reg_dummy_31_24_lsb 24 -#define xd_p_reg_dummy_39_32 0xA60C -#define reg_dummy_39_32_pos 0 -#define reg_dummy_39_32_len 8 -#define reg_dummy_39_32_lsb 32 -#define xd_p_reg_dummy_47_40 0xA60D -#define reg_dummy_47_40_pos 0 -#define reg_dummy_47_40_len 8 -#define reg_dummy_47_40_lsb 40 -#define xd_p_reg_dummy_55_48 0xA60E -#define reg_dummy_55_48_pos 0 -#define reg_dummy_55_48_len 8 -#define reg_dummy_55_48_lsb 48 -#define xd_p_reg_dummy_63_56 0xA60F -#define reg_dummy_63_56_pos 0 -#define reg_dummy_63_56_len 8 -#define reg_dummy_63_56_lsb 56 -#define xd_p_reg_dummy_71_64 0xA610 -#define reg_dummy_71_64_pos 0 -#define reg_dummy_71_64_len 8 -#define reg_dummy_71_64_lsb 64 -#define xd_p_reg_dummy_79_72 0xA611 -#define reg_dummy_79_72_pos 0 -#define reg_dummy_79_72_len 8 -#define reg_dummy_79_72_lsb 72 -#define xd_p_reg_dummy_87_80 0xA612 -#define reg_dummy_87_80_pos 0 -#define reg_dummy_87_80_len 8 -#define reg_dummy_87_80_lsb 80 -#define xd_p_reg_dummy_95_88 0xA613 -#define reg_dummy_95_88_pos 0 -#define reg_dummy_95_88_len 8 -#define reg_dummy_95_88_lsb 88 -#define xd_p_reg_dummy_103_96 0xA614 -#define reg_dummy_103_96_pos 0 -#define reg_dummy_103_96_len 8 -#define reg_dummy_103_96_lsb 96 - -#define xd_p_reg_unplug_flag 0xA615 -#define reg_unplug_flag_pos 0 -#define reg_unplug_flag_len 1 -#define reg_unplug_flag_lsb 104 - -#define xd_p_reg_api_dca_stes_request 0xA615 -#define reg_api_dca_stes_request_pos 1 -#define reg_api_dca_stes_request_len 1 -#define reg_api_dca_stes_request_lsb 0 - -#define xd_p_reg_back_to_dca_flag 0xA615 -#define reg_back_to_dca_flag_pos 2 -#define reg_back_to_dca_flag_len 1 -#define reg_back_to_dca_flag_lsb 106 - -#define xd_p_reg_api_retrain_request 0xA615 -#define reg_api_retrain_request_pos 3 -#define reg_api_retrain_request_len 1 -#define reg_api_retrain_request_lsb 0 - -#define xd_p_reg_Dyn_Top_Try_flag 0xA615 -#define reg_Dyn_Top_Try_flag_pos 3 -#define reg_Dyn_Top_Try_flag_len 1 -#define reg_Dyn_Top_Try_flag_lsb 107 - -#define xd_p_reg_API_retrain_freeze_flag 0xA615 -#define reg_API_retrain_freeze_flag_pos 4 -#define reg_API_retrain_freeze_flag_len 1 -#define reg_API_retrain_freeze_flag_lsb 108 - -#define xd_p_reg_dummy_111_104 0xA615 -#define reg_dummy_111_104_pos 0 -#define reg_dummy_111_104_len 8 -#define reg_dummy_111_104_lsb 104 -#define xd_p_reg_dummy_119_112 0xA616 -#define reg_dummy_119_112_pos 0 -#define reg_dummy_119_112_len 8 -#define reg_dummy_119_112_lsb 112 -#define xd_p_reg_dummy_127_120 0xA617 -#define reg_dummy_127_120_pos 0 -#define reg_dummy_127_120_len 8 -#define reg_dummy_127_120_lsb 120 -#define xd_p_reg_dummy_135_128 0xA618 -#define reg_dummy_135_128_pos 0 -#define reg_dummy_135_128_len 8 -#define reg_dummy_135_128_lsb 128 - -#define xd_p_reg_dummy_143_136 0xA619 -#define reg_dummy_143_136_pos 0 -#define reg_dummy_143_136_len 8 -#define reg_dummy_143_136_lsb 136 - -#define xd_p_reg_CCIR_dis 0xA619 -#define reg_CCIR_dis_pos 0 -#define reg_CCIR_dis_len 1 -#define reg_CCIR_dis_lsb 0 - -#define xd_p_reg_dummy_151_144 0xA61A -#define reg_dummy_151_144_pos 0 -#define reg_dummy_151_144_len 8 -#define reg_dummy_151_144_lsb 144 - -#define xd_p_reg_dummy_159_152 0xA61B -#define reg_dummy_159_152_pos 0 -#define reg_dummy_159_152_len 8 -#define reg_dummy_159_152_lsb 152 - -#define xd_p_reg_dummy_167_160 0xA61C -#define reg_dummy_167_160_pos 0 -#define reg_dummy_167_160_len 8 -#define reg_dummy_167_160_lsb 160 - -#define xd_p_reg_dummy_175_168 0xA61D -#define reg_dummy_175_168_pos 0 -#define reg_dummy_175_168_len 8 -#define reg_dummy_175_168_lsb 168 - -#define xd_p_reg_dummy_183_176 0xA61E -#define reg_dummy_183_176_pos 0 -#define reg_dummy_183_176_len 8 -#define reg_dummy_183_176_lsb 176 - -#define xd_p_reg_ofsm_read_rbc_en 0xA61E -#define reg_ofsm_read_rbc_en_pos 2 -#define reg_ofsm_read_rbc_en_len 1 -#define reg_ofsm_read_rbc_en_lsb 0 - -#define xd_p_reg_ce_filter_selection_dis 0xA61E -#define reg_ce_filter_selection_dis_pos 1 -#define reg_ce_filter_selection_dis_len 1 -#define reg_ce_filter_selection_dis_lsb 0 - -#define xd_p_reg_OFSM_version_control_7_0 0xA611 -#define reg_OFSM_version_control_7_0_pos 0 -#define reg_OFSM_version_control_7_0_len 8 -#define reg_OFSM_version_control_7_0_lsb 0 - -#define xd_p_reg_OFSM_version_control_15_8 0xA61F -#define reg_OFSM_version_control_15_8_pos 0 -#define reg_OFSM_version_control_15_8_len 8 -#define reg_OFSM_version_control_15_8_lsb 0 - -#define xd_p_reg_OFSM_version_control_23_16 0xA620 -#define reg_OFSM_version_control_23_16_pos 0 -#define reg_OFSM_version_control_23_16_len 8 -#define reg_OFSM_version_control_23_16_lsb 0 - -#define xd_p_reg_dummy_191_184 0xA61F -#define reg_dummy_191_184_pos 0 -#define reg_dummy_191_184_len 8 -#define reg_dummy_191_184_lsb 184 - -#define xd_p_reg_dummy_199_192 0xA620 -#define reg_dummy_199_192_pos 0 -#define reg_dummy_199_192_len 8 -#define reg_dummy_199_192_lsb 192 - -#define xd_p_reg_ce_en 0xABC0 -#define reg_ce_en_pos 0 -#define reg_ce_en_len 1 -#define reg_ce_en_lsb 0 -#define xd_p_reg_ce_fctrl_en 0xABC0 -#define reg_ce_fctrl_en_pos 1 -#define reg_ce_fctrl_en_len 1 -#define reg_ce_fctrl_en_lsb 0 -#define xd_p_reg_ce_fste_tdi 0xABC0 -#define reg_ce_fste_tdi_pos 2 -#define reg_ce_fste_tdi_len 1 -#define reg_ce_fste_tdi_lsb 0 -#define xd_p_reg_ce_dynamic 0xABC0 -#define reg_ce_dynamic_pos 3 -#define reg_ce_dynamic_len 1 -#define reg_ce_dynamic_lsb 0 -#define xd_p_reg_ce_conf 0xABC0 -#define reg_ce_conf_pos 4 -#define reg_ce_conf_len 2 -#define reg_ce_conf_lsb 0 -#define xd_p_reg_ce_dyn12 0xABC0 -#define reg_ce_dyn12_pos 6 -#define reg_ce_dyn12_len 1 -#define reg_ce_dyn12_lsb 0 -#define xd_p_reg_ce_derot_en 0xABC0 -#define reg_ce_derot_en_pos 7 -#define reg_ce_derot_en_len 1 -#define reg_ce_derot_en_lsb 0 -#define xd_p_reg_ce_dynamic_th_7_0 0xABC1 -#define reg_ce_dynamic_th_7_0_pos 0 -#define reg_ce_dynamic_th_7_0_len 8 -#define reg_ce_dynamic_th_7_0_lsb 0 -#define xd_p_reg_ce_dynamic_th_15_8 0xABC2 -#define reg_ce_dynamic_th_15_8_pos 0 -#define reg_ce_dynamic_th_15_8_len 8 -#define reg_ce_dynamic_th_15_8_lsb 8 -#define xd_p_reg_ce_s1 0xABC3 -#define reg_ce_s1_pos 0 -#define reg_ce_s1_len 5 -#define reg_ce_s1_lsb 0 -#define xd_p_reg_ce_var_forced_value 0xABC3 -#define reg_ce_var_forced_value_pos 5 -#define reg_ce_var_forced_value_len 3 -#define reg_ce_var_forced_value_lsb 0 -#define xd_p_reg_ce_data_im_7_0 0xABC4 -#define reg_ce_data_im_7_0_pos 0 -#define reg_ce_data_im_7_0_len 8 -#define reg_ce_data_im_7_0_lsb 0 -#define xd_p_reg_ce_data_im_8 0xABC5 -#define reg_ce_data_im_8_pos 0 -#define reg_ce_data_im_8_len 1 -#define reg_ce_data_im_8_lsb 0 -#define xd_p_reg_ce_data_re_6_0 0xABC5 -#define reg_ce_data_re_6_0_pos 1 -#define reg_ce_data_re_6_0_len 7 -#define reg_ce_data_re_6_0_lsb 0 -#define xd_p_reg_ce_data_re_8_7 0xABC6 -#define reg_ce_data_re_8_7_pos 0 -#define reg_ce_data_re_8_7_len 2 -#define reg_ce_data_re_8_7_lsb 7 -#define xd_p_reg_ce_tone_5_0 0xABC6 -#define reg_ce_tone_5_0_pos 2 -#define reg_ce_tone_5_0_len 6 -#define reg_ce_tone_5_0_lsb 0 -#define xd_p_reg_ce_tone_12_6 0xABC7 -#define reg_ce_tone_12_6_pos 0 -#define reg_ce_tone_12_6_len 7 -#define reg_ce_tone_12_6_lsb 6 -#define xd_p_reg_ce_centroid_drift_th 0xABC8 -#define reg_ce_centroid_drift_th_pos 0 -#define reg_ce_centroid_drift_th_len 8 -#define reg_ce_centroid_drift_th_lsb 0 -#define xd_p_reg_ce_centroid_count_max 0xABC9 -#define reg_ce_centroid_count_max_pos 0 -#define reg_ce_centroid_count_max_len 4 -#define reg_ce_centroid_count_max_lsb 0 -#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA -#define reg_ce_centroid_bias_inc_7_0_pos 0 -#define reg_ce_centroid_bias_inc_7_0_len 8 -#define reg_ce_centroid_bias_inc_7_0_lsb 0 -#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB -#define reg_ce_centroid_bias_inc_8_pos 0 -#define reg_ce_centroid_bias_inc_8_len 1 -#define reg_ce_centroid_bias_inc_8_lsb 0 -#define xd_p_reg_ce_var_th0_7_0 0xABCC -#define reg_ce_var_th0_7_0_pos 0 -#define reg_ce_var_th0_7_0_len 8 -#define reg_ce_var_th0_7_0_lsb 0 -#define xd_p_reg_ce_var_th0_15_8 0xABCD -#define reg_ce_var_th0_15_8_pos 0 -#define reg_ce_var_th0_15_8_len 8 -#define reg_ce_var_th0_15_8_lsb 8 -#define xd_p_reg_ce_var_th1_7_0 0xABCE -#define reg_ce_var_th1_7_0_pos 0 -#define reg_ce_var_th1_7_0_len 8 -#define reg_ce_var_th1_7_0_lsb 0 -#define xd_p_reg_ce_var_th1_15_8 0xABCF -#define reg_ce_var_th1_15_8_pos 0 -#define reg_ce_var_th1_15_8_len 8 -#define reg_ce_var_th1_15_8_lsb 8 -#define xd_p_reg_ce_var_th2_7_0 0xABD0 -#define reg_ce_var_th2_7_0_pos 0 -#define reg_ce_var_th2_7_0_len 8 -#define reg_ce_var_th2_7_0_lsb 0 -#define xd_p_reg_ce_var_th2_15_8 0xABD1 -#define reg_ce_var_th2_15_8_pos 0 -#define reg_ce_var_th2_15_8_len 8 -#define reg_ce_var_th2_15_8_lsb 8 -#define xd_p_reg_ce_var_th3_7_0 0xABD2 -#define reg_ce_var_th3_7_0_pos 0 -#define reg_ce_var_th3_7_0_len 8 -#define reg_ce_var_th3_7_0_lsb 0 -#define xd_p_reg_ce_var_th3_15_8 0xABD3 -#define reg_ce_var_th3_15_8_pos 0 -#define reg_ce_var_th3_15_8_len 8 -#define reg_ce_var_th3_15_8_lsb 8 -#define xd_p_reg_ce_var_th4_7_0 0xABD4 -#define reg_ce_var_th4_7_0_pos 0 -#define reg_ce_var_th4_7_0_len 8 -#define reg_ce_var_th4_7_0_lsb 0 -#define xd_p_reg_ce_var_th4_15_8 0xABD5 -#define reg_ce_var_th4_15_8_pos 0 -#define reg_ce_var_th4_15_8_len 8 -#define reg_ce_var_th4_15_8_lsb 8 -#define xd_p_reg_ce_var_th5_7_0 0xABD6 -#define reg_ce_var_th5_7_0_pos 0 -#define reg_ce_var_th5_7_0_len 8 -#define reg_ce_var_th5_7_0_lsb 0 -#define xd_p_reg_ce_var_th5_15_8 0xABD7 -#define reg_ce_var_th5_15_8_pos 0 -#define reg_ce_var_th5_15_8_len 8 -#define reg_ce_var_th5_15_8_lsb 8 -#define xd_p_reg_ce_var_th6_7_0 0xABD8 -#define reg_ce_var_th6_7_0_pos 0 -#define reg_ce_var_th6_7_0_len 8 -#define reg_ce_var_th6_7_0_lsb 0 -#define xd_p_reg_ce_var_th6_15_8 0xABD9 -#define reg_ce_var_th6_15_8_pos 0 -#define reg_ce_var_th6_15_8_len 8 -#define reg_ce_var_th6_15_8_lsb 8 -#define xd_p_reg_ce_fctrl_reset 0xABDA -#define reg_ce_fctrl_reset_pos 0 -#define reg_ce_fctrl_reset_len 1 -#define reg_ce_fctrl_reset_lsb 0 -#define xd_p_reg_ce_cent_auto_clr_en 0xABDA -#define reg_ce_cent_auto_clr_en_pos 1 -#define reg_ce_cent_auto_clr_en_len 1 -#define reg_ce_cent_auto_clr_en_lsb 0 -#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA -#define reg_ce_fctrl_auto_reset_en_pos 2 -#define reg_ce_fctrl_auto_reset_en_len 1 -#define reg_ce_fctrl_auto_reset_en_lsb 0 -#define xd_p_reg_ce_var_forced_en 0xABDA -#define reg_ce_var_forced_en_pos 3 -#define reg_ce_var_forced_en_len 1 -#define reg_ce_var_forced_en_lsb 0 -#define xd_p_reg_ce_cent_forced_en 0xABDA -#define reg_ce_cent_forced_en_pos 4 -#define reg_ce_cent_forced_en_len 1 -#define reg_ce_cent_forced_en_lsb 0 -#define xd_p_reg_ce_var_max 0xABDA -#define reg_ce_var_max_pos 5 -#define reg_ce_var_max_len 3 -#define reg_ce_var_max_lsb 0 -#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB -#define reg_ce_cent_forced_value_7_0_pos 0 -#define reg_ce_cent_forced_value_7_0_len 8 -#define reg_ce_cent_forced_value_7_0_lsb 0 -#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC -#define reg_ce_cent_forced_value_11_8_pos 0 -#define reg_ce_cent_forced_value_11_8_len 4 -#define reg_ce_cent_forced_value_11_8_lsb 8 -#define xd_p_reg_ce_fctrl_rd 0xABDD -#define reg_ce_fctrl_rd_pos 0 -#define reg_ce_fctrl_rd_len 1 -#define reg_ce_fctrl_rd_lsb 0 -#define xd_p_reg_ce_centroid_max_6_0 0xABDD -#define reg_ce_centroid_max_6_0_pos 1 -#define reg_ce_centroid_max_6_0_len 7 -#define reg_ce_centroid_max_6_0_lsb 0 -#define xd_p_reg_ce_centroid_max_11_7 0xABDE -#define reg_ce_centroid_max_11_7_pos 0 -#define reg_ce_centroid_max_11_7_len 5 -#define reg_ce_centroid_max_11_7_lsb 7 -#define xd_p_reg_ce_var 0xABDF -#define reg_ce_var_pos 0 -#define reg_ce_var_len 3 -#define reg_ce_var_lsb 0 -#define xd_p_reg_ce_fctrl_rdy 0xABDF -#define reg_ce_fctrl_rdy_pos 3 -#define reg_ce_fctrl_rdy_len 1 -#define reg_ce_fctrl_rdy_lsb 0 -#define xd_p_reg_ce_centroid_out_3_0 0xABDF -#define reg_ce_centroid_out_3_0_pos 4 -#define reg_ce_centroid_out_3_0_len 4 -#define reg_ce_centroid_out_3_0_lsb 0 -#define xd_p_reg_ce_centroid_out_11_4 0xABE0 -#define reg_ce_centroid_out_11_4_pos 0 -#define reg_ce_centroid_out_11_4_len 8 -#define reg_ce_centroid_out_11_4_lsb 4 -#define xd_p_reg_ce_bias_7_0 0xABE1 -#define reg_ce_bias_7_0_pos 0 -#define reg_ce_bias_7_0_len 8 -#define reg_ce_bias_7_0_lsb 0 -#define xd_p_reg_ce_bias_11_8 0xABE2 -#define reg_ce_bias_11_8_pos 0 -#define reg_ce_bias_11_8_len 4 -#define reg_ce_bias_11_8_lsb 8 -#define xd_p_reg_ce_m1_3_0 0xABE2 -#define reg_ce_m1_3_0_pos 4 -#define reg_ce_m1_3_0_len 4 -#define reg_ce_m1_3_0_lsb 0 -#define xd_p_reg_ce_m1_11_4 0xABE3 -#define reg_ce_m1_11_4_pos 0 -#define reg_ce_m1_11_4_len 8 -#define reg_ce_m1_11_4_lsb 4 -#define xd_p_reg_ce_rh0_7_0 0xABE4 -#define reg_ce_rh0_7_0_pos 0 -#define reg_ce_rh0_7_0_len 8 -#define reg_ce_rh0_7_0_lsb 0 -#define xd_p_reg_ce_rh0_15_8 0xABE5 -#define reg_ce_rh0_15_8_pos 0 -#define reg_ce_rh0_15_8_len 8 -#define reg_ce_rh0_15_8_lsb 8 -#define xd_p_reg_ce_rh0_23_16 0xABE6 -#define reg_ce_rh0_23_16_pos 0 -#define reg_ce_rh0_23_16_len 8 -#define reg_ce_rh0_23_16_lsb 16 -#define xd_p_reg_ce_rh0_31_24 0xABE7 -#define reg_ce_rh0_31_24_pos 0 -#define reg_ce_rh0_31_24_len 8 -#define reg_ce_rh0_31_24_lsb 24 -#define xd_p_reg_ce_rh3_real_7_0 0xABE8 -#define reg_ce_rh3_real_7_0_pos 0 -#define reg_ce_rh3_real_7_0_len 8 -#define reg_ce_rh3_real_7_0_lsb 0 -#define xd_p_reg_ce_rh3_real_15_8 0xABE9 -#define reg_ce_rh3_real_15_8_pos 0 -#define reg_ce_rh3_real_15_8_len 8 -#define reg_ce_rh3_real_15_8_lsb 8 -#define xd_p_reg_ce_rh3_real_23_16 0xABEA -#define reg_ce_rh3_real_23_16_pos 0 -#define reg_ce_rh3_real_23_16_len 8 -#define reg_ce_rh3_real_23_16_lsb 16 -#define xd_p_reg_ce_rh3_real_31_24 0xABEB -#define reg_ce_rh3_real_31_24_pos 0 -#define reg_ce_rh3_real_31_24_len 8 -#define reg_ce_rh3_real_31_24_lsb 24 -#define xd_p_reg_ce_rh3_imag_7_0 0xABEC -#define reg_ce_rh3_imag_7_0_pos 0 -#define reg_ce_rh3_imag_7_0_len 8 -#define reg_ce_rh3_imag_7_0_lsb 0 -#define xd_p_reg_ce_rh3_imag_15_8 0xABED -#define reg_ce_rh3_imag_15_8_pos 0 -#define reg_ce_rh3_imag_15_8_len 8 -#define reg_ce_rh3_imag_15_8_lsb 8 -#define xd_p_reg_ce_rh3_imag_23_16 0xABEE -#define reg_ce_rh3_imag_23_16_pos 0 -#define reg_ce_rh3_imag_23_16_len 8 -#define reg_ce_rh3_imag_23_16_lsb 16 -#define xd_p_reg_ce_rh3_imag_31_24 0xABEF -#define reg_ce_rh3_imag_31_24_pos 0 -#define reg_ce_rh3_imag_31_24_len 8 -#define reg_ce_rh3_imag_31_24_lsb 24 -#define xd_p_reg_feq_fix_eh2_7_0 0xABF0 -#define reg_feq_fix_eh2_7_0_pos 0 -#define reg_feq_fix_eh2_7_0_len 8 -#define reg_feq_fix_eh2_7_0_lsb 0 -#define xd_p_reg_feq_fix_eh2_15_8 0xABF1 -#define reg_feq_fix_eh2_15_8_pos 0 -#define reg_feq_fix_eh2_15_8_len 8 -#define reg_feq_fix_eh2_15_8_lsb 8 -#define xd_p_reg_feq_fix_eh2_23_16 0xABF2 -#define reg_feq_fix_eh2_23_16_pos 0 -#define reg_feq_fix_eh2_23_16_len 8 -#define reg_feq_fix_eh2_23_16_lsb 16 -#define xd_p_reg_feq_fix_eh2_31_24 0xABF3 -#define reg_feq_fix_eh2_31_24_pos 0 -#define reg_feq_fix_eh2_31_24_len 8 -#define reg_feq_fix_eh2_31_24_lsb 24 -#define xd_p_reg_ce_m2_central_7_0 0xABF4 -#define reg_ce_m2_central_7_0_pos 0 -#define reg_ce_m2_central_7_0_len 8 -#define reg_ce_m2_central_7_0_lsb 0 -#define xd_p_reg_ce_m2_central_15_8 0xABF5 -#define reg_ce_m2_central_15_8_pos 0 -#define reg_ce_m2_central_15_8_len 8 -#define reg_ce_m2_central_15_8_lsb 8 -#define xd_p_reg_ce_fftshift 0xABF6 -#define reg_ce_fftshift_pos 0 -#define reg_ce_fftshift_len 4 -#define reg_ce_fftshift_lsb 0 -#define xd_p_reg_ce_fftshift1 0xABF6 -#define reg_ce_fftshift1_pos 4 -#define reg_ce_fftshift1_len 4 -#define reg_ce_fftshift1_lsb 0 -#define xd_p_reg_ce_fftshift2 0xABF7 -#define reg_ce_fftshift2_pos 0 -#define reg_ce_fftshift2_len 4 -#define reg_ce_fftshift2_lsb 0 -#define xd_p_reg_ce_top_mobile 0xABF7 -#define reg_ce_top_mobile_pos 4 -#define reg_ce_top_mobile_len 1 -#define reg_ce_top_mobile_lsb 0 -#define xd_p_reg_strong_sginal_detected 0xA2BC -#define reg_strong_sginal_detected_pos 2 -#define reg_strong_sginal_detected_len 1 -#define reg_strong_sginal_detected_lsb 0 - -#define XD_MP2IF_BASE 0xB000 -#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE) -#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE) -#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE) -#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE) -#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE) -#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE) - -extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d); -extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, - u8 * value); -extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len); -extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, - u8 value); -extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len); -extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, - u8 addr, u8 * values, int len); -extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len); -extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, - u8 pos, u8 len, u8 * value); -extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, - u8 pos, u8 len, u8 value); -extern int af9005_send_command(struct dvb_usb_device *d, u8 command, - u8 * wbuf, int wlen, u8 * rbuf, int rlen); -extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, - u8 * values, int len); -extern int af9005_tuner_attach(struct dvb_usb_adapter *adap); -extern int af9005_led_control(struct dvb_usb_device *d, int onoff); - -extern u8 regmask[8]; - -/* remote control decoder */ -extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, - u32 * event, int *state); -extern struct rc_map_table rc_map_af9005_table[]; -extern int rc_map_af9005_table_size; - -#endif diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c deleted file mode 100644 index 5e45ae60542..00000000000 --- a/drivers/media/dvb/dvb-usb/az6027.c +++ /dev/null @@ -1,1182 +0,0 @@ -/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027) - * receiver. - * - * Copyright (C) 2009 Adams.Xu - * - * 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 "az6027.h" - -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" - -#include "stb6100.h" -#include "stb6100_cfg.h" -#include "dvb_ca_en50221.h" - -int dvb_usb_az6027_debug; -module_param_named(debug, dvb_usb_az6027_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct az6027_device_state { - struct dvb_ca_en50221 ca; - struct mutex ca_mutex; - u8 power_state; -}; - -static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = { - - /* 0x0000000b, SYSREG */ - { STB0899_DEV_ID , 0x30 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x99 }, - { STB0899_DISF22RX , 0xa8 }, - /* SYSREG ? */ - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0xfe }, - { STB0899_IRQSTATUS_2 , 0x03 }, - { STB0899_IRQSTATUS_1 , 0x7c }, - { STB0899_IRQSTATUS_0 , 0xf4 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x33 }, - { STB0899_IOPVALUE3 , 0x6d }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x60 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x01 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x01 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x23 }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xf7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xf1 }, - { STB0899_LDT2 , 0xe3 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfd }, - { STB0899_QDCCOMP , 0xff }, - { STB0899_POWERI , 0x0c }, - { STB0899_POWERQ , 0x0f }, - { STB0899_RCOMP , 0x6c }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x06 }, - { STB0899_AGC2I2 , 0x00 }, - { STB0899_TLIR , 0x30 }, - { STB0899_RTF , 0x7f }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xbc }, - { STB0899_CFRM , 0xea }, - { STB0899_CFRL , 0x31 }, - { STB0899_NIRM , 0x2b }, - { STB0899_NIRL , 0x80 }, - { STB0899_ISYMB , 0x1d }, - { STB0899_QSYMB , 0xa6 }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0x02 }, - { STB0899_EQUAQ1 , 0xff }, - { STB0899_EQUAI2 , 0x04 }, - { STB0899_EQUAQ2 , 0x05 }, - { STB0899_EQUAI3 , 0x02 }, - { STB0899_EQUAQ3 , 0xfd }, - { STB0899_EQUAI4 , 0x03 }, - { STB0899_EQUAQ4 , 0x07 }, - { STB0899_EQUAI5 , 0x08 }, - { STB0899_EQUAQ5 , 0xf5 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0x86 }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x0a }, - { STB0899_ECNT3L , 0xad }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xb0 }, - { STB0899_VTH23 , 0x7a }, - { STB0899_VTH34 , 0x58 }, - { STB0899_VTH56 , 0x38 }, - { STB0899_VTH67 , 0x34 }, - { STB0899_VTH78 , 0x24 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x41 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x00 }, - { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x1b }, - { STB0899_TSLLSTKL , 0xb3 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0x00 }, - { STB0899_PCKLENUL , 0xbc }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xbd }, - { STB0899_TSSTATUS , 0x90 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x95 }, - { STB0899_ERRCTRL3 , 0x8d }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x19 }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0xf0 }, - { STB0899_MATSTRL , 0x02 }, - { STB0899_UPLSTRM , 0x45 }, - { STB0899_UPLSTRL , 0x60 }, - { STB0899_DFLSTRM , 0xe3 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x47 }, - { STB0899_SYNCDSTRM , 0x05 }, - { STB0899_SYNCDSTRL , 0x18 }, - { STB0899_CFGPDELSTATUS1 , 0x19 }, - { STB0899_CFGPDELSTATUS2 , 0x2b }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x01 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - - - -struct stb0899_config az6027_stb0899_config = { - .init_dev = az6027_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = az6027_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL, -}; - -struct stb6100_config az6027_stb6100_config = { - .tuner_address = 0xc0, - .refclock = 27000000, -}; - - -/* check for mutex FIXME */ -int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) -{ - int ret = -1; - if (mutex_lock_interruptible(&d->usb_mutex)) - return -EAGAIN; - - ret = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value, - index, - b, - blen, - 2000); - - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else - ret = 0; - - deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); - debug_dump(b, blen, deb_xfer); - - mutex_unlock(&d->usb_mutex); - return ret; -} - -static int az6027_usb_out_op(struct dvb_usb_device *d, - u8 req, - u16 value, - u16 index, - u8 *b, - int blen) -{ - int ret; - - deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); - debug_dump(b, blen, deb_xfer); - - if (mutex_lock_interruptible(&d->usb_mutex)) - return -EAGAIN; - - ret = usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value, - index, - b, - blen, - 2000); - - if (ret != blen) { - warn("usb out operation failed. (%d)", ret); - mutex_unlock(&d->usb_mutex); - return -EIO; - } else{ - mutex_unlock(&d->usb_mutex); - return 0; - } -} - -static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - deb_info("%s %d", __func__, onoff); - - req = 0xBC; - value = onoff; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - warn("usb out operation failed. (%d)", ret); - - return ret; -} - -/* keys for the enclosed remote control */ -static struct rc_map_table rc_map_az6027_table[] = { - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, -}; - -/* remote control stuff (does not work with my box) */ -static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - return 0; -} - -/* -int az6027_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 v = onoff; - return az6027_usb_out_op(d,0xBC,v,3,NULL,1); -} -*/ - -static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, - int address) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - if (slot != 0) - return -EINVAL; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - mutex_lock(&state->ca_mutex); - - req = 0xC1; - value = address; - index = 0; - blen = 1; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EINVAL; - } else { - ret = b[0]; - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - -static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, - int address, - u8 value) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value1; - u16 index; - int blen; - - deb_info("%s %d", __func__, slot); - if (slot != 0) - return -EINVAL; - - mutex_lock(&state->ca_mutex); - req = 0xC2; - value1 = address; - index = value; - blen = 0; - - ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); - if (ret != 0) - warn("usb out operation failed. (%d)", ret); - - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - if (slot != 0) - return -EINVAL; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - mutex_lock(&state->ca_mutex); - - req = 0xC3; - value = address; - index = 0; - blen = 2; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EINVAL; - } else { - if (b[0] == 0) - warn("Read CI IO error"); - - ret = b[1]; - deb_info("read cam data = %x from 0x%x", b[1], value); - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - -static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address, - u8 value) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value1; - u16 index; - int blen; - - if (slot != 0) - return -EINVAL; - - mutex_lock(&state->ca_mutex); - req = 0xC4; - value1 = address; - index = value; - blen = 0; - - ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - req = 0xC8; - value = 0; - index = 0; - blen = 1; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else{ - ret = b[0]; - } - kfree(b); - return ret; -} - -static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret, i; - u8 req; - u16 value; - u16 index; - int blen; - - mutex_lock(&state->ca_mutex); - - req = 0xC6; - value = 1; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(d, req, value, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - - msleep(500); - req = 0xC6; - value = 0; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(d, req, value, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - - for (i = 0; i < 15; i++) { - msleep(100); - - if (CI_CamReady(ca, slot)) { - deb_info("CAM Ready"); - break; - } - } - msleep(5000); - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - return 0; -} - -static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - deb_info("%s", __func__); - mutex_lock(&state->ca_mutex); - req = 0xC7; - value = 1; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(d, req, value, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - mutex_lock(&state->ca_mutex); - - req = 0xC5; - value = 0; - index = 0; - blen = 1; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else - ret = 0; - - if (!ret && b[0] == 1) { - ret = DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - - -static void az6027_ci_uninit(struct dvb_usb_device *d) -{ - struct az6027_device_state *state; - - deb_info("%s", __func__); - - if (NULL == d) - return; - - state = (struct az6027_device_state *)d->priv; - if (NULL == state) - return; - - if (NULL == state->ca.data) - return; - - dvb_ca_en50221_release(&state->ca); - - memset(&state->ca, 0, sizeof(state->ca)); -} - - -static int az6027_ci_init(struct dvb_usb_adapter *a) -{ - struct dvb_usb_device *d = a->dev; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - int ret; - - deb_info("%s", __func__); - - mutex_init(&state->ca_mutex); - - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = az6027_ci_read_attribute_mem; - state->ca.write_attribute_mem = az6027_ci_write_attribute_mem; - state->ca.read_cam_control = az6027_ci_read_cam_control; - state->ca.write_cam_control = az6027_ci_write_cam_control; - state->ca.slot_reset = az6027_ci_slot_reset; - state->ca.slot_shutdown = az6027_ci_slot_shutdown; - state->ca.slot_ts_enable = az6027_ci_slot_ts_enable; - state->ca.poll_slot_status = az6027_ci_poll_slot_status; - state->ca.data = d; - - ret = dvb_ca_en50221_init(&a->dvb_adap, - &state->ca, - 0, /* flags */ - 1);/* n_slots */ - if (ret != 0) { - err("Cannot initialize CI: Error %d.", ret); - memset(&state->ca, 0, sizeof(state->ca)); - return ret; - } - - deb_info("CI initialized."); - - return 0; -} - -/* -static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) -{ - az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6); - return 0; -} -*/ - -static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - - u8 buf; - struct dvb_usb_adapter *adap = fe->dvb->priv; - - struct i2c_msg i2c_msg = { - .addr = 0x99, - .flags = 0, - .buf = &buf, - .len = 1 - }; - - /* - * 2 --18v - * 1 --13v - * 0 --off - */ - switch (voltage) { - case SEC_VOLTAGE_13: - buf = 1; - i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); - break; - - case SEC_VOLTAGE_18: - buf = 2; - i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); - break; - - case SEC_VOLTAGE_OFF: - buf = 0; - i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); - break; - - default: - return -EINVAL; - } - return 0; -} - - -static int az6027_frontend_poweron(struct dvb_usb_adapter *adap) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - req = 0xBC; - value = 1; /* power on */ - index = 3; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - return 0; -} -static int az6027_frontend_reset(struct dvb_usb_adapter *adap) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - /* reset demodulator */ - req = 0xC0; - value = 1; /* high */ - index = 3; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - req = 0xC0; - value = 0; /* low */ - index = 3; - blen = 0; - msleep_interruptible(200); - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - msleep_interruptible(200); - - req = 0xC0; - value = 1; /*high */ - index = 3; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - msleep_interruptible(200); - return 0; -} - -static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - /* TS passthrough */ - req = 0xC7; - value = onoff; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - return 0; -} - -static int az6027_frontend_attach(struct dvb_usb_adapter *adap) -{ - - az6027_frontend_poweron(adap); - az6027_frontend_reset(adap); - - deb_info("adap = %p, dev = %p\n", adap, adap->dev); - adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); - - if (adap->fe_adap[0].fe) { - deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); - if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { - deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); - adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage; - az6027_ci_init(adap); - } else { - adap->fe_adap[0].fe = NULL; - } - } else - warn("no front-end attached\n"); - - az6027_frontend_tsbypass(adap, 0); - - return 0; -} - -static struct dvb_usb_device_properties az6027_properties; - -static void az6027_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - az6027_ci_uninit(d); - dvb_usb_device_exit(intf); -} - - -static int az6027_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, - &az6027_properties, - THIS_MODULE, - NULL, - adapter_nr); -} - -/* I2C */ -static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, j = 0, len = 0; - u16 index; - u16 value; - int length; - u8 req; - u8 *data; - - data = kmalloc(256, GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) { - kfree(data); - return -EAGAIN; - } - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - - if (msg[i].addr == 0x99) { - req = 0xBE; - index = 0; - value = msg[i].buf[0] & 0x00ff; - length = 1; - az6027_usb_out_op(d, req, value, index, data, length); - } - - if (msg[i].addr == 0xd0) { - /* write/read request */ - if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { - req = 0xB9; - index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); - value = msg[i].addr + (msg[i].len << 8); - length = msg[i + 1].len + 6; - az6027_usb_in_op(d, req, value, index, data, length); - len = msg[i + 1].len; - for (j = 0; j < len; j++) - msg[i + 1].buf[j] = data[j + 5]; - - i++; - } else { - - /* demod 16bit addr */ - req = 0xBD; - index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); - value = msg[i].addr + (2 << 8); - length = msg[i].len - 2; - len = msg[i].len - 2; - for (j = 0; j < len; j++) - data[j] = msg[i].buf[j + 2]; - az6027_usb_out_op(d, req, value, index, data, length); - } - } - - if (msg[i].addr == 0xc0) { - if (msg[i].flags & I2C_M_RD) { - - req = 0xB9; - index = 0x0; - value = msg[i].addr; - length = msg[i].len + 6; - az6027_usb_in_op(d, req, value, index, data, length); - len = msg[i].len; - for (j = 0; j < len; j++) - msg[i].buf[j] = data[j + 5]; - - } else { - - req = 0xBD; - index = msg[i].buf[0] & 0x00FF; - value = msg[i].addr + (1 << 8); - length = msg[i].len - 1; - len = msg[i].len - 1; - - for (j = 0; j < len; j++) - data[j] = msg[i].buf[j + 1]; - - az6027_usb_out_op(d, req, value, index, data, length); - } - } - } - mutex_unlock(&d->i2c_mutex); - kfree(data); - - return i; -} - - -static u32 az6027_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm az6027_i2c_algo = { - .master_xfer = az6027_i2c_xfer, - .functionality = az6027_i2c_func, -}; - -int az6027_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - u8 *b; - s16 ret; - - b = kmalloc(16, GFP_KERNEL); - if (!b) - return -ENOMEM; - - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - 0xb7, - USB_TYPE_VENDOR | USB_DIR_IN, - 6, - 0, - b, - 6, - USB_CTRL_GET_TIMEOUT); - - *cold = ret <= 0; - kfree(b); - deb_info("cold: %d\n", *cold); - return 0; -} - - -static struct usb_device_id az6027_usb_table[] = { - { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V1) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, az6027_usb_table); - -static struct dvb_usb_device_properties az6027_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-az6027-03.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct az6027_device_state), - .identify_state = az6027_identify_state, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = az6027_streaming_ctrl, - .frontend_attach = az6027_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, -/* - .power_ctrl = az6027_power_ctrl, - .read_mac_address = az6027_read_mac_addr, - */ - .rc.legacy = { - .rc_map_table = rc_map_az6027_table, - .rc_map_size = ARRAY_SIZE(rc_map_az6027_table), - .rc_interval = 400, - .rc_query = az6027_rc_query, - }, - - .i2c_algo = &az6027_i2c_algo, - - .num_device_descs = 6, - .devices = { - { - .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", - .cold_ids = { &az6027_usb_table[0], NULL }, - .warm_ids = { NULL }, - }, { - .name = "TERRATEC S7", - .cold_ids = { &az6027_usb_table[1], NULL }, - .warm_ids = { NULL }, - }, { - .name = "TERRATEC S7 MKII", - .cold_ids = { &az6027_usb_table[2], NULL }, - .warm_ids = { NULL }, - }, { - .name = "Technisat SkyStar USB 2 HD CI", - .cold_ids = { &az6027_usb_table[3], NULL }, - .warm_ids = { NULL }, - }, { - .name = "Technisat SkyStar USB 2 HD CI", - .cold_ids = { &az6027_usb_table[4], NULL }, - .warm_ids = { NULL }, - }, { - .name = "Elgato EyeTV Sat", - .cold_ids = { &az6027_usb_table[5], NULL }, - .warm_ids = { NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver az6027_usb_driver = { - .name = "dvb_usb_az6027", - .probe = az6027_usb_probe, - .disconnect = az6027_usb_disconnect, - .id_table = az6027_usb_table, -}; - -module_usb_driver(az6027_usb_driver); - -MODULE_AUTHOR("Adams Xu "); -MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/az6027.h b/drivers/media/dvb/dvb-usb/az6027.h deleted file mode 100644 index f3afe17f3f3..00000000000 --- a/drivers/media/dvb/dvb-usb/az6027.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _DVB_USB_VP6027_H_ -#define _DVB_USB_VP6027_H_ - -#define DVB_USB_LOG_PREFIX "az6027" -#include "dvb-usb.h" - - -extern int dvb_usb_az6027_debug; -#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args) -#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args) - -#endif diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c deleted file mode 100644 index 0a98548ecd1..00000000000 --- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) - * - * Based on the dvb-usb-framework code and the - * original Terratec Cinergy T2 driver by: - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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 "cinergyT2.h" - - -/* debug */ -int dvb_usb_cinergyt2_debug; - -module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " - "(or-able))."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct cinergyt2_state { - u8 rc_counter; -}; - -/* We are missing a release hook with usb_device data */ -static struct dvb_usb_device *cinergyt2_usb_device; - -static struct dvb_usb_device_properties cinergyt2_properties; - -static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) -{ - char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; - char result[64]; - return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, - sizeof(result), 0); -} - -static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) -{ - char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; - char state[3]; - return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); -} - -static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) -{ - char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; - char state[3]; - int ret; - - adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev); - - ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, - sizeof(state), 0); - if (ret < 0) { - deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " - "state info\n"); - } - - /* Copy this pointer as we are gonna need it in the release phase */ - cinergyt2_usb_device = adap->dev; - - return 0; -} - -static struct rc_map_table rc_map_cinergyt2_table[] = { - { 0x0401, KEY_POWER }, - { 0x0402, KEY_1 }, - { 0x0403, KEY_2 }, - { 0x0404, KEY_3 }, - { 0x0405, KEY_4 }, - { 0x0406, KEY_5 }, - { 0x0407, KEY_6 }, - { 0x0408, KEY_7 }, - { 0x0409, KEY_8 }, - { 0x040a, KEY_9 }, - { 0x040c, KEY_0 }, - { 0x040b, KEY_VIDEO }, - { 0x040d, KEY_REFRESH }, - { 0x040e, KEY_SELECT }, - { 0x040f, KEY_EPG }, - { 0x0410, KEY_UP }, - { 0x0414, KEY_DOWN }, - { 0x0411, KEY_LEFT }, - { 0x0413, KEY_RIGHT }, - { 0x0412, KEY_OK }, - { 0x0415, KEY_TEXT }, - { 0x0416, KEY_INFO }, - { 0x0417, KEY_RED }, - { 0x0418, KEY_GREEN }, - { 0x0419, KEY_YELLOW }, - { 0x041a, KEY_BLUE }, - { 0x041c, KEY_VOLUMEUP }, - { 0x041e, KEY_VOLUMEDOWN }, - { 0x041d, KEY_MUTE }, - { 0x041b, KEY_CHANNELUP }, - { 0x041f, KEY_CHANNELDOWN }, - { 0x0440, KEY_PAUSE }, - { 0x044c, KEY_PLAY }, - { 0x0458, KEY_RECORD }, - { 0x0454, KEY_PREVIOUS }, - { 0x0448, KEY_STOP }, - { 0x045c, KEY_NEXT } -}; - -/* Number of keypresses to ignore before detect repeating */ -#define RC_REPEAT_DELAY 3 - -static int repeatable_keys[] = { - KEY_UP, - KEY_DOWN, - KEY_LEFT, - KEY_RIGHT, - KEY_VOLUMEUP, - KEY_VOLUMEDOWN, - KEY_CHANNELUP, - KEY_CHANNELDOWN -}; - -static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct cinergyt2_state *st = d->priv; - u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; - int i; - - *state = REMOTE_NO_KEY_PRESSED; - - dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); - if (key[4] == 0xff) { - /* key repeat */ - st->rc_counter++; - if (st->rc_counter > RC_REPEAT_DELAY) { - for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { - if (d->last_event == repeatable_keys[i]) { - *state = REMOTE_KEY_REPEAT; - *event = d->last_event; - deb_rc("repeat key, event %x\n", - *event); - return 0; - } - } - deb_rc("repeated key (non repeatable)\n"); - } - return 0; - } - - /* hack to pass checksum on the custom field */ - key[2] = ~key[1]; - dvb_usb_nec_rc_key_to_event(d, key, event, state); - if (key[0] != 0) { - if (*event != d->last_event) - st->rc_counter = 0; - - deb_rc("key: %x %x %x %x %x\n", - key[0], key[1], key[2], key[3], key[4]); - } - return 0; -} - -static int cinergyt2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &cinergyt2_properties, - THIS_MODULE, NULL, adapter_nr); -} - - -static struct usb_device_id cinergyt2_usb_table[] = { - { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); - -static struct dvb_usb_device_properties cinergyt2_properties = { - .size_of_priv = sizeof(struct cinergyt2_state), - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cinergyt2_streaming_ctrl, - .frontend_attach = cinergyt2_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - } - }, - - .power_ctrl = cinergyt2_power_ctrl, - - .rc.legacy = { - .rc_interval = 50, - .rc_map_table = rc_map_cinergyt2_table, - .rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table), - .rc_query = cinergyt2_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 1, - - .num_device_descs = 1, - .devices = { - { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", - .cold_ids = {NULL}, - .warm_ids = { &cinergyt2_usb_table[0], NULL }, - }, - { NULL }, - } -}; - - -static struct usb_driver cinergyt2_driver = { - .name = "cinergyT2", - .probe = cinergyt2_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = cinergyt2_usb_table -}; - -module_usb_driver(cinergyt2_driver); - -MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tomi Orava"); diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c deleted file mode 100644 index 1efc028a76c..00000000000 --- a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) - * - * Based on the dvb-usb-framework code and the - * original Terratec Cinergy T2 driver by: - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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 "cinergyT2.h" - - -/** - * convert linux-dvb frontend parameter set into TPS. - * See ETSI ETS-300744, section 4.6.2, table 9 for details. - * - * This function is probably reusable and may better get placed in a support - * library. - * - * We replace errornous fields by default TPS fields (the ones with value 0). - */ - -static uint16_t compute_tps(struct dtv_frontend_properties *op) -{ - uint16_t tps = 0; - - switch (op->code_rate_HP) { - case FEC_2_3: - tps |= (1 << 7); - break; - case FEC_3_4: - tps |= (2 << 7); - break; - case FEC_5_6: - tps |= (3 << 7); - break; - case FEC_7_8: - tps |= (4 << 7); - break; - case FEC_1_2: - case FEC_AUTO: - default: - /* tps |= (0 << 7) */; - } - - switch (op->code_rate_LP) { - case FEC_2_3: - tps |= (1 << 4); - break; - case FEC_3_4: - tps |= (2 << 4); - break; - case FEC_5_6: - tps |= (3 << 4); - break; - case FEC_7_8: - tps |= (4 << 4); - break; - case FEC_1_2: - case FEC_AUTO: - default: - /* tps |= (0 << 4) */; - } - - switch (op->modulation) { - case QAM_16: - tps |= (1 << 13); - break; - case QAM_64: - tps |= (2 << 13); - break; - case QPSK: - default: - /* tps |= (0 << 13) */; - } - - switch (op->transmission_mode) { - case TRANSMISSION_MODE_8K: - tps |= (1 << 0); - break; - case TRANSMISSION_MODE_2K: - default: - /* tps |= (0 << 0) */; - } - - switch (op->guard_interval) { - case GUARD_INTERVAL_1_16: - tps |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - tps |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - tps |= (3 << 2); - break; - case GUARD_INTERVAL_1_32: - default: - /* tps |= (0 << 2) */; - } - - switch (op->hierarchy) { - case HIERARCHY_1: - tps |= (1 << 10); - break; - case HIERARCHY_2: - tps |= (2 << 10); - break; - case HIERARCHY_4: - tps |= (3 << 10); - break; - case HIERARCHY_NONE: - default: - /* tps |= (0 << 10) */; - } - - return tps; -} - -struct cinergyt2_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; -}; - -static int cinergyt2_fe_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg result; - u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, - sizeof(result), 0); - if (ret < 0) - return ret; - - *status = 0; - - if (0xffff - le16_to_cpu(result.gain) > 30) - *status |= FE_HAS_SIGNAL; - if (result.lock_bits & (1 << 6)) - *status |= FE_HAS_LOCK; - if (result.lock_bits & (1 << 5)) - *status |= FE_HAS_SYNC; - if (result.lock_bits & (1 << 4)) - *status |= FE_HAS_CARRIER; - if (result.lock_bits & (1 << 1)) - *status |= FE_HAS_VITERBI; - - if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != - (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) - *status &= ~FE_HAS_LOCK; - - return 0; -} - -static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); - if (ret < 0) - return ret; - - *ber = le32_to_cpu(status.viterbi_error_rate); - return 0; -} - -static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, - sizeof(status), 0); - if (ret < 0) { - err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", - ret); - return ret; - } - *unc = le32_to_cpu(status.uncorrected_block_count); - return 0; -} - -static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); - if (ret < 0) { - err("cinergyt2_fe_read_signal_strength() Failed!" - " (Error=%d)\n", ret); - return ret; - } - *strength = (0xffff - le16_to_cpu(status.gain)); - return 0; -} - -static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); - if (ret < 0) { - err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); - return ret; - } - *snr = (status.snr << 8) | status.snr; - return 0; -} - -static int cinergyt2_fe_init(struct dvb_frontend *fe) -{ - return 0; -} - -static int cinergyt2_fe_sleep(struct dvb_frontend *fe) -{ - deb_info("cinergyt2_fe_sleep() Called\n"); - return 0; -} - -static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_set_parameters_msg param; - char result[2]; - int err; - - param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - param.tps = cpu_to_le16(compute_tps(fep)); - param.freq = cpu_to_le32(fep->frequency / 1000); - param.flags = 0; - - switch (fep->bandwidth_hz) { - default: - case 8000000: - param.bandwidth = 8; - break; - case 7000000: - param.bandwidth = 7; - break; - case 6000000: - param.bandwidth = 6; - break; - } - - err = dvb_usb_generic_rw(state->d, - (char *)¶m, sizeof(param), - result, sizeof(result), 0); - if (err < 0) - err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); - - return (err < 0) ? err : 0; -} - -static void cinergyt2_fe_release(struct dvb_frontend *fe) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - if (state != NULL) - kfree(state); -} - -static struct dvb_frontend_ops cinergyt2_fe_ops; - -struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) -{ - struct cinergyt2_fe_state *s = kzalloc(sizeof( - struct cinergyt2_fe_state), GFP_KERNEL); - if (s == NULL) - return NULL; - - s->d = d; - memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - return &s->fe; -} - - -static struct dvb_frontend_ops cinergyt2_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = DRIVER_NAME, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 - | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 - | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 - | FE_CAN_FEC_AUTO | FE_CAN_QPSK - | FE_CAN_QAM_16 | FE_CAN_QAM_64 - | FE_CAN_QAM_AUTO - | FE_CAN_TRANSMISSION_MODE_AUTO - | FE_CAN_GUARD_INTERVAL_AUTO - | FE_CAN_HIERARCHY_AUTO - | FE_CAN_RECOVER - | FE_CAN_MUTE_TS - }, - - .release = cinergyt2_fe_release, - - .init = cinergyt2_fe_init, - .sleep = cinergyt2_fe_sleep, - - .set_frontend = cinergyt2_fe_set_frontend, - .get_tune_settings = cinergyt2_fe_get_tune_settings, - - .read_status = cinergyt2_fe_read_status, - .read_ber = cinergyt2_fe_read_ber, - .read_signal_strength = cinergyt2_fe_read_signal_strength, - .read_snr = cinergyt2_fe_read_snr, - .read_ucblocks = cinergyt2_fe_read_unc_blocks, -}; diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h deleted file mode 100644 index 84efe03771e..00000000000 --- a/drivers/media/dvb/dvb-usb/cinergyT2.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) - * - * Based on the dvb-usb-framework code and the - * original Terratec Cinergy T2 driver by: - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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 _DVB_USB_CINERGYT2_H_ -#define _DVB_USB_CINERGYT2_H_ - -#include - -#define DVB_USB_LOG_PREFIX "cinergyT2" -#include "dvb-usb.h" - -#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" - -extern int dvb_usb_cinergyt2_debug; - -#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args) -#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args) -#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args) -#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args) -#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args) -#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args) -#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args) -#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args) -#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args) - - - -enum cinergyt2_ep1_cmd { - CINERGYT2_EP1_PID_TABLE_RESET = 0x01, - CINERGYT2_EP1_PID_SETUP = 0x02, - CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, - CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, - CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, - CINERGYT2_EP1_START_SCAN = 0x06, - CINERGYT2_EP1_CONTINUE_SCAN = 0x07, - CINERGYT2_EP1_GET_RC_EVENTS = 0x08, - CINERGYT2_EP1_SLEEP_MODE = 0x09, - CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A -}; - - -struct dvbt_get_status_msg { - uint32_t freq; - uint8_t bandwidth; - uint16_t tps; - uint8_t flags; - __le16 gain; - uint8_t snr; - __le32 viterbi_error_rate; - uint32_t rs_error_rate; - __le32 uncorrected_block_count; - uint8_t lock_bits; - uint8_t prev_lock_bits; -} __attribute__((packed)); - - -struct dvbt_set_parameters_msg { - uint8_t cmd; - __le32 freq; - uint8_t bandwidth; - __le16 tps; - uint8_t flags; -} __attribute__((packed)); - - -extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d); - -#endif /* _DVB_USB_CINERGYT2_H_ */ - diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c deleted file mode 100644 index 3940bb0f9ef..00000000000 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ /dev/null @@ -1,2043 +0,0 @@ -/* DVB USB compliant linux driver for Conexant USB reference design. - * - * The Conexant reference design I saw on their website was only for analogue - * capturing (using the cx25842). The box I took to write this driver (reverse - * engineered) is the one labeled Medion MD95700. In addition to the cx25842 - * for analogue capturing it also has a cx22702 DVB-T demodulator on the main - * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard. - * - * Maybe it is a little bit premature to call this driver cxusb, but I assume - * the USB protocol is identical or at least inherited from the reference - * design, so it can be reused for the "analogue-only" device (if it will - * appear at all). - * - * TODO: Use the cx25840-driver for the analogue part - * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) - * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) - * - * 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 -#include -#include - -#include "cxusb.h" - -#include "cx22702.h" -#include "lgdt330x.h" -#include "mt352.h" -#include "mt352_priv.h" -#include "zl10353.h" -#include "tuner-xc2028.h" -#include "tuner-simple.h" -#include "mxl5005s.h" -#include "max2165.h" -#include "dib7000p.h" -#include "dib0070.h" -#include "lgs8gxx.h" -#include "atbm8830.h" - -/* debug */ -static int dvb_usb_cxusb_debug; -module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) -#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) - -static int cxusb_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 sndbuf[1+wlen]; - memset(sndbuf, 0, 1+wlen); - - sndbuf[0] = cmd; - memcpy(&sndbuf[1], wbuf, wlen); - if (wo) - return dvb_usb_generic_write(d, sndbuf, 1+wlen); - else - return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); -} - -/* GPIO */ -static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) -{ - struct cxusb_state *st = d->priv; - u8 o[2], i; - - if (st->gpio_write_state[GPIO_TUNER] == onoff) - return; - - o[0] = GPIO_TUNER; - o[1] = onoff; - cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); - - if (i != 0x01) - deb_info("gpio_write failed.\n"); - - st->gpio_write_state[GPIO_TUNER] = onoff; -} - -static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, - u8 newval) -{ - u8 o[2], gpio_state; - int rc; - - o[0] = 0xff & ~changemask; /* mask of bits to keep */ - o[1] = newval & changemask; /* new values for bits */ - - rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); - if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) - deb_info("bluebird_gpio_write failed.\n"); - - return rc < 0 ? rc : gpio_state; -} - -static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) -{ - cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); - msleep(5); - cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); -} - -static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) -{ - cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); -} - -static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, - u8 addr, int onoff) -{ - u8 o[2] = {addr, onoff}; - u8 i; - int rc; - - rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); - - if (rc < 0) - return rc; - if (i == 0x01) - return 0; - else { - deb_info("gpio_write failed.\n"); - return -EIO; - } -} - -/* I2C */ -static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - - if (d->udev->descriptor.idVendor == USB_VID_MEDION) - switch (msg[i].addr) { - case 0x63: - cxusb_gpio_tuner(d, 0); - break; - default: - cxusb_gpio_tuner(d, 1); - break; - } - - if (msg[i].flags & I2C_M_RD) { - /* read only */ - u8 obuf[3], ibuf[1+msg[i].len]; - obuf[0] = 0; - obuf[1] = msg[i].len; - obuf[2] = msg[i].addr; - if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3, - ibuf, 1+msg[i].len) < 0) { - warn("i2c read failed"); - break; - } - memcpy(msg[i].buf, &ibuf[1], msg[i].len); - } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && - msg[i].addr == msg[i+1].addr) { - /* write to then read from same address */ - u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; - obuf[0] = msg[i].len; - obuf[1] = msg[i+1].len; - obuf[2] = msg[i].addr; - memcpy(&obuf[3], msg[i].buf, msg[i].len); - - if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3+msg[i].len, - ibuf, 1+msg[i+1].len) < 0) - break; - - if (ibuf[0] != 0x08) - deb_i2c("i2c read may have failed\n"); - - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); - - i++; - } else { - /* write only */ - u8 obuf[2+msg[i].len], ibuf; - obuf[0] = msg[i].addr; - obuf[1] = msg[i].len; - memcpy(&obuf[2], msg[i].buf, msg[i].len); - - if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, - 2+msg[i].len, &ibuf,1) < 0) - break; - if (ibuf != 0x08) - deb_i2c("i2c write may have failed\n"); - } - } - - mutex_unlock(&d->i2c_mutex); - return i == num ? num : -EREMOTEIO; -} - -static u32 cxusb_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm cxusb_i2c_algo = { - .master_xfer = cxusb_i2c_xfer, - .functionality = cxusb_i2c_func, -}; - -static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = 0; - if (onoff) - return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); - else - return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); -} - -static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - if (!onoff) - return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); - if (d->state == DVB_USB_STATE_INIT && - usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); - if (!ret) { - /* FIXME: We don't know why, but we need to configure the - * lgdt3303 with the register settings below on resume */ - int i; - u8 buf, bufs[] = { - 0x0e, 0x2, 0x00, 0x7f, - 0x0e, 0x2, 0x02, 0xfe, - 0x0e, 0x2, 0x02, 0x01, - 0x0e, 0x2, 0x00, 0x03, - 0x0e, 0x2, 0x0d, 0x40, - 0x0e, 0x2, 0x0e, 0x87, - 0x0e, 0x2, 0x0f, 0x8e, - 0x0e, 0x2, 0x10, 0x01, - 0x0e, 0x2, 0x14, 0xd7, - 0x0e, 0x2, 0x47, 0x88, - }; - msleep(20); - for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) { - ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, - bufs+i, 4, &buf, 1); - if (ret) - break; - if (buf != 0x8) - return -EREMOTEIO; - } - } - return ret; -} - -static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = 0; - if (onoff) - return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); - else - return 0; -} - -static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int rc = 0; - - rc = cxusb_power_ctrl(d, onoff); - if (!onoff) - cxusb_nano2_led(d, 0); - - return rc; -} - -static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - u8 b; - ret = cxusb_power_ctrl(d, onoff); - if (!onoff) - return ret; - - msleep(128); - cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); - msleep(100); - return ret; -} - -static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 buf[2] = { 0x03, 0x00 }; - if (onoff) - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); - else - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); - - return 0; -} - -static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (onoff) - cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0); - else - cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF, - NULL, 0, NULL, 0); - return 0; -} - -static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) -{ - int ep = d->props.generic_bulk_ctrl_endpoint; - const int timeout = 100; - const int junk_len = 32; - u8 *junk; - int rd_count; - - /* Discard remaining data in video pipe */ - junk = kmalloc(junk_len, GFP_KERNEL); - if (!junk) - return; - while (1) { - if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, ep), - junk, junk_len, &rd_count, timeout) < 0) - break; - if (!rd_count) - break; - } - kfree(junk); -} - -static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) -{ - struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream; - const int timeout = 100; - const int junk_len = p->u.bulk.buffersize; - u8 *junk; - int rd_count; - - /* Discard remaining data in video pipe */ - junk = kmalloc(junk_len, GFP_KERNEL); - if (!junk) - return; - while (1) { - if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, p->endpoint), - junk, junk_len, &rd_count, timeout) < 0) - break; - if (!rd_count) - break; - } - kfree(junk); -} - -static int cxusb_d680_dmb_streaming_ctrl( - struct dvb_usb_adapter *adap, int onoff) -{ - if (onoff) { - u8 buf[2] = { 0x03, 0x00 }; - cxusb_d680_dmb_drain_video(adap->dev); - return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, - buf, sizeof(buf), NULL, 0); - } else { - int ret = cxusb_ctrl_msg(adap->dev, - CMD_STREAMING_OFF, NULL, 0, NULL, 0); - return ret; - } -} - -static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - u8 ircode[4]; - int i; - - cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&keymap[i]) == ircode[2] && - rc5_data(&keymap[i]) == ircode[3]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - -static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, - int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - u8 ircode[4]; - int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) - return 0; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&keymap[i]) == ircode[1] && - rc5_data(&keymap[i]) == ircode[2]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - -static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, - int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - u8 ircode[2]; - int i; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) - return 0; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&keymap[i]) == ircode[0] && - rc5_data(&keymap[i]) == ircode[1]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - -static struct rc_map_table rc_map_dvico_mce_table[] = { - { 0xfe02, KEY_TV }, - { 0xfe0e, KEY_MP3 }, - { 0xfe1a, KEY_DVD }, - { 0xfe1e, KEY_FAVORITES }, - { 0xfe16, KEY_SETUP }, - { 0xfe46, KEY_POWER2 }, - { 0xfe0a, KEY_EPG }, - { 0xfe49, KEY_BACK }, - { 0xfe4d, KEY_MENU }, - { 0xfe51, KEY_UP }, - { 0xfe5b, KEY_LEFT }, - { 0xfe5f, KEY_RIGHT }, - { 0xfe53, KEY_DOWN }, - { 0xfe5e, KEY_OK }, - { 0xfe59, KEY_INFO }, - { 0xfe55, KEY_TAB }, - { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ - { 0xfe12, KEY_NEXTSONG }, /* Skip */ - { 0xfe42, KEY_ENTER }, /* Windows/Start */ - { 0xfe15, KEY_VOLUMEUP }, - { 0xfe05, KEY_VOLUMEDOWN }, - { 0xfe11, KEY_CHANNELUP }, - { 0xfe09, KEY_CHANNELDOWN }, - { 0xfe52, KEY_CAMERA }, - { 0xfe5a, KEY_TUNER }, /* Live */ - { 0xfe19, KEY_OPEN }, - { 0xfe0b, KEY_1 }, - { 0xfe17, KEY_2 }, - { 0xfe1b, KEY_3 }, - { 0xfe07, KEY_4 }, - { 0xfe50, KEY_5 }, - { 0xfe54, KEY_6 }, - { 0xfe48, KEY_7 }, - { 0xfe4c, KEY_8 }, - { 0xfe58, KEY_9 }, - { 0xfe13, KEY_ANGLE }, /* Aspect */ - { 0xfe03, KEY_0 }, - { 0xfe1f, KEY_ZOOM }, - { 0xfe43, KEY_REWIND }, - { 0xfe47, KEY_PLAYPAUSE }, - { 0xfe4f, KEY_FASTFORWARD }, - { 0xfe57, KEY_MUTE }, - { 0xfe0d, KEY_STOP }, - { 0xfe01, KEY_RECORD }, - { 0xfe4e, KEY_POWER }, -}; - -static struct rc_map_table rc_map_dvico_portable_table[] = { - { 0xfc02, KEY_SETUP }, /* Profile */ - { 0xfc43, KEY_POWER2 }, - { 0xfc06, KEY_EPG }, - { 0xfc5a, KEY_BACK }, - { 0xfc05, KEY_MENU }, - { 0xfc47, KEY_INFO }, - { 0xfc01, KEY_TAB }, - { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ - { 0xfc49, KEY_VOLUMEUP }, - { 0xfc09, KEY_VOLUMEDOWN }, - { 0xfc54, KEY_CHANNELUP }, - { 0xfc0b, KEY_CHANNELDOWN }, - { 0xfc16, KEY_CAMERA }, - { 0xfc40, KEY_TUNER }, /* ATV/DTV */ - { 0xfc45, KEY_OPEN }, - { 0xfc19, KEY_1 }, - { 0xfc18, KEY_2 }, - { 0xfc1b, KEY_3 }, - { 0xfc1a, KEY_4 }, - { 0xfc58, KEY_5 }, - { 0xfc59, KEY_6 }, - { 0xfc15, KEY_7 }, - { 0xfc14, KEY_8 }, - { 0xfc17, KEY_9 }, - { 0xfc44, KEY_ANGLE }, /* Aspect */ - { 0xfc55, KEY_0 }, - { 0xfc07, KEY_ZOOM }, - { 0xfc0a, KEY_REWIND }, - { 0xfc08, KEY_PLAYPAUSE }, - { 0xfc4b, KEY_FASTFORWARD }, - { 0xfc5b, KEY_MUTE }, - { 0xfc04, KEY_STOP }, - { 0xfc56, KEY_RECORD }, - { 0xfc57, KEY_POWER }, - { 0xfc41, KEY_UNKNOWN }, /* INPUT */ - { 0xfc00, KEY_UNKNOWN }, /* HD */ -}; - -static struct rc_map_table rc_map_d680_dmb_table[] = { - { 0x0038, KEY_UNKNOWN }, /* TV/AV */ - { 0x080c, KEY_ZOOM }, - { 0x0800, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0009, KEY_9 }, - { 0x000a, KEY_MUTE }, - { 0x0829, KEY_BACK }, - { 0x0012, KEY_CHANNELUP }, - { 0x0813, KEY_CHANNELDOWN }, - { 0x002b, KEY_VOLUMEUP }, - { 0x082c, KEY_VOLUMEDOWN }, - { 0x0020, KEY_UP }, - { 0x0821, KEY_DOWN }, - { 0x0011, KEY_LEFT }, - { 0x0810, KEY_RIGHT }, - { 0x000d, KEY_OK }, - { 0x081f, KEY_RECORD }, - { 0x0017, KEY_PLAYPAUSE }, - { 0x0816, KEY_PLAYPAUSE }, - { 0x000b, KEY_STOP }, - { 0x0827, KEY_FASTFORWARD }, - { 0x0026, KEY_REWIND }, - { 0x081e, KEY_UNKNOWN }, /* Time Shift */ - { 0x000e, KEY_UNKNOWN }, /* Snapshot */ - { 0x082d, KEY_UNKNOWN }, /* Mouse Cursor */ - { 0x000f, KEY_UNKNOWN }, /* Minimize/Maximize */ - { 0x0814, KEY_UNKNOWN }, /* Shuffle */ - { 0x0025, KEY_POWER }, -}; - -static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) -{ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -static int cxusb_mt352_demod_init(struct dvb_frontend* fe) -{ /* used in both lgz201 and th7579 */ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - return 0; -} - -static struct cx22702_config cxusb_cx22702_config = { - .demod_address = 0x63, - .output_mode = CX22702_PARALLEL_OUTPUT, -}; - -static struct lgdt330x_config cxusb_lgdt3303_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, -}; - -static struct lgdt330x_config cxusb_aver_lgdt3303_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .clock_polarity_flip = 2, -}; - -static struct mt352_config cxusb_dee1601_config = { - .demod_address = 0x0f, - .demod_init = cxusb_dee1601_demod_init, -}; - -static struct zl10353_config cxusb_zl10353_dee1601_config = { - .demod_address = 0x0f, - .parallel_ts = 1, -}; - -static struct mt352_config cxusb_mt352_config = { - /* used in both lgz201 and th7579 */ - .demod_address = 0x0f, - .demod_init = cxusb_mt352_demod_init, -}; - -static struct zl10353_config cxusb_zl10353_xc3028_config = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, -}; - -static struct mt352_config cxusb_mt352_xc3028_config = { - .demod_address = 0x0f, - .if2 = 4560, - .no_tuner = 1, - .demod_init = cxusb_mt352_demod_init, -}; - -/* FIXME: needs tweaking */ -static struct mxl5005s_config aver_a868r_tuner = { - .i2c_address = 0x63, - .if_freq = 6000000UL, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -/* FIXME: needs tweaking */ -static struct mxl5005s_config d680_dmb_tuner = { - .i2c_address = 0x63, - .if_freq = 36125000UL, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct max2165_config mygica_d689_max2165_cfg = { - .i2c_address = 0x60, - .osc_clk = 20 -}; - -/* Callbacks for DVB USB */ -static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); - return 0; -} - -static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, - NULL, DVB_PLL_THOMSON_DTT7579); - return 0; -} - -static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201); - return 0; -} - -static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, - NULL, DVB_PLL_THOMSON_DTT7579); - return 0; -} - -static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); - return 0; -} - -static int dvico_bluebird_xc2028_callback(void *ptr, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = ptr; - struct dvb_usb_device *d = adap->dev; - - switch (command) { - case XC2028_TUNER_RESET: - deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg); - cxusb_bluebird_gpio_pulse(d, 0x01, 1); - break; - case XC2028_RESET_CLK: - deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg); - break; - default: - deb_info("%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; - } - - return 0; -} - -static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &adap->dev->i2c_adap, - .i2c_addr = 0x61, - }; - static struct xc2028_ctrl ctl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - }; - - /* FIXME: generalize & move to common area */ - adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback; - - fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg); - if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) - return -EIO; - - fe->ops.tuner_ops.set_config(fe, &ctl); - - return 0; -} - -static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, &aver_a868r_tuner); - return 0; -} - -static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, &d680_dmb_tuner); - return (fe == NULL) ? -EIO : 0; -} - -static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); - return (fe == NULL) ? -EIO : 0; -} - -static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 b; - if (usb_set_interface(adap->dev->udev, 0, 6) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - - adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 7) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, - &cxusb_lgdt3303_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe != NULL) - return 0; - - return -EIO; -} - -static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) -{ - /* used in both lgz201 and th7579 */ - if (usb_set_interface(adap->dev->udev, 0, 0) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 0) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_dee1601_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 ircode[4]; - int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; - - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - /* reset the tuner and demodulator */ - cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); - cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - adap->fe_adap[0].fe = - dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config_no_i2c_gate, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) == NULL) - return -EIO; - - /* try to determine if there is no IR decoder on the I2C bus */ - for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) { - msleep(20); - if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) - goto no_IR; - if (ircode[0] == 0 && ircode[1] == 0) - continue; - if (ircode[2] + ircode[3] != 0xff) { -no_IR: - adap->dev->props.rc.legacy.rc_map_table = NULL; - info("No IR receiver detected on this device."); - break; - } - } - - return 0; -} - -static struct dibx000_agc_config dib7070_agc_config = { - .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, - - /* - * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 - */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | - (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - .inv_gain = 600, - .time_stabiliz = 10, - .alpha_level = 0, - .thlock = 118, - .wbd_inv = 0, - .wbd_ref = 3530, - .wbd_sel = 1, - .wbd_alpha = 5, - .agc1_max = 65535, - .agc1_min = 0, - .agc2_max = 65535, - .agc2_min = 0, - .agc1_pt1 = 0, - .agc1_pt2 = 40, - .agc1_pt3 = 183, - .agc1_slope1 = 206, - .agc1_slope2 = 255, - .agc2_pt1 = 72, - .agc2_pt2 = 152, - .agc2_slope1 = 88, - .agc2_slope2 = 90, - .alpha_mant = 17, - .alpha_exp = 27, - .beta_mant = 23, - .beta_exp = 51, - .perform_agc_softsplit = 0, -}; - -static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - .internal = 60000, - .sampling = 15000, - .pll_prediv = 1, - .pll_ratio = 20, - .pll_range = 3, - .pll_reset = 1, - .pll_bypass = 0, - .enable_refdiv = 0, - .bypclk_div = 0, - .IO_CLK_en_core = 1, - .ADClkSrc = 1, - .modulo = 2, - /* refsel, sel, freq_15k */ - .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), - .ifreq = (0 << 25) | 0, - .timf = 20452225, - .xtal_hz = 12000000, -}; - -static struct dib7000p_config cxusb_dualdig4_rev2_config = { - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = 0xfcef, - .gpio_val = 0x0110, - - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, -}; - -static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) { - printk(KERN_WARNING "Unable to enumerate dib7000p\n"); - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config); - if (adap->fe_adap[0].fe == NULL) - return -EIO; - - return 0; -} - -static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - return dib7000p_set_gpio(fe, 8, 0, !onoff); -} - -static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - return 0; -} - -static struct dib0070_config dib7070p_dib0070_config = { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, -}; - -struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *); -}; - -static int dib7070_set_param_override(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - switch (band) { - case BAND_VHF: offset = 950; break; - default: - case BAND_UHF: offset = 550; break; - } - - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - - return state->set_param_save(fe); -} - -static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = - dib7000p_get_i2c_master(adap->fe_adap[0].fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7070p_dib0070_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override; - return 0; -} - -static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - /* reset the tuner and demodulator */ - cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); - cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - adap->fe_adap[0].fe = dvb_attach(mt352_attach, - &cxusb_mt352_xc3028_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; - - return -EIO; -} - -static struct lgs8gxx_config d680_lgs8gl5_cfg = { - .prod = LGS8GXX_PROD_LGS8GL5, - .demod_address = 0x19, - .serial_ts = 0, - .ts_clk_pol = 0, - .ts_clk_gated = 1, - .if_clk_freq = 30400, /* 30.4 MHz */ - .if_freq = 5725, /* 5.725 MHz */ - .if_neg_center = 0, - .ext_adc = 0, - .adc_signed = 0, - .if_neg_edge = 0, -}; - -static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - int n; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); - - /* Drain USB pipes to avoid hang after reboot */ - for (n = 0; n < 5; n++) { - cxusb_d680_dmb_drain_message(d); - cxusb_d680_dmb_drain_video(d); - msleep(200); - } - - /* Reset the tuner */ - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { - err("clear tuner gpio failed"); - return -EIO; - } - msleep(100); - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { - err("set tuner gpio failed"); - return -EIO; - } - msleep(100); - - /* Attach frontend */ - adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) - return -EIO; - - return 0; -} - -static struct atbm8830_config mygica_d689_atbm8830_cfg = { - .prod = ATBM8830_PROD_8830, - .demod_address = 0x40, - .serial_ts = 0, - .ts_sampling_edge = 1, - .ts_clk_gated = 0, - .osc_clk_freq = 30400, /* in kHz */ - .if_freq = 0, /* zero IF */ - .zif_swap_iq = 1, - .agc_min = 0x2E, - .agc_max = 0x90, - .agc_hold_loop = 0, -}; - -static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); - - - /* Reset the tuner */ - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { - err("clear tuner gpio failed"); - return -EIO; - } - msleep(100); - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { - err("set tuner gpio failed"); - return -EIO; - } - msleep(100); - - /* Attach frontend */ - adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, - &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) - return -EIO; - - return 0; -} - -/* - * DViCO has shipped two devices with the same USB ID, but only one of them - * needs a firmware download. Check the device class details to see if they - * have non-default values to decide whether the device is actually cold or - * not, and forget a match if it turns out we selected the wrong device. - */ -static int bluebird_fx2_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int wascold = *cold; - - *cold = udev->descriptor.bDeviceClass == 0xff && - udev->descriptor.bDeviceSubClass == 0xff && - udev->descriptor.bDeviceProtocol == 0xff; - - if (*cold && !wascold) - *desc = NULL; - - return 0; -} - -/* - * DViCO bluebird firmware needs the "warm" product ID to be patched into the - * firmware file before download. - */ - -static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; -static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, - const struct firmware *fw) -{ - int pos; - - for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { - int idoff = dvico_firmware_id_offsets[pos]; - - if (fw->size < idoff + 4) - continue; - - if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && - fw->data[idoff + 1] == USB_VID_DVICO >> 8) { - struct firmware new_fw; - u8 *new_fw_data = vmalloc(fw->size); - int ret; - - if (!new_fw_data) - return -ENOMEM; - - memcpy(new_fw_data, fw->data, fw->size); - new_fw.size = fw->size; - new_fw.data = new_fw_data; - - new_fw_data[idoff + 2] = - le16_to_cpu(udev->descriptor.idProduct) + 1; - new_fw_data[idoff + 3] = - le16_to_cpu(udev->descriptor.idProduct) >> 8; - - ret = usb_cypress_load_firmware(udev, &new_fw, - CYPRESS_FX2); - vfree(new_fw_data); - return ret; - } - } - - return -EINVAL; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties cxusb_medion_properties; -static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; -static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; -static struct dvb_usb_device_properties cxusb_aver_a868r_properties; -static struct dvb_usb_device_properties cxusb_d680_dmb_properties; -static struct dvb_usb_device_properties cxusb_mygica_d689_properties; - -static int cxusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_nano2_needsfirmware_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_dualdig4_rev2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, - THIS_MODULE, NULL, adapter_nr) || - 0) - return 0; - - return -EINVAL; -} - -static struct usb_device_id cxusb_table [] = { - { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, cxusb_table); - -static struct dvb_usb_device_properties cxusb_medion_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_cx22702_frontend_attach, - .tuner_attach = cxusb_fmd1216me_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - .power_ctrl = cxusb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Medion MD95700 (MDUSBTV-HYBRID)", - { NULL }, - { &cxusb_table[0], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_lgdt3303_frontend_attach, - .tuner_attach = cxusb_lgh064f_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV5 USB Gold", - { &cxusb_table[1], NULL }, - { &cxusb_table[2], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dee1601_frontend_attach, - .tuner_attach = cxusb_dee1601_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 150, - .rc_map_table = rc_map_dvico_mce_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 3, - .devices = { - { "DViCO FusionHDTV DVB-T Dual USB", - { &cxusb_table[3], NULL }, - { &cxusb_table[4], NULL }, - }, - { "DigitalNow DVB-T Dual USB", - { &cxusb_table[9], NULL }, - { &cxusb_table[10], NULL }, - }, - { "DViCO FusionHDTV DVB-T Dual Digital 2", - { &cxusb_table[11], NULL }, - { &cxusb_table[12], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mt352_frontend_attach, - .tuner_attach = cxusb_lgz201_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T USB (LGZ201)", - { &cxusb_table[5], NULL }, - { &cxusb_table[6], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mt352_frontend_attach, - .tuner_attach = cxusb_dtt7579_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T USB (TH7579)", - { &cxusb_table[7], NULL }, - { &cxusb_table[8], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_mce_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_query = cxusb_bluebird2_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T Dual Digital 4", - { NULL }, - { &cxusb_table[13], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .identify_state = bluebird_fx2_identify_state, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_nano2_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_nano2_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_bluebird2_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2", - { NULL }, - { &cxusb_table[14], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-02.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - .identify_state = bluebird_fx2_identify_state, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_nano2_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_nano2_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", - { &cxusb_table[14], NULL }, - { &cxusb_table[15], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_aver_streaming_ctrl, - .frontend_attach = cxusb_aver_lgdt3303_frontend_attach, - .tuner_attach = cxusb_mxl5003s_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - .power_ctrl = cxusb_aver_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "AVerMedia AVerTVHD Volar (A868R)", - { NULL }, - { &cxusb_table[16], NULL }, - }, - } -}; - -static -struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .size_of_priv = sizeof(struct dib0700_adapter_state), - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, - .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_mce_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_query = cxusb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", - { NULL }, - { &cxusb_table[17], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, - .frontend_attach = cxusb_d680_dmb_frontend_attach, - .tuner_attach = cxusb_d680_dmb_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_d680_dmb_table, - .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), - .rc_query = cxusb_d680_dmb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { - "Conexant DMB-TH Stick", - { NULL }, - { &cxusb_table[18], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, - .frontend_attach = cxusb_mygica_d689_frontend_attach, - .tuner_attach = cxusb_mygica_d689_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_d680_dmb_table, - .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), - .rc_query = cxusb_d680_dmb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { - "Mygica D689 DMB-TH", - { NULL }, - { &cxusb_table[19], NULL }, - }, - } -}; - -static struct usb_driver cxusb_driver = { - .name = "dvb_usb_cxusb", - .probe = cxusb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = cxusb_table, -}; - -module_usb_driver(cxusb_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_AUTHOR("Michael Krufky "); -MODULE_AUTHOR("Chris Pascoe "); -MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); -MODULE_VERSION("1.0-alpha"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h deleted file mode 100644 index 1a51eafd31b..00000000000 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _DVB_USB_CXUSB_H_ -#define _DVB_USB_CXUSB_H_ - -#define DVB_USB_LOG_PREFIX "cxusb" -#include "dvb-usb.h" - -/* usb commands - some of it are guesses, don't have a reference yet */ -#define CMD_BLUEBIRD_GPIO_RW 0x05 - -#define CMD_I2C_WRITE 0x08 -#define CMD_I2C_READ 0x09 - -#define CMD_GPIO_READ 0x0d -#define CMD_GPIO_WRITE 0x0e -#define GPIO_TUNER 0x02 - -#define CMD_POWER_OFF 0xdc -#define CMD_POWER_ON 0xde - -#define CMD_STREAMING_ON 0x36 -#define CMD_STREAMING_OFF 0x37 - -#define CMD_AVER_STREAM_ON 0x18 -#define CMD_AVER_STREAM_OFF 0x19 - -#define CMD_GET_IR_CODE 0x47 - -#define CMD_ANALOG 0x50 -#define CMD_DIGITAL 0x51 - -struct cxusb_state { - u8 gpio_write_state[3]; -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h deleted file mode 100644 index 7de125c0b36..00000000000 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Linux driver for devices based on the DiBcom DiB0700 USB bridge - * - * 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. - * - * Copyright (C) 2005-6 DiBcom, SA - */ -#ifndef _DIB0700_H_ -#define _DIB0700_H_ - -#define DVB_USB_LOG_PREFIX "dib0700" -#include "dvb-usb.h" - -#include "dib07x0.h" - -extern int dvb_usb_dib0700_debug; -#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) -#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) -#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) -#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) - -#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ - /* higher than 1.21 */ -#define REQUEST_I2C_READ 0x2 -#define REQUEST_I2C_WRITE 0x3 -#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ -#define REQUEST_JUMPRAM 0x8 -#define REQUEST_SET_CLOCK 0xB -#define REQUEST_SET_GPIO 0xC -#define REQUEST_ENABLE_VIDEO 0xF - // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) - // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) - // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) -#define REQUEST_SET_I2C_PARAM 0x10 -#define REQUEST_SET_RC 0x11 -#define REQUEST_NEW_I2C_READ 0x12 -#define REQUEST_NEW_I2C_WRITE 0x13 -#define REQUEST_GET_VERSION 0x15 - -struct dib0700_state { - u8 channel_state; - u16 mt2060_if1[2]; - u8 rc_toggle; - u8 rc_counter; - u8 is_dib7000pc; - u8 fw_use_new_i2c_api; - u8 disable_streaming_master_mode; - u32 fw_version; - u32 nb_packet_buffer_size; - int (*read_status)(struct dvb_frontend *, fe_status_t *); - int (*sleep)(struct dvb_frontend* fe); - u8 buf[255]; -}; - -extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, - u32 *romversion, u32 *ramversion, u32 *fwtype); -extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); -extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); -extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); -extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); -extern int dib0700_rc_setup(struct dvb_usb_device *d); -extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); -extern struct i2c_algorithm dib0700_i2c_algo; -extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold); -extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type); -extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); - -extern int dib0700_device_count; -extern int dvb_usb_dib0700_ir_proto; -extern struct dvb_usb_device_properties dib0700_devices[]; -extern struct usb_device_id dib0700_usb_id_table[]; - -#endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c deleted file mode 100644 index ef87229de6a..00000000000 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ /dev/null @@ -1,845 +0,0 @@ -/* Linux driver for devices based on the DiBcom DiB0700 USB bridge - * - * 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. - * - * Copyright (C) 2005-6 DiBcom, SA - */ -#include "dib0700.h" - -/* debug */ -int dvb_usb_dib0700_debug; -module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); - -static int nb_packet_buffer_size = 21; -module_param(nb_packet_buffer_size, int, 0644); -MODULE_PARM_DESC(nb_packet_buffer_size, - "Set the dib0700 driver data buffer size. This parameter " - "corresponds to the number of TS packets. The actual size of " - "the data buffer corresponds to this parameter " - "multiplied by 188 (default: 21)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - - -int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, - u32 *romversion, u32 *ramversion, u32 *fwtype) -{ - struct dib0700_state *st = d->priv; - int ret; - - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - st->buf, 16, USB_CTRL_GET_TIMEOUT); - if (hwversion != NULL) - *hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) | - (st->buf[2] << 8) | st->buf[3]; - if (romversion != NULL) - *romversion = (st->buf[4] << 24) | (st->buf[5] << 16) | - (st->buf[6] << 8) | st->buf[7]; - if (ramversion != NULL) - *ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) | - (st->buf[10] << 8) | st->buf[11]; - if (fwtype != NULL) - *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) | - (st->buf[14] << 8) | st->buf[15]; - mutex_unlock(&d->usb_mutex); - return ret; -} - -/* expecting rx buffer: request data[0] data[1] ... data[2] */ -static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) -{ - int status; - - deb_data(">>> "); - debug_dump(tx, txlen, deb_data); - - status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), - tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, - USB_CTRL_GET_TIMEOUT); - - if (status != txlen) - deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen); - - return status < 0 ? status : 0; -} - -/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ -int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) -{ - u16 index, value; - int status; - - if (txlen < 2) { - err("tx buffer length is smaller than 2. Makes no sense."); - return -EINVAL; - } - if (txlen > 4) { - err("tx buffer length is larger than 4. Not supported."); - return -EINVAL; - } - - deb_data(">>> "); - debug_dump(tx,txlen,deb_data); - - value = ((txlen - 2) << 8) | tx[1]; - index = 0; - if (txlen > 2) - index |= (tx[2] << 8); - if (txlen > 3) - index |= tx[3]; - - status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], - USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, - USB_CTRL_GET_TIMEOUT); - - if (status < 0) - deb_info("ep 0 read error (status = %d)\n",status); - - deb_data("<<< "); - debug_dump(rx, rxlen, deb_data); - - return status; /* length in case of success */ -} - -int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) -{ - struct dib0700_state *st = d->priv; - int ret; - - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - st->buf[0] = REQUEST_SET_GPIO; - st->buf[1] = gpio; - st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6); - - ret = dib0700_ctrl_wr(d, st->buf, 3); - - mutex_unlock(&d->usb_mutex); - return ret; -} - -static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) -{ - struct dib0700_state *st = d->priv; - int ret; - - if (st->fw_version >= 0x10201) { - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - st->buf[0] = REQUEST_SET_USB_XFER_LEN; - st->buf[1] = (nb_ts_packets >> 8) & 0xff; - st->buf[2] = nb_ts_packets & 0xff; - - deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); - - ret = dib0700_ctrl_wr(d, st->buf, 3); - mutex_unlock(&d->usb_mutex); - } else { - deb_info("this firmware does not allow to change the USB xfer len\n"); - ret = -EIO; - } - - return ret; -} - -/* - * I2C master xfer function (supported in 1.20 firmware) - */ -static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - /* The new i2c firmware messages are more reliable and in particular - properly support i2c read calls not preceded by a write */ - - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct dib0700_state *st = d->priv; - uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ - uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ - uint8_t en_start = 0; - uint8_t en_stop = 0; - int result, i; - - /* Ensure nobody else hits the i2c bus while we're sending our - sequence of messages, (such as the remote control thread) */ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EINTR; - - for (i = 0; i < num; i++) { - if (i == 0) { - /* First message in the transaction */ - en_start = 1; - } else if (!(msg[i].flags & I2C_M_NOSTART)) { - /* Device supports repeated-start */ - en_start = 1; - } else { - /* Not the first packet and device doesn't support - repeated start */ - en_start = 0; - } - if (i == (num - 1)) { - /* Last message in the transaction */ - en_stop = 1; - } - - if (msg[i].flags & I2C_M_RD) { - /* Read request */ - u16 index, value; - uint8_t i2c_dest; - - i2c_dest = (msg[i].addr << 1); - value = ((en_start << 7) | (en_stop << 6) | - (msg[i].len & 0x3F)) << 8 | i2c_dest; - /* I2C ctrl + FE bus; */ - index = ((gen_mode << 6) & 0xC0) | - ((bus_mode << 4) & 0x30); - - result = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev, 0), - REQUEST_NEW_I2C_READ, - USB_TYPE_VENDOR | USB_DIR_IN, - value, index, msg[i].buf, - msg[i].len, - USB_CTRL_GET_TIMEOUT); - if (result < 0) { - deb_info("i2c read error (status = %d)\n", result); - break; - } - - deb_data("<<< "); - debug_dump(msg[i].buf, msg[i].len, deb_data); - - } else { - /* Write request */ - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - mutex_unlock(&d->i2c_mutex); - return -EINTR; - } - st->buf[0] = REQUEST_NEW_I2C_WRITE; - st->buf[1] = msg[i].addr << 1; - st->buf[2] = (en_start << 7) | (en_stop << 6) | - (msg[i].len & 0x3F); - /* I2C ctrl + FE bus; */ - st->buf[3] = ((gen_mode << 6) & 0xC0) | - ((bus_mode << 4) & 0x30); - /* The Actual i2c payload */ - memcpy(&st->buf[4], msg[i].buf, msg[i].len); - - deb_data(">>> "); - debug_dump(st->buf, msg[i].len + 4, deb_data); - - result = usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev, 0), - REQUEST_NEW_I2C_WRITE, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, st->buf, msg[i].len + 4, - USB_CTRL_GET_TIMEOUT); - mutex_unlock(&d->usb_mutex); - if (result < 0) { - deb_info("i2c write error (status = %d)\n", result); - break; - } - } - } - mutex_unlock(&d->i2c_mutex); - return i; -} - -/* - * I2C master xfer function (pre-1.20 firmware) - */ -static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, - struct i2c_msg *msg, int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct dib0700_state *st = d->priv; - int i,len; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EINTR; - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - mutex_unlock(&d->i2c_mutex); - return -EINTR; - } - - for (i = 0; i < num; i++) { - /* fill in the address */ - st->buf[1] = msg[i].addr << 1; - /* fill the buffer */ - memcpy(&st->buf[2], msg[i].buf, msg[i].len); - - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - st->buf[0] = REQUEST_I2C_READ; - st->buf[1] |= 1; - - /* special thing in the current firmware: when length is zero the read-failed */ - len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2, - msg[i+1].buf, msg[i+1].len); - if (len <= 0) { - deb_info("I2C read failed on address 0x%02x\n", - msg[i].addr); - break; - } - - msg[i+1].len = len; - - i++; - } else { - st->buf[0] = REQUEST_I2C_WRITE; - if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0) - break; - } - } - mutex_unlock(&d->usb_mutex); - mutex_unlock(&d->i2c_mutex); - - return i; -} - -static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct dib0700_state *st = d->priv; - - if (st->fw_use_new_i2c_api == 1) { - /* User running at least fw 1.20 */ - return dib0700_i2c_xfer_new(adap, msg, num); - } else { - /* Use legacy calls */ - return dib0700_i2c_xfer_legacy(adap, msg, num); - } -} - -static u32 dib0700_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm dib0700_i2c_algo = { - .master_xfer = dib0700_i2c_xfer, - .functionality = dib0700_i2c_func, -}; - -int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - s16 ret; - u8 *b; - - b = kmalloc(16, GFP_KERNEL); - if (!b) - return -ENOMEM; - - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT); - - deb_info("FW GET_VERSION length: %d\n",ret); - - *cold = ret <= 0; - deb_info("cold: %d\n", *cold); - - kfree(b); - return 0; -} - -static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, - u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv, - u16 pll_loopdiv, u16 free_div, u16 dsuScaler) -{ - struct dib0700_state *st = d->priv; - int ret; - - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - st->buf[0] = REQUEST_SET_CLOCK; - st->buf[1] = (en_pll << 7) | (pll_src << 6) | - (pll_range << 5) | (clock_gpio3 << 4); - st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */ - st->buf[3] = pll_prediv & 0xff; /* LSB */ - st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */ - st->buf[5] = pll_loopdiv & 0xff; /* LSB */ - st->buf[6] = (free_div >> 8) & 0xff; /* MSB */ - st->buf[7] = free_div & 0xff; /* LSB */ - st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */ - st->buf[9] = dsuScaler & 0xff; /* LSB */ - - ret = dib0700_ctrl_wr(d, st->buf, 10); - mutex_unlock(&d->usb_mutex); - - return ret; -} - -int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) -{ - struct dib0700_state *st = d->priv; - u16 divider; - int ret; - - if (scl_kHz == 0) - return -EINVAL; - - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - st->buf[0] = REQUEST_SET_I2C_PARAM; - divider = (u16) (30000 / scl_kHz); - st->buf[1] = 0; - st->buf[2] = (u8) (divider >> 8); - st->buf[3] = (u8) (divider & 0xff); - divider = (u16) (72000 / scl_kHz); - st->buf[4] = (u8) (divider >> 8); - st->buf[5] = (u8) (divider & 0xff); - divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */ - st->buf[6] = (u8) (divider >> 8); - st->buf[7] = (u8) (divider & 0xff); - - deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", - (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) | - st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz); - - ret = dib0700_ctrl_wr(d, st->buf, 8); - mutex_unlock(&d->usb_mutex); - - return ret; -} - - -int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3) -{ - switch (clk_MHz) { - case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break; - default: return -EINVAL; - } - return 0; -} - -static int dib0700_jumpram(struct usb_device *udev, u32 address) -{ - int ret = 0, actlen; - u8 *buf; - - buf = kmalloc(8, GFP_KERNEL); - if (!buf) - return -ENOMEM; - buf[0] = REQUEST_JUMPRAM; - buf[1] = 0; - buf[2] = 0; - buf[3] = 0; - buf[4] = (address >> 24) & 0xff; - buf[5] = (address >> 16) & 0xff; - buf[6] = (address >> 8) & 0xff; - buf[7] = address & 0xff; - - if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { - deb_fw("jumpram to 0x%x failed\n",address); - goto out; - } - if (actlen != 8) { - deb_fw("jumpram to 0x%x failed\n",address); - ret = -EIO; - goto out; - } -out: - kfree(buf); - return ret; -} - -int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) -{ - struct hexline hx; - int pos = 0, ret, act_len, i, adap_num; - u8 *buf; - u32 fw_version; - - buf = kmalloc(260, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { - deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n", - hx.addr, hx.len, hx.chk); - - buf[0] = hx.len; - buf[1] = (hx.addr >> 8) & 0xff; - buf[2] = hx.addr & 0xff; - buf[3] = hx.type; - memcpy(&buf[4],hx.data,hx.len); - buf[4+hx.len] = hx.chk; - - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x01), - buf, - hx.len + 5, - &act_len, - 1000); - - if (ret < 0) { - err("firmware download failed at %d with %d",pos,ret); - goto out; - } - } - - if (ret == 0) { - /* start the firmware */ - if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) { - info("firmware started successfully."); - msleep(500); - } - } else - ret = -EIO; - - /* the number of ts packet has to be at least 1 */ - if (nb_packet_buffer_size < 1) - nb_packet_buffer_size = 1; - - /* get the fimware version */ - usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - buf, 16, USB_CTRL_GET_TIMEOUT); - fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; - - /* set the buffer size - DVB-USB is allocating URB buffers - * only after the firwmare download was successful */ - for (i = 0; i < dib0700_device_count; i++) { - for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; - adap_num++) { - if (fw_version >= 0x10201) { - dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; - } else { - /* for fw version older than 1.20.1, - * the buffersize has to be n times 512 */ - dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; - if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512) - dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512; - } - } - } -out: - kfree(buf); - return ret; -} - -int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct dib0700_state *st = adap->dev->priv; - int ret; - - if ((onoff != 0) && (st->fw_version >= 0x10201)) { - /* for firmware later than 1.20.1, - * the USB xfer length can be set */ - ret = dib0700_set_usb_xfer_len(adap->dev, - st->nb_packet_buffer_size); - if (ret < 0) { - deb_info("can not set the USB xfer len\n"); - return ret; - } - } - - if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - st->buf[0] = REQUEST_ENABLE_VIDEO; - /* this bit gives a kind of command, - * rather than enabling something or not */ - st->buf[1] = (onoff << 4) | 0x00; - - if (st->disable_streaming_master_mode == 1) - st->buf[2] = 0x00; - else - st->buf[2] = 0x01 << 4; /* Master mode */ - - st->buf[3] = 0x00; - - deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); - - st->channel_state &= ~0x3; - if ((adap->fe_adap[0].stream.props.endpoint != 2) - && (adap->fe_adap[0].stream.props.endpoint != 3)) { - deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint); - if (onoff) - st->channel_state |= 1 << (adap->id); - else - st->channel_state |= 1 << ~(adap->id); - } else { - if (onoff) - st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2); - else - st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint); - } - - st->buf[2] |= st->channel_state; - - deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); - - ret = dib0700_ctrl_wr(adap->dev, st->buf, 4); - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - -int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) -{ - struct dvb_usb_device *d = rc->priv; - struct dib0700_state *st = d->priv; - int new_proto, ret; - - if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - err("could not acquire lock"); - return -EINTR; - } - - st->buf[0] = REQUEST_SET_RC; - st->buf[1] = 0; - st->buf[2] = 0; - - /* Set the IR mode */ - if (rc_type == RC_TYPE_RC5) - new_proto = 1; - else if (rc_type == RC_TYPE_NEC) - new_proto = 0; - else if (rc_type == RC_TYPE_RC6) { - if (st->fw_version < 0x10200) { - ret = -EINVAL; - goto out; - } - - new_proto = 2; - } else { - ret = -EINVAL; - goto out; - } - - st->buf[1] = new_proto; - - ret = dib0700_ctrl_wr(d, st->buf, 3); - if (ret < 0) { - err("ir protocol setup failed"); - goto out; - } - - d->props.rc.core.protocol = rc_type; - -out: - mutex_unlock(&d->usb_mutex); - return ret; -} - -/* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY_V1_20 10 - -/* This is the structure of the RC response packet starting in firmware 1.20 */ -struct dib0700_rc_response { - u8 report_id; - u8 data_state; - union { - u16 system16; - struct { - u8 not_system; - u8 system; - }; - }; - u8 data; - u8 not_data; -}; -#define RC_MSG_SIZE_V1_20 6 - -static void dib0700_rc_urb_completion(struct urb *purb) -{ - struct dvb_usb_device *d = purb->context; - struct dib0700_rc_response *poll_reply; - u32 uninitialized_var(keycode); - u8 toggle; - - deb_info("%s()\n", __func__); - if (d->rc_dev == NULL) { - /* This will occur if disable_rc_polling=1 */ - kfree(purb->transfer_buffer); - usb_free_urb(purb); - return; - } - - poll_reply = purb->transfer_buffer; - - if (purb->status < 0) { - deb_info("discontinuing polling\n"); - kfree(purb->transfer_buffer); - usb_free_urb(purb); - return; - } - - if (purb->actual_length != RC_MSG_SIZE_V1_20) { - deb_info("malformed rc msg size=%d\n", purb->actual_length); - goto resubmit; - } - - deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n", - poll_reply->report_id, poll_reply->data_state, - poll_reply->system, poll_reply->not_system, - poll_reply->data, poll_reply->not_data, - purb->actual_length); - - switch (d->props.rc.core.protocol) { - case RC_TYPE_NEC: - toggle = 0; - - /* NEC protocol sends repeat code as 0 0 0 FF */ - if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00) - && (poll_reply->not_data == 0xff)) { - poll_reply->data_state = 2; - break; - } - - if ((poll_reply->system ^ poll_reply->not_system) != 0xff) { - deb_data("NEC extended protocol\n"); - /* NEC extended code - 24 bits */ - keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data; - } else { - deb_data("NEC normal protocol\n"); - /* normal NEC code - 16 bits */ - keycode = poll_reply->system << 8 | poll_reply->data; - } - - break; - default: - deb_data("RC5 protocol\n"); - /* RC5 Protocol */ - toggle = poll_reply->report_id; - keycode = poll_reply->system << 8 | poll_reply->data; - - break; - } - - if ((poll_reply->data + poll_reply->not_data) != 0xff) { - /* Key failed integrity check */ - err("key failed integrity check: %04x %02x %02x", - poll_reply->system, - poll_reply->data, poll_reply->not_data); - goto resubmit; - } - - rc_keydown(d->rc_dev, keycode, toggle); - -resubmit: - /* Clean the buffer before we requeue */ - memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20); - - /* Requeue URB */ - usb_submit_urb(purb, GFP_ATOMIC); -} - -int dib0700_rc_setup(struct dvb_usb_device *d) -{ - struct dib0700_state *st = d->priv; - struct urb *purb; - int ret; - - /* Poll-based. Don't initialize bulk mode */ - if (st->fw_version < 0x10200) - return 0; - - /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ - purb = usb_alloc_urb(0, GFP_KERNEL); - if (purb == NULL) { - err("rc usb alloc urb failed"); - return -ENOMEM; - } - - purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL); - if (purb->transfer_buffer == NULL) { - err("rc kzalloc failed"); - usb_free_urb(purb); - return -ENOMEM; - } - - purb->status = -EINPROGRESS; - usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), - purb->transfer_buffer, RC_MSG_SIZE_V1_20, - dib0700_rc_urb_completion, d); - - ret = usb_submit_urb(purb, GFP_ATOMIC); - if (ret) { - err("rc submit urb failed"); - kfree(purb->transfer_buffer); - usb_free_urb(purb); - } - - return ret; -} - -static int dib0700_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int i; - struct dvb_usb_device *dev; - - for (i = 0; i < dib0700_device_count; i++) - if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, - &dev, adapter_nr) == 0) { - struct dib0700_state *st = dev->priv; - u32 hwversion, romversion, fw_version, fwtype; - - dib0700_get_version(dev, &hwversion, &romversion, - &fw_version, &fwtype); - - deb_info("Firmware version: %x, %d, 0x%x, %d\n", - hwversion, romversion, fw_version, fwtype); - - st->fw_version = fw_version; - st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; - - /* Disable polling mode on newer firmwares */ - if (st->fw_version >= 0x10200) - dev->props.rc.core.bulk_mode = true; - else - dev->props.rc.core.bulk_mode = false; - - dib0700_rc_setup(dev); - - return 0; - } - - return -ENODEV; -} - -static struct usb_driver dib0700_driver = { - .name = "dvb_usb_dib0700", - .probe = dib0700_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dib0700_usb_id_table, -}; - -module_usb_driver(dib0700_driver); - -MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw"); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c deleted file mode 100644 index 510001da6e8..00000000000 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ /dev/null @@ -1,4813 +0,0 @@ -/* Linux driver for devices based on the DiBcom DiB0700 USB bridge - * - * 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. - * - * Copyright (C) 2005-9 DiBcom, SA et al - */ -#include "dib0700.h" - -#include "dib3000mc.h" -#include "dib7000m.h" -#include "dib7000p.h" -#include "dib8000.h" -#include "dib9000.h" -#include "mt2060.h" -#include "mt2266.h" -#include "tuner-xc2028.h" -#include "xc5000.h" -#include "xc4000.h" -#include "s5h1411.h" -#include "dib0070.h" -#include "dib0090.h" -#include "lgdt3305.h" -#include "mxl5007t.h" - -static int force_lna_activation; -module_param(force_lna_activation, int, 0644); -MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " - "if applicable for the device (default: 0=automatic/off)."); - -struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *); - const struct firmware *frontend_firmware; -}; - -/* Hauppauge Nova-T 500 (aka Bristol) - * has a LNA on GPIO0 which is enabled by setting 1 */ -static struct mt2060_config bristol_mt2060_config[2] = { - { - .i2c_address = 0x60, - .clock_out = 3, - }, { - .i2c_address = 0x61, - } -}; - - -static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 42598, - .agc1_min = 17694, - .agc2_max = 45875, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 59, - - .agc1_slope1 = 0, - .agc1_slope2 = 69, - - .agc2_pt1 = 0, - .agc2_pt2 = 59, - - .agc2_slope1 = 111, - .agc2_slope2 = 28, -}; - -static struct dib3000mc_config bristol_dib3000mc_config[2] = { - { .agc = &bristol_dib3000p_mt2060_agc_config, - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - .output_mpeg2_in_188_bytes = 1, - }, - { .agc = &bristol_dib3000p_mt2060_agc_config, - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - .output_mpeg2_in_188_bytes = 1, - } -}; - -static int bristol_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); - - if (force_lna_activation) - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - else - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); - - if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); - return -ENODEV; - } - } - st->mt2060_if1[adap->id] = 1220; - return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, - (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; -} - -static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) -{ - struct i2c_msg msg[2] = { - { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, - }; - if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; - return 0; -} - -static int bristol_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); - s8 a; - int if1=1220; - if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && - adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { - if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; - } - return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, - &bristol_mt2060_config[adap->id], if1) == NULL ? - -ENODEV : 0; -} - -/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ - -/* MT226x */ -static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { - { - BAND_UHF, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 1130, - 21, - - 0, - 118, - - 0, - 3530, - 1, - 0, - - 65535, - 33770, - 65535, - 23592, - - 0, - 62, - 255, - 64, - 64, - 132, - 192, - 80, - 80, - - 17, - 27, - 23, - 51, - - 1, - }, { - BAND_VHF | BAND_LBAND, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 2372, - 21, - - 0, - 118, - - 0, - 3530, - 1, - 0, - - 65535, - 0, - 65535, - 23592, - - 0, - 128, - 128, - 128, - 0, - 128, - 253, - 81, - 0, - - 17, - 27, - 23, - 51, - - 1, - } -}; - -static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { - 60000, 30000, - 1, 8, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - 0, - 20452225, -}; - -static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { - { .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - - .agc_config_count = 2, - .agc = stk7700d_7000p_mt2266_agc_config, - .bw = &stk7700d_mt2266_pll_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - }, - { .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - - .agc_config_count = 2, - .agc = stk7700d_7000p_mt2266_agc_config, - .bw = &stk7700d_mt2266_pll_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - } -}; - -static struct mt2266_config stk7700d_mt2266_config[2] = { - { .i2c_address = 0x60 - }, - { .i2c_address = 0x60 - } -}; - -static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - stk7700d_dib7000p_mt2266_config) - != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - } - - adap->fe_adap[0].fe = - dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, - 0x80 + (adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, - stk7700d_dib7000p_mt2266_config) - != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - } - - adap->fe_adap[0].fe = - dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, - 0x80 + (adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c, - &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; -} - -/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */ -static struct dibx000_agc_config xc3028_agc_config = { - BAND_VHF | BAND_UHF, /* band_caps */ - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | - (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ - - 712, /* inv_gain */ - 21, /* time_stabiliz */ - - 0, /* alpha_level */ - 118, /* thlock */ - - 0, /* wbd_inv */ - 2867, /* wbd_ref */ - 0, /* wbd_sel */ - 2, /* wbd_alpha */ - - 0, /* agc1_max */ - 0, /* agc1_min */ - 39718, /* agc2_max */ - 9930, /* agc2_min */ - 0, /* agc1_pt1 */ - 0, /* agc1_pt2 */ - 0, /* agc1_pt3 */ - 0, /* agc1_slope1 */ - 0, /* agc1_slope2 */ - 0, /* agc2_pt1 */ - 128, /* agc2_pt2 */ - 29, /* agc2_slope1 */ - 29, /* agc2_slope2 */ - - 17, /* alpha_mant */ - 27, /* alpha_exp */ - 23, /* beta_mant */ - 51, /* beta_exp */ - - 1, /* perform_agc_softsplit */ -}; - -/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */ -static struct dibx000_bandwidth_config xc3028_bw_config = { - 60000, 30000, /* internal, sampling */ - 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ - 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, - modulo */ - (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ - (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ - 20452225, /* timf */ - 30000000, /* xtal_hz */ -}; - -static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { - .output_mpeg2_in_188_bytes = 1, - .tuner_is_baseband = 1, - - .agc_config_count = 1, - .agc = &xc3028_agc_config, - .bw = &xc3028_bw_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, -}; - -static int stk7700ph_xc3028_callback(void *ptr, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = ptr; - - switch (command) { - case XC2028_TUNER_RESET: - /* Send the tuner in then out of reset */ - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - break; - case XC2028_RESET_CLK: - break; - default: - err("%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; - } - return 0; -} - -static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_DIBCOM52, -}; - -static struct xc2028_config stk7700ph_xc3028_config = { - .i2c_addr = 0x61, - .ctrl = &stk7700ph_xc3028_ctrl, -}; - -static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct usb_device_descriptor *desc = &adap->dev->udev->descriptor; - - if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) && - desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - msleep(10); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &stk7700ph_dib7700_xc3028_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &stk7700ph_dib7700_xc3028_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *tun_i2c; - - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - stk7700ph_xc3028_config.i2c_adap = tun_i2c; - - /* FIXME: generalize & move to common area */ - adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback; - - return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config) - == NULL ? -ENODEV : 0; -} - -#define DEFAULT_RC_INTERVAL 50 - -static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; - -/* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY 6 - -/* - * This function is used only when firmware is < 1.20 version. Newer - * firmwares use bulk mode, with functions implemented at dib0700_core, - * at dib0700_rc_urb_completion() - */ -static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) -{ - u8 key[4]; - u32 keycode; - u8 toggle; - int i; - struct dib0700_state *st = d->priv; - - if (st->fw_version >= 0x10200) { - /* For 1.20 firmware , We need to keep the RC polling - callback so we can reuse the input device setup in - dvb-usb-remote.c. However, the actual work is being done - in the bulk URB completion handler. */ - return 0; - } - - i = dib0700_ctrl_rd(d, rc_request, 2, key, 4); - if (i <= 0) { - err("RC Query Failed"); - return -1; - } - - /* losing half of KEY_0 events from Philipps rc5 remotes.. */ - if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0) - return 0; - - /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ - - dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ - - d->last_event = 0; - switch (d->props.rc.core.protocol) { - case RC_TYPE_NEC: - /* NEC protocol sends repeat code as 0 0 0 FF */ - if ((key[3-2] == 0x00) && (key[3-3] == 0x00) && - (key[3] == 0xff)) - keycode = d->last_event; - else { - keycode = key[3-2] << 8 | key[3-3]; - d->last_event = keycode; - } - - rc_keydown(d->rc_dev, keycode, 0); - break; - default: - /* RC-5 protocol changes toggle bit on new keypress */ - keycode = key[3-2] << 8 | key[3-3]; - toggle = key[3-1]; - rc_keydown(d->rc_dev, keycode, toggle); - - break; - } - return 0; -} - -/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ -static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { - BAND_UHF | BAND_VHF, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 712, - 41, - - 0, - 118, - - 0, - 4095, - 0, - 0, - - 42598, - 17694, - 45875, - 2621, - 0, - 76, - 139, - 52, - 59, - 107, - 172, - 57, - 70, - - 21, - 25, - 28, - 48, - - 1, - { 0, - 107, - 51800, - 24700 - }, -}; - -static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { - BAND_UHF | BAND_VHF, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 712, - 41, - - 0, - 118, - - 0, - 4095, - 0, - 0, - - 42598, - 16384, - 42598, - 0, - - 0, - 137, - 255, - - 0, - 255, - - 0, - 0, - - 0, - 41, - - 15, - 25, - - 28, - 48, - - 0, -}; - -static struct dibx000_bandwidth_config stk7700p_pll_config = { - 60000, 30000, - 1, 8, 3, 1, 0, - 0, 0, 1, 1, 0, - (3 << 14) | (1 << 12) | (524 << 0), - 60258167, - 20452225, - 30000000, -}; - -static struct dib7000m_config stk7700p_dib7000m_config = { - .dvbt_mode = 1, - .output_mpeg2_in_188_bytes = 1, - .quartz_direct = 1, - - .agc_config_count = 1, - .agc = &stk7700p_7000m_mt2060_agc_config, - .bw = &stk7700p_pll_config, - - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, -}; - -static struct dib7000p_config stk7700p_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &stk7700p_7000p_mt2060_agc_config, - .bw = &stk7700p_pll_config, - - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, -}; - -static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - /* unless there is no real power management in DVB - we leave the device on GPIO6 */ - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50); - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); - dib0700_ctrl_clock(adap->dev, 72, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100); - - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - st->mt2060_if1[0] = 1220; - - if (dib7000pc_detection(&adap->dev->i2c_adap)) { - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); - st->is_dib7000pc = 1; - } else - adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static struct mt2060_config stk7700p_mt2060_config = { - 0x60 -}; - -static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct dib0700_state *st = adap->dev->priv; - struct i2c_adapter *tun_i2c; - s8 a; - int if1=1220; - if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && - adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) { - if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; - } - if (st->is_dib7000pc) - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - else - tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - - return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config, - if1) == NULL ? -ENODEV : 0; -} - -/* DIB7070 generic */ -static struct dibx000_agc_config dib7070_agc_config = { - BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 600, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 65535, - 0, - - 65535, - 0, - - 0, - 40, - 183, - 206, - 255, - 72, - 152, - 88, - 90, - - 17, - 27, - 23, - 51, - - 0, -}; - -static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - deb_info("reset: %d", onoff); - return dib7000p_set_gpio(fe, 8, 0, !onoff); -} - -static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - deb_info("sleep: %d", onoff); - return dib7000p_set_gpio(fe, 9, 0, onoff); -} - -static struct dib0070_config dib7070p_dib0070_config[2] = { - { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 4, - .charge_pump = 2, - }, { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, - .charge_pump = 2, - } -}; - -static struct dib0070_config dib7770p_dib0070_config = { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 0, - .flip_chip = 1, - .charge_pump = 2, -}; - -static int dib7070_set_param_override(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - switch (band) { - case BAND_VHF: offset = 950; break; - case BAND_UHF: - default: offset = 550; break; - } - deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe); -} - -static int dib7770_set_param_override(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - switch (band) { - case BAND_VHF: - dib7000p_set_gpio(fe, 0, 0, 1); - offset = 850; - break; - case BAND_UHF: - default: - dib7000p_set_gpio(fe, 0, 0, 0); - offset = 250; - break; - } - deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe); -} - -static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7770p_dib0070_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override; - return 0; -} - -static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - - if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) - return -ENODEV; - } else { - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) - return -ENODEV; - } - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override; - return 0; -} - -static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, - u16 pid, int onoff) -{ - struct dib0700_state *st = adapter->dev->priv; - if (st->is_dib7000pc) - return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); - return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); -} - -static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) -{ - struct dib0700_state *st = adapter->dev->priv; - if (st->is_dib7000pc) - return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); - return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); -} - -static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) -{ - return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); -} - -static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) -{ - return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); -} - -static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - 60000, 15000, - 1, 20, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20452225, - 12000000, -}; - -static struct dib7000p_config dib7070p_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, -}; - -/* STK7070P */ -static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct usb_device_descriptor *p = &adap->dev->udev->descriptor; - if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && - p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &dib7070p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &dib7070p_dib7000p_config); - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -/* STK7770P */ -static struct dib7000p_config dib7770p_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .enable_current_mirror = 1, - .disable_sample_and_hold = 0, -}; - -static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct usb_device_descriptor *p = &adap->dev->udev->descriptor; - if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && - p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &dib7770p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &dib7770p_dib7000p_config); - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -/* DIB807x generic */ -static struct dibx000_agc_config dib807x_agc_config[2] = { - { - BAND_VHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, - * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, - * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, - * P_agc_write=0 */ - (0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) | - (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | - (0 << 0), /* setup*/ - - 600, /* inv_gain*/ - 10, /* time_stabiliz*/ - - 0, /* alpha_level*/ - 118, /* thlock*/ - - 0, /* wbd_inv*/ - 3530, /* wbd_ref*/ - 1, /* wbd_sel*/ - 5, /* wbd_alpha*/ - - 65535, /* agc1_max*/ - 0, /* agc1_min*/ - - 65535, /* agc2_max*/ - 0, /* agc2_min*/ - - 0, /* agc1_pt1*/ - 40, /* agc1_pt2*/ - 183, /* agc1_pt3*/ - 206, /* agc1_slope1*/ - 255, /* agc1_slope2*/ - 72, /* agc2_pt1*/ - 152, /* agc2_pt2*/ - 88, /* agc2_slope1*/ - 90, /* agc2_slope2*/ - - 17, /* alpha_mant*/ - 27, /* alpha_exp*/ - 23, /* beta_mant*/ - 51, /* beta_exp*/ - - 0, /* perform_agc_softsplit*/ - }, { - BAND_UHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, - * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, - * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, - * P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) | - (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | - (0 << 0), /* setup */ - - 600, /* inv_gain*/ - 10, /* time_stabiliz*/ - - 0, /* alpha_level*/ - 118, /* thlock*/ - - 0, /* wbd_inv*/ - 3530, /* wbd_ref*/ - 1, /* wbd_sel*/ - 5, /* wbd_alpha*/ - - 65535, /* agc1_max*/ - 0, /* agc1_min*/ - - 65535, /* agc2_max*/ - 0, /* agc2_min*/ - - 0, /* agc1_pt1*/ - 40, /* agc1_pt2*/ - 183, /* agc1_pt3*/ - 206, /* agc1_slope1*/ - 255, /* agc1_slope2*/ - 72, /* agc2_pt1*/ - 152, /* agc2_pt2*/ - 88, /* agc2_slope1*/ - 90, /* agc2_slope2*/ - - 17, /* alpha_mant*/ - 27, /* alpha_exp*/ - 23, /* beta_mant*/ - 51, /* beta_exp*/ - - 0, /* perform_agc_softsplit*/ - } -}; - -static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = { - 60000, 15000, /* internal, sampling*/ - 1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/ - 0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core, - ADClkSrc, modulo */ - (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ - (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ - 18179755, /* timf*/ - 12000000, /* xtal_hz*/ -}; - -static struct dib8000_config dib807x_dib8000_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib807x_agc_config, - .pll = &dib807x_bw_config_12_mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 1, - .agc_control = &dib0070_ctrl_agc_filter, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - }, { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib807x_agc_config, - .pll = &dib807x_bw_config_12_mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .agc_control = &dib0070_ctrl_agc_filter, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - } -}; - -static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - return dib8000_set_gpio(fe, 5, 0, !onoff); -} - -static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - return dib8000_set_gpio(fe, 0, 0, onoff); -} - -static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { - { 240, 7}, - { 0xffff, 6}, -}; - -static struct dib0070_config dib807x_dib0070_config[2] = { - { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 4, - .vga_filter = 1, - .force_crystal_mode = 1, - .enable_third_order_filter = 1, - .charge_pump = 0, - .wbd_gain = dib8070_wbd_gain_cfg, - .osc_buffer_state = 0, - .freq_offset_khz_uhf = -100, - .freq_offset_khz_vhf = -100, - }, { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 2, - .vga_filter = 1, - .force_crystal_mode = 1, - .enable_third_order_filter = 1, - .charge_pump = 0, - .wbd_gain = dib8070_wbd_gain_cfg, - .osc_buffer_state = 0, - .freq_offset_khz_uhf = -25, - .freq_offset_khz_vhf = -25, - } -}; - -static int dib807x_set_param_override(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset = dib0070_wbd_offset(fe); - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - switch (band) { - case BAND_VHF: - offset += 750; - break; - case BAND_UHF: /* fall-thru wanted */ - default: - offset += 250; break; - } - deb_info("WBD for DiB8000: %d\n", offset); - dib8000_set_wbd_ref(fe, offset); - - return state->set_param_save(fe); -} - -static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib807x_dib0070_config[0]) == NULL) - return -ENODEV; - } else { - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib807x_dib0070_config[1]) == NULL) - return -ENODEV; - } - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override; - return 0; -} - -static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, - u16 pid, int onoff) -{ - return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); -} - -static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, - int onoff) -{ - return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); -} - -/* STK807x */ -static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - 0x80, 0); - - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, - &dib807x_dib8000_config[0]); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -/* STK807xPVR */ -static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(500); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0); - - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, - &dib807x_dib8000_config[0]); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) -{ - /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0); - - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, - &dib807x_dib8000_config[1]); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -/* STK8096GP */ -static struct dibx000_agc_config dib8090_agc_config[2] = { - { - BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 787, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 65535, - 0, - - 65535, - 0, - - 0, - 32, - 114, - 143, - 144, - 114, - 227, - 116, - 117, - - 28, - 26, - 31, - 51, - - 0, - }, - { - BAND_CBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 787, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 0, - 0, - - 65535, - 0, - - 0, - 32, - 114, - 143, - 144, - 114, - 227, - 116, - 117, - - 28, - 26, - 31, - 51, - - 0, - } -}; - -static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { - 54000, 13500, - 1, 18, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (599 << 0), - (0 << 25) | 0, - 20199727, - 12000000, -}; - -static int dib8090_get_adc_power(struct dvb_frontend *fe) -{ - return dib8000_get_adc_power(fe, 1); -} - -static struct dib8000_config dib809x_dib8000_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, - .pll = &dib8090_pll_config_12mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 0x31, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - .diversity_delay = 48, - .refclksel = 3, - }, { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, - .pll = &dib8090_pll_config_12mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 0x31, - .output_mode = OUTMODE_DIVERSITY, - .drives = 0x2d08, - .diversity_delay = 1, - .refclksel = 3, - } -}; - -static struct dib0090_wbd_slope dib8090_wbd_table[] = { - /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */ - { 120, 0, 500, 0, 500, 4 }, /* CBAND */ - { 170, 0, 450, 0, 450, 4 }, /* CBAND */ - { 380, 48, 373, 28, 259, 6 }, /* VHF */ - { 860, 34, 700, 36, 616, 6 }, /* high UHF */ - { 0xFFFF, 34, 700, 36, 616, 6 }, /* default */ -}; - -static struct dib0090_config dib809x_dib0090_config = { - .io.pll_bypass = 1, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 20, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 12000, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clkouttobamse = 1, - .analog_output = 1, - .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, - .use_pwm_agc = 1, - .clkoutdrive = 1, - .get_adc_power = dib8090_get_adc_power, - .freq_offset_khz_uhf = -63, - .freq_offset_khz_vhf = -143, - .wbd = dib8090_wbd_table, - .fref_clock_ratio = 6, -}; - -static int dib8096_set_param_override(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - u16 target; - int ret = 0; - enum frontend_tune_state tune_state = CT_SHUTDOWN; - u16 ltgain, rf_gain_limit; - - ret = state->set_param_save(fe); - if (ret < 0) - return ret; - - target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; - dib8000_set_wbd_ref(fe, target); - - - if (band == BAND_CBAND) { - deb_info("tuning in CBAND - soft-AGC startup\n"); - dib0090_set_tune_state(fe, CT_AGC_START); - do { - ret = dib0090_gain_control(fe); - msleep(ret); - tune_state = dib0090_get_tune_state(fe); - if (tune_state == CT_AGC_STEP_0) - dib8000_set_gpio(fe, 6, 0, 1); - else if (tune_state == CT_AGC_STEP_1) { - dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); - if (rf_gain_limit == 0) - dib8000_set_gpio(fe, 6, 0, 0); - } - } while (tune_state < CT_AGC_STOP); - dib0090_pwm_gain_reset(fe); - dib8000_pwm_agc_reset(fe); - dib8000_set_tune_state(fe, CT_DEMOD_START); - } else { - deb_info("not tuning in CBAND - standard AGC startup\n"); - dib0090_pwm_gain_reset(fe); - } - - return 0; -} - -static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override; - return 0; -} - -static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); - - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c; - struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1); - - if (fe_slave) { - tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; - fe_slave->dvb = adap->fe_adap[0].fe->dvb; - fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; - } - tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override; - - return 0; -} - -static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe_slave; - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(1000); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0); - - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - if (adap->fe_adap[0].fe == NULL) - return -ENODEV; - - fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); - dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); - - return fe_slave == NULL ? -ENODEV : 0; -} - -/* TFE8096P */ -static struct dibx000_agc_config dib8096p_agc_config[2] = { - { - .band_caps = BAND_UHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, - P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, - P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, - P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) - | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) - | (0 << 4) | (5 << 1) | (0 << 0), - - .inv_gain = 684, - .time_stabiliz = 10, - - .alpha_level = 0, - .thlock = 118, - - .wbd_inv = 0, - .wbd_ref = 1200, - .wbd_sel = 3, - .wbd_alpha = 5, - - .agc1_max = 65535, - .agc1_min = 0, - - .agc2_max = 32767, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 0, - .agc1_pt3 = 105, - .agc1_slope1 = 0, - .agc1_slope2 = 156, - .agc2_pt1 = 105, - .agc2_pt2 = 255, - .agc2_slope1 = 54, - .agc2_slope2 = 0, - - .alpha_mant = 28, - .alpha_exp = 26, - .beta_mant = 31, - .beta_exp = 51, - - .perform_agc_softsplit = 0, - } , { - .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, - P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, - P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, - P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) - | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) - | (0 << 4) | (5 << 1) | (0 << 0), - - .inv_gain = 732, - .time_stabiliz = 10, - - .alpha_level = 0, - .thlock = 118, - - .wbd_inv = 0, - .wbd_ref = 1200, - .wbd_sel = 3, - .wbd_alpha = 5, - - .agc1_max = 65535, - .agc1_min = 0, - - .agc2_max = 32767, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 0, - .agc1_pt3 = 98, - .agc1_slope1 = 0, - .agc1_slope2 = 167, - .agc2_pt1 = 98, - .agc2_pt2 = 255, - .agc2_slope1 = 52, - .agc2_slope2 = 0, - - .alpha_mant = 28, - .alpha_exp = 26, - .beta_mant = 31, - .beta_exp = 51, - - .perform_agc_softsplit = 0, - } -}; - -static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = { - 108000, 13500, - 1, 9, 1, 0, 0, - 0, 0, 0, 0, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20199729, - 12000000, -}; - -static struct dib8000_config tfe8096p_dib8000_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib8096p_agc_config, - .pll = &dib8096p_clock_config_12_mhz, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .agc_control = NULL, - .diversity_delay = 48, - .output_mode = OUTMODE_MPEG2_FIFO, - .enMpegOutput = 1, -}; - -static struct dib0090_wbd_slope dib8096p_wbd_table[] = { - { 380, 81, 850, 64, 540, 4}, - { 860, 51, 866, 21, 375, 4}, - {1700, 0, 250, 0, 100, 6}, - {2600, 0, 250, 0, 100, 6}, - { 0xFFFF, 0, 0, 0, 0, 0}, -}; - -static const struct dib0090_config tfe8096p_dib0090_config = { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib8096p_tuner_sleep, - .sleep = dib8096p_tuner_sleep, - - .freq_offset_khz_uhf = -143, - .freq_offset_khz_vhf = -143, - - .get_adc_power = dib8090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 1, - - .wbd = dib8096p_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - .force_cband_input = 0, -}; - -struct dibx090p_adc { - u32 freq; /* RF freq MHz */ - u32 timf; /* New Timf */ - u32 pll_loopdiv; /* New prediv */ - u32 pll_prediv; /* New loopdiv */ -}; - -struct dibx090p_adc dib8090p_adc_tab[] = { - { 50000, 17043521, 16, 3}, /* 64 MHz */ - {878000, 20199729, 9, 1}, /* 60 MHz */ - {0xffffffff, 0, 0, 0}, /* 60 MHz */ -}; - -static int dib8096p_agc_startup(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - struct dibx000_bandwidth_config pll; - u16 target; - int better_sampling_freq = 0, ret; - struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0]; - - ret = state->set_param_save(fe); - if (ret < 0) - return ret; - memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); - - dib0090_pwm_gain_reset(fe); - /* dib0090_get_wbd_target is returning any possible - temperature compensated wbd-target */ - target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; - dib8000_set_wbd_ref(fe, target); - - - while (p->frequency / 1000 > adc_table->freq) { - better_sampling_freq = 1; - adc_table++; - } - - if ((adc_table->freq != 0xffffffff) && better_sampling_freq) { - pll.pll_ratio = adc_table->pll_loopdiv; - pll.pll_prediv = adc_table->pll_prediv; - dib8000_update_pll(fe, &pll); - dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf); - } - return 0; -} - -static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1); - - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, - &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, - &tfe8096p_dib0090_config) == NULL) - return -ENODEV; - - dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup; - return 0; -} - -/* STK9090M */ -static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) -{ - return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); -} - -static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) -{ - return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); -} - -static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - return dib9000_set_gpio(fe, 5, 0, !onoff); -} - -static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - return dib9000_set_gpio(fe, 0, 0, onoff); -} - -static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) -{ - u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 }; - u8 rb[2]; - struct i2c_msg msg[2] = { - {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2}, - {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, - }; - u8 index_data; - - dibx000_i2c_set_speed(i2c, 250); - - if (i2c_transfer(i2c, msg, 2) != 2) - return -EIO; - - switch (rb[0] << 8 | rb[1]) { - case 0: - deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n"); - return -EIO; - case 1: - deb_info("Found DiB0170 rev2"); - break; - case 2: - deb_info("Found DiB0190 rev2"); - break; - default: - deb_info("DiB01x0 not found"); - return -EIO; - } - - for (index_data = 0; index_data < len; index_data += 2) { - wb[2] = (data[index_data + 1] >> 8) & 0xff; - wb[3] = (data[index_data + 1]) & 0xff; - - if (data[index_data] == 0) { - wb[0] = (data[index_data] >> 8) & 0xff; - wb[1] = (data[index_data]) & 0xff; - msg[0].len = 2; - if (i2c_transfer(i2c, msg, 2) != 2) - return -EIO; - wb[2] |= rb[0]; - wb[3] |= rb[1] & ~(3 << 4); - } - - wb[0] = (data[index_data] >> 8)&0xff; - wb[1] = (data[index_data])&0xff; - msg[0].len = 4; - if (i2c_transfer(i2c, &msg[0], 1) != 1) - return -EIO; - } - return 0; -} - -static struct dib9000_config stk9090m_config = { - .output_mpeg2_in_188_bytes = 1, - .output_mode = OUTMODE_MPEG2_FIFO, - .vcxo_timer = 279620, - .timing_frequency = 20452225, - .demod_clock_khz = 60000, - .xtal_clock_khz = 30000, - .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), - .subband = { - 2, - { - { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */ - { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */ - { 0 }, - }, - }, - .gpio_function = { - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, - }, -}; - -static struct dib9000_config nim9090md_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - .output_mode = OUTMODE_MPEG2_FIFO, - .vcxo_timer = 279620, - .timing_frequency = 20452225, - .demod_clock_khz = 60000, - .xtal_clock_khz = 30000, - .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), - }, { - .output_mpeg2_in_188_bytes = 1, - .output_mode = OUTMODE_DIVERSITY, - .vcxo_timer = 279620, - .timing_frequency = 20452225, - .demod_clock_khz = 60000, - .xtal_clock_khz = 30000, - .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), - .subband = { - 2, - { - { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */ - { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */ - { 0 }, - }, - }, - .gpio_function = { - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, - }, - } -}; - -static struct dib0090_config dib9090_dib0090_config = { - .io.pll_bypass = 0, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 8, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 30000, - .reset = dib90x0_tuner_reset, - .sleep = dib90x0_tuner_sleep, - .clkouttobamse = 0, - .analog_output = 0, - .use_pwm_agc = 0, - .clkoutdrive = 0, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, -}; - -static struct dib0090_config nim9090md_dib0090_config[2] = { - { - .io.pll_bypass = 0, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 8, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 30000, - .reset = dib90x0_tuner_reset, - .sleep = dib90x0_tuner_sleep, - .clkouttobamse = 1, - .analog_output = 0, - .use_pwm_agc = 0, - .clkoutdrive = 0, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - }, { - .io.pll_bypass = 0, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 8, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 30000, - .reset = dib90x0_tuner_reset, - .sleep = dib90x0_tuner_sleep, - .clkouttobamse = 0, - .analog_output = 0, - .use_pwm_agc = 0, - .clkoutdrive = 0, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - } -}; - - -static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct dib0700_state *st = adap->dev->priv; - u32 fw_version; - - /* Make use of the new i2c functions from FW 1.20 */ - dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); - if (fw_version >= 0x10200) - st->fw_use_new_i2c_api = 1; - dib0700_set_i2c_speed(adap->dev, 340); - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80); - - if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { - deb_info("%s: Upload failed. (file not found?)\n", __func__); - return -ENODEV; - } else { - deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); - } - stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; - stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; - - adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); - u16 data_dib190[10] = { - 1, 0x1374, - 2, 0x01a2, - 7, 0x0020, - 0, 0x00ef, - 8, 0x0486, - }; - - if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL) - return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); - if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) - return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 1500); - if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) - return -ENODEV; - release_firmware(state->frontend_firmware); - return 0; -} - -static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct dib0700_state *st = adap->dev->priv; - struct i2c_adapter *i2c; - struct dvb_frontend *fe_slave; - u32 fw_version; - - /* Make use of the new i2c functions from FW 1.20 */ - dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); - if (fw_version >= 0x10200) - st->fw_use_new_i2c_api = 1; - dib0700_set_i2c_speed(adap->dev, 340); - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { - deb_info("%s: Upload failed. (file not found?)\n", __func__); - return -EIO; - } else { - deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); - } - nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size; - nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data; - nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size; - nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; - - dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); - adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); - - if (adap->fe_adap[0].fe == NULL) - return -ENODEV; - - i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); - dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); - - fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); - dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); - - return fe_slave == NULL ? -ENODEV : 0; -} - -static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c; - struct dvb_frontend *fe_slave; - u16 data_dib190[10] = { - 1, 0x5374, - 2, 0x01ae, - 7, 0x0020, - 0, 0x00ef, - 8, 0x0406, - }; - i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); - if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL) - return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); - if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) - return -ENODEV; - - dib0700_set_i2c_speed(adap->dev, 1500); - if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) - return -ENODEV; - - fe_slave = dib9000_get_slave_frontend(adap->fe_adap[0].fe, 1); - if (fe_slave != NULL) { - i2c = dib9000_get_component_bus_interface(adap->fe_adap[0].fe); - dib9000_set_i2c_adapter(fe_slave, i2c); - - i2c = dib9000_get_tuner_interface(fe_slave); - if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) - return -ENODEV; - fe_slave->dvb = adap->fe_adap[0].fe->dvb; - dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500); - if (dib9000_firmware_post_pll_init(fe_slave) < 0) - return -ENODEV; - } - release_firmware(state->frontend_firmware); - - return 0; -} - -/* NIM7090 */ -struct dib7090p_best_adc { - u32 timf; - u32 pll_loopdiv; - u32 pll_prediv; -}; - -static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc) -{ - u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; - - u16 xtal = 12000; - u32 fcp_min = 1900; /* PLL Minimum Frequency comparator KHz */ - u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */ - u32 fdem_max = 76000; - u32 fdem_min = 69500; - u32 fcp = 0, fs = 0, fdem = 0; - u32 harmonic_id = 0; - - adc->pll_loopdiv = loopdiv; - adc->pll_prediv = prediv; - adc->timf = 0; - - deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min); - - /* Find Min and Max prediv */ - while ((xtal/max_prediv) >= fcp_min) - max_prediv++; - - max_prediv--; - min_prediv = max_prediv; - while ((xtal/min_prediv) <= fcp_max) { - min_prediv--; - if (min_prediv == 1) - break; - } - deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); - - min_prediv = 2; - - for (prediv = min_prediv ; prediv < max_prediv; prediv++) { - fcp = xtal / prediv; - if (fcp > fcp_min && fcp < fcp_max) { - for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { - fdem = ((xtal/prediv) * loopdiv); - fs = fdem / 4; - /* test min/max system restrictions */ - - if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { - spur = 0; - /* test fs harmonics positions */ - for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { - if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { - spur = 1; - break; - } - } - - if (!spur) { - adc->pll_loopdiv = loopdiv; - adc->pll_prediv = prediv; - adc->timf = 2396745143UL/fdem*(1 << 9); - adc->timf += ((2396745143UL%fdem) << 9)/fdem; - deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf); - break; - } - } - } - } - if (!spur) - break; - } - - - if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0) - return -EINVAL; - else - return 0; -} - -static int dib7090_agc_startup(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - struct dibx000_bandwidth_config pll; - u16 target; - struct dib7090p_best_adc adc; - int ret; - - ret = state->set_param_save(fe); - if (ret < 0) - return ret; - - memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); - dib0090_pwm_gain_reset(fe); - target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; - dib7000p_set_wbd_ref(fe, target); - - if (dib7090p_get_best_sampling(fe, &adc) == 0) { - pll.pll_ratio = adc.pll_loopdiv; - pll.pll_prediv = adc.pll_prediv; - - dib7000p_update_pll(fe, &pll); - dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); - } - return 0; -} - -static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - deb_info("AGC restart callback: %d", restart); - if (restart == 0) /* before AGC startup */ - dib0090_set_dc_servo(fe, 1); - return 0; -} - -static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global) -{ - u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1; - s16 wbd_delta; - - if ((fe->dtv_property_cache.frequency) < 400000000) - threshold_agc1 = 25000; - else - threshold_agc1 = 30000; - - wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2; - wbd_offset = dib0090_get_wbd_offset(fe); - dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd); - wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ; - - deb_info("update lna, agc_global=%d agc1=%d agc2=%d", - agc_global, agc1, agc2); - deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d", - wbd, wbd_target, wbd_offset, wbd_delta); - - if ((agc1 < threshold_agc1) && (wbd_delta > 0)) { - dib0090_set_switch(fe, 1, 1, 1); - dib0090_set_vga(fe, 0); - dib0090_update_rframp_7090(fe, 0); - dib0090_update_tuning_table_7090(fe, 0); - } else { - dib0090_set_vga(fe, 1); - dib0090_update_rframp_7090(fe, 1); - dib0090_update_tuning_table_7090(fe, 1); - dib0090_set_switch(fe, 0, 0, 0); - } - - return 0; -} - -static struct dib0090_wbd_slope dib7090_wbd_table[] = { - { 380, 81, 850, 64, 540, 4}, - { 860, 51, 866, 21, 375, 4}, - {1700, 0, 250, 0, 100, 6}, - {2600, 0, 250, 0, 100, 6}, - { 0xFFFF, 0, 0, 0, 0, 0}, -}; - -static struct dib0090_wbd_slope dib7090e_wbd_table[] = { - { 380, 81, 850, 64, 540, 4}, - { 700, 51, 866, 21, 320, 4}, - { 860, 48, 666, 18, 330, 6}, - {1700, 0, 250, 0, 100, 6}, - {2600, 0, 250, 0, 100, 6}, - { 0xFFFF, 0, 0, 0, 0, 0}, -}; - -static struct dibx000_agc_config dib7090_agc_config[2] = { - { - .band_caps = BAND_UHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - .inv_gain = 687, - .time_stabiliz = 10, - - .alpha_level = 0, - .thlock = 118, - - .wbd_inv = 0, - .wbd_ref = 1200, - .wbd_sel = 3, - .wbd_alpha = 5, - - .agc1_max = 65535, - .agc1_min = 0, - - .agc2_max = 65535, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 32, - .agc1_pt3 = 114, - .agc1_slope1 = 143, - .agc1_slope2 = 144, - .agc2_pt1 = 114, - .agc2_pt2 = 227, - .agc2_slope1 = 116, - .agc2_slope2 = 117, - - .alpha_mant = 18, - .alpha_exp = 0, - .beta_mant = 20, - .beta_exp = 59, - - .perform_agc_softsplit = 0, - } , { - .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - .inv_gain = 732, - .time_stabiliz = 10, - - .alpha_level = 0, - .thlock = 118, - - .wbd_inv = 0, - .wbd_ref = 1200, - .wbd_sel = 3, - .wbd_alpha = 5, - - .agc1_max = 65535, - .agc1_min = 0, - - .agc2_max = 65535, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 0, - .agc1_pt3 = 98, - .agc1_slope1 = 0, - .agc1_slope2 = 167, - .agc2_pt1 = 98, - .agc2_pt2 = 255, - .agc2_slope1 = 104, - .agc2_slope2 = 0, - - .alpha_mant = 18, - .alpha_exp = 0, - .beta_mant = 20, - .beta_exp = 59, - - .perform_agc_softsplit = 0, - } -}; - -static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { - 60000, 15000, - 1, 5, 0, 0, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20452225, - 15000000, -}; - -static struct dib7000p_config nim7090_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_FIFO, - .enMpegOutput = 1, -}; - -static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .default_i2c_addr = 0x90, - .enMpegOutput = 1, - }, { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .default_i2c_addr = 0x92, - .enMpegOutput = 0, - } -}; - -static struct dib7000p_config tfe7090e_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = dib7090e_update_lna, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_FIFO, - .enMpegOutput = 1, -}; - -static const struct dib0090_config nim7090_dib0090_config = { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, -}; - -static const struct dib0090_config tfe7090e_dib0090_config = { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090e_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - .force_cband_input = 1, - .is_dib7090e = 1, -}; - -static struct dib7000p_config tfe7790e_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = dib7090e_update_lna, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .enMpegOutput = 1, -}; - -static const struct dib0090_config tfe7790e_dib0090_config = { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090e_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - .force_cband_input = 1, - .is_dib7090e = 1, - .force_crystal_mode = 1, -}; - -static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { - { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 50, - .freq_offset_khz_vhf = 70, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - }, { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = -50, - .freq_offset_khz_vhf = -70, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - } -}; - -static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* The TFE7090 requires the dib0700 to not be in master mode */ - st->disable_streaming_master_mode = 1; - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - /* initialize IC 0 */ - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - - dib0700_set_i2c_speed(adap->dev, 340); - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - if (adap->fe_adap[0].fe == NULL) - return -ENODEV; - - dib7090_slave_reset(adap->fe_adap[0].fe); - - return 0; -} - -static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *i2c; - - if (adap->dev->adapter[0].fe_adap[0].fe == NULL) { - err("the master dib7090 has to be initialized first"); - return -ENODEV; /* the master device has not been initialized */ - } - - i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); - if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); - dib0700_set_i2c_speed(adap->dev, 200); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, - 1, 0x10, &tfe7090e_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, - 0x80, &tfe7090e_dib7000p_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* The TFE7790E requires the dib0700 to not be in master mode */ - st->disable_streaming_master_mode = 1; - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(20); - dib0700_ctrl_clock(adap->dev, 72, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, - 1, 0x10, &tfe7790e_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, - 0x80, &tfe7790e_dib7000p_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = - dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, - &tfe7790e_dib0090_config) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = - dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, - &tfe7090e_dib0090_config) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -/* STK7070PD */ -static struct dib7000p_config stk7070pd_dib7000p_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - }, { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - } -}; - -static void stk7070pd_init(struct dvb_usb_device *dev) -{ - dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(dev, 72, 1); - - msleep(10); - dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1); -} - -static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) -{ - stk7070pd_init(adap->dev); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, - stk7070pd_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) -{ - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int novatd_read_status_override(struct dvb_frontend *fe, - fe_status_t *stat) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *dev = adap->dev; - struct dib0700_state *state = dev->priv; - int ret; - - ret = state->read_status(fe, stat); - - if (!ret) - dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, - !!(*stat & FE_HAS_LOCK)); - - return ret; -} - -static int novatd_sleep_override(struct dvb_frontend* fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *dev = adap->dev; - struct dib0700_state *state = dev->priv; - - /* turn off LED */ - dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0); - - return state->sleep(fe); -} - -/** - * novatd_frontend_attach - Nova-TD specific attach - * - * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for - * information purposes. - */ -static int novatd_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *dev = adap->dev; - struct dib0700_state *st = dev->priv; - - if (adap->id == 0) { - stk7070pd_init(dev); - - /* turn the power LED on, the other two off (just in case) */ - dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0); - dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0); - dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18, - stk7070pd_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap, - adap->id == 0 ? 0x80 : 0x82, - &stk7070pd_dib7000p_config[adap->id]); - - if (adap->fe_adap[0].fe == NULL) - return -ENODEV; - - st->read_status = adap->fe_adap[0].fe->ops.read_status; - adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override; - st->sleep = adap->fe_adap[0].fe->ops.sleep; - adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override; - - return 0; -} - -/* S5H1411 */ -static struct s5h1411_config pinnacle_801e_config = { - .output_mode = S5H1411_PARALLEL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, - .qam_if = S5H1411_IF_44000, - .vsb_if = S5H1411_IF_44000, - .inversion = S5H1411_INVERSION_OFF, - .status_mode = S5H1411_DEMODLOCKING -}; - -/* Pinnacle PCTV HD Pro 801e GPIOs map: - GPIO0 - currently unknown - GPIO1 - xc5000 tuner reset - GPIO2 - CX25843 sleep - GPIO3 - currently unknown - GPIO4 - currently unknown - GPIO6 - currently unknown - GPIO7 - currently unknown - GPIO9 - currently unknown - GPIO10 - CX25843 reset - */ -static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* Make use of the new i2c functions from FW 1.20 */ - st->fw_use_new_i2c_api = 1; - - /* The s5h1411 requires the dib0700 to not be in master mode */ - st->disable_streaming_master_mode = 1; - - /* All msleep values taken from Windows USB trace */ - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); - dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(400); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(60); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); - msleep(30); - - /* Put the CX25843 to sleep for now since we're in digital mode */ - dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); - - /* GPIOs are initialized, do the attach */ - adap->fe_adap[0].fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, - &adap->dev->i2c_adap); - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int dib0700_xc5000_tuner_callback(void *priv, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = priv; - - if (command == XC5000_TUNER_RESET) { - /* Reset the tuner */ - dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); - msleep(10); - } else { - err("xc5000: unknown tuner callback command: %d\n", command); - return -EINVAL; - } - - return 0; -} - -static struct xc5000_config s5h1411_xc5000_tunerconfig = { - .i2c_address = 0x64, - .if_khz = 5380, -}; - -static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) -{ - /* FIXME: generalize & move to common area */ - adap->fe_adap[0].fe->callback = dib0700_xc5000_tuner_callback; - - return dvb_attach(xc5000_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, - &s5h1411_xc5000_tunerconfig) - == NULL ? -ENODEV : 0; -} - -static int dib0700_xc4000_tuner_callback(void *priv, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = priv; - - if (command == XC4000_TUNER_RESET) { - /* Reset the tuner */ - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); - msleep(10); - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - } else { - err("xc4000: unknown tuner callback command: %d\n", command); - return -EINVAL; - } - - return 0; -} - -static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = { - .band_caps = BAND_UHF | BAND_VHF, - .setup = 0x64, - .inv_gain = 0x02c8, - .time_stabiliz = 0x15, - .alpha_level = 0x00, - .thlock = 0x76, - .wbd_inv = 0x01, - .wbd_ref = 0x0b33, - .wbd_sel = 0x00, - .wbd_alpha = 0x02, - .agc1_max = 0x00, - .agc1_min = 0x00, - .agc2_max = 0x9b26, - .agc2_min = 0x26ca, - .agc1_pt1 = 0x00, - .agc1_pt2 = 0x00, - .agc1_pt3 = 0x00, - .agc1_slope1 = 0x00, - .agc1_slope2 = 0x00, - .agc2_pt1 = 0x00, - .agc2_pt2 = 0x80, - .agc2_slope1 = 0x1d, - .agc2_slope2 = 0x1d, - .alpha_mant = 0x11, - .alpha_exp = 0x1b, - .beta_mant = 0x17, - .beta_exp = 0x33, - .perform_agc_softsplit = 0x00, -}; - -static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = { - 60000, 30000, /* internal, sampling */ - 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ - 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, */ - /* ADClkSrc, modulo */ - (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */ - 39370534, /* ifreq */ - 20452225, /* timf */ - 30000000 /* xtal */ -}; - -/* FIXME: none of these inputs are validated yet */ -static struct dib7000p_config pctv_340e_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &stk7700p_7000p_xc4000_agc_config, - .bw = &stk7700p_xc4000_pll_config, - - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, -}; - -/* PCTV 340e GPIOs map: - dib0700: - GPIO2 - CX25843 sleep - GPIO3 - CS5340 reset - GPIO5 - IRD - GPIO6 - Power Supply - GPIO8 - LNA (1=off 0=on) - GPIO10 - CX25843 reset - dib7000: - GPIO8 - xc4000 reset - */ -static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* Power Supply on */ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(50); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(100); /* Allow power supply to settle before probing */ - - /* cx25843 reset */ - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(1); /* cx25843 datasheet say 350us required */ - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - - /* LNA off for now */ - dib0700_set_gpio(adap->dev, GPIO8, GPIO_OUT, 1); - - /* Put the CX25843 to sleep for now since we're in digital mode */ - dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); - - /* FIXME: not verified yet */ - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(500); - - if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) { - /* Demodulator not found for some reason? */ - return -ENODEV; - } - - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, - &pctv_340e_config); - st->is_dib7000pc = 1; - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static struct xc4000_config dib7000p_xc4000_tunerconfig = { - .i2c_address = 0x61, - .default_pm = 1, - .dvb_amplitude = 0, - .set_smoothedcvbs = 0, - .if_khz = 5400 -}; - -static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *tun_i2c; - - /* The xc4000 is not on the main i2c bus */ - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - if (tun_i2c == NULL) { - printk(KERN_ERR "Could not reach tuner i2c bus\n"); - return 0; - } - - /* Setup the reset callback */ - adap->fe_adap[0].fe->callback = dib0700_xc4000_tuner_callback; - - return dvb_attach(xc4000_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7000p_xc4000_tunerconfig) - == NULL ? -ENODEV : 0; -} - -static struct lgdt3305_config hcw_lgdt3305_config = { - .i2c_addr = 0x0e, - .mpeg_mode = LGDT3305_MPEG_PARALLEL, - .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_LOW, - .deny_i2c_rptr = 0, - .spectral_inversion = 1, - .qam_if_khz = 6000, - .vsb_if_khz = 6000, - .usref_8vsb = 0x0500, -}; - -static struct mxl5007t_config hcw_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_25_MHZ, - .if_freq_hz = MxL_IF_6_MHZ, - .invert_if = 1, -}; - -/* TIGER-ATSC map: - GPIO0 - LNA_CTR (H: LNA power enabled, L: LNA power disabled) - GPIO1 - ANT_SEL (H: VPA, L: MCX) - GPIO4 - SCL2 - GPIO6 - EN_TUNER - GPIO7 - SDA2 - GPIO10 - DEM_RST - - MXL is behind LG's i2c repeater. LG is on SCL2/SDA2 gpios on the DIB - */ -static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* Make use of the new i2c functions from FW 1.20 */ - st->fw_use_new_i2c_api = 1; - - st->disable_streaming_master_mode = 1; - - /* fe power enable */ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(30); - - /* demod reset */ - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(30); - - adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach, - &hcw_lgdt3305_config, - &adap->dev->i2c_adap); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x60, - &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; -} - - -/* DVB-USB and USB stuff follows */ -struct usb_device_id dib0700_usb_id_table[] = { -/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, -/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, - { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, - { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, -/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, - { USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, -/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, - { USB_DEVICE(USB_VID_PINNACLE, - USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, - { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, -/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, -/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_USB_XE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_EXPRESSCARD_320CX) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV72E) }, -/* 30 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73E) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_EC372S) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, -/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, -/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, - { USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) }, - { USB_DEVICE(USB_VID_SONY, USB_PID_SONY_PLAYTV) }, -/* 45 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_PD378S) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, -/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, -/* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, -/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, - { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) }, - { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, -/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DIVERSITY) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090M) }, -/* 70 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM8096MD) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, -/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) }, -/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, - { 0 } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); - -#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ - .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ - .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-1.20.fw", \ - .download_firmware = dib0700_download_firmware, \ - .no_reconnect = 1, \ - .size_of_priv = sizeof(struct dib0700_state), \ - .i2c_algo = &dib0700_i2c_algo, \ - .identify_state = dib0700_identify_state - -#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ - .streaming_ctrl = dib0700_streaming_ctrl, \ - .stream = { \ - .type = USB_BULK, \ - .count = 4, \ - .endpoint = ep, \ - .u = { \ - .bulk = { \ - .buffersize = 39480, \ - } \ - } \ - } - -struct dvb_usb_device_properties dib0700_devices[] = { - { - DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk7700p_pid_filter, - .pid_filter_ctrl = stk7700p_pid_filter_ctrl, - .frontend_attach = stk7700p_frontend_attach, - .tuner_attach = stk7700p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - }, - }, - - .num_device_descs = 8, - .devices = { - { "DiBcom STK7700P reference design", - { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, - { NULL }, - }, - { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL }, - { NULL }, - }, - { "AVerMedia AVerTV DVB-T Volar", - { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] }, - { NULL }, - }, - { "Compro Videomate U500", - { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, - { NULL }, - }, - { "Uniwill STK7700P based (Hama and others)", - { &dib0700_usb_id_table[7], NULL }, - { NULL }, - }, - { "Leadtek Winfast DTV Dongle (STK7700P based)", - { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] }, - { NULL }, - }, - { "AVerMedia AVerTV DVB-T Express", - { &dib0700_usb_id_table[20] }, - { NULL }, - }, - { "Gigabyte U7000", - { &dib0700_usb_id_table[21], NULL }, - { NULL }, - } - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = bristol_frontend_attach, - .tuner_attach = bristol_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - }, { - .num_frontends = 1, - .fe = {{ - .frontend_attach = bristol_frontend_attach, - .tuner_attach = bristol_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - } - }, - - .num_device_descs = 1, - .devices = { - { "Hauppauge Nova-T 500 Dual DVB-T", - { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700d_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - }, { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700d_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - } - }, - - .num_device_descs = 5, - .devices = { - { "Pinnacle PCTV 2000e", - { &dib0700_usb_id_table[11], NULL }, - { NULL }, - }, - { "Terratec Cinergy DT XS Diversity", - { &dib0700_usb_id_table[12], NULL }, - { NULL }, - }, - { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", - { &dib0700_usb_id_table[13], NULL }, - { NULL }, - }, - { "DiBcom STK7700D reference design", - { &dib0700_usb_id_table[14], NULL }, - { NULL }, - }, - { "YUAN High-Tech DiBcom STK7700D", - { &dib0700_usb_id_table[55], NULL }, - { NULL }, - }, - - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700P2_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - }, - }, - - .num_device_descs = 3, - .devices = { - { "ASUS My Cinema U3000 Mini DVBT Tuner", - { &dib0700_usb_id_table[23], NULL }, - { NULL }, - }, - { "Yuan EC372S", - { &dib0700_usb_id_table[31], NULL }, - { NULL }, - }, - { "Terratec Cinergy T Express", - { &dib0700_usb_id_table[42], NULL }, - { NULL }, - } - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070p_frontend_attach, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 12, - .devices = { - { "DiBcom STK7070P reference design", - { &dib0700_usb_id_table[15], NULL }, - { NULL }, - }, - { "Pinnacle PCTV DVB-T Flash Stick", - { &dib0700_usb_id_table[16], NULL }, - { NULL }, - }, - { "Artec T14BR DVB-T", - { &dib0700_usb_id_table[22], NULL }, - { NULL }, - }, - { "ASUS My Cinema U3100 Mini DVBT Tuner", - { &dib0700_usb_id_table[24], NULL }, - { NULL }, - }, - { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[25], NULL }, - { NULL }, - }, - { "Hauppauge Nova-T MyTV.t", - { &dib0700_usb_id_table[26], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 72e", - { &dib0700_usb_id_table[29], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 73e", - { &dib0700_usb_id_table[30], NULL }, - { NULL }, - }, - { "Elgato EyeTV DTT", - { &dib0700_usb_id_table[49], NULL }, - { NULL }, - }, - { "Yuan PD378S", - { &dib0700_usb_id_table[45], NULL }, - { NULL }, - }, - { "Elgato EyeTV Dtt Dlx PD378S", - { &dib0700_usb_id_table[50], NULL }, - { NULL }, - }, - { "Elgato EyeTV DTT rev. 2", - { &dib0700_usb_id_table[81], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070p_frontend_attach, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 3, - .devices = { - { "Pinnacle PCTV 73A", - { &dib0700_usb_id_table[56], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 73e SE", - { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 282e", - { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = novatd_frontend_attach, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = novatd_frontend_attach, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - } - }, - - .num_device_descs = 1, - .devices = { - { "Hauppauge Nova-TD Stick (52009)", - { &dib0700_usb_id_table[35], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach0, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach1, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - } - }, - - .num_device_descs = 5, - .devices = { - { "DiBcom STK7070PD reference design", - { &dib0700_usb_id_table[17], NULL }, - { NULL }, - }, - { "Pinnacle PCTV Dual DVB-T Diversity Stick", - { &dib0700_usb_id_table[18], NULL }, - { NULL }, - }, - { "Hauppauge Nova-TD-500 (84xxx)", - { &dib0700_usb_id_table[36], NULL }, - { NULL }, - }, - { "Terratec Cinergy DT USB XS Diversity/ T5", - { &dib0700_usb_id_table[43], - &dib0700_usb_id_table[53], NULL}, - { NULL }, - }, - { "Sony PlayTV", - { &dib0700_usb_id_table[44], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach0, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach1, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - .size_of_priv = sizeof(struct dib0700_adapter_state), - } - }, - - .num_device_descs = 1, - .devices = { - { "Elgato EyeTV Diversity", - { &dib0700_usb_id_table[68], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_NEC_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700ph_frontend_attach, - .tuner_attach = stk7700ph_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 9, - .devices = { - { "Terratec Cinergy HT USB XE", - { &dib0700_usb_id_table[27], NULL }, - { NULL }, - }, - { "Pinnacle Expresscard 320cx", - { &dib0700_usb_id_table[28], NULL }, - { NULL }, - }, - { "Terratec Cinergy HT Express", - { &dib0700_usb_id_table[32], NULL }, - { NULL }, - }, - { "Gigabyte U8000-RH", - { &dib0700_usb_id_table[37], NULL }, - { NULL }, - }, - { "YUAN High-Tech STK7700PH", - { &dib0700_usb_id_table[38], NULL }, - { NULL }, - }, - { "Asus My Cinema-U3000Hybrid", - { &dib0700_usb_id_table[39], NULL }, - { NULL }, - }, - { "YUAN High-Tech MC770", - { &dib0700_usb_id_table[48], NULL }, - { NULL }, - }, - { "Leadtek WinFast DTV Dongle H", - { &dib0700_usb_id_table[51], NULL }, - { NULL }, - }, - { "YUAN High-Tech STK7700D", - { &dib0700_usb_id_table[54], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = s5h1411_frontend_attach, - .tuner_attach = xc5000_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 2, - .devices = { - { "Pinnacle PCTV HD Pro USB Stick", - { &dib0700_usb_id_table[40], NULL }, - { NULL }, - }, - { "Pinnacle PCTV HD USB Stick", - { &dib0700_usb_id_table[41], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = lgdt3305_frontend_attach, - .tuner_attach = mxl5007t_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 2, - .devices = { - { "Hauppauge ATSC MiniCard (B200)", - { &dib0700_usb_id_table[46], NULL }, - { NULL }, - }, - { "Hauppauge ATSC MiniCard (B210)", - { &dib0700_usb_id_table[47], NULL }, - { NULL }, - }, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7770p_frontend_attach, - .tuner_attach = dib7770p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 4, - .devices = { - { "DiBcom STK7770P reference design", - { &dib0700_usb_id_table[59], NULL }, - { NULL }, - }, - { "Terratec Cinergy T USB XXS (HD)/ T3", - { &dib0700_usb_id_table[33], - &dib0700_usb_id_table[52], - &dib0700_usb_id_table[60], NULL}, - { NULL }, - }, - { "TechniSat AirStar TeleStick 2", - { &dib0700_usb_id_table[74], NULL }, - { NULL }, - }, - { "Medion CTX1921 DVB-T USB", - { &dib0700_usb_id_table[75], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk807x_frontend_attach, - .tuner_attach = dib807x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 3, - .devices = { - { "DiBcom STK807xP reference design", - { &dib0700_usb_id_table[62], NULL }, - { NULL }, - }, - { "Prolink Pixelview SBTVD", - { &dib0700_usb_id_table[63], NULL }, - { NULL }, - }, - { "EvolutePC TVWay+", - { &dib0700_usb_id_table[64], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_NEC_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk807xpvr_frontend_attach0, - .tuner_attach = dib807x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk807xpvr_frontend_attach1, - .tuner_attach = dib807x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom STK807xPVR reference design", - { &dib0700_usb_id_table[61], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk809x_frontend_attach, - .tuner_attach = dib809x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom STK8096GP reference design", - { &dib0700_usb_id_table[67], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = dib90x0_pid_filter, - .pid_filter_ctrl = dib90x0_pid_filter_ctrl, - .frontend_attach = stk9090m_frontend_attach, - .tuner_attach = dib9090_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom STK9090M reference design", - { &dib0700_usb_id_table[69], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = nim8096md_frontend_attach, - .tuner_attach = nim8096md_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom NIM8096MD reference design", - { &dib0700_usb_id_table[70], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = dib90x0_pid_filter, - .pid_filter_ctrl = dib90x0_pid_filter_ctrl, - .frontend_attach = nim9090md_frontend_attach, - .tuner_attach = nim9090md_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom NIM9090MD reference design", - { &dib0700_usb_id_table[71], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = nim7090_frontend_attach, - .tuner_attach = nim7090_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom NIM7090 reference design", - { &dib0700_usb_id_table[72], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7090pvr_frontend0_attach, - .tuner_attach = tfe7090pvr_tuner0_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7090pvr_frontend1_attach, - .tuner_attach = tfe7090pvr_tuner1_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom TFE7090PVR reference design", - { &dib0700_usb_id_table[73], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = pctv340e_frontend_attach, - .tuner_attach = xc4000_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }}, - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 2, - .devices = { - { "Pinnacle PCTV 340e HD Pro USB Stick", - { &dib0700_usb_id_table[76], NULL }, - { NULL }, - }, - { "Pinnacle PCTV Hybrid Stick Solo", - { &dib0700_usb_id_table[77], NULL }, - { NULL }, - }, - }, - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7090e_frontend_attach, - .tuner_attach = tfe7090e_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - } }, - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom TFE7090E reference design", - { &dib0700_usb_id_table[78], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7790e_frontend_attach, - .tuner_attach = tfe7790e_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - } }, - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom TFE7790E reference design", - { &dib0700_usb_id_table[79], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = tfe8096p_frontend_attach, - .tuner_attach = tfe8096p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - } }, - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom TFE8096P reference design", - { &dib0700_usb_id_table[80], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, -}; - -int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/dvb/dvb-usb/dib07x0.h b/drivers/media/dvb/dvb-usb/dib07x0.h deleted file mode 100644 index 7e62c101852..00000000000 --- a/drivers/media/dvb/dvb-usb/dib07x0.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _DIB07X0_H_ -#define _DIB07X0_H_ - -enum dib07x0_gpios { - GPIO0 = 0, - GPIO1 = 2, - GPIO2 = 3, - GPIO3 = 4, - GPIO4 = 5, - GPIO5 = 6, - GPIO6 = 8, - GPIO7 = 10, - GPIO8 = 11, - GPIO9 = 14, - GPIO10 = 15, -}; - -#define GPIO_IN 0 -#define GPIO_OUT 1 - -#endif diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c deleted file mode 100644 index a76bbb29ca3..00000000000 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ /dev/null @@ -1,479 +0,0 @@ -/* Common methods for dibusb-based-receivers. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); -MODULE_LICENSE("GPL"); - -#define deb_info(args...) dprintk(debug,0x01,args) - -/* common stuff used by the different dibusb modules */ -int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) { - err("error while controlling the fifo of the demod."); - return -ENODEV; - } - } - return 0; -} -EXPORT_SYMBOL(dibusb_streaming_ctrl); - -int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe_adap[0].fe, - index, pid, onoff); - } - return 0; -} -EXPORT_SYMBOL(dibusb_pid_filter); - -int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0) - err("could not handle pid_parser"); - } - return 0; -} -EXPORT_SYMBOL(dibusb_pid_filter_ctrl); - -int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b[3]; - int ret; - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; - b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; - ret = dvb_usb_generic_write(d,b,3); - msleep(10); - return ret; -} -EXPORT_SYMBOL(dibusb_power_ctrl); - -int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 b[3] = { 0 }; - int ret; - - if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) - return ret; - - if (onoff) { - b[0] = DIBUSB_REQ_SET_STREAMING_MODE; - b[1] = 0x00; - if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) - return ret; - } - - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; - return dvb_usb_generic_write(adap->dev,b,3); -} -EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); - -int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - if (onoff) { - u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; - return dvb_usb_generic_write(d,b,3); - } else - return 0; -} -EXPORT_SYMBOL(dibusb2_0_power_ctrl); - -static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ - /* write only ? */ - int wo = (rbuf == NULL || rlen == 0), - len = 2 + wlen + (wo ? 0 : 2); - - sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; - sndbuf[1] = (addr << 1) | (wo ? 0 : 1); - - memcpy(&sndbuf[2],wbuf,wlen); - - if (!wo) { - sndbuf[wlen+2] = (rlen >> 8) & 0xff; - sndbuf[wlen+3] = rlen & 0xff; - } - - return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); -} - -/* - * I2C master xfer function - */ -static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - 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].flags & I2C_M_RD) == 0 - && (msg[i+1].flags & I2C_M_RD)) { - if (dibusb_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 ((msg[i].flags & I2C_M_RD) == 0) { - if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) - break; - } else if (msg[i].addr != 0x50) { - /* 0x50 is the address of the eeprom - we need to protect it - * from dibusb's bad i2c implementation: reads without - * writing the offset before are forbidden */ - if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) - break; - } - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 dibusb_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm dibusb_i2c_algo = { - .master_xfer = dibusb_i2c_xfer, - .functionality = dibusb_i2c_func, -}; -EXPORT_SYMBOL(dibusb_i2c_algo); - -int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) -{ - u8 wbuf[1] = { offs }; - return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); -} -EXPORT_SYMBOL(dibusb_read_eeprom_byte); - -/* 3000MC/P stuff */ -// Config Adjacent channels Perf -cal22 -static struct dibx000_agc_config dib3000p_mt2060_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 48497, - .agc1_min = 23593, - .agc2_max = 46531, - .agc2_min = 24904, - - .agc1_pt1 = 0x65, - .agc1_pt2 = 0x69, - - .agc1_slope1 = 0x51, - .agc1_slope2 = 0x27, - - .agc2_pt1 = 0, - .agc2_pt2 = 0x33, - - .agc2_slope1 = 0x35, - .agc2_slope2 = 0x37, -}; - -static struct dib3000mc_config stk3000p_dib3000p_config = { - &dib3000p_mt2060_agc_config, - - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - - .output_mpeg2_in_188_bytes = 1, - - .agc_command1 = 1, - .agc_command2 = 1, -}; - -static struct dibx000_agc_config dib3000p_panasonic_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 56361, - .agc1_min = 22282, - .agc2_max = 47841, - .agc2_min = 36045, - - .agc1_pt1 = 0x3b, - .agc1_pt2 = 0x6b, - - .agc1_slope1 = 0x55, - .agc1_slope2 = 0x1d, - - .agc2_pt1 = 0, - .agc2_pt2 = 0x0a, - - .agc2_slope1 = 0x95, - .agc2_slope2 = 0x1e, -}; - -#if defined(CONFIG_DVB_DIB3000MC) || \ - (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) - -static struct dib3000mc_config mod3000p_dib3000p_config = { - &dib3000p_panasonic_agc_config, - - .max_time = 0x51, - .ln_adc_level = 0x1cc7, - - .output_mpeg2_in_188_bytes = 1, - - .agc_command1 = 1, - .agc_command2 = 1, -}; - -int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == - USB_PID_LITEON_DVB_T_WARM) { - msleep(1000); - } - - adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, - &adap->dev->i2c_adap, - DEFAULT_DIB3000P_I2C_ADDRESS, - &mod3000p_dib3000p_config); - if ((adap->fe_adap[0].fe) == NULL) - adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, - &adap->dev->i2c_adap, - DEFAULT_DIB3000MC_I2C_ADDRESS, - &mod3000p_dib3000p_config); - if ((adap->fe_adap[0].fe) != NULL) { - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - st->ops.pid_parse = dib3000mc_pid_parse; - st->ops.pid_ctrl = dib3000mc_pid_control; - } - return 0; - } - return -ENODEV; -} -EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); - -static struct mt2060_config stk3000p_mt2060_config = { - 0x60 -}; - -int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - u8 a,b; - u16 if1 = 1220; - struct i2c_adapter *tun_i2c; - - // First IF calibration for Liteon Sticks - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { - - dibusb_read_eeprom_byte(adap->dev,0x7E,&a); - dibusb_read_eeprom_byte(adap->dev,0x7F,&b); - - if (a == 0x00) - if1 += b; - else if (a == 0x80) - if1 -= b; - else - warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); - - } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && - adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { - u8 desc; - dibusb_read_eeprom_byte(adap->dev, 7, &desc); - if (desc == 2) { - a = 127; - do { - dibusb_read_eeprom_byte(adap->dev, a, &desc); - a--; - } while (a > 7 && (desc == 0xff || desc == 0x00)); - if (desc & 0x80) - if1 -= (0xff - desc); - else - if1 += desc; - } - } - - tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); - if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { - /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) - return -ENOMEM; - } else { - st->mt2060_present = 1; - /* set the correct parameters for the dib3000p */ - dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config); - } - return 0; -} -EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); -#endif - -/* - * common remote control stuff - */ -struct rc_map_table rc_map_dibusb_table[] = { - /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ - { 0x0016, KEY_POWER }, - { 0x0010, KEY_MUTE }, - { 0x0003, KEY_1 }, - { 0x0001, KEY_2 }, - { 0x0006, KEY_3 }, - { 0x0009, KEY_4 }, - { 0x001d, KEY_5 }, - { 0x001f, KEY_6 }, - { 0x000d, KEY_7 }, - { 0x0019, KEY_8 }, - { 0x001b, KEY_9 }, - { 0x0015, KEY_0 }, - { 0x0005, KEY_CHANNELUP }, - { 0x0002, KEY_CHANNELDOWN }, - { 0x001e, KEY_VOLUMEUP }, - { 0x000a, KEY_VOLUMEDOWN }, - { 0x0011, KEY_RECORD }, - { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x0014, KEY_PLAY }, - { 0x001a, KEY_STOP }, - { 0x0040, KEY_REWIND }, - { 0x0012, KEY_FASTFORWARD }, - { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x004c, KEY_PAUSE }, - { 0x004d, KEY_SCREEN }, /* Full screen mode. */ - { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ - { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x001c, KEY_EPG }, /* EPG */ - { 0x0000, KEY_TAB }, /* Tab */ - { 0x0048, KEY_INFO }, /* Preview */ - { 0x0004, KEY_LIST }, /* RecordList */ - { 0x000f, KEY_TEXT }, /* Teletext */ - /* Key codes for the KWorld/ADSTech/JetWay remote. */ - { 0x8612, KEY_POWER }, - { 0x860f, KEY_SELECT }, /* source */ - { 0x860c, KEY_UNKNOWN }, /* scan */ - { 0x860b, KEY_EPG }, - { 0x8610, KEY_MUTE }, - { 0x8601, KEY_1 }, - { 0x8602, KEY_2 }, - { 0x8603, KEY_3 }, - { 0x8604, KEY_4 }, - { 0x8605, KEY_5 }, - { 0x8606, KEY_6 }, - { 0x8607, KEY_7 }, - { 0x8608, KEY_8 }, - { 0x8609, KEY_9 }, - { 0x860a, KEY_0 }, - { 0x8618, KEY_ZOOM }, - { 0x861c, KEY_UNKNOWN }, /* preview */ - { 0x8613, KEY_UNKNOWN }, /* snap */ - { 0x8600, KEY_UNDO }, - { 0x861d, KEY_RECORD }, - { 0x860d, KEY_STOP }, - { 0x860e, KEY_PAUSE }, - { 0x8616, KEY_PLAY }, - { 0x8611, KEY_BACK }, - { 0x8619, KEY_FORWARD }, - { 0x8614, KEY_UNKNOWN }, /* pip */ - { 0x8615, KEY_ESC }, - { 0x861a, KEY_UP }, - { 0x861e, KEY_DOWN }, - { 0x861f, KEY_LEFT }, - { 0x861b, KEY_RIGHT }, - - /* Key codes for the DiBcom MOD3000 remote. */ - { 0x8000, KEY_MUTE }, - { 0x8001, KEY_TEXT }, - { 0x8002, KEY_HOME }, - { 0x8003, KEY_POWER }, - - { 0x8004, KEY_RED }, - { 0x8005, KEY_GREEN }, - { 0x8006, KEY_YELLOW }, - { 0x8007, KEY_BLUE }, - - { 0x8008, KEY_DVD }, - { 0x8009, KEY_AUDIO }, - { 0x800a, KEY_IMAGES }, /* Pictures */ - { 0x800b, KEY_VIDEO }, - - { 0x800c, KEY_BACK }, - { 0x800d, KEY_UP }, - { 0x800e, KEY_RADIO }, - { 0x800f, KEY_EPG }, - - { 0x8010, KEY_LEFT }, - { 0x8011, KEY_OK }, - { 0x8012, KEY_RIGHT }, - { 0x8013, KEY_UNKNOWN }, /* SAP */ - - { 0x8014, KEY_TV }, - { 0x8015, KEY_DOWN }, - { 0x8016, KEY_MENU }, /* DVD Menu */ - { 0x8017, KEY_LAST }, - - { 0x8018, KEY_RECORD }, - { 0x8019, KEY_STOP }, - { 0x801a, KEY_PAUSE }, - { 0x801b, KEY_PLAY }, - - { 0x801c, KEY_PREVIOUS }, - { 0x801d, KEY_REWIND }, - { 0x801e, KEY_FASTFORWARD }, - { 0x801f, KEY_NEXT}, - - { 0x8040, KEY_1 }, - { 0x8041, KEY_2 }, - { 0x8042, KEY_3 }, - { 0x8043, KEY_CHANNELUP }, - - { 0x8044, KEY_4 }, - { 0x8045, KEY_5 }, - { 0x8046, KEY_6 }, - { 0x8047, KEY_CHANNELDOWN }, - - { 0x8048, KEY_7 }, - { 0x8049, KEY_8 }, - { 0x804a, KEY_9 }, - { 0x804b, KEY_VOLUMEUP }, - - { 0x804c, KEY_CLEAR }, - { 0x804d, KEY_0 }, - { 0x804e, KEY_ENTER }, - { 0x804f, KEY_VOLUMEDOWN }, -}; -EXPORT_SYMBOL(rc_map_dibusb_table); - -int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; - dvb_usb_generic_rw(d,&cmd,1,key,5,0); - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} -EXPORT_SYMBOL(dibusb_rc_query); diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c deleted file mode 100644 index a4ac37e0e98..00000000000 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ /dev/null @@ -1,471 +0,0 @@ -/* DVB USB compliant linux driver for mobile DVB-T USB devices based on - * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B) - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * based on GPL code from DiBcom, which has - * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dibusb_state *st = adap->priv; - - return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr); -} - -static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib3000_config demod_cfg; - struct dibusb_state *st = adap->priv; - - demod_cfg.demod_address = 0x8; - - adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg, - &adap->dev->i2c_adap, &st->ops); - if ((adap->fe_adap[0].fe) == NULL) - return -ENODEV; - - adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; - - return 0; -} - -static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - - st->tuner_addr = 0x61; - - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, - DVB_PLL_TUA6010XS); - return 0; -} - -static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - - st->tuner_addr = 0x60; - - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, - DVB_PLL_TDA665X); - return 0; -} - -/* Some of the Artec 1.1 device aren't equipped with the default tuner - * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures - * this out. */ -static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) -{ - u8 b[2] = { 0,0 }, b2[1]; - int ret = 0; - struct i2c_msg msg[2] = { - { .flags = 0, .buf = b, .len = 2 }, - { .flags = I2C_M_RD, .buf = b2, .len = 1 }, - }; - struct dibusb_state *st = adap->priv; - - /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ - msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; - - if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) - adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); - - if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { - err("tuner i2c write failed."); - ret = -EREMOTEIO; - } - - if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) - adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); - - if (b2[0] == 0xfe) { - info("This device has the Thomson Cable onboard. Which is default."); - ret = dibusb_thomson_tuner_attach(adap); - } else { - info("This device has the Panasonic ENV77H11D5 onboard."); - ret = dibusb_panasonic_tuner_attach(adap); - } - - return ret; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties dibusb1_1_properties; -static struct dvb_usb_device_properties dibusb1_1_an2235_properties; -static struct dvb_usb_device_properties dibusb2_0b_properties; -static struct dvb_usb_device_properties artec_t1_usb2_properties; - -static int dibusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dibusb2_0b_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -EINVAL; -} - -/* do not change the order of the ID table */ -static struct usb_device_id dibusb_dib3000mb_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, -/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, -/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, -/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, -/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, -/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, -/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, -/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, -/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) }, -/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, -/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, -/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, -/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, -/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, -/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, -/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, -/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, - -/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ -/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, -/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, -/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, - -/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, - -/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, - -/* - * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices - * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that - * have been left on the device. If you don't have such a device but an Artec - * device that's supposed to work with this driver but is not detected by it, - * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. - */ - -#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY -/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, -#endif - - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); - -static struct dvb_usb_device_properties dibusb1_1_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_AN2135, - - .firmware = "dvb-usb-dibusb-5.0.0.11.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - - .power_ctrl = dibusb_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 9, - .devices = { - { "AVerMedia AverTV DVBT USB1.1", - { &dibusb_dib3000mb_table[0], NULL }, - { &dibusb_dib3000mb_table[1], NULL }, - }, - { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", - { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL}, - { &dibusb_dib3000mb_table[3], NULL }, - }, - { "DiBcom USB1.1 DVB-T reference design (MOD3000)", - { &dibusb_dib3000mb_table[5], NULL }, - { &dibusb_dib3000mb_table[6], NULL }, - }, - { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", - { &dibusb_dib3000mb_table[7], NULL }, - { &dibusb_dib3000mb_table[8], NULL }, - }, - { "Grandtec USB1.1 DVB-T", - { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL }, - { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL }, - }, - { "Unknown USB1.1 DVB-T device ???? please report the name to the author", - { &dibusb_dib3000mb_table[13], NULL }, - { &dibusb_dib3000mb_table[14], NULL }, - }, - { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device", - { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL}, - { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL}, - }, - { "Artec T1 USB1.1 TVBOX with AN2135", - { &dibusb_dib3000mb_table[19], NULL }, - { &dibusb_dib3000mb_table[20], NULL }, - }, - { "VideoWalker DVB-T USB", - { &dibusb_dib3000mb_table[25], NULL }, - { &dibusb_dib3000mb_table[26], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_AN2235, - - .firmware = "dvb-usb-dibusb-an2235-01.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - }, - }, - .power_ctrl = dibusb_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - -#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY - .num_device_descs = 2, -#else - .num_device_descs = 1, -#endif - .devices = { - { "Artec T1 USB1.1 TVBOX with AN2235", - { &dibusb_dib3000mb_table[21], NULL }, - { &dibusb_dib3000mb_table[22], NULL }, - }, -#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY - { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[30], NULL }, - { NULL }, - }, - { NULL }, -#endif - } -}; - -static struct dvb_usb_device_properties dibusb2_0b_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .firmware = "dvb-usb-adstech-usb2-02.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_thomson_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb2_0_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 2, - .devices = { - { "KWorld/ADSTech Instant DVB-T USB2.0", - { &dibusb_dib3000mb_table[23], NULL }, - { &dibusb_dib3000mb_table[24], NULL }, - }, - { "KWorld Xpert DVB-T USB2.0", - { &dibusb_dib3000mb_table[27], NULL }, - { NULL } - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties artec_t1_usb2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .firmware = "dvb-usb-dibusb-6.0.0.8.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb2_0_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Artec T1 USB2.0", - { &dibusb_dib3000mb_table[28], NULL }, - { &dibusb_dib3000mb_table[29], NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver dibusb_driver = { - .name = "dvb_usb_dibusb_mb", - .probe = dibusb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dibusb_dib3000mb_table, -}; - -module_usb_driver(dibusb_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c deleted file mode 100644 index 9d1a59d09c5..00000000000 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ /dev/null @@ -1,149 +0,0 @@ -/* DVB USB compliant linux driver for mobile DVB-T USB devices based on - * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P) - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * based on GPL code from DiBcom, which has - * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* USB Driver stuff */ -static struct dvb_usb_device_properties dibusb_mc_properties; - -static int dibusb_mc_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE, - NULL, adapter_nr); -} - -/* do not change the order of the ID table */ -static struct usb_device_id dibusb_dib3000mc_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) -/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, -/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, -/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, -/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, -/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, -/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, -/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, -/* 14 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) }, -/* 15 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); - -static struct dvb_usb_device_properties dibusb_mc_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-dibusb-6.0.0.8.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb2_0_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* FIXME */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 8, - .devices = { - { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", - { &dibusb_dib3000mc_table[0], NULL }, - { &dibusb_dib3000mc_table[1], NULL }, - }, - { "Artec T1 USB2.0 TVBOX (please check the warm ID)", - { &dibusb_dib3000mc_table[2], NULL }, - { &dibusb_dib3000mc_table[3], NULL }, - }, - { "LITE-ON USB2.0 DVB-T Tuner", - /* Also rebranded as Intuix S800, Toshiba */ - { &dibusb_dib3000mc_table[4], NULL }, - { &dibusb_dib3000mc_table[5], NULL }, - }, - { "MSI Digivox Mini SL", - { &dibusb_dib3000mc_table[6], NULL }, - { &dibusb_dib3000mc_table[7], NULL }, - }, - { "GRAND - USB2.0 DVB-T adapter", - { &dibusb_dib3000mc_table[8], NULL }, - { &dibusb_dib3000mc_table[9], NULL }, - }, - { "Artec T14 - USB2.0 DVB-T", - { &dibusb_dib3000mc_table[10], NULL }, - { &dibusb_dib3000mc_table[11], NULL }, - }, - { "Leadtek - USB2.0 Winfast DTV dongle", - { &dibusb_dib3000mc_table[12], NULL }, - { &dibusb_dib3000mc_table[13], NULL }, - }, - { "Humax/Coex DVB-T USB Stick 2.0 High Speed", - { &dibusb_dib3000mc_table[14], NULL }, - { &dibusb_dib3000mc_table[15], NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver dibusb_mc_driver = { - .name = "dvb_usb_dibusb_mc", - .probe = dibusb_mc_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dibusb_dib3000mc_table, -}; - -module_usb_driver(dibusb_mc_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h deleted file mode 100644 index e47c321b3ff..00000000000 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Header file for all dibusb-based-receivers. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_DIBUSB_H_ -#define _DVB_USB_DIBUSB_H_ - -#ifndef DVB_USB_LOG_PREFIX - #define DVB_USB_LOG_PREFIX "dibusb" -#endif -#include "dvb-usb.h" - -#include "dib3000.h" -#include "dib3000mc.h" -#include "mt2060.h" - -/* - * protocol of all dibusb related devices - */ - -/* - * bulk msg to/from endpoint 0x01 - * - * general structure: - * request_byte parameter_bytes - */ - -#define DIBUSB_REQ_START_READ 0x00 -#define DIBUSB_REQ_START_DEMOD 0x01 - -/* - * i2c read - * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word - * bulk read: byte_buffer (length_word bytes) - */ -#define DIBUSB_REQ_I2C_READ 0x02 - -/* - * i2c write - * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes - */ -#define DIBUSB_REQ_I2C_WRITE 0x03 - -/* - * polling the value of the remote control - * bulk write: 0x04 - * bulk read: byte_buffer (5 bytes) - */ -#define DIBUSB_REQ_POLL_REMOTE 0x04 - -/* additional status values for Hauppauge Remote Control Protocol */ -#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01 -#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03 - -/* streaming mode: - * bulk write: 0x05 mode_byte - * - * mode_byte is mostly 0x00 - */ -#define DIBUSB_REQ_SET_STREAMING_MODE 0x05 - -/* interrupt the internal read loop, when blocking */ -#define DIBUSB_REQ_INTR_READ 0x06 - -/* io control - * 0x07 cmd_byte param_bytes - * - * param_bytes can be up to 32 bytes - * - * cmd_byte function parameter name - * 0x00 power mode - * 0x00 sleep - * 0x01 wakeup - * - * 0x01 enable streaming - * 0x02 disable streaming - * - * - */ -#define DIBUSB_REQ_SET_IOCTL 0x07 - -/* IOCTL commands */ - -/* change the power mode in firmware */ -#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00 -#define DIBUSB_IOCTL_POWER_SLEEP 0x00 -#define DIBUSB_IOCTL_POWER_WAKEUP 0x01 - -/* modify streaming of the FX2 */ -#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01 -#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02 - -struct dibusb_state { - struct dib_fe_xfer_ops ops; - int mt2060_present; - u8 tuner_addr; -}; - -struct dibusb_device_state { - /* for RC5 remote control */ - int old_toggle; - int last_repeat_count; -}; - -extern struct i2c_algorithm dibusb_i2c_algo; - -extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *); -extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *); - -extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int); -extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int); -extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int); -extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int); - -extern int dibusb_power_ctrl(struct dvb_usb_device *, int); -extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int); - -#define DEFAULT_RC_INTERVAL 150 -//#define DEFAULT_RC_INTERVAL 100000 - -extern struct rc_map_table rc_map_dibusb_table[]; -extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *); -extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *); - -#endif diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c deleted file mode 100644 index ff34419a4c8..00000000000 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ /dev/null @@ -1,354 +0,0 @@ -/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 - * receiver - * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * - * partly based on the SDK published by Nebula Electronics - * - * 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 "digitv.h" - -#include "mt352.h" -#include "nxt6000.h" - -/* debug */ -static int dvb_usb_digitv_debug; -module_param_named(debug,dvb_usb_digitv_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) - -static int digitv_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 sndbuf[7],rcvbuf[7]; - memset(sndbuf,0,7); memset(rcvbuf,0,7); - - sndbuf[0] = cmd; - sndbuf[1] = vv; - sndbuf[2] = wo ? wlen : rlen; - - if (wo) { - memcpy(&sndbuf[3],wbuf,wlen); - dvb_usb_generic_write(d,sndbuf,7); - } else { - dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); - memcpy(rbuf,&rcvbuf[3],rlen); - } - return 0; -} - -/* I2C */ -static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, - msg[i+1].buf,msg[i+1].len) < 0) - break; - i++; - } else - if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], - &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 digitv_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm digitv_i2c_algo = { - .master_xfer = digitv_i2c_xfer, - .functionality = digitv_i2c_func, -}; - -/* Callbacks for DVB USB */ -static int digitv_identify_state (struct usb_device *udev, struct - dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, - int *cold) -{ - *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; - return 0; -} - -static int digitv_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; - static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, - 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, - 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, - 0x75, 0x32 }; - int i; - - for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) - mt352_write(fe, &reset_buf[i], 2); - - msleep(1); - - for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) - mt352_write(fe, &init_buf[i], 2); - - return 0; -} - -static struct mt352_config digitv_mt352_config = { - .demod_init = digitv_mt352_demod_init, -}; - -static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - u8 b[5]; - - fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b)); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); -} - -static struct nxt6000_config digitv_nxt6000_config = { - .clock_inversion = 1, -}; - -static int digitv_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct digitv_state *st = adap->dev->priv; - - adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) { - st->is_nxt6000 = 0; - return 0; - } - adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, - &digitv_nxt6000_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) { - st->is_nxt6000 = 1; - return 0; - } - return -EIO; -} - -static int digitv_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct digitv_state *st = adap->dev->priv; - - if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4)) - return -ENODEV; - - if (st->is_nxt6000) - adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; - - return 0; -} - -static struct rc_map_table rc_map_digitv_table[] = { - { 0x5f55, KEY_0 }, - { 0x6f55, KEY_1 }, - { 0x9f55, KEY_2 }, - { 0xaf55, KEY_3 }, - { 0x5f56, KEY_4 }, - { 0x6f56, KEY_5 }, - { 0x9f56, KEY_6 }, - { 0xaf56, KEY_7 }, - { 0x5f59, KEY_8 }, - { 0x6f59, KEY_9 }, - { 0x9f59, KEY_TV }, - { 0xaf59, KEY_AUX }, - { 0x5f5a, KEY_DVD }, - { 0x6f5a, KEY_POWER }, - { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ - { 0xaf5a, KEY_AUDIO }, - { 0x5f65, KEY_INFO }, - { 0x6f65, KEY_F13 }, /* 16:9 */ - { 0x9f65, KEY_F14 }, /* 14:9 */ - { 0xaf65, KEY_EPG }, - { 0x5f66, KEY_EXIT }, - { 0x6f66, KEY_MENU }, - { 0x9f66, KEY_UP }, - { 0xaf66, KEY_DOWN }, - { 0x5f69, KEY_LEFT }, - { 0x6f69, KEY_RIGHT }, - { 0x9f69, KEY_ENTER }, - { 0xaf69, KEY_CHANNELUP }, - { 0x5f6a, KEY_CHANNELDOWN }, - { 0x6f6a, KEY_VOLUMEUP }, - { 0x9f6a, KEY_VOLUMEDOWN }, - { 0xaf6a, KEY_RED }, - { 0x5f95, KEY_GREEN }, - { 0x6f95, KEY_YELLOW }, - { 0x9f95, KEY_BLUE }, - { 0xaf95, KEY_SUBTITLE }, - { 0x5f96, KEY_F15 }, /* AD */ - { 0x6f96, KEY_TEXT }, - { 0x9f96, KEY_MUTE }, - { 0xaf96, KEY_REWIND }, - { 0x5f99, KEY_STOP }, - { 0x6f99, KEY_PLAY }, - { 0x9f99, KEY_FASTFORWARD }, - { 0xaf99, KEY_F16 }, /* chapter */ - { 0x5f9a, KEY_PAUSE }, - { 0x6f9a, KEY_PLAY }, - { 0x9f9a, KEY_RECORD }, - { 0xaf9a, KEY_F17 }, /* picture in picture */ - { 0x5fa5, KEY_KPPLUS }, /* zoom in */ - { 0x6fa5, KEY_KPMINUS }, /* zoom out */ - { 0x9fa5, KEY_F18 }, /* capture */ - { 0xafa5, KEY_F19 }, /* web */ - { 0x5fa6, KEY_EMAIL }, - { 0x6fa6, KEY_PHONE }, - { 0x9fa6, KEY_PC }, -}; - -static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - int i; - u8 key[5]; - u8 b[4] = { 0 }; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); - - /* Tell the device we've read the remote. Not sure how necessary - this is, but the Nebula SDK does it. */ - digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); - - /* if something is inside the buffer, simulate key press */ - if (key[1] != 0) - { - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] && - rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) { - *event = d->props.rc.legacy.rc_map_table[i].keycode; - *state = REMOTE_KEY_PRESSED; - return 0; - } - } - } - - if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties digitv_properties; - -static int digitv_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d, - adapter_nr); - if (ret == 0) { - u8 b[4] = { 0 }; - - if (d != NULL) { /* do that only when the firmware is loaded */ - b[0] = 1; - digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); - - b[0] = 0; - digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); - } - } - return ret; -} - -static struct usb_device_id digitv_table [] = { - { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, digitv_table); - -static struct dvb_usb_device_properties digitv_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-digitv-02.fw", - - .size_of_priv = sizeof(struct digitv_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = digitv_frontend_attach, - .tuner_attach = digitv_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .identify_state = digitv_identify_state, - - .rc.legacy = { - .rc_interval = 1000, - .rc_map_table = rc_map_digitv_table, - .rc_map_size = ARRAY_SIZE(rc_map_digitv_table), - .rc_query = digitv_rc_query, - }, - - .i2c_algo = &digitv_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Nebula Electronics uDigiTV DVB-T USB2.0)", - { &digitv_table[0], NULL }, - { NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver digitv_driver = { - .name = "dvb_usb_digitv", - .probe = digitv_probe, - .disconnect = dvb_usb_device_exit, - .id_table = digitv_table, -}; - -module_usb_driver(digitv_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); -MODULE_VERSION("1.0-alpha"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h deleted file mode 100644 index 908c09f4966..00000000000 --- a/drivers/media/dvb/dvb-usb/digitv.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _DVB_USB_DIGITV_H_ -#define _DVB_USB_DIGITV_H_ - -#define DVB_USB_LOG_PREFIX "digitv" -#include "dvb-usb.h" - -struct digitv_state { - int is_nxt6000; -}; - -/* protocol (from usblogging and the SDK: - * - * Always 7 bytes bulk message(s) for controlling - * - * First byte describes the command. Reads are 2 consecutive transfer (as always). - * - * General structure: - * - * write or first message of a read: - * VV B0 B1 B2 B3 - * - * second message of a read - * VV R0 R1 R2 R3 - * - * whereas 0 < len <= 4 - * - * I2C address is stored somewhere inside the device. - * - * 0x01 read from EEPROM - * VV = offset; B* = 0; R* = value(s) - * - * 0x02 read register of the COFDM - * VV = register; B* = 0; R* = value(s) - * - * 0x05 write register of the COFDM - * VV = register; B* = value(s); - * - * 0x06 write to the tuner (only for NXT6000) - * VV = 0; B* = PLL data; len = 4; - * - * 0x03 read remote control - * VV = 0; B* = 0; len = 4; R* = key - * - * 0x07 write to the remote (don't know why one should this, resetting ?) - * VV = 0; B* = key; len = 4; - * - * 0x08 write remote type - * VV = 0; B[0] = 0x01, len = 4 - * - * 0x09 write device init - * TODO - */ -#define USB_READ_EEPROM 1 - -#define USB_READ_COFDM 2 -#define USB_WRITE_COFDM 5 - -#define USB_WRITE_TUNER 6 - -#define USB_READ_REMOTE 3 -#define USB_WRITE_REMOTE 7 -#define USB_WRITE_REMOTE_TYPE 8 - -#define USB_DEV_INIT 9 - -#endif diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c deleted file mode 100644 index 3d81daa4917..00000000000 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ /dev/null @@ -1,210 +0,0 @@ -/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. - * - * Copyright (C) 2005 Patrick Boettcher - * - * 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 "dtt200u.h" - -struct dtt200u_fe_state { - struct dvb_usb_device *d; - - fe_status_t stat; - - struct dtv_frontend_properties fep; - struct dvb_frontend frontend; -}; - -static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 st = GET_TUNE_STATUS, b[3]; - - dvb_usb_generic_rw(state->d,&st,1,b,3,0); - - switch (b[0]) { - case 0x01: - *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - break; - case 0x00: /* pending */ - *stat = FE_TIMEDOUT; /* during set_frontend */ - break; - default: - case 0x02: /* failed */ - *stat = 0; - break; - } - return 0; -} - -static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_VIT_ERR_CNT,b[3]; - dvb_usb_generic_rw(state->d,&bw,1,b,3,0); - *ber = (b[0] << 16) | (b[1] << 8) | b[2]; - return 0; -} - -static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_RS_UNCOR_BLK_CNT,b[2]; - - dvb_usb_generic_rw(state->d,&bw,1,b,2,0); - *unc = (b[0] << 8) | b[1]; - return 0; -} - -static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_AGC, b; - dvb_usb_generic_rw(state->d,&bw,1,&b,1,0); - *strength = (b << 8) | b; - return 0; -} - -static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_SNR,br; - dvb_usb_generic_rw(state->d,&bw,1,&br,1,0); - *snr = ~((br << 8) | br); - return 0; -} - -static int dtt200u_fe_init(struct dvb_frontend* fe) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 b = SET_INIT; - return dvb_usb_generic_write(state->d,&b,1); -} - -static int dtt200u_fe_sleep(struct dvb_frontend* fe) -{ - return dtt200u_fe_init(fe); -} - -static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1500; - tune->step_size = 0; - tune->max_drift = 0; - return 0; -} - -static int dtt200u_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct dtt200u_fe_state *state = fe->demodulator_priv; - int i; - fe_status_t st; - u16 freq = fep->frequency / 250000; - u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; - - switch (fep->bandwidth_hz) { - case 8000000: - bwbuf[1] = 8; - break; - case 7000000: - bwbuf[1] = 7; - break; - case 6000000: - bwbuf[1] = 6; - break; - default: - return -EINVAL; - } - - dvb_usb_generic_write(state->d,bwbuf,2); - - freqbuf[1] = freq & 0xff; - freqbuf[2] = (freq >> 8) & 0xff; - dvb_usb_generic_write(state->d,freqbuf,3); - - for (i = 0; i < 30; i++) { - msleep(20); - dtt200u_fe_read_status(fe, &st); - if (st & FE_TIMEDOUT) - continue; - } - - return 0; -} - -static int dtt200u_fe_get_frontend(struct dvb_frontend* fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct dtt200u_fe_state *state = fe->demodulator_priv; - memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties)); - return 0; -} - -static void dtt200u_fe_release(struct dvb_frontend* fe) -{ - struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops dtt200u_fe_ops; - -struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) -{ - struct dtt200u_fe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL); - if (state == NULL) - goto error; - - deb_info("attaching frontend dtt200u\n"); - - state->d = d; - - memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; -error: - return NULL; -} - -static struct dvb_frontend_ops dtt200u_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "WideView USB DVB-T", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dtt200u_fe_release, - - .init = dtt200u_fe_init, - .sleep = dtt200u_fe_sleep, - - .set_frontend = dtt200u_fe_set_frontend, - .get_frontend = dtt200u_fe_get_frontend, - .get_tune_settings = dtt200u_fe_get_tune_settings, - - .read_status = dtt200u_fe_read_status, - .read_ber = dtt200u_fe_read_ber, - .read_signal_strength = dtt200u_fe_read_signal_strength, - .read_snr = dtt200u_fe_read_snr, - .read_ucblocks = dtt200u_fe_read_unc_blocks, -}; diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c deleted file mode 100644 index 66f205c112b..00000000000 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ /dev/null @@ -1,368 +0,0 @@ -/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Steve Chang from WideView for providing support for the WT-220U. - * - * 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 "dtt200u.h" - -/* debug */ -int dvb_usb_dtt200u_debug; -module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = SET_INIT; - - if (onoff) - dvb_usb_generic_write(d,&b,2); - - return 0; -} - -static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 b_streaming[2] = { SET_STREAMING, onoff }; - u8 b_rst_pid = RESET_PID_FILTER; - - dvb_usb_generic_write(adap->dev, b_streaming, 2); - - if (onoff == 0) - dvb_usb_generic_write(adap->dev, &b_rst_pid, 1); - return 0; -} - -static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - u8 b_pid[4]; - pid = onoff ? pid : 0; - - b_pid[0] = SET_PID_FILTER; - b_pid[1] = index; - b_pid[2] = pid & 0xff; - b_pid[3] = (pid >> 8) & 0x1f; - - return dvb_usb_generic_write(adap->dev, b_pid, 4); -} - -/* remote control */ -/* key list for the tiny remote control (Yakumo, don't know about the others) */ -static struct rc_map_table rc_map_dtt200u_table[] = { - { 0x8001, KEY_MUTE }, - { 0x8002, KEY_CHANNELDOWN }, - { 0x8003, KEY_VOLUMEDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, - { 0x800c, KEY_ZOOM }, - { 0x800d, KEY_0 }, - { 0x800e, KEY_SELECT }, - { 0x8012, KEY_POWER }, - { 0x801a, KEY_CHANNELUP }, - { 0x801b, KEY_8 }, - { 0x801e, KEY_VOLUMEUP }, - { 0x801f, KEY_9 }, -}; - -static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd = GET_RC_CODE; - dvb_usb_generic_rw(d,&cmd,1,key,5,0); - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} - -static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev); - return 0; -} - -static struct dvb_usb_device_properties dtt200u_properties; -static struct dvb_usb_device_properties wt220u_fc_properties; -static struct dvb_usb_device_properties wt220u_properties; -static struct dvb_usb_device_properties wt220u_zl0353_properties; -static struct dvb_usb_device_properties wt220u_miglia_properties; - -static int dtt200u_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &dtt200u_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_fc_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_miglia_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -ENODEV; -} - -static struct usb_device_id dtt200u_usb_table [] = { - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, - { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); - -static struct dvb_usb_device_properties dtt200u_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-dtt200u-01.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", - .cold_ids = { &dtt200u_usb_table[0], NULL }, - .warm_ids = { &dtt200u_usb_table[1], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-02.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, - .warm_ids = { &dtt200u_usb_table[3], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_fc_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-fc03.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[6], NULL }, - .warm_ids = { &dtt200u_usb_table[7], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_zl0353_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-zl0353-01.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (based on ZL353)", - .cold_ids = { &dtt200u_usb_table[4], NULL }, - .warm_ids = { &dtt200u_usb_table[5], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_miglia_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-miglia-01.fw", - - .num_adapters = 1, - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (Miglia)", - .cold_ids = { &dtt200u_usb_table[9], NULL }, - /* This device turns into WT220U_ZL0353_WARM when fw - has been uploaded */ - .warm_ids = { NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver dtt200u_usb_driver = { - .name = "dvb_usb_dtt200u", - .probe = dtt200u_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dtt200u_usb_table, -}; - -module_usb_driver(dtt200u_usb_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h deleted file mode 100644 index 005b0a7df35..00000000000 --- a/drivers/media/dvb/dvb-usb/dtt200u.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_DTT200U_H_ -#define _DVB_USB_DTT200U_H_ - -#define DVB_USB_LOG_PREFIX "dtt200u" - -#include "dvb-usb.h" - -extern int dvb_usb_dtt200u_debug; -#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args) - -/* guessed protocol description (reverse engineered): - * read - * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 - * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal) - */ - -#define GET_SPEED 0x00 -#define GET_TUNE_STATUS 0x81 -#define GET_RC_CODE 0x84 -#define GET_CONFIGURATION 0x88 -#define GET_AGC 0x89 -#define GET_SNR 0x8a -#define GET_VIT_ERR_CNT 0x8c -#define GET_RS_ERR_CNT 0x8d -#define GET_RS_UNCOR_BLK_CNT 0x8e - -/* write - * 01 - init - * 02 - frequency (divided by 250000) - * 03 - bandwidth - * 04 - pid table (index pid(7:0) pid(12:8)) - * 05 - reset the pid table - * 08 - transfer switch - */ - -#define SET_INIT 0x01 -#define SET_RF_FREQ 0x02 -#define SET_BANDWIDTH 0x03 -#define SET_PID_FILTER 0x04 -#define RESET_PID_FILTER 0x05 -#define SET_STREAMING 0x08 - -extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); - -#endif diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c deleted file mode 100644 index 3d11df41cac..00000000000 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T - * - * Copyright (C) 2008 Antoine Jacquet - * http://royale.zerezo.com/dtv5100/ - * - * Inspired by gl861.c and au6610.c drivers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "dtv5100.h" -#include "zl10353.h" -#include "qt1010.h" - -/* debug */ -static int dvb_usb_dtv5100_debug; -module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 request; - u8 type; - u16 value; - u16 index; - - switch (wlen) { - case 1: - /* write { reg }, read { value } */ - request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : - DTV5100_TUNER_READ); - type = USB_TYPE_VENDOR | USB_DIR_IN; - value = 0; - break; - case 2: - /* write { reg, value } */ - request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : - DTV5100_TUNER_WRITE); - type = USB_TYPE_VENDOR | USB_DIR_OUT; - value = wbuf[1]; - break; - default: - warn("wlen = %x, aborting.", wlen); - return -EINVAL; - } - index = (addr << 8) + wbuf[0]; - - msleep(1); /* avoid I2C errors */ - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, - type, value, index, rbuf, rlen, - DTV5100_USB_TIMEOUT); -} - -/* I2C */ -static int dtv5100_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 (dtv5100_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 (dtv5100_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 dtv5100_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dtv5100_i2c_algo = { - .master_xfer = dtv5100_i2c_xfer, - .functionality = dtv5100_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config dtv5100_zl10353_config = { - .demod_address = DTV5100_DEMOD_ADDR, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) - return -EIO; - - /* disable i2c gate, or it won't work... is this safe? */ - adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; - - return 0; -} - -static struct qt1010_config dtv5100_qt1010_config = { - .i2c_address = DTV5100_TUNER_ADDR -}; - -static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, - adap->fe_adap[0].fe, &adap->dev->i2c_adap, - &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties dtv5100_properties; - -static int dtv5100_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int i, ret; - struct usb_device *udev = interface_to_usbdev(intf); - - /* initialize non qt1010/zl10353 part? */ - for (i = 0; dtv5100_init[i].request; i++) { - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - dtv5100_init[i].request, - USB_TYPE_VENDOR | USB_DIR_OUT, - dtv5100_init[i].value, - dtv5100_init[i].index, NULL, 0, - DTV5100_USB_TIMEOUT); - if (ret) - return ret; - } - - ret = dvb_usb_device_init(intf, &dtv5100_properties, - THIS_MODULE, NULL, adapter_nr); - if (ret) - return ret; - - return 0; -} - -static struct usb_device_id dtv5100_table[] = { - { USB_DEVICE(0x06be, 0xa232) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, dtv5100_table); - -static struct dvb_usb_device_properties dtv5100_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - .frontend_attach = dtv5100_frontend_attach, - .tuner_attach = dtv5100_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } }, - - .i2c_algo = &dtv5100_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "AME DTV-5100 USB2.0 DVB-T", - .cold_ids = { NULL }, - .warm_ids = { &dtv5100_table[0], NULL }, - }, - } -}; - -static struct usb_driver dtv5100_driver = { - .name = "dvb_usb_dtv5100", - .probe = dtv5100_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dtv5100_table, -}; - -module_usb_driver(dtv5100_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h deleted file mode 100644 index 93e96e04a82..00000000000 --- a/drivers/media/dvb/dvb-usb/dtv5100.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T - * - * Copyright (C) 2008 Antoine Jacquet - * http://royale.zerezo.com/dtv5100/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _DVB_USB_DTV5100_H_ -#define _DVB_USB_DTV5100_H_ - -#define DVB_USB_LOG_PREFIX "dtv5100" -#include "dvb-usb.h" - -#define DTV5100_USB_TIMEOUT 500 - -#define DTV5100_DEMOD_ADDR 0x00 -#define DTV5100_DEMOD_WRITE 0xc0 -#define DTV5100_DEMOD_READ 0xc1 - -#define DTV5100_TUNER_ADDR 0xc4 -#define DTV5100_TUNER_WRITE 0xc7 -#define DTV5100_TUNER_READ 0xc8 - -#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" -#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" - -static struct { - u8 request; - u8 value; - u16 index; -} dtv5100_init[] = { - { 0x000000c5, 0x00000000, 0x00000001 }, - { 0x000000c5, 0x00000001, 0x00000001 }, - { } /* Terminating entry */ -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h deleted file mode 100644 index 6b7b2a89242..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ /dev/null @@ -1,52 +0,0 @@ -/* dvb-usb-common.h is part of the DVB USB library. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * a header file containing prototypes and types for internal use of the dvb-usb-lib - */ -#ifndef _DVB_USB_COMMON_H_ -#define _DVB_USB_COMMON_H_ - -#define DVB_USB_LOG_PREFIX "dvb-usb" -#include "dvb-usb.h" - -extern int dvb_usb_debug; -extern int dvb_usb_disable_rc_polling; - -#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) -#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) -#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) -#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) -#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) -#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) -#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) -#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) -#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) - -/* commonly used methods */ -extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); - -extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); - -extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); -extern int usb_urb_exit(struct usb_data_stream *stream); -extern int usb_urb_submit(struct usb_data_stream *stream); -extern int usb_urb_kill(struct usb_data_stream *stream); - -extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); - -extern int dvb_usb_i2c_init(struct dvb_usb_device *); -extern int dvb_usb_i2c_exit(struct dvb_usb_device *); - -extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, - short *adapter_nums); -extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); - -extern int dvb_usb_remote_init(struct dvb_usb_device *); -extern int dvb_usb_remote_exit(struct dvb_usb_device *); - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c deleted file mode 100644 index 719413b15f2..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ /dev/null @@ -1,288 +0,0 @@ -/* dvb-usb-dvb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for initializing and handling the - * linux-dvb API. - */ -#include "dvb-usb-common.h" - -/* does the complete input transfer handling */ -static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) -{ - struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; - int newfeedcount, ret; - - if (adap == NULL) - return -ENODEV; - - if ((adap->active_fe < 0) || - (adap->active_fe >= adap->num_frontends_initialized)) { - return -EINVAL; - } - - newfeedcount = adap->feedcount + (onoff ? 1 : -1); - - /* stop feed before setting a new pid if there will be no pid anymore */ - if (newfeedcount == 0) { - deb_ts("stop feeding\n"); - usb_urb_kill(&adap->fe_adap[adap->active_fe].stream); - - if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0); - if (ret < 0) { - err("error while stopping stream."); - return ret; - } - } - } - - adap->feedcount = newfeedcount; - - /* activate the pid on the device specific pid_filter */ - deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n", - adap->fe_adap[adap->active_fe].pid_filtering ? - "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, - dvbdmxfeed->index, onoff ? "on" : "off"); - if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->fe_adap[adap->active_fe].pid_filtering && - adap->props.fe[adap->active_fe].pid_filter != NULL) - adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); - - /* start the feed if this was the first feed and there is still a feed - * for reception. - */ - if (adap->feedcount == onoff && adap->feedcount > 0) { - deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); - - deb_ts("controlling pid parser\n"); - if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props.fe[adap->active_fe].caps & - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap, - adap->fe_adap[adap->active_fe].pid_filtering); - if (ret < 0) { - err("could not handle pid_parser"); - return ret; - } - } - deb_ts("start feeding\n"); - if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1); - if (ret < 0) { - err("error while enabling fifo."); - return ret; - } - } - - } - return 0; -} - -static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,1); -} - -static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,0); -} - -int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) -{ - int i; - int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, - adap->dev->owner, &adap->dev->udev->dev, - adapter_nums); - - if (ret < 0) { - deb_info("dvb_register_adapter failed: error %d", ret); - goto err; - } - adap->dvb_adap.priv = adap; - - if (adap->dev->props.read_mac_address) { - if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %pM",adap->dvb_adap.proposed_mac); - else - err("MAC address reading failed."); - } - - - adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - adap->demux.priv = adap; - - adap->demux.filternum = 0; - for (i = 0; i < adap->props.num_frontends; i++) { - if (adap->demux.filternum < adap->fe_adap[i].max_feed_count) - adap->demux.filternum = adap->fe_adap[i].max_feed_count; - } - adap->demux.feednum = adap->demux.filternum; - adap->demux.start_feed = dvb_usb_start_feed; - adap->demux.stop_feed = dvb_usb_stop_feed; - adap->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&adap->demux)) < 0) { - err("dvb_dmx_init failed: error %d",ret); - goto err_dmx; - } - - adap->dmxdev.filternum = adap->demux.filternum; - adap->dmxdev.demux = &adap->demux.dmx; - adap->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { - err("dvb_dmxdev_init failed: error %d",ret); - goto err_dmx_dev; - } - - if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, - &adap->demux.dmx)) < 0) { - err("dvb_net_init failed: error %d",ret); - goto err_net_init; - } - - adap->state |= DVB_USB_ADAP_STATE_DVB; - return 0; - -err_net_init: - dvb_dmxdev_release(&adap->dmxdev); -err_dmx_dev: - dvb_dmx_release(&adap->demux); -err_dmx: - dvb_unregister_adapter(&adap->dvb_adap); -err: - return ret; -} - -int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) -{ - if (adap->state & DVB_USB_ADAP_STATE_DVB) { - deb_info("unregistering DVB part\n"); - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - adap->state &= ~DVB_USB_ADAP_STATE_DVB; - } - return 0; -} - -static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - int ret = (adap->props.frontend_ctrl) ? - adap->props.frontend_ctrl(fe, onoff) : 0; - - if (ret < 0) { - err("frontend_ctrl request failed"); - return ret; - } - if (onoff) - adap->active_fe = fe->id; - - return 0; -} - -static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - dvb_usb_device_power_ctrl(adap->dev, 1); - - dvb_usb_set_active_fe(fe, 1); - - if (adap->fe_adap[fe->id].fe_init) - adap->fe_adap[fe->id].fe_init(fe); - - return 0; -} - -static int dvb_usb_fe_sleep(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - if (adap->fe_adap[fe->id].fe_sleep) - adap->fe_adap[fe->id].fe_sleep(fe); - - dvb_usb_set_active_fe(fe, 0); - - return dvb_usb_device_power_ctrl(adap->dev, 0); -} - -int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) -{ - int ret, i; - - /* register all given adapter frontends */ - for (i = 0; i < adap->props.num_frontends; i++) { - - if (adap->props.fe[i].frontend_attach == NULL) { - err("strange: '%s' #%d,%d " - "doesn't want to attach a frontend.", - adap->dev->desc->name, adap->id, i); - - return 0; - } - - ret = adap->props.fe[i].frontend_attach(adap); - if (ret || adap->fe_adap[i].fe == NULL) { - /* only print error when there is no FE at all */ - if (i == 0) - err("no frontend was attached by '%s'", - adap->dev->desc->name); - - return 0; - } - - adap->fe_adap[i].fe->id = i; - - /* re-assign sleep and wakeup functions */ - adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init; - adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup; - adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; - adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; - - if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) { - err("Frontend %d registration failed.", i); - dvb_frontend_detach(adap->fe_adap[i].fe); - adap->fe_adap[i].fe = NULL; - /* In error case, do not try register more FEs, - * still leaving already registered FEs alive. */ - if (i == 0) - return -ENODEV; - else - return 0; - } - - /* only attach the tuner if the demod is there */ - if (adap->props.fe[i].tuner_attach != NULL) - adap->props.fe[i].tuner_attach(adap); - - adap->num_frontends_initialized++; - } - - return 0; -} - -int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) -{ - int i = adap->num_frontends_initialized - 1; - - /* unregister all given adapter frontends */ - for (; i >= 0; i--) { - if (adap->fe_adap[i].fe != NULL) { - dvb_unregister_frontend(adap->fe_adap[i].fe); - dvb_frontend_detach(adap->fe_adap[i].fe); - } - } - adap->num_frontends_initialized = 0; - - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c deleted file mode 100644 index 733a7ff7b20..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c +++ /dev/null @@ -1,146 +0,0 @@ -/* dvb-usb-firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. - * - * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem. - */ -#include "dvb-usb-common.h" - -#include - -struct usb_cypress_controller { - int id; - const char *name; /* name of the usb controller */ - u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ -}; - -static struct usb_cypress_controller cypress[] = { - { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, -}; - -/* - * load a firmware packet to the device - */ -static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) -{ - return usb_control_msg(udev, usb_sndctrlpipe(udev,0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); -} - -int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) -{ - struct hexline hx; - u8 reset; - int ret,pos=0; - - /* stop the CPU */ - reset = 1; - if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) - err("could not stop the USB controller CPU."); - - while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { - deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); - ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); - - if (ret != hx.len) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", - ret,hx.len); - ret = -EINVAL; - break; - } - } - if (ret < 0) { - err("firmware download failed at %d with %d",pos,ret); - return ret; - } - - if (ret == 0) { - /* restart the CPU */ - reset = 0; - if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - } else - ret = -EIO; - - return ret; -} -EXPORT_SYMBOL(usb_cypress_load_firmware); - -int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) -{ - int ret; - const struct firmware *fw = NULL; - - if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - props->firmware,ret); - return ret; - } - - info("downloading firmware from file '%s'",props->firmware); - - switch (props->usb_ctrl) { - case CYPRESS_AN2135: - case CYPRESS_AN2235: - case CYPRESS_FX2: - ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl); - break; - case DEVICE_SPECIFIC: - if (props->download_firmware) - ret = props->download_firmware(udev,fw); - else { - err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); - ret = -EINVAL; - } - break; - default: - ret = -EINVAL; - break; - } - - release_firmware(fw); - return ret; -} - -int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos) -{ - u8 *b = (u8 *) &fw->data[*pos]; - int data_offs = 4; - if (*pos >= fw->size) - return 0; - - memset(hx,0,sizeof(struct hexline)); - - hx->len = b[0]; - - if ((*pos + hx->len + 4) >= fw->size) - return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); - hx->type = b[3]; - - if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data field */ - hx->addr |= (b[4] << 24) | (b[5] << 16); -/* hx->len -= 2; - data_offs += 2; */ - } - memcpy(hx->data,&b[data_offs],hx->len); - hx->chk = b[hx->len + data_offs]; - - *pos += hx->len + 5; - - return *pos; -} -EXPORT_SYMBOL(dvb_usb_get_hexline); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c deleted file mode 100644 index 88e4a62abc4..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ /dev/null @@ -1,43 +0,0 @@ -/* dvb-usb-i2c.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for (de-)initializing an I2C adapter. - */ -#include "dvb-usb-common.h" - -int dvb_usb_i2c_init(struct dvb_usb_device *d) -{ - int ret = 0; - - if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER)) - return 0; - - if (d->props.i2c_algo == NULL) { - err("no i2c algorithm specified"); - return -EINVAL; - } - - strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props.i2c_algo; - d->i2c_adap.algo_data = NULL; - d->i2c_adap.dev.parent = &d->udev->dev; - - i2c_set_adapdata(&d->i2c_adap, d); - - if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) - err("could not add i2c adapter"); - - d->state |= DVB_USB_STATE_I2C; - - return ret; -} - -int dvb_usb_i2c_exit(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_I2C) - i2c_del_adapter(&d->i2c_adap); - d->state &= ~DVB_USB_STATE_I2C; - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c deleted file mode 100644 index 169196ec2d4..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * DVB USB library - provides a generic interface for a DVB USB device driver. - * - * dvb-usb-init.c - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dvb-usb-common.h" - -/* debug */ -int dvb_usb_debug; -module_param_named(debug, dvb_usb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); - -int dvb_usb_disable_rc_polling; -module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); -MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); - -static int dvb_usb_force_pid_filter_usage; -module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); - -static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) -{ - struct dvb_usb_adapter *adap; - int ret, n, o; - - for (n = 0; n < d->props.num_adapters; n++) { - adap = &d->adapter[n]; - adap->dev = d; - adap->id = n; - - memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); - - for (o = 0; o < adap->props.num_frontends; o++) { - struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o]; - /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); - return -ENODEV; - } - - if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count); - adap->fe_adap[o].pid_filtering = 1; - adap->fe_adap[o].max_feed_count = props->pid_filter_count; - } else { - info("will pass the complete MPEG2 transport stream to the software demuxer."); - adap->fe_adap[o].pid_filtering = 0; - adap->fe_adap[o].max_feed_count = 255; - } - - if (!adap->fe_adap[o].pid_filtering && - dvb_usb_force_pid_filter_usage && - props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - info("pid filter enabled by module option."); - adap->fe_adap[o].pid_filtering = 1; - adap->fe_adap[o].max_feed_count = props->pid_filter_count; - } - - if (props->size_of_priv > 0) { - adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); - if (adap->fe_adap[o].priv == NULL) { - err("no memory for priv for adapter %d fe %d.", n, o); - return -ENOMEM; - } - } - } - - if (adap->props.size_of_priv > 0) { - adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); - if (adap->priv == NULL) { - err("no memory for priv for adapter %d.", n); - return -ENOMEM; - } - } - - if ((ret = dvb_usb_adapter_stream_init(adap)) || - (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || - (ret = dvb_usb_adapter_frontend_init(adap))) { - return ret; - } - - /* use exclusive FE lock if there is multiple shared FEs */ - if (adap->fe_adap[1].fe) - adap->dvb_adap.mfe_shared = 1; - - d->num_adapters_initialized++; - d->state |= DVB_USB_STATE_DVB; - } - - /* - * when reloading the driver w/o replugging the device - * sometimes a timeout occures, this helps - */ - if (d->props.generic_bulk_ctrl_endpoint != 0) { - usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - } - - return 0; -} - -static int dvb_usb_adapter_exit(struct dvb_usb_device *d) -{ - int n; - - for (n = 0; n < d->num_adapters_initialized; n++) { - dvb_usb_adapter_frontend_exit(&d->adapter[n]); - dvb_usb_adapter_dvb_exit(&d->adapter[n]); - dvb_usb_adapter_stream_exit(&d->adapter[n]); - kfree(d->adapter[n].priv); - } - d->num_adapters_initialized = 0; - d->state &= ~DVB_USB_STATE_DVB; - return 0; -} - - -/* general initialization functions */ -static int dvb_usb_exit(struct dvb_usb_device *d) -{ - deb_info("state before exiting everything: %x\n", d->state); - dvb_usb_remote_exit(d); - dvb_usb_adapter_exit(d); - dvb_usb_i2c_exit(d); - deb_info("state should be zero now: %x\n", d->state); - d->state = DVB_USB_STATE_INIT; - kfree(d->priv); - kfree(d); - return 0; -} - -static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) -{ - int ret = 0; - - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - - d->state = DVB_USB_STATE_INIT; - - if (d->props.size_of_priv > 0) { - d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); - return -ENOMEM; - } - } - - /* check the capabilities and set appropriate variables */ - dvb_usb_device_power_ctrl(d, 1); - - if ((ret = dvb_usb_i2c_init(d)) || - (ret = dvb_usb_adapter_init(d, adapter_nums))) { - dvb_usb_exit(d); - return ret; - } - - if ((ret = dvb_usb_remote_init(d))) - err("could not initialize remote control."); - - dvb_usb_device_power_ctrl(d, 0); - - return 0; -} - -/* determine the name and the state of the just found USB device */ -static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) -{ - int i, j; - struct dvb_usb_device_description *desc = NULL; - - *cold = -1; - - for (i = 0; i < props->num_device_descs; i++) { - - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { - deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); - if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = 1; - desc = &props->devices[i]; - break; - } - } - - if (desc != NULL) - break; - - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { - deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); - if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = 0; - desc = &props->devices[i]; - break; - } - } - } - - if (desc != NULL && props->identify_state != NULL) - props->identify_state(udev, props, &desc, cold); - - return desc; -} - -int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - if (onoff) - d->powered++; - else - d->powered--; - - if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ - deb_info("power control: %d\n", onoff); - if (d->props.power_ctrl) - return d->props.power_ctrl(d, onoff); - } - return 0; -} - -/* - * USB - */ -int dvb_usb_device_init(struct usb_interface *intf, - struct dvb_usb_device_properties *props, - struct module *owner, struct dvb_usb_device **du, - short *adapter_nums) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct dvb_usb_device *d = NULL; - struct dvb_usb_device_description *desc = NULL; - - int ret = -ENOMEM, cold = 0; - - if (du != NULL) - *du = NULL; - - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { - deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); - return -ENODEV; - } - - if (cold) { - info("found a '%s' in cold state, will try to load a firmware", desc->name); - ret = dvb_usb_download_firmware(udev, props); - if (!props->no_reconnect || ret != 0) - return ret; - } - - info("found a '%s' in warm state.", desc->name); - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); - return -ENOMEM; - } - - d->udev = udev; - memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); - d->desc = desc; - d->owner = owner; - - usb_set_intfdata(intf, d); - - if (du != NULL) - *du = d; - - ret = dvb_usb_init(d, adapter_nums); - - if (ret == 0) - info("%s successfully initialized and connected.", desc->name); - else - info("%s error while loading driver (%d)", desc->name, ret); - return ret; -} -EXPORT_SYMBOL(dvb_usb_device_init); - -void dvb_usb_device_exit(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = "generic DVB-USB module"; - - usb_set_intfdata(intf, NULL); - if (d != NULL && d->desc != NULL) { - name = d->desc->name; - dvb_usb_exit(d); - } - info("%s successfully deinitialized and disconnected.", name); - -} -EXPORT_SYMBOL(dvb_usb_device_exit); - -MODULE_VERSION("1.0"); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c deleted file mode 100644 index 41bacff2496..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ /dev/null @@ -1,391 +0,0 @@ -/* dvb-usb-remote.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for initializing the input-device and for handling remote-control-queries. - */ -#include "dvb-usb-common.h" -#include - -static unsigned int -legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, - struct rc_map_table *keymap, - unsigned int keymap_size) -{ - unsigned int index; - unsigned int scancode; - - if (ke->flags & INPUT_KEYMAP_BY_INDEX) { - index = ke->index; - } else { - if (input_scancode_to_scalar(ke, &scancode)) - return keymap_size; - - /* See if we can match the raw key code. */ - for (index = 0; index < keymap_size; index++) - if (keymap[index].scancode == scancode) - break; - - /* See if there is an unused hole in the map */ - if (index >= keymap_size) { - for (index = 0; index < keymap_size; index++) { - if (keymap[index].keycode == KEY_RESERVED || - keymap[index].keycode == KEY_UNKNOWN) { - break; - } - } - } - } - - return index; -} - -static int legacy_dvb_usb_getkeycode(struct input_dev *dev, - struct input_keymap_entry *ke) -{ - struct dvb_usb_device *d = input_get_drvdata(dev); - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - unsigned int keymap_size = d->props.rc.legacy.rc_map_size; - unsigned int index; - - index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); - if (index >= keymap_size) - return -EINVAL; - - ke->keycode = keymap[index].keycode; - if (ke->keycode == KEY_UNKNOWN) - ke->keycode = KEY_RESERVED; - ke->len = sizeof(keymap[index].scancode); - memcpy(&ke->scancode, &keymap[index].scancode, ke->len); - ke->index = index; - - return 0; -} - -static int legacy_dvb_usb_setkeycode(struct input_dev *dev, - const struct input_keymap_entry *ke, - unsigned int *old_keycode) -{ - struct dvb_usb_device *d = input_get_drvdata(dev); - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - unsigned int keymap_size = d->props.rc.legacy.rc_map_size; - unsigned int index; - - index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); - /* - * FIXME: Currently, it is not possible to increase the size of - * scancode table. For it to happen, one possibility - * would be to allocate a table with key_map_size + 1, - * copying data, appending the new key on it, and freeing - * the old one - or maybe just allocating some spare space - */ - if (index >= keymap_size) - return -EINVAL; - - *old_keycode = keymap[index].keycode; - keymap->keycode = ke->keycode; - __set_bit(ke->keycode, dev->keybit); - - if (*old_keycode != KEY_RESERVED) { - __clear_bit(*old_keycode, dev->keybit); - for (index = 0; index < keymap_size; index++) { - if (keymap[index].keycode == *old_keycode) { - __set_bit(*old_keycode, dev->keybit); - break; - } - } - } - - return 0; -} - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - * whether the remote control has received anything. - * - * TODO: Fix the repeat rate of the input device. - */ -static void legacy_dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, rc_query_work.work); - u32 event; - int state; - - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the driver was running */ - if (dvb_usb_disable_rc_polling) - return; - - if (d->props.rc.legacy.rc_query(d,&event,&state)) { - err("error while querying for an remote control event."); - goto schedule; - } - - - switch (state) { - case REMOTE_NO_KEY_PRESSED: - break; - case REMOTE_KEY_PRESSED: - deb_rc("key pressed\n"); - d->last_event = event; - case REMOTE_KEY_REPEAT: - deb_rc("key repeated\n"); - input_event(d->input_dev, EV_KEY, event, 1); - input_sync(d->input_dev); - input_event(d->input_dev, EV_KEY, d->last_event, 0); - input_sync(d->input_dev); - break; - default: - break; - } - -/* improved repeat handling ??? - switch (state) { - case REMOTE_NO_KEY_PRESSED: - deb_rc("NO KEY PRESSED\n"); - if (d->last_state != REMOTE_NO_KEY_PRESSED) { - deb_rc("releasing event %d\n",d->last_event); - input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(d->rc_input_dev); - } - d->last_state = REMOTE_NO_KEY_PRESSED; - d->last_event = 0; - break; - case REMOTE_KEY_PRESSED: - deb_rc("KEY PRESSED\n"); - deb_rc("pressing event %d\n",event); - - input_event(d->rc_input_dev, EV_KEY, event, 1); - input_sync(d->rc_input_dev); - - d->last_event = event; - d->last_state = REMOTE_KEY_PRESSED; - break; - case REMOTE_KEY_REPEAT: - deb_rc("KEY_REPEAT\n"); - if (d->last_state != REMOTE_NO_KEY_PRESSED) { - deb_rc("repeating event %d\n",d->last_event); - input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); - input_sync(d->rc_input_dev); - d->last_state = REMOTE_KEY_REPEAT; - } - default: - break; - } -*/ - -schedule: - schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); -} - -static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int i, err, rc_interval; - struct input_dev *input_dev; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->name = "IR-receiver inside an USB DVB receiver"; - input_dev->phys = d->rc_phys; - usb_to_input_id(d->udev, &input_dev->id); - input_dev->dev.parent = &d->udev->dev; - d->input_dev = input_dev; - d->rc_dev = NULL; - - input_dev->getkeycode = legacy_dvb_usb_getkeycode; - input_dev->setkeycode = legacy_dvb_usb_setkeycode; - - /* set the bits for the keys */ - deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - deb_rc("setting bit for event %d item %d\n", - d->props.rc.legacy.rc_map_table[i].keycode, i); - set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); - } - - /* setting these two values to non-zero, we have to manage key repeats */ - input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; - input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; - - input_set_drvdata(input_dev, d); - - err = input_register_device(input_dev); - if (err) - input_free_device(input_dev); - - rc_interval = d->props.rc.legacy.rc_interval; - - INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); - - info("schedule remote query interval to %d msecs.", rc_interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(rc_interval)); - - d->state |= DVB_USB_STATE_REMOTE; - - return err; -} - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - * whether the remote control has received anything. - * - * TODO: Fix the repeat rate of the input device. - */ -static void dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, rc_query_work.work); - int err; - - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init - */ - if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) - return; - - err = d->props.rc.core.rc_query(d); - if (err) - err("error %d while querying for an remote control event.", err); - - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->props.rc.core.rc_interval)); -} - -static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int err, rc_interval; - struct rc_dev *dev; - - dev = rc_allocate_device(); - if (!dev) - return -ENOMEM; - - dev->driver_name = d->props.rc.core.module_name; - dev->map_name = d->props.rc.core.rc_codes; - dev->change_protocol = d->props.rc.core.change_protocol; - dev->allowed_protos = d->props.rc.core.allowed_protos; - dev->driver_type = d->props.rc.core.driver_type; - usb_to_input_id(d->udev, &dev->input_id); - dev->input_name = "IR-receiver inside an USB DVB receiver"; - dev->input_phys = d->rc_phys; - dev->dev.parent = &d->udev->dev; - dev->priv = d; - - err = rc_register_device(dev); - if (err < 0) { - rc_free_device(dev); - return err; - } - - d->input_dev = NULL; - d->rc_dev = dev; - - if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) - return 0; - - /* Polling mode - initialize a work queue for handling it */ - INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - - rc_interval = d->props.rc.core.rc_interval; - - info("schedule remote query interval to %d msecs.", rc_interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(rc_interval)); - - return 0; -} - -int dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int err; - - if (dvb_usb_disable_rc_polling) - return 0; - - if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) - d->props.rc.mode = DVB_RC_LEGACY; - else if (d->props.rc.core.rc_codes) - d->props.rc.mode = DVB_RC_CORE; - else - return 0; - - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - - /* Start the remote-control polling. */ - if (d->props.rc.legacy.rc_interval < 40) - d->props.rc.legacy.rc_interval = 100; /* default */ - - if (d->props.rc.mode == DVB_RC_LEGACY) - err = legacy_dvb_usb_remote_init(d); - else - err = rc_core_dvb_usb_remote_init(d); - if (err) - return err; - - d->state |= DVB_USB_STATE_REMOTE; - - return 0; -} - -int dvb_usb_remote_exit(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_REMOTE) { - cancel_delayed_work_sync(&d->rc_query_work); - if (d->props.rc.mode == DVB_RC_LEGACY) - input_unregister_device(d->input_dev); - else - rc_unregister_device(d->rc_dev); - } - d->state &= ~DVB_USB_STATE_REMOTE; - return 0; -} - -#define DVB_USB_RC_NEC_EMPTY 0x00 -#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 -#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 -int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, - u8 keybuf[5], u32 *event, int *state) -{ - int i; - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - switch (keybuf[0]) { - case DVB_USB_RC_NEC_EMPTY: - break; - case DVB_USB_RC_NEC_KEY_PRESSED: - if ((u8) ~keybuf[1] != keybuf[2] || - (u8) ~keybuf[3] != keybuf[4]) { - deb_err("remote control checksum failed.\n"); - break; - } - /* See if we can match the raw key code. */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (rc5_custom(&keymap[i]) == keybuf[1] && - rc5_data(&keymap[i]) == keybuf[3]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - return 0; - } - deb_err("key mapping failed - no appropriate key found in keymapping\n"); - break; - case DVB_USB_RC_NEC_KEY_REPEATED: - *state = REMOTE_KEY_REPEAT; - break; - default: - deb_err("unknown type of remote status: %d\n",keybuf[0]); - break; - } - return 0; -} -EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c deleted file mode 100644 index 5c8f651344f..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ /dev/null @@ -1,121 +0,0 @@ -/* dvb-usb-urb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file keeps functions for initializing and handling the - * USB and URB stuff. - */ -#include "dvb-usb-common.h" - -int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen, int delay_ms) -{ - int actlen,ret = -ENOMEM; - - if (!d || wbuf == NULL || wlen == 0) - return -EINVAL; - - if (d->props.generic_bulk_ctrl_endpoint == 0) { - err("endpoint for generic control not specified."); - return -EINVAL; - } - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - deb_xfer(">>> "); - debug_dump(wbuf,wlen,deb_xfer); - - ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, - 2000); - - if (ret) - err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); - else - ret = actlen != wlen ? -1 : 0; - - /* an answer is expected, and no error before */ - if (!ret && rbuf && rlen) { - if (delay_ms) - msleep(delay_ms); - - ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint_response ? - d->props.generic_bulk_ctrl_endpoint_response : - d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, - 2000); - - if (ret) - err("recv bulk message failed: %d",ret); - else { - deb_xfer("<<< "); - debug_dump(rbuf,actlen,deb_xfer); - } - } - - mutex_unlock(&d->usb_mutex); - return ret; -} -EXPORT_SYMBOL(dvb_usb_generic_rw); - -int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) -{ - return dvb_usb_generic_rw(d,buf,len,NULL,0,0); -} -EXPORT_SYMBOL(dvb_usb_generic_write); - -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter(&adap->demux, buffer, length); -} - -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_204(&adap->demux, buffer, length); -} - -static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, - u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_raw(&adap->demux, buffer, length); -} - -int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) -{ - int i, ret = 0; - for (i = 0; i < adap->props.num_frontends; i++) { - - adap->fe_adap[i].stream.udev = adap->dev->udev; - if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) - adap->fe_adap[i].stream.complete = - dvb_usb_data_complete_204; - else - if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) - adap->fe_adap[i].stream.complete = - dvb_usb_data_complete_raw; - else - adap->fe_adap[i].stream.complete = dvb_usb_data_complete; - adap->fe_adap[i].stream.user_priv = adap; - ret = usb_urb_init(&adap->fe_adap[i].stream, - &adap->props.fe[i].stream); - if (ret < 0) - break; - } - return ret; -} - -int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) -{ - int i; - for (i = 0; i < adap->props.num_frontends; i++) - usb_urb_exit(&adap->fe_adap[i].stream); - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h deleted file mode 100644 index aab0f99bc89..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ /dev/null @@ -1,483 +0,0 @@ -/* dvb-usb.h is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * the headerfile, all dvb-usb-drivers have to include. - * - * TODO: clean-up the structures for unused fields and update the comments - */ -#ifndef __DVB_USB_H__ -#define __DVB_USB_H__ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "dmxdev.h" - -#include "dvb-pll.h" - -#include "dvb-usb-ids.h" - -/* debug */ -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var,level,args...) \ - do { if ((var & level)) { printk(args); } } while (0) - -#define debug_dump(b,l,func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ - func("\n");\ -} -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define debug_dump(b,l,func) - -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" - -#endif - -/* generic log methods - taken from usb.h */ -#ifndef DVB_USB_LOG_PREFIX - #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)" -#endif - -#undef err -#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -/** - * struct dvb_usb_device_description - name and its according USB IDs - * @name: real name of the box, regardless which DVB USB device class is in use - * @cold_ids: array of struct usb_device_id which describe the device in - * pre-firmware state - * @warm_ids: array of struct usb_device_id which describe the device in - * post-firmware state - * - * Each DVB USB device class can have one or more actual devices, this struct - * assigns a name to it. - */ -struct dvb_usb_device_description { - const char *name; - -#define DVB_USB_ID_MAX_NUM 15 - struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; - struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; -}; - -static inline u8 rc5_custom(struct rc_map_table *key) -{ - return (key->scancode >> 8) & 0xff; -} - -static inline u8 rc5_data(struct rc_map_table *key) -{ - return key->scancode & 0xff; -} - -static inline u16 rc5_scan(struct rc_map_table *key) -{ - return key->scancode & 0xffff; -} - -struct dvb_usb_device; -struct dvb_usb_adapter; -struct usb_data_stream; - -/** - * Properties of USB streaming - TODO this structure should be somewhere else - * describes the kind of USB transfer used for data-streaming. - * (BULK or ISOC) - */ -struct usb_data_stream_properties { -#define USB_BULK 1 -#define USB_ISOC 2 - int type; - int count; - int endpoint; - - union { - struct { - int buffersize; /* per URB */ - } bulk; - struct { - int framesperurb; - int framesize; - int interval; - } isoc; - } u; -}; - -/** - * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. - * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. - * @caps: capabilities of the DVB USB device. - * @pid_filter_count: number of PID filter position in the optional hardware - * PID-filter. - * @num_frontends: number of frontends of the DVB USB adapter. - * @frontend_ctrl: called to power on/off active frontend. - * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the - * device (not URB submitting/killing). - * @pid_filter_ctrl: called to en/disable the PID filter, if any. - * @pid_filter: called to set/unset a PID for filtering. - * @frontend_attach: called to attach the possible frontends (fill fe-field - * of struct dvb_usb_device). - * @tuner_attach: called to attach the correct tuner and to fill pll_addr, - * pll_desc and pll_init_buf of struct dvb_usb_device). - * @stream: configuration of the USB streaming - */ -struct dvb_usb_adapter_fe_properties { -#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 -#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 -#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 -#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 -#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 - int caps; - int pid_filter_count; - - int (*streaming_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - - int (*frontend_attach) (struct dvb_usb_adapter *); - int (*tuner_attach) (struct dvb_usb_adapter *); - - struct usb_data_stream_properties stream; - - int size_of_priv; -}; - -#define MAX_NO_OF_FE_PER_ADAP 3 -struct dvb_usb_adapter_properties { - int size_of_priv; - - int (*frontend_ctrl) (struct dvb_frontend *, int); - - int num_frontends; - struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; -}; - -/** - * struct dvb_rc_legacy - old properties of remote controller - * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable - * remote control handling). - * @rc_map_size: number of items in @rc_map_table. - * @rc_query: called to query an event event. - * @rc_interval: time in ms between two queries. - */ -struct dvb_rc_legacy { -/* remote control properties */ -#define REMOTE_NO_KEY_PRESSED 0x00 -#define REMOTE_KEY_PRESSED 0x01 -#define REMOTE_KEY_REPEAT 0x02 - struct rc_map_table *rc_map_table; - int rc_map_size; - int (*rc_query) (struct dvb_usb_device *, u32 *, int *); - int rc_interval; -}; - -/** - * struct dvb_rc properties of remote controller, using rc-core - * @rc_codes: name of rc codes table - * @protocol: type of protocol(s) currently used by the driver - * @allowed_protos: protocol(s) supported by the driver - * @driver_type: Used to point if a device supports raw mode - * @change_protocol: callback to change protocol - * @rc_query: called to query an event event. - * @rc_interval: time in ms between two queries. - * @bulk_mode: device supports bulk mode for RC (disable polling mode) - */ -struct dvb_rc { - char *rc_codes; - u64 protocol; - u64 allowed_protos; - enum rc_driver_type driver_type; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); - char *module_name; - int (*rc_query) (struct dvb_usb_device *d); - int rc_interval; - bool bulk_mode; /* uses bulk mode */ -}; - -/** - * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one - * based on rc-core - * This is initialized/used only inside dvb-usb-remote.c. - * It shouldn't be set by the drivers. - */ -enum dvb_usb_mode { - DVB_RC_LEGACY, - DVB_RC_CORE, -}; - -/** - * struct dvb_usb_device_properties - properties of a dvb-usb-device - * @usb_ctrl: which USB device-side controller is in use. Needed for firmware - * download. - * @firmware: name of the firmware file. - * @download_firmware: called to download the firmware when the usb_ctrl is - * DEVICE_SPECIFIC. - * @no_reconnect: device doesn't do a reconnect after downloading the firmware, - * so do the warm initialization right after it - * - * @size_of_priv: how many bytes shall be allocated for the private field - * of struct dvb_usb_device. - * - * @power_ctrl: called to enable/disable power of the device. - * @read_mac_address: called to read the MAC address of the device. - * @identify_state: called to determine the state (cold or warm), when it - * is not distinguishable by the USB IDs. - * - * @rc: remote controller properties - * - * @i2c_algo: i2c_algorithm if the device has I2CoverUSB. - * - * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic - * endpoint which received control messages with bulk transfers. When this - * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- - * helper functions. - * - * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate - * endpoint for responses to control messages sent with bulk transfers via - * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used - * instead of the generic_bulk_ctrl_endpoint when reading usb responses in - * the dvb_usb_generic_rw helper function. - * - * @num_device_descs: number of struct dvb_usb_device_description in @devices - * @devices: array of struct dvb_usb_device_description compatibles with these - * properties. - */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 -struct dvb_usb_device_properties { - -#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 - int caps; - -#define DEVICE_SPECIFIC 0 -#define CYPRESS_AN2135 1 -#define CYPRESS_AN2235 2 -#define CYPRESS_FX2 3 - int usb_ctrl; - int (*download_firmware) (struct usb_device *, const struct firmware *); - const char *firmware; - int no_reconnect; - - int size_of_priv; - - int num_adapters; - struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - - int (*power_ctrl) (struct dvb_usb_device *, int); - int (*read_mac_address) (struct dvb_usb_device *, u8 []); - int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, - struct dvb_usb_device_description **, int *); - - struct { - enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ - struct dvb_rc_legacy legacy; - struct dvb_rc core; - } rc; - - struct i2c_algorithm *i2c_algo; - - int generic_bulk_ctrl_endpoint; - int generic_bulk_ctrl_endpoint_response; - - int num_device_descs; - struct dvb_usb_device_description devices[12]; -}; - -/** - * struct usb_data_stream - generic object of an USB stream - * @buf_num: number of buffer allocated. - * @buf_size: size of each buffer in buf_list. - * @buf_list: array containing all allocate buffers for streaming. - * @dma_addr: list of dma_addr_t for each buffer in buf_list. - * - * @urbs_initialized: number of URBs initialized. - * @urbs_submitted: number of URBs submitted. - */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 -struct usb_data_stream { - struct usb_device *udev; - struct usb_data_stream_properties props; - -#define USB_STATE_INIT 0x00 -#define USB_STATE_URB_BUF 0x01 - int state; - - void (*complete) (struct usb_data_stream *, u8 *, size_t); - - struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; - int buf_num; - unsigned long buf_size; - u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; - dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; - - int urbs_initialized; - int urbs_submitted; - - void *user_priv; -}; - -/** - * struct dvb_usb_adapter - a DVB adapter on a USB device - * @id: index of this adapter (starting with 0). - * - * @feedcount: number of reqested feeds (used for streaming-activation) - * @pid_filtering: is hardware pid_filtering used or not. - * - * @pll_addr: I2C address of the tuner for programming - * @pll_init: array containing the initialization buffer - * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board - * - * @dvb_adap: device's dvb_adapter. - * @dmxdev: device's dmxdev. - * @demux: device's software demuxer. - * @dvb_net: device's dvb_net interfaces. - * @dvb_frontend: device's frontend. - * @max_feed_count: how many feeds can be handled simultaneously by this - * device - * - * @fe_init: rerouted frontend-init (wakeup) function. - * @fe_sleep: rerouted frontend-sleep function. - * - * @stream: the usb data stream. - */ -struct dvb_usb_fe_adapter { - struct dvb_frontend *fe; - - int (*fe_init) (struct dvb_frontend *); - int (*fe_sleep) (struct dvb_frontend *); - - struct usb_data_stream stream; - - int pid_filtering; - int max_feed_count; - - void *priv; -}; - -struct dvb_usb_adapter { - struct dvb_usb_device *dev; - struct dvb_usb_adapter_properties props; - -#define DVB_USB_ADAP_STATE_INIT 0x000 -#define DVB_USB_ADAP_STATE_DVB 0x001 - int state; - - u8 id; - - int feedcount; - - /* dvb */ - struct dvb_adapter dvb_adap; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - - struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP]; - int active_fe; - int num_frontends_initialized; - - void *priv; -}; - -/** - * struct dvb_usb_device - object of a DVB USB device - * @props: copy of the struct dvb_usb_properties this device belongs to. - * @desc: pointer to the device's struct dvb_usb_device_description. - * @state: initialization and runtime state of the device. - * - * @powered: indicated whether the device is power or not. - * Powered is in/decremented for each call to modify the state. - * @udev: pointer to the device's struct usb_device. - * - * @usb_mutex: semaphore of USB control messages (reading needs two messages) - * @i2c_mutex: semaphore for i2c-transfers - * - * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB - * - * @rc_dev: rc device for the remote control (rc-core mode) - * @input_dev: input device for the remote control (legacy mode) - * @rc_query_work: struct work_struct frequent rc queries - * @last_event: last triggered event - * @last_state: last state (no, pressed, repeat) - * @owner: owner of the dvb_adapter - * @priv: private data of the actual driver (allocate by dvb-usb, size defined - * in size_of_priv of dvb_usb_properties). - */ -struct dvb_usb_device { - struct dvb_usb_device_properties props; - struct dvb_usb_device_description *desc; - - struct usb_device *udev; - -#define DVB_USB_STATE_INIT 0x000 -#define DVB_USB_STATE_I2C 0x001 -#define DVB_USB_STATE_DVB 0x002 -#define DVB_USB_STATE_REMOTE 0x004 - int state; - - int powered; - - /* locking */ - struct mutex usb_mutex; - - /* i2c */ - struct mutex i2c_mutex; - struct i2c_adapter i2c_adap; - - int num_adapters_initialized; - struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - - /* remote control */ - struct rc_dev *rc_dev; - struct input_dev *input_dev; - char rc_phys[64]; - struct delayed_work rc_query_work; - u32 last_event; - int last_state; - - struct module *owner; - - void *priv; -}; - -extern int dvb_usb_device_init(struct usb_interface *, - struct dvb_usb_device_properties *, - struct module *, struct dvb_usb_device **, - short *adapter_nums); -extern void dvb_usb_device_exit(struct usb_interface *); - -/* the generic read/write method for device control */ -extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); -extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); - -/* commonly used remote control parsing */ -extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); - -/* commonly used firmware download types and function */ -struct hexline { - u8 len; - u32 addr; - u8 type; - u8 data[255]; - u8 chk; -}; -extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); -extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); - - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c deleted file mode 100644 index 384fe8eec21..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ /dev/null @@ -1,403 +0,0 @@ -/* dvb-usb-dvb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for initializing and handling the - * linux-dvb API. - */ -#include "dvb_usb_common.h" - -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter(&adap->demux, buf, len); -} - -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter_204(&adap->demux, buf, len); -} - -static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter_raw(&adap->demux, buf, len); -} - -int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) -{ - pr_debug("%s: adap=%d\n", __func__, adap->id); - - adap->stream.udev = adap_to_d(adap)->udev; - adap->stream.user_priv = adap; - adap->stream.complete = dvb_usb_data_complete; - - return usb_urb_initv2(&adap->stream, &adap->props->stream); -} - -int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) -{ - pr_debug("%s: adap=%d\n", __func__, adap->id); - usb_urb_exitv2(&adap->stream); - - return 0; -} - -/* does the complete input transfer handling */ -static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count) -{ - struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \ - "%04x (%04d) at index %d '%s'\n", __func__, adap->id, - adap->active_fe, dvbdmxfeed->type, - adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, - dvbdmxfeed->pid, dvbdmxfeed->index, - (count == 1) ? "on" : "off"); - - if (adap->active_fe == -1) - return -EINVAL; - - adap->feed_count += count; - - /* stop feeding if it is last pid */ - if (adap->feed_count == 0) { - pr_debug("%s: stop feeding\n", __func__); - usb_urb_killv2(&adap->stream); - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl(adap, 0); - if (ret < 0) { - pr_err("%s: streaming_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_mutex_unlock; - } - } - mutex_unlock(&adap->sync_mutex); - } - - /* activate the pid on the device pid filter */ - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props->pid_filter) - ret = adap->props->pid_filter(adap, dvbdmxfeed->index, - dvbdmxfeed->pid, (count == 1) ? 1 : 0); - if (ret < 0) - pr_err("%s: pid_filter() failed=%d\n", - KBUILD_MODNAME, ret); - - /* start feeding if it is first pid */ - if (adap->feed_count == 1 && count == 1) { - struct usb_data_stream_properties stream_props; - mutex_lock(&adap->sync_mutex); - pr_debug("%s: start feeding\n", __func__); - - /* resolve input and output streaming paramters */ - if (d->props->get_stream_config) { - memcpy(&stream_props, &adap->props->stream, - sizeof(struct usb_data_stream_properties)); - ret = d->props->get_stream_config( - adap->fe[adap->active_fe], - &adap->ts_type, &stream_props); - if (ret < 0) - goto err_mutex_unlock; - } else { - stream_props = adap->props->stream; - } - - switch (adap->ts_type) { - case DVB_USB_FE_TS_TYPE_204: - adap->stream.complete = dvb_usb_data_complete_204; - break; - case DVB_USB_FE_TS_TYPE_RAW: - adap->stream.complete = dvb_usb_data_complete_raw; - break; - case DVB_USB_FE_TS_TYPE_188: - default: - adap->stream.complete = dvb_usb_data_complete; - break; - } - - usb_urb_submitv2(&adap->stream, &stream_props); - - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props->caps & - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props->pid_filter_ctrl) { - ret = adap->props->pid_filter_ctrl(adap, - adap->pid_filtering); - if (ret < 0) { - pr_err("%s: pid_filter_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_mutex_unlock; - } - } - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl(adap, 1); - if (ret < 0) { - pr_err("%s: streaming_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_mutex_unlock; - } - } - } - - return 0; -err_mutex_unlock: - mutex_unlock(&adap->sync_mutex); - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, 1); -} - -static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, -1); -} - -int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - pr_debug("%s: adap=%d\n", __func__, adap->id); - - ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, - &d->udev->dev, d->props->adapter_nr); - if (ret < 0) { - pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, - ret); - goto err; - } - - adap->dvb_adap.priv = adap; - - if (d->props->read_mac_address) { - ret = d->props->read_mac_address(adap, - adap->dvb_adap.proposed_mac); - if (ret < 0) - goto err_dmx; - - pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, - adap->dvb_adap.proposed_mac); - } - - adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - adap->demux.priv = adap; - adap->demux.filternum = 0; - if (adap->demux.filternum < adap->max_feed_count) - adap->demux.filternum = adap->max_feed_count; - adap->demux.feednum = adap->demux.filternum; - adap->demux.start_feed = dvb_usb_start_feed; - adap->demux.stop_feed = dvb_usb_stop_feed; - adap->demux.write_to_decoder = NULL; - ret = dvb_dmx_init(&adap->demux); - if (ret < 0) { - pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); - goto err_dmx; - } - - adap->dmxdev.filternum = adap->demux.filternum; - adap->dmxdev.demux = &adap->demux.dmx; - adap->dmxdev.capabilities = 0; - ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); - if (ret < 0) { - pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, - ret); - goto err_dmx_dev; - } - - ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - if (ret < 0) { - pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); - goto err_net_init; - } - - mutex_init(&adap->sync_mutex); - - return 0; -err_net_init: - dvb_dmxdev_release(&adap->dmxdev); -err_dmx_dev: - dvb_dmx_release(&adap->demux); -err_dmx: - dvb_unregister_adapter(&adap->dvb_adap); -err: - adap->dvb_adap.priv = NULL; - return ret; -} - -int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) -{ - pr_debug("%s: adap=%d\n", __func__, adap->id); - - if (adap->dvb_adap.priv) { - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - } - - return 0; -} - -static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap_to_d(adap); - mutex_lock(&adap->sync_mutex); - pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); - - ret = dvb_usbv2_device_power_ctrl(d, 1); - if (ret < 0) - goto err; - - if (d->props->frontend_ctrl) { - ret = d->props->frontend_ctrl(fe, 1); - if (ret < 0) - goto err; - } - - if (adap->fe_init[fe->id]) { - ret = adap->fe_init[fe->id](fe); - if (ret < 0) - goto err; - } - - adap->active_fe = fe->id; - mutex_unlock(&adap->sync_mutex); - - return 0; -err: - mutex_unlock(&adap->sync_mutex); - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_fe_sleep(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap_to_d(adap); - mutex_lock(&adap->sync_mutex); - pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); - - if (adap->fe_sleep[fe->id]) { - ret = adap->fe_sleep[fe->id](fe); - if (ret < 0) - goto err; - } - - if (d->props->frontend_ctrl) { - ret = d->props->frontend_ctrl(fe, 0); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_device_power_ctrl(d, 0); - if (ret < 0) - goto err; - - adap->active_fe = -1; - mutex_unlock(&adap->sync_mutex); - - return 0; -err: - mutex_unlock(&adap->sync_mutex); - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) -{ - int ret, i, count_registered = 0; - struct dvb_usb_device *d = adap_to_d(adap); - pr_debug("%s: adap=%d\n", __func__, adap->id); - - memset(adap->fe, 0, sizeof(adap->fe)); - adap->active_fe = -1; - - if (d->props->frontend_attach) { - ret = d->props->frontend_attach(adap); - if (ret < 0) { - pr_debug("%s: frontend_attach() failed=%d\n", __func__, - ret); - goto err_dvb_frontend_detach; - } - } else { - pr_debug("%s: frontend_attach() do not exists\n", __func__); - ret = 0; - goto err; - } - - for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { - adap->fe[i]->id = i; - - /* re-assign sleep and wakeup functions */ - adap->fe_init[i] = adap->fe[i]->ops.init; - adap->fe[i]->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep[i] = adap->fe[i]->ops.sleep; - adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; - - ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); - if (ret < 0) { - pr_err("%s: frontend%d registration failed\n", - KBUILD_MODNAME, i); - goto err_dvb_unregister_frontend; - } - - count_registered++; - } - - if (d->props->tuner_attach) { - ret = d->props->tuner_attach(adap); - if (ret < 0) { - pr_debug("%s: tuner_attach() failed=%d\n", __func__, - ret); - goto err_dvb_unregister_frontend; - } - } - - return 0; - -err_dvb_unregister_frontend: - for (i = count_registered - 1; i >= 0; i--) - dvb_unregister_frontend(adap->fe[i]); - -err_dvb_frontend_detach: - for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { - if (adap->fe[i]) - dvb_frontend_detach(adap->fe[i]); - } - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) -{ - int i; - pr_debug("%s: adap=%d\n", __func__, adap->id); - - for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { - if (adap->fe[i]) { - dvb_unregister_frontend(adap->fe[i]); - dvb_frontend_detach(adap->fe[i]); - } - } - - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c deleted file mode 100644 index f856ab6648c..00000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ /dev/null @@ -1,117 +0,0 @@ -/* dvb-usb-remote.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for initializing the input-device and for - * handling remote-control-queries. - */ -#include "dvb_usb_common.h" -#include - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - * whether the remote control has received anything. - * - * TODO: Fix the repeat rate of the input device. - */ -static void dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = container_of(work, - struct dvb_usb_device, rc_query_work.work); - int ret; - - /* TODO: need a lock here. We can simply skip checking for the remote - control if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init - */ - if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) - return; - - ret = d->rc.query(d); - if (ret < 0) - pr_err("%s: error %d while querying for an remote control " \ - "event\n", KBUILD_MODNAME, ret); - - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); -} - -int dvb_usbv2_remote_init(struct dvb_usb_device *d) -{ - int ret; - struct rc_dev *dev; - - if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) - return 0; - - ret = d->props->get_rc_config(d, &d->rc); - if (ret < 0) - goto err; - - dev = rc_allocate_device(); - if (!dev) { - ret = -ENOMEM; - goto err; - } - - dev->dev.parent = &d->udev->dev; - dev->input_name = "IR-receiver inside an USB DVB receiver"; - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - dev->input_phys = d->rc_phys; - usb_to_input_id(d->udev, &dev->input_id); - /* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props->driver_name; - dev->driver_type = d->rc.driver_type; - dev->allowed_protos = d->rc.allowed_protos; - dev->change_protocol = d->rc.change_protocol; - dev->priv = d; - /* select used keymap */ - if (d->rc.map_name) - dev->map_name = d->rc.map_name; - else if (d->rc_map) - dev->map_name = d->rc_map; - else - dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ - - ret = rc_register_device(dev); - if (ret < 0) { - rc_free_device(dev); - goto err; - } - - d->input_dev = NULL; - d->rc_dev = dev; - - /* start polling if needed */ - if (d->rc.query && !d->rc.bulk_mode) { - /* initialize a work queue for handling polling */ - INIT_DELAYED_WORK(&d->rc_query_work, - dvb_usb_read_remote_control); - pr_info("%s: schedule remote query interval to %d msecs\n", - KBUILD_MODNAME, d->rc.interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - } - - d->state |= DVB_USB_STATE_REMOTE; - - return 0; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_remote_exit(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_REMOTE) { - cancel_delayed_work_sync(&d->rc_query_work); - rc_unregister_device(d->rc_dev); - } - - d->state &= ~DVB_USB_STATE_REMOTE; - - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c deleted file mode 100644 index 9382895b1b8..00000000000 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ /dev/null @@ -1,1951 +0,0 @@ -/* DVB USB framework compliant Linux driver for the - * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, - * TeVii S600, S630, S650, S660, S480, - * Prof 1100, 7500, - * Geniatech SU3000 Cards - * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by) - * - * 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 "dw2102.h" -#include "si21xx.h" -#include "stv0299.h" -#include "z0194a.h" -#include "stv0288.h" -#include "stb6000.h" -#include "eds1547.h" -#include "cx24116.h" -#include "tda1002x.h" -#include "mt312.h" -#include "zl10039.h" -#include "ds3000.h" -#include "stv0900.h" -#include "stv6110.h" -#include "stb6100.h" -#include "stb6100_proc.h" - -#ifndef USB_PID_DW2102 -#define USB_PID_DW2102 0x2102 -#endif - -#ifndef USB_PID_DW2104 -#define USB_PID_DW2104 0x2104 -#endif - -#ifndef USB_PID_DW3101 -#define USB_PID_DW3101 0x3101 -#endif - -#ifndef USB_PID_CINERGY_S -#define USB_PID_CINERGY_S 0x0064 -#endif - -#ifndef USB_PID_TEVII_S630 -#define USB_PID_TEVII_S630 0xd630 -#endif - -#ifndef USB_PID_TEVII_S650 -#define USB_PID_TEVII_S650 0xd650 -#endif - -#ifndef USB_PID_TEVII_S660 -#define USB_PID_TEVII_S660 0xd660 -#endif - -#ifndef USB_PID_TEVII_S480_1 -#define USB_PID_TEVII_S480_1 0xd481 -#endif - -#ifndef USB_PID_TEVII_S480_2 -#define USB_PID_TEVII_S480_2 0xd482 -#endif - -#ifndef USB_PID_PROF_1100 -#define USB_PID_PROF_1100 0xb012 -#endif - -#define DW210X_READ_MSG 0 -#define DW210X_WRITE_MSG 1 - -#define REG_1F_SYMBOLRATE_BYTE0 0x1f -#define REG_20_SYMBOLRATE_BYTE1 0x20 -#define REG_21_SYMBOLRATE_BYTE2 0x21 -/* on my own*/ -#define DW2102_VOLTAGE_CTRL (0x1800) -#define SU3000_STREAM_CTRL (0x1900) -#define DW2102_RC_QUERY (0x1a00) -#define DW2102_LED_CTRL (0x1b00) - -#define err_str "did not find the firmware file. (%s) " \ - "Please see linux/Documentation/dvb/ for more details " \ - "on firmware-problems." - -struct rc_map_dvb_usb_table_table { - struct rc_map_table *rc_keys; - int rc_keys_size; -}; - -struct su3000_state { - u8 initialized; -}; - -struct s6x0_state { - int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); -}; - -/* debug */ -static int dvb_usb_dw2102_debug; -module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." - DVB_USB_DEBUG_STATUS); - -/* keymaps */ -static int ir_keymap; -module_param_named(keymap, ir_keymap, int, 0644); -MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." - " 256=none"); - -/* demod probe */ -static int demod_probe = 1; -module_param_named(demod, demod_probe, int, 0644); -MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " - "4=stv0903+stb6100(or-able))."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, - u16 index, u8 * data, u16 len, int flags) -{ - int ret; - u8 *u8buf; - unsigned int pipe = (flags == DW210X_READ_MSG) ? - usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); - u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; - - u8buf = kmalloc(len, GFP_KERNEL); - if (!u8buf) - return -ENOMEM; - - - if (flags == DW210X_WRITE_MSG) - memcpy(u8buf, data, len); - ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, - value, index , u8buf, len, 2000); - - if (flags == DW210X_READ_MSG) - memcpy(data, u8buf, len); - - kfree(u8buf); - return ret; -} - -/* I2C */ -static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0; - u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; - u16 value; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: - /* read stv0299 register */ - value = msg[0].buf[0];/* register */ - for (i = 0; i < msg[1].len; i++) { - dw210x_op_rw(d->udev, 0xb5, value + i, 0, - buf6, 2, DW210X_READ_MSG); - msg[1].buf[i] = buf6[0]; - } - break; - case 1: - switch (msg[0].addr) { - case 0x68: - /* write to stv0299 register */ - buf6[0] = 0x2a; - buf6[1] = msg[0].buf[0]; - buf6[2] = msg[0].buf[1]; - dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 3, DW210X_WRITE_MSG); - break; - case 0x60: - if (msg[0].flags == 0) { - /* write to tuner pll */ - buf6[0] = 0x2c; - buf6[1] = 5; - buf6[2] = 0xc0; - buf6[3] = msg[0].buf[0]; - buf6[4] = msg[0].buf[1]; - buf6[5] = msg[0].buf[2]; - buf6[6] = msg[0].buf[3]; - dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 7, DW210X_WRITE_MSG); - } else { - /* read from tuner */ - dw210x_op_rw(d->udev, 0xb5, 0, 0, - buf6, 1, DW210X_READ_MSG); - msg[0].buf[0] = buf6[0]; - } - break; - case (DW2102_RC_QUERY): - dw210x_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW210X_READ_MSG); - msg[0].buf[0] = buf6[0]; - msg[0].buf[1] = buf6[1]; - break; - case (DW2102_VOLTAGE_CTRL): - buf6[0] = 0x30; - buf6[1] = msg[0].buf[0]; - dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW210X_WRITE_MSG); - break; - } - - break; - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: - /* read si2109 register by number */ - buf6[0] = msg[0].addr << 1; - buf6[1] = msg[0].len; - buf6[2] = msg[0].buf[0]; - dw210x_op_rw(d->udev, 0xc2, 0, 0, - buf6, msg[0].len + 2, DW210X_WRITE_MSG); - /* read si2109 register */ - dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, - buf6, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, buf6 + 2, msg[1].len); - - break; - case 1: - switch (msg[0].addr) { - case 0x68: - /* write to si2109 register */ - buf6[0] = msg[0].addr << 1; - buf6[1] = msg[0].len; - memcpy(buf6 + 2, msg[0].buf, msg[0].len); - dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, - msg[0].len + 2, DW210X_WRITE_MSG); - break; - case(DW2102_RC_QUERY): - dw210x_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW210X_READ_MSG); - msg[0].buf[0] = buf6[0]; - msg[0].buf[1] = buf6[1]; - break; - case(DW2102_VOLTAGE_CTRL): - buf6[0] = 0x30; - buf6[1] = msg[0].buf[0]; - dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW210X_WRITE_MSG); - break; - } - break; - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: { - /* read */ - /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - obuf[2] = msg[0].buf[0]; - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - /* second read registers */ - dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf + 2, msg[1].len); - - break; - } - case 1: - switch (msg[0].addr) { - case 0x68: { - /* write to register */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } - case 0x61: { - /* write to tuner */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } - case(DW2102_RC_QUERY): { - u8 ibuf[2]; - dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); - break; - } - case(DW2102_VOLTAGE_CTRL): { - u8 obuf[2]; - obuf[0] = 0x30; - obuf[1] = msg[0].buf[0]; - dw210x_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - } - - break; - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int len, i, j; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (j = 0; j < num; j++) { - switch (msg[j].addr) { - case(DW2102_RC_QUERY): { - u8 ibuf[2]; - dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf , 2); - break; - } - case(DW2102_VOLTAGE_CTRL): { - u8 obuf[2]; - obuf[0] = 0x30; - obuf[1] = msg[j].buf[0]; - dw210x_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - /*case 0x55: cx24116 - case 0x6a: stv0903 - case 0x68: ds3000, stv0903 - case 0x60: ts2020, stv6110, stb6100 */ - default: { - if (msg[j].flags == I2C_M_RD) { - /* read registers */ - u8 ibuf[msg[j].len + 2]; - dw210x_op_rw(d->udev, 0xc3, - (msg[j].addr << 1) + 1, 0, - ibuf, msg[j].len + 2, - DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf + 2, msg[j].len); - mdelay(10); - } else if (((msg[j].buf[0] == 0xb0) && - (msg[j].addr == 0x68)) || - ((msg[j].buf[0] == 0xf7) && - (msg[j].addr == 0x55))) { - /* write firmware */ - u8 obuf[19]; - obuf[0] = msg[j].addr << 1; - obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); - obuf[2] = msg[j].buf[0]; - len = msg[j].len - 1; - i = 1; - do { - memcpy(obuf + 3, msg[j].buf + i, - (len > 16 ? 16 : len)); - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, - DW210X_WRITE_MSG); - i += 16; - len -= 16; - } while (len > 0); - } else { - /* write registers */ - u8 obuf[msg[j].len + 2]; - obuf[0] = msg[j].addr << 1; - obuf[1] = msg[j].len; - memcpy(obuf + 2, msg[j].buf, msg[j].len); - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); - } - break; - } - } - - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: { - /* read */ - /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - obuf[2] = msg[0].buf[0]; - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - /* second read registers */ - dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf + 2, msg[1].len); - - break; - } - case 1: - switch (msg[0].addr) { - case 0x60: - case 0x0c: { - /* write to register */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } - case(DW2102_RC_QUERY): { - u8 ibuf[2]; - dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); - break; - } - } - - break; - } - - for (i = 0; i < num; i++) { - deb_xfer("%02x:%02x: %s ", i, msg[i].addr, - msg[i].flags == 0 ? ">>>" : "<<<"); - debug_dump(msg[i].buf, msg[i].len, deb_xfer); - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct usb_device *udev; - int len, i, j; - - if (!d) - return -ENODEV; - udev = d->udev; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (j = 0; j < num; j++) { - switch (msg[j].addr) { - case (DW2102_RC_QUERY): { - u8 ibuf[5]; - dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 5, DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf + 3, 2); - break; - } - case (DW2102_VOLTAGE_CTRL): { - u8 obuf[2]; - - obuf[0] = 1; - obuf[1] = msg[j].buf[1];/* off-on */ - dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - obuf[0] = 3; - obuf[1] = msg[j].buf[0];/* 13v-18v */ - dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - case (DW2102_LED_CTRL): { - u8 obuf[2]; - - obuf[0] = 5; - obuf[1] = msg[j].buf[0]; - dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - /*case 0x55: cx24116 - case 0x6a: stv0903 - case 0x68: ds3000, stv0903 - case 0x60: ts2020, stv6110, stb6100 - case 0xa0: eeprom */ - default: { - if (msg[j].flags == I2C_M_RD) { - /* read registers */ - u8 ibuf[msg[j].len]; - dw210x_op_rw(d->udev, 0x91, 0, 0, - ibuf, msg[j].len, - DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf, msg[j].len); - break; - } else if ((msg[j].buf[0] == 0xb0) && - (msg[j].addr == 0x68)) { - /* write firmware */ - u8 obuf[19]; - obuf[0] = (msg[j].len > 16 ? - 18 : msg[j].len + 1); - obuf[1] = msg[j].addr << 1; - obuf[2] = msg[j].buf[0]; - len = msg[j].len - 1; - i = 1; - do { - memcpy(obuf + 3, msg[j].buf + i, - (len > 16 ? 16 : len)); - dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, - DW210X_WRITE_MSG); - i += 16; - len -= 16; - } while (len > 0); - } else if (j < (num - 1)) { - /* write register addr before read */ - u8 obuf[msg[j].len + 2]; - obuf[0] = msg[j + 1].len; - obuf[1] = (msg[j].addr << 1); - memcpy(obuf + 2, msg[j].buf, msg[j].len); - dw210x_op_rw(d->udev, - udev->descriptor.idProduct == - 0x7500 ? 0x92 : 0x90, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); - break; - } else { - /* write registers */ - u8 obuf[msg[j].len + 2]; - obuf[0] = msg[j].len + 1; - obuf[1] = (msg[j].addr << 1); - memcpy(obuf + 2, msg[j].buf, msg[j].len); - dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); - break; - } - break; - } - } - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - u8 obuf[0x40], ibuf[0x40]; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 1: - switch (msg[0].addr) { - case SU3000_STREAM_CTRL: - obuf[0] = msg[0].buf[0] + 0x36; - obuf[1] = 3; - obuf[2] = 0; - if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0) - err("i2c transfer failed."); - break; - case DW2102_RC_QUERY: - obuf[0] = 0x10; - if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0) - err("i2c transfer failed."); - msg[0].buf[1] = ibuf[0]; - msg[0].buf[0] = ibuf[1]; - break; - default: - /* always i2c write*/ - obuf[0] = 0x08; - obuf[1] = msg[0].addr; - obuf[2] = msg[0].len; - - memcpy(&obuf[3], msg[0].buf, msg[0].len); - - if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3, - ibuf, 1, 0) < 0) - err("i2c transfer failed."); - - } - break; - case 2: - /* always i2c read */ - obuf[0] = 0x09; - obuf[1] = msg[0].len; - obuf[2] = msg[1].len; - obuf[3] = msg[0].addr; - memcpy(&obuf[4], msg[0].buf, msg[0].len); - - if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4, - ibuf, msg[1].len + 1, 0) < 0) - err("i2c transfer failed."); - - memcpy(msg[1].buf, &ibuf[1], msg[1].len); - break; - default: - warn("more than 2 i2c messages at a time is not handled yet."); - break; - } - mutex_unlock(&d->i2c_mutex); - return num; -} - -static u32 dw210x_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dw2102_i2c_algo = { - .master_xfer = dw2102_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw2102_serit_i2c_algo = { - .master_xfer = dw2102_serit_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw2102_earda_i2c_algo = { - .master_xfer = dw2102_earda_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw2104_i2c_algo = { - .master_xfer = dw2104_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw3101_i2c_algo = { - .master_xfer = dw3101_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm s6x0_i2c_algo = { - .master_xfer = s6x0_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm su3000_i2c_algo = { - .master_xfer = su3000_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - int i; - u8 ibuf[] = {0, 0}; - u8 eeprom[256], eepromline[16]; - - for (i = 0; i < 256; i++) { - if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { - err("read eeprom failed."); - return -1; - } else { - eepromline[i%16] = ibuf[0]; - eeprom[i] = ibuf[0]; - } - if ((i % 16) == 15) { - deb_xfer("%02x: ", i - 15); - debug_dump(eepromline, 16, deb_xfer); - } - } - - memcpy(mac, eeprom + 8, 6); - return 0; -}; - -static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - int i, ret; - u8 ibuf[] = { 0 }, obuf[] = { 0 }; - u8 eeprom[256], eepromline[16]; - struct i2c_msg msg[] = { - { - .addr = 0xa0 >> 1, - .flags = 0, - .buf = obuf, - .len = 1, - }, { - .addr = 0xa0 >> 1, - .flags = I2C_M_RD, - .buf = ibuf, - .len = 1, - } - }; - - for (i = 0; i < 256; i++) { - obuf[0] = i; - ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); - if (ret != 2) { - err("read eeprom failed."); - return -1; - } else { - eepromline[i % 16] = ibuf[0]; - eeprom[i] = ibuf[0]; - } - - if ((i % 16) == 15) { - deb_xfer("%02x: ", i - 15); - debug_dump(eepromline, 16, deb_xfer); - } - } - - memcpy(mac, eeprom + 16, 6); - return 0; -}; - -static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - static u8 command_start[] = {0x00}; - static u8 command_stop[] = {0x01}; - struct i2c_msg msg = { - .addr = SU3000_STREAM_CTRL, - .flags = 0, - .buf = onoff ? command_start : command_stop, - .len = 1 - }; - - i2c_transfer(&adap->dev->i2c_adap, &msg, 1); - - return 0; -} - -static int su3000_power_ctrl(struct dvb_usb_device *d, int i) -{ - struct su3000_state *state = (struct su3000_state *)d->priv; - u8 obuf[] = {0xde, 0}; - - info("%s: %d, initialized %d\n", __func__, i, state->initialized); - - if (i && !state->initialized) { - state->initialized = 1; - /* reset board */ - dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0); - } - - return 0; -} - -static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - int i; - u8 obuf[] = { 0x1f, 0xf0 }; - u8 ibuf[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = 0x51, - .flags = 0, - .buf = obuf, - .len = 2, - }, { - .addr = 0x51, - .flags = I2C_M_RD, - .buf = ibuf, - .len = 1, - - } - }; - - for (i = 0; i < 6; i++) { - obuf[1] = 0xf0 + i; - if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) - break; - else - mac[i] = ibuf[0]; - - debug_dump(mac, 6, printk); - } - - return 0; -} - -static int su3000_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - info("%s\n", __func__); - - *cold = 0; - return 0; -} - -static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - static u8 command_13v[] = {0x00, 0x01}; - static u8 command_18v[] = {0x01, 0x01}; - static u8 command_off[] = {0x00, 0x00}; - struct i2c_msg msg = { - .addr = DW2102_VOLTAGE_CTRL, - .flags = 0, - .buf = command_off, - .len = 2, - }; - - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - if (voltage == SEC_VOLTAGE_18) - msg.buf = command_18v; - else if (voltage == SEC_VOLTAGE_13) - msg.buf = command_13v; - - i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); - - return 0; -} - -static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct dvb_usb_adapter *d = - (struct dvb_usb_adapter *)(fe->dvb->priv); - struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; - - dw210x_set_voltage(fe, voltage); - if (st->old_set_voltage) - st->old_set_voltage(fe, voltage); - - return 0; -} - -static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) -{ - static u8 led_off[] = { 0 }; - static u8 led_on[] = { 1 }; - struct i2c_msg msg = { - .addr = DW2102_LED_CTRL, - .flags = 0, - .buf = led_off, - .len = 1 - }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - - if (offon) - msg.buf = led_on; - i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); -} - -static struct stv0299_config sharp_z0194a_config = { - .demod_address = 0x68, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static struct cx24116_config dw2104_config = { - .demod_address = 0x55, - .mpg_clk_pos_pol = 0x01, -}; - -static struct si21xx_config serit_sp1511lhb_config = { - .demod_address = 0x68, - .min_delay_ms = 100, - -}; - -static struct tda10023_config dw3101_tda10023_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static struct mt312_config zl313_config = { - .demod_address = 0x0e, -}; - -static struct ds3000_config dw2104_ds3000_config = { - .demod_address = 0x68, -}; - -static struct stv0900_config dw2104a_stv0900_config = { - .demod_address = 0x6a, - .demod_mode = 0, - .xtal = 27000000, - .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ - .diseqc_mode = 2,/* 2/3 PWM */ - .tun1_maddress = 0,/* 0x60 */ - .tun1_adc = 0,/* 2 Vpp */ - .path1_mode = 3, -}; - -static struct stb6100_config dw2104a_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static struct stv0900_config dw2104_stv0900_config = { - .demod_address = 0x68, - .demod_mode = 0, - .xtal = 8000000, - .clkmode = 3, - .diseqc_mode = 2, - .tun1_maddress = 0, - .tun1_adc = 1,/* 1 Vpp */ - .path1_mode = 3, -}; - -static struct stv6110_config dw2104_stv6110_config = { - .i2c_address = 0x60, - .mclk = 16000000, - .clk_div = 1, -}; - -static struct stv0900_config prof_7500_stv0900_config = { - .demod_address = 0x6a, - .demod_mode = 0, - .xtal = 27000000, - .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ - .diseqc_mode = 2,/* 2/3 PWM */ - .tun1_maddress = 0,/* 0x60 */ - .tun1_adc = 0,/* 2 Vpp */ - .path1_mode = 3, - .tun1_type = 3, - .set_lock_led = dw210x_led_ctrl, -}; - -static struct ds3000_config su3000_ds3000_config = { - .demod_address = 0x68, - .ci_mode = 1, -}; - -static int dw2104_frontend_attach(struct dvb_usb_adapter *d) -{ - struct dvb_tuner_ops *tuner_ops = NULL; - - if (demod_probe & 4) { - d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe_adap[0].fe != NULL) { - if (dvb_attach(stb6100_attach, d->fe_adap[0].fe, - &dw2104a_stb6100_config, - &d->dev->i2c_adap)) { - tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops; - tuner_ops->set_frequency = stb6100_set_freq; - tuner_ops->get_frequency = stb6100_get_freq; - tuner_ops->set_bandwidth = stb6100_set_bandw; - tuner_ops->get_bandwidth = stb6100_get_bandw; - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached STV0900+STB6100!\n"); - return 0; - } - } - } - - if (demod_probe & 2) { - d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe_adap[0].fe != NULL) { - if (dvb_attach(stv6110_attach, d->fe_adap[0].fe, - &dw2104_stv6110_config, - &d->dev->i2c_adap)) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached STV0900+STV6110A!\n"); - return 0; - } - } - } - - if (demod_probe & 1) { - d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached cx24116!\n"); - return 0; - } - } - - d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached DS3000!\n"); - return 0; - } - - return -EIO; -} - -static struct dvb_usb_device_properties dw2102_properties; -static struct dvb_usb_device_properties dw2104_properties; -static struct dvb_usb_device_properties s6x0_properties; - -static int dw2102_frontend_attach(struct dvb_usb_adapter *d) -{ - if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { - /*dw2102_properties.adapter->tuner_attach = NULL;*/ - d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached si21xx!\n"); - return 0; - } - } - - if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { - if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, - &d->dev->i2c_adap)) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0288!\n"); - return 0; - } - } - } - - if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { - /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ - d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0299!\n"); - return 0; - } - } - return -EIO; -} - -static int dw3101_frontend_attach(struct dvb_usb_adapter *d) -{ - d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, - &d->dev->i2c_adap, 0x48); - if (d->fe_adap[0].fe != NULL) { - info("Attached tda10023!\n"); - return 0; - } - return -EIO; -} - -static int zl100313_frontend_attach(struct dvb_usb_adapter *d) -{ - d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { - if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60, - &d->dev->i2c_adap)) { - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - info("Attached zl100313+zl10039!\n"); - return 0; - } - } - - return -EIO; -} - -static int stv0288_frontend_attach(struct dvb_usb_adapter *d) -{ - u8 obuf[] = {7, 1}; - - d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, - &d->dev->i2c_adap); - - if (d->fe_adap[0].fe == NULL) - return -EIO; - - if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap)) - return -EIO; - - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - - dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - - info("Attached stv0288+stb6000!\n"); - - return 0; - -} - -static int ds3000_frontend_attach(struct dvb_usb_adapter *d) -{ - struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; - u8 obuf[] = {7, 1}; - - d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, - &d->dev->i2c_adap); - - if (d->fe_adap[0].fe == NULL) - return -EIO; - - st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage; - d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage; - - dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - - info("Attached ds3000+ds2020!\n"); - - return 0; -} - -static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) -{ - u8 obuf[] = {7, 1}; - - d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe_adap[0].fe == NULL) - return -EIO; - - d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; - - dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - - info("Attached STV0900+STB6100A!\n"); - - return 0; -} - -static int su3000_frontend_attach(struct dvb_usb_adapter *d) -{ - u8 obuf[3] = { 0xe, 0x80, 0 }; - u8 ibuf[] = { 0 }; - - if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) - err("command 0x0e transfer failed."); - - obuf[0] = 0xe; - obuf[1] = 0x83; - obuf[2] = 0; - - if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) - err("command 0x0e transfer failed."); - - obuf[0] = 0xe; - obuf[1] = 0x83; - obuf[2] = 1; - - if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) - err("command 0x0e transfer failed."); - - obuf[0] = 0x51; - - if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) - err("command 0x51 transfer failed."); - - d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe == NULL) - return -EIO; - - info("Attached DS3000!\n"); - - return 0; -} - -static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, - &adap->dev->i2c_adap, DVB_PLL_OPERA1); - return 0; -} - -static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, - &adap->dev->i2c_adap, DVB_PLL_TUA6034); - - return 0; -} - -static struct rc_map_table rc_map_dw210x_table[] = { - { 0xf80a, KEY_POWER2 }, /*power*/ - { 0xf80c, KEY_MUTE }, /*mute*/ - { 0xf811, KEY_1 }, - { 0xf812, KEY_2 }, - { 0xf813, KEY_3 }, - { 0xf814, KEY_4 }, - { 0xf815, KEY_5 }, - { 0xf816, KEY_6 }, - { 0xf817, KEY_7 }, - { 0xf818, KEY_8 }, - { 0xf819, KEY_9 }, - { 0xf810, KEY_0 }, - { 0xf81c, KEY_CHANNELUP }, /*ch+*/ - { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ - { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ - { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ - { 0xf804, KEY_RECORD }, /*rec*/ - { 0xf809, KEY_FAVORITES }, /*fav*/ - { 0xf808, KEY_REWIND }, /*rewind*/ - { 0xf807, KEY_FASTFORWARD }, /*fast*/ - { 0xf80b, KEY_PAUSE }, /*pause*/ - { 0xf802, KEY_ESC }, /*cancel*/ - { 0xf803, KEY_TAB }, /*tab*/ - { 0xf800, KEY_UP }, /*up*/ - { 0xf81f, KEY_OK }, /*ok*/ - { 0xf801, KEY_DOWN }, /*down*/ - { 0xf805, KEY_CAMERA }, /*cap*/ - { 0xf806, KEY_STOP }, /*stop*/ - { 0xf840, KEY_ZOOM }, /*full*/ - { 0xf81e, KEY_TV }, /*tvmode*/ - { 0xf81b, KEY_LAST }, /*recall*/ -}; - -static struct rc_map_table rc_map_tevii_table[] = { - { 0xf80a, KEY_POWER }, - { 0xf80c, KEY_MUTE }, - { 0xf811, KEY_1 }, - { 0xf812, KEY_2 }, - { 0xf813, KEY_3 }, - { 0xf814, KEY_4 }, - { 0xf815, KEY_5 }, - { 0xf816, KEY_6 }, - { 0xf817, KEY_7 }, - { 0xf818, KEY_8 }, - { 0xf819, KEY_9 }, - { 0xf810, KEY_0 }, - { 0xf81c, KEY_MENU }, - { 0xf80f, KEY_VOLUMEDOWN }, - { 0xf81a, KEY_LAST }, - { 0xf80e, KEY_OPEN }, - { 0xf804, KEY_RECORD }, - { 0xf809, KEY_VOLUMEUP }, - { 0xf808, KEY_CHANNELUP }, - { 0xf807, KEY_PVR }, - { 0xf80b, KEY_TIME }, - { 0xf802, KEY_RIGHT }, - { 0xf803, KEY_LEFT }, - { 0xf800, KEY_UP }, - { 0xf81f, KEY_OK }, - { 0xf801, KEY_DOWN }, - { 0xf805, KEY_TUNER }, - { 0xf806, KEY_CHANNELDOWN }, - { 0xf840, KEY_PLAYPAUSE }, - { 0xf81e, KEY_REWIND }, - { 0xf81b, KEY_FAVORITES }, - { 0xf81d, KEY_BACK }, - { 0xf84d, KEY_FASTFORWARD }, - { 0xf844, KEY_EPG }, - { 0xf84c, KEY_INFO }, - { 0xf841, KEY_AB }, - { 0xf843, KEY_AUDIO }, - { 0xf845, KEY_SUBTITLE }, - { 0xf84a, KEY_LIST }, - { 0xf846, KEY_F1 }, - { 0xf847, KEY_F2 }, - { 0xf85e, KEY_F3 }, - { 0xf85c, KEY_F4 }, - { 0xf852, KEY_F5 }, - { 0xf85a, KEY_F6 }, - { 0xf856, KEY_MODE }, - { 0xf858, KEY_SWITCHVIDEOMODE }, -}; - -static struct rc_map_table rc_map_tbs_table[] = { - { 0xf884, KEY_POWER }, - { 0xf894, KEY_MUTE }, - { 0xf887, KEY_1 }, - { 0xf886, KEY_2 }, - { 0xf885, KEY_3 }, - { 0xf88b, KEY_4 }, - { 0xf88a, KEY_5 }, - { 0xf889, KEY_6 }, - { 0xf88f, KEY_7 }, - { 0xf88e, KEY_8 }, - { 0xf88d, KEY_9 }, - { 0xf892, KEY_0 }, - { 0xf896, KEY_CHANNELUP }, - { 0xf891, KEY_CHANNELDOWN }, - { 0xf893, KEY_VOLUMEUP }, - { 0xf88c, KEY_VOLUMEDOWN }, - { 0xf883, KEY_RECORD }, - { 0xf898, KEY_PAUSE }, - { 0xf899, KEY_OK }, - { 0xf89a, KEY_SHUFFLE }, - { 0xf881, KEY_UP }, - { 0xf890, KEY_LEFT }, - { 0xf882, KEY_RIGHT }, - { 0xf888, KEY_DOWN }, - { 0xf895, KEY_FAVORITES }, - { 0xf897, KEY_SUBTITLE }, - { 0xf89d, KEY_ZOOM }, - { 0xf89f, KEY_EXIT }, - { 0xf89e, KEY_MENU }, - { 0xf89c, KEY_EPG }, - { 0xf880, KEY_PREVIOUS }, - { 0xf89b, KEY_MODE } -}; - -static struct rc_map_table rc_map_su3000_table[] = { - { 0x25, KEY_POWER }, /* right-bottom Red */ - { 0x0a, KEY_MUTE }, /* -/-- */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, - { 0x20, KEY_UP }, /* CH+ */ - { 0x21, KEY_DOWN }, /* CH+ */ - { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ - { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ - { 0x1f, KEY_RECORD }, - { 0x17, KEY_PLAY }, - { 0x16, KEY_PAUSE }, - { 0x0b, KEY_STOP }, - { 0x27, KEY_FASTFORWARD },/* >> */ - { 0x26, KEY_REWIND }, /* << */ - { 0x0d, KEY_OK }, /* Mute */ - { 0x11, KEY_LEFT }, /* VOL- */ - { 0x10, KEY_RIGHT }, /* VOL+ */ - { 0x29, KEY_BACK }, /* button under 9 */ - { 0x2c, KEY_MENU }, /* TTX */ - { 0x2b, KEY_EPG }, /* EPG */ - { 0x1e, KEY_RED }, /* OSD */ - { 0x0e, KEY_GREEN }, /* Window */ - { 0x2d, KEY_YELLOW }, /* button under << */ - { 0x0f, KEY_BLUE }, /* bottom yellow button */ - { 0x14, KEY_AUDIO }, /* Snapshot */ - { 0x38, KEY_TV }, /* TV/Radio */ - { 0x0c, KEY_ESC } /* upper Red button */ -}; - -static struct rc_map_dvb_usb_table_table keys_tables[] = { - { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, - { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, - { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, - { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, -}; - -static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int keymap_size = d->props.rc.legacy.rc_map_size; - u8 key[2]; - struct i2c_msg msg = { - .addr = DW2102_RC_QUERY, - .flags = I2C_M_RD, - .buf = key, - .len = 2 - }; - int i; - /* override keymap */ - if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { - keymap = keys_tables[ir_keymap - 1].rc_keys ; - keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; - } else if (ir_keymap > ARRAY_SIZE(keys_tables)) - return 0; /* none */ - - *state = REMOTE_NO_KEY_PRESSED; - if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { - for (i = 0; i < keymap_size ; i++) { - if (rc5_data(&keymap[i]) == msg.buf[0]) { - *state = REMOTE_KEY_PRESSED; - *event = keymap[i].keycode; - break; - } - - } - - if ((*state) == REMOTE_KEY_PRESSED) - deb_rc("%s: found rc key: %x, %x, event: %x\n", - __func__, key[0], key[1], (*event)); - else if (key[0] != 0xff) - deb_rc("%s: unknown rc key: %x, %x\n", - __func__, key[0], key[1]); - - } - - return 0; -} - -enum dw2102_table_entry { - CYPRESS_DW2102, - CYPRESS_DW2101, - CYPRESS_DW2104, - TEVII_S650, - TERRATEC_CINERGY_S, - CYPRESS_DW3101, - TEVII_S630, - PROF_1100, - TEVII_S660, - PROF_7500, - GENIATECH_SU3000, - TERRATEC_CINERGY_S2, - TEVII_S480_1, - TEVII_S480_2, - X3M_SPC1400HD, -}; - -static struct usb_device_id dw2102_table[] = { - [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, - [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, - [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, - [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, - [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, - [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, - [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, - [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, - [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)}, - [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)}, - [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, - [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, - [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, - [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, - { } -}; - -MODULE_DEVICE_TABLE(usb, dw2102_table); - -static int dw2102_load_firmware(struct usb_device *dev, - const struct firmware *frmwr) -{ - u8 *b, *p; - int ret = 0, i; - u8 reset; - u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; - const struct firmware *fw; - const char *fw_2101 = "dvb-usb-dw2101.fw"; - - switch (dev->descriptor.idProduct) { - case 0x2101: - ret = request_firmware(&fw, fw_2101, &dev->dev); - if (ret != 0) { - err(err_str, fw_2101); - return ret; - } - break; - default: - fw = frmwr; - break; - } - info("start downloading DW210X firmware"); - p = kmalloc(fw->size, GFP_KERNEL); - reset = 1; - /*stop the CPU*/ - dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); - - if (p != NULL) { - memcpy(p, fw->data, fw->size); - for (i = 0; i < fw->size; i += 0x40) { - b = (u8 *) p + i; - if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, - DW210X_WRITE_MSG) != 0x40) { - err("error while transferring firmware"); - ret = -EINVAL; - break; - } - } - /* restart the CPU */ - reset = 0; - if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, - DW210X_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, - DW210X_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - /* init registers */ - switch (dev->descriptor.idProduct) { - case USB_PID_TEVII_S650: - dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; - dw2104_properties.rc.legacy.rc_map_size = - ARRAY_SIZE(rc_map_tevii_table); - case USB_PID_DW2104: - reset = 1; - dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, - DW210X_WRITE_MSG); - /* break omitted intentionally */ - case USB_PID_DW3101: - reset = 0; - dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW210X_WRITE_MSG); - break; - case USB_PID_CINERGY_S: - case USB_PID_DW2102: - dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW210X_READ_MSG); - /* check STV0299 frontend */ - dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, - DW210X_READ_MSG); - if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { - dw2102_properties.i2c_algo = &dw2102_i2c_algo; - dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach; - break; - } else { - /* check STV0288 frontend */ - reset16[0] = 0xd0; - reset16[1] = 1; - reset16[2] = 0; - dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, - DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, - DW210X_READ_MSG); - if (reset16[2] == 0x11) { - dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; - break; - } - } - case 0x2101: - dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, - DW210X_READ_MSG); - dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW210X_READ_MSG); - dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW210X_READ_MSG); - dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW210X_READ_MSG); - break; - } - - msleep(100); - kfree(p); - } - return ret; -} - -static struct dvb_usb_device_properties dw2102_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dw2102.fw", - .no_reconnect = 1, - - .i2c_algo = &dw2102_serit_i2c_algo, - - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = dw210x_read_mac_address, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = dw2102_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .num_device_descs = 3, - .devices = { - {"DVBWorld DVB-S 2102 USB2.0", - {&dw2102_table[CYPRESS_DW2102], NULL}, - {NULL}, - }, - {"DVBWorld DVB-S 2101 USB2.0", - {&dw2102_table[CYPRESS_DW2101], NULL}, - {NULL}, - }, - {"TerraTec Cinergy S USB", - {&dw2102_table[TERRATEC_CINERGY_S], NULL}, - {NULL}, - }, - } -}; - -static struct dvb_usb_device_properties dw2104_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dw2104.fw", - .no_reconnect = 1, - - .i2c_algo = &dw2104_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = dw210x_read_mac_address, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = dw2104_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .num_device_descs = 2, - .devices = { - { "DVBWorld DW2104 USB2.0", - {&dw2102_table[CYPRESS_DW2104], NULL}, - {NULL}, - }, - { "TeVii S650 USB2.0", - {&dw2102_table[TEVII_S650], NULL}, - {NULL}, - }, - } -}; - -static struct dvb_usb_device_properties dw3101_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dw3101.fw", - .no_reconnect = 1, - - .i2c_algo = &dw3101_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = dw210x_read_mac_address, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = dw3101_frontend_attach, - .tuner_attach = dw3101_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .num_device_descs = 1, - .devices = { - { "DVBWorld DVB-C 3101 USB2.0", - {&dw2102_table[CYPRESS_DW3101], NULL}, - {NULL}, - }, - } -}; - -static struct dvb_usb_device_properties s6x0_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct s6x0_state), - .firmware = "dvb-usb-s630.fw", - .no_reconnect = 1, - - .i2c_algo = &s6x0_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_tevii_table, - .rc_map_size = ARRAY_SIZE(rc_map_tevii_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = s6x0_read_mac_address, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = zl100313_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .num_device_descs = 1, - .devices = { - {"TeVii S630 USB", - {&dw2102_table[TEVII_S630], NULL}, - {NULL}, - }, - } -}; - -struct dvb_usb_device_properties *p1100; -static struct dvb_usb_device_description d1100 = { - "Prof 1100 USB ", - {&dw2102_table[PROF_1100], NULL}, - {NULL}, -}; - -struct dvb_usb_device_properties *s660; -static struct dvb_usb_device_description d660 = { - "TeVii S660 USB", - {&dw2102_table[TEVII_S660], NULL}, - {NULL}, -}; - -static struct dvb_usb_device_description d480_1 = { - "TeVii S480.1 USB", - {&dw2102_table[TEVII_S480_1], NULL}, - {NULL}, -}; - -static struct dvb_usb_device_description d480_2 = { - "TeVii S480.2 USB", - {&dw2102_table[TEVII_S480_2], NULL}, - {NULL}, -}; - -struct dvb_usb_device_properties *p7500; -static struct dvb_usb_device_description d7500 = { - "Prof 7500 USB DVB-S2", - {&dw2102_table[PROF_7500], NULL}, - {NULL}, -}; - -static struct dvb_usb_device_properties su3000_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct su3000_state), - .power_ctrl = su3000_power_ctrl, - .num_adapters = 1, - .identify_state = su3000_identify_state, - .i2c_algo = &su3000_i2c_algo, - - .rc.legacy = { - .rc_map_table = rc_map_su3000_table, - .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .read_mac_address = su3000_read_mac_address, - - .generic_bulk_ctrl_endpoint = 0x01, - - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = su3000_streaming_ctrl, - .frontend_attach = su3000_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - } - }}, - } - }, - .num_device_descs = 3, - .devices = { - { "SU3000HD DVB-S USB2.0", - { &dw2102_table[GENIATECH_SU3000], NULL }, - { NULL }, - }, - { "Terratec Cinergy S2 USB HD", - { &dw2102_table[TERRATEC_CINERGY_S2], NULL }, - { NULL }, - }, - { "X3M TV SPC1400HD PCI", - { &dw2102_table[X3M_SPC1400HD], NULL }, - { NULL }, - }, - } -}; - -static int dw2102_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - p1100 = kmemdup(&s6x0_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p1100) - return -ENOMEM; - /* copy default structure */ - /* fill only different fields */ - p1100->firmware = "dvb-usb-p1100.fw"; - p1100->devices[0] = d1100; - p1100->rc.legacy.rc_map_table = rc_map_tbs_table; - p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); - p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; - - s660 = kmemdup(&s6x0_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!s660) { - kfree(p1100); - return -ENOMEM; - } - s660->firmware = "dvb-usb-s660.fw"; - s660->num_device_descs = 3; - s660->devices[0] = d660; - s660->devices[1] = d480_1; - s660->devices[2] = d480_2; - s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach; - - p7500 = kmemdup(&s6x0_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p7500) { - kfree(p1100); - kfree(s660); - return -ENOMEM; - } - p7500->firmware = "dvb-usb-p7500.fw"; - p7500->devices[0] = d7500; - p7500->rc.legacy.rc_map_table = rc_map_tbs_table; - p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); - p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; - - if (0 == dvb_usb_device_init(intf, &dw2102_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dw2104_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dw3101_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &s6x0_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, p1100, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, s660, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, p7500, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &su3000_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -ENODEV; -} - -static struct usb_driver dw2102_driver = { - .name = "dw2102", - .probe = dw2102_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dw2102_table, -}; - -module_usb_driver(dw2102_driver); - -MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); -MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," - " DVB-C 3101 USB2.0," - " TeVii S600, S630, S650, S660, S480," - " Prof 1100, 7500 USB2.0," - " Geniatech SU3000 devices"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h deleted file mode 100644 index 5cd0b0eb6ce..00000000000 --- a/drivers/media/dvb/dvb-usb/dw2102.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _DW2102_H_ -#define _DW2102_H_ - -#define DVB_USB_LOG_PREFIX "dw2102" -#include "dvb-usb.h" - -#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args) -#endif diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c deleted file mode 100644 index 90a70c66a96..00000000000 --- a/drivers/media/dvb/dvb-usb/friio-fe.c +++ /dev/null @@ -1,473 +0,0 @@ -/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. - * - * Copyright (C) 2009 Akihiro Tsukada - * - * 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 -#include -#include - -#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, const 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 [+ 142857 (center freq. shift)] */ - f = freq / state->frontend.ops.info.frequency_stepsize; - /* add 399[1/7 MHZ] = 57MHz for the IF */ - f += 399; - /* add center frequency shift if necessary */ - if (f % 7 == 0) - f++; - 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_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; -} - - -/* filter out un-supported properties to notify users */ -static int jdvbt90502_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - int r = 0; - - switch (tvp->cmd) { - case DTV_DELIVERY_SYSTEM: - if (tvp->u.data != SYS_ISDBT) - r = -EINVAL; - break; - case DTV_CLEAR: - case DTV_TUNE: - case DTV_FREQUENCY: - break; - default: - r = -EINVAL; - } - return r; -} - -static int jdvbt90502_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - p->inversion = INVERSION_AUTO; - p->bandwidth_hz = 6000000; - p->code_rate_HP = FEC_AUTO; - p->code_rate_LP = FEC_AUTO; - p->modulation = QAM_64; - p->transmission_mode = TRANSMISSION_MODE_AUTO; - p->guard_interval = GUARD_INTERVAL_AUTO; - p->hierarchy = HIERARCHY_AUTO; - return 0; -} - -static int jdvbt90502_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - - /** - * NOTE: ignore all the parameters 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); - - /* for recovery from DTV_CLEAN */ - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - - ret = jdvbt90502_pll_set_freq(state, p->frequency); - if (ret) { - deb_fe("%s:ret == %d\n", __func__, ret); - return -EREMOTEIO; - } - - 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}, -}; - -static const 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; - } - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - 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 = { - .delsys = { SYS_ISDBT }, - .info = { - .name = "Comtech JDVBT90502 ISDB-T", - .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, - .write = _jdvbt90502_write, - - .set_property = jdvbt90502_set_property, - - .set_frontend = jdvbt90502_set_frontend, - .get_frontend = jdvbt90502_get_frontend, - - .read_status = jdvbt90502_read_status, - .read_signal_strength = jdvbt90502_read_signal_strength, -}; diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c deleted file mode 100644 index 474a17e4db0..00000000000 --- a/drivers/media/dvb/dvb-usb/friio.c +++ /dev/null @@ -1,522 +0,0 @@ -/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. - * - * Copyright (C) 2009 Akihiro Tsukada - * - * 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; - u32 mask; - u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0; - - buf = kmalloc(2, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - 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); - - kfree(buf); - 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, *wbuf; - - deb_info("%s called.\n", __func__); - - wbuf = kmalloc(3, GFP_KERNEL); - if (!wbuf) - return -ENOMEM; - - rbuf = kmalloc(2, GFP_KERNEL); - if (!rbuf) { - kfree(wbuf); - return -ENOMEM; - } - - /* 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: - kfree(wbuf); - kfree(rbuf); - 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_adap[0].fe = jdvbt90502_attach(adap->dev); - if (adap->fe_adap[0].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, -}; - -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. */ - { - .num_frontends = 1, - .fe = {{ - .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_usb_driver(friio_driver); - -MODULE_AUTHOR("Akihiro Tsukada "); -MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver"); -MODULE_VERSION("0.2"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/friio.h b/drivers/media/dvb/dvb-usb/friio.h deleted file mode 100644 index 0f461ca10cb..00000000000 --- a/drivers/media/dvb/dvb-usb/friio.h +++ /dev/null @@ -1,99 +0,0 @@ -/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. - * - * Copyright (C) 2009 Akihiro Tsukada - * - * 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) control: 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/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c deleted file mode 100644 index 67957dd99ed..00000000000 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ /dev/null @@ -1,369 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module - * - * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) - * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) - * - * Thanks to GENPIX for the sample code used to implement this module. - * - * This module is based off the vp7045 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 "gp8psk.h" - -struct gp8psk_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; - u8 lock; - u16 snr; - unsigned long next_status_check; - unsigned long status_check_interval; -}; - -static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 status; - gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); - return status & bmDCtuned; -} - -static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) -{ - struct gp8psk_fe_state *state = fe->demodulator_priv; - return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); -} - -static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) -{ - u8 buf[6]; - if (time_after(jiffies,st->next_status_check)) { - gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); - gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); - st->snr = (buf[1]) << 8 | buf[0]; - st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; - } - return 0; -} - -static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - gp8psk_fe_update_status(st); - - if (st->lock) - *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - *status = 0; - - if (*status & FE_HAS_LOCK) - st->status_check_interval = 1000; - else - st->status_check_interval = 100; - return 0; -} - -/* not supported by this Frontend */ -static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - (void) fe; - *ber = 0; - return 0; -} - -/* not supported by this Frontend */ -static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - (void) fe; - *unc = 0; - return 0; -} - -static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - gp8psk_fe_update_status(st); - /* snr is reported in dBu*256 */ - *snr = st->snr; - return 0; -} - -static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - gp8psk_fe_update_status(st); - /* snr is reported in dBu*256 */ - /* snr / 38.4 ~= 100% strength */ - /* snr * 17 returns 100% strength as 65535 */ - if (st->snr > 0xf00) - *strength = 0xffff; - else - *strength = (st->snr << 4) + st->snr; /* snr*17 */ - return 0; -} - -static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) -{ - struct gp8psk_fe_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 cmd[10]; - u32 freq = c->frequency * 1000; - int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); - - deb_fe("%s()\n", __func__); - - cmd[4] = freq & 0xff; - cmd[5] = (freq >> 8) & 0xff; - cmd[6] = (freq >> 16) & 0xff; - cmd[7] = (freq >> 24) & 0xff; - - /* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */ - if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8) - c->delivery_system = SYS_TURBO; - - switch (c->delivery_system) { - case SYS_DVBS: - if (c->modulation != QPSK) { - deb_fe("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } - c->fec_inner = FEC_AUTO; - break; - case SYS_DVBS2: /* kept for backwards compatibility */ - deb_fe("%s: DVB-S2 delivery system selected\n", __func__); - break; - case SYS_TURBO: - deb_fe("%s: Turbo-FEC delivery system selected\n", __func__); - break; - - default: - deb_fe("%s: unsupported delivery system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; - } - - cmd[0] = c->symbol_rate & 0xff; - cmd[1] = (c->symbol_rate >> 8) & 0xff; - cmd[2] = (c->symbol_rate >> 16) & 0xff; - cmd[3] = (c->symbol_rate >> 24) & 0xff; - switch (c->modulation) { - case QPSK: - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_tuned_to_DCII(fe)) - gp8psk_bcm4500_reload(state->d); - switch (c->fec_inner) { - case FEC_1_2: - cmd[9] = 0; break; - case FEC_2_3: - cmd[9] = 1; break; - case FEC_3_4: - cmd[9] = 2; break; - case FEC_5_6: - cmd[9] = 3; break; - case FEC_7_8: - cmd[9] = 4; break; - case FEC_AUTO: - cmd[9] = 5; break; - default: - cmd[9] = 5; break; - } - if (c->delivery_system == SYS_TURBO) - cmd[8] = ADV_MOD_TURBO_QPSK; - else - cmd[8] = ADV_MOD_DVB_QPSK; - break; - case PSK_8: /* PSK_8 is for compatibility with DN */ - cmd[8] = ADV_MOD_TURBO_8PSK; - switch (c->fec_inner) { - case FEC_2_3: - cmd[9] = 0; break; - case FEC_3_4: - cmd[9] = 1; break; - case FEC_3_5: - cmd[9] = 2; break; - case FEC_5_6: - cmd[9] = 3; break; - case FEC_8_9: - cmd[9] = 4; break; - default: - cmd[9] = 0; break; - } - break; - case QAM_16: /* QAM_16 is for compatibility with DN */ - cmd[8] = ADV_MOD_TURBO_16QAM; - cmd[9] = 0; - break; - default: /* Unknown modulation */ - deb_fe("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } - - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - gp8psk_set_tuner_mode(fe, 0); - gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); - - state->lock = 0; - state->next_status_check = jiffies; - state->status_check_interval = 200; - - return 0; -} - -static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - - deb_fe("%s\n",__func__); - - if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, - m->msg, m->msg_len)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, - fe_sec_mini_cmd_t burst) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 cmd; - - deb_fe("%s\n",__func__); - - /* These commands are certainly wrong */ - cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; - - if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, - &cmd, 0)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - - if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, - (tone == SEC_TONE_ON), 0, NULL, 0)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - - if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, - voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); -} - -static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - u8 cmd = sw_cmd & 0x7f; - - if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, - NULL, 0)) { - return -EINVAL; - } - if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), - 0, NULL, 0)) { - return -EINVAL; - } - - return 0; -} - -static void gp8psk_fe_release(struct dvb_frontend* fe) -{ - struct gp8psk_fe_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops gp8psk_fe_ops; - -struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) -{ - struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); - if (s == NULL) - goto error; - - s->d = d; - memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - - goto success; -error: - return NULL; -success: - return &s->fe; -} - - -static struct dvb_frontend_ops gp8psk_fe_ops = { - .delsys = { SYS_DVBS }, - .info = { - .name = "Genpix DVB-S", - .frequency_min = 800000, - .frequency_max = 2250000, - .frequency_stepsize = 100, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - /* - * FE_CAN_QAM_16 is for compatibility - * (Myth incorrectly detects Turbo-QPSK as plain QAM-16) - */ - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC - }, - - .release = gp8psk_fe_release, - - .init = NULL, - .sleep = NULL, - - .set_frontend = gp8psk_fe_set_frontend, - - .get_tune_settings = gp8psk_fe_get_tune_settings, - - .read_status = gp8psk_fe_read_status, - .read_ber = gp8psk_fe_read_ber, - .read_signal_strength = gp8psk_fe_read_signal_strength, - .read_snr = gp8psk_fe_read_snr, - .read_ucblocks = gp8psk_fe_read_unc_blocks, - - .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, - .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, - .set_tone = gp8psk_fe_set_tone, - .set_voltage = gp8psk_fe_set_voltage, - .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, - .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage -}; diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c deleted file mode 100644 index 5d0384dd45b..00000000000 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ /dev/null @@ -1,328 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module - * - * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) - * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) - * - * Thanks to GENPIX for the sample code used to implement this module. - * - * This module is based off the vp7045 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 "gp8psk.h" - -/* debug */ -static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; -int dvb_usb_gp8psk_debug; -module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) -{ - return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); -} - -static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) -{ - return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); -} - -static void gp8psk_info(struct dvb_usb_device *d) -{ - u8 fpga_vers, fw_vers[6]; - - if (!gp8psk_get_fw_version(d, fw_vers)) - info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", - fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), - 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); - else - info("failed to get FW version"); - - if (!gp8psk_get_fpga_version(d, &fpga_vers)) - info("FPGA Version = %i", fpga_vers); - else - info("failed to get FPGA version"); -} - -int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) -{ - int ret = 0,try = 0; - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - while (ret >= 0 && ret != blen && try < 3) { - ret = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value,index,b,blen, - 2000); - deb_info("reading number %d (ret: %d)\n",try,ret); - try++; - } - - if (ret < 0 || ret != blen) { - warn("usb in %d operation failed.", req); - ret = -EIO; - } else - ret = 0; - - deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - mutex_unlock(&d->usb_mutex); - - return ret; -} - -int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - - deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - if (usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value,index,b,blen, - 2000) != blen) { - warn("usb out operation failed."); - ret = -EIO; - } else - ret = 0; - mutex_unlock(&d->usb_mutex); - - return ret; -} - -static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) -{ - int ret; - const struct firmware *fw = NULL; - const u8 *ptr; - u8 *buf; - if ((ret = request_firmware(&fw, bcm4500_firmware, - &d->udev->dev)) != 0) { - err("did not find the bcm4500 firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - bcm4500_firmware,ret); - return ret; - } - - ret = -EINVAL; - - if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) - goto out_rel_fw; - - info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); - - ptr = fw->data; - buf = kmalloc(64, GFP_KERNEL | GFP_DMA); - if (!buf) { - ret = -ENOMEM; - goto out_rel_fw; - } - - while (ptr[0] != 0xff) { - u16 buflen = ptr[0] + 4; - if (ptr + buflen >= fw->data + fw->size) { - err("failed to load bcm4500 firmware."); - goto out_free; - } - memcpy(buf, ptr, buflen); - if (dvb_usb_generic_write(d, buf, buflen)) { - err("failed to load bcm4500 firmware."); - goto out_free; - } - ptr += buflen; - } - - ret = 0; - -out_free: - kfree(buf); -out_rel_fw: - release_firmware(fw); - - return ret; -} - -static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 status, buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - - if (onoff) { - gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); - if (! (status & bm8pskStarted)) { /* started */ - if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) - gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - gp8psk_info(d); - } - - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ - if(gp8psk_load_bcm4500fw(d)) - return -EINVAL; - - if (! (status & bmIntersilOn)) /* LNB Power */ - if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, - &buf, 1)) - return -EINVAL; - - /* Set DVB mode to 1 */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) - return -EINVAL; - /* Abort possible TS (if previous tune crashed) */ - if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) - return -EINVAL; - } else { - /* Turn off LNB power */ - if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) - gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); - } - return 0; -} - -int gp8psk_bcm4500_reload(struct dvb_usb_device *d) -{ - u8 buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn On 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - /* load BCM4500 firmware */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_load_bcm4500fw(d)) - return -EINVAL; - return 0; -} - -static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); -} - -static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev); - return 0; -} - -static struct dvb_usb_device_properties gp8psk_properties; - -static int gp8psk_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - struct usb_device *udev = interface_to_usbdev(intf); - ret = dvb_usb_device_init(intf, &gp8psk_properties, - THIS_MODULE, NULL, adapter_nr); - if (ret == 0) { - info("found Genpix USB device pID = %x (hex)", - le16_to_cpu(udev->descriptor.idProduct)); - } - return ret; -} - -static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, -/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); - -static struct dvb_usb_device_properties gp8psk_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-gp8psk-01.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = gp8psk_streaming_ctrl, - .frontend_attach = gp8psk_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }}, - } - }, - .power_ctrl = gp8psk_power_ctrl, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 4, - .devices = { - { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", - .cold_ids = { &gp8psk_usb_table[0], NULL }, - .warm_ids = { &gp8psk_usb_table[1], NULL }, - }, - { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[2], NULL }, - }, - { .name = "Genpix SkyWalker-1 DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[3], NULL }, - }, - { .name = "Genpix SkyWalker-2 DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[4], NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver gp8psk_usb_driver = { - .name = "dvb_usb_gp8psk", - .probe = gp8psk_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = gp8psk_usb_table, -}; - -module_usb_driver(gp8psk_usb_driver); - -MODULE_AUTHOR("Alan Nisota "); -MODULE_DESCRIPTION("Driver for Genpix DVB-S"); -MODULE_VERSION("1.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h deleted file mode 100644 index ed32b9da484..00000000000 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ /dev/null @@ -1,100 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module - * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) - * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) - * - * Thanks to GENPIX for the sample code used to implement this module. - * - * This module is based off the vp7045 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_GP8PSK_H_ -#define _DVB_USB_GP8PSK_H_ - -#define DVB_USB_LOG_PREFIX "gp8psk" -#include "dvb-usb.h" - -extern int dvb_usb_gp8psk_debug; -#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) -#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args) - -/* Twinhan Vendor requests */ -#define TH_COMMAND_IN 0xC0 -#define TH_COMMAND_OUT 0xC1 - -/* gp8psk commands */ - -#define GET_8PSK_CONFIG 0x80 /* in */ -#define SET_8PSK_CONFIG 0x81 -#define I2C_WRITE 0x83 -#define I2C_READ 0x84 -#define ARM_TRANSFER 0x85 -#define TUNE_8PSK 0x86 -#define GET_SIGNAL_STRENGTH 0x87 /* in */ -#define LOAD_BCM4500 0x88 -#define BOOT_8PSK 0x89 /* in */ -#define START_INTERSIL 0x8A /* in */ -#define SET_LNB_VOLTAGE 0x8B -#define SET_22KHZ_TONE 0x8C -#define SEND_DISEQC_COMMAND 0x8D -#define SET_DVB_MODE 0x8E -#define SET_DN_SWITCH 0x8F -#define GET_SIGNAL_LOCK 0x90 /* in */ -#define GET_FW_VERS 0x92 -#define GET_SERIAL_NUMBER 0x93 /* in */ -#define USE_EXTRA_VOLT 0x94 -#define GET_FPGA_VERS 0x95 -#define CW3K_INIT 0x9d - -/* PSK_configuration bits */ -#define bm8pskStarted 0x01 -#define bm8pskFW_Loaded 0x02 -#define bmIntersilOn 0x04 -#define bmDVBmode 0x08 -#define bm22kHz 0x10 -#define bmSEL18V 0x20 -#define bmDCtuned 0x40 -#define bmArmed 0x80 - -/* Satellite modulation modes */ -#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ -#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ -#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ -#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ - -#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ -#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ -#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ -#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ -#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ -#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ - -#define GET_USB_SPEED 0x07 - -#define RESET_FX2 0x13 - -#define FW_VERSION_READ 0x0B -#define VENDOR_STRING_READ 0x0C -#define PRODUCT_STRING_READ 0x0D -#define FW_BCD_VERSION_READ 0x14 - -/* firmware revision id's */ -#define GP8PSK_FW_REV1 0x020604 -#define GP8PSK_FW_REV2 0x020704 -#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0]) - -extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); -extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen); -extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); - -#endif diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c deleted file mode 100644 index 288af29a8bb..00000000000 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver - * - * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ - -#include "m920x.h" - -#include "mt352.h" -#include "mt352_priv.h" -#include "qt1010.h" -#include "tda1004x.h" -#include "tda827x.h" - -#include -#include "tuner-simple.h" -#include - -/* debug */ -static int dvb_usb_m920x_debug; -module_param_named(debug,dvb_usb_m920x_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid); - -static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, - u16 index, void *data, int size) -{ - int ret; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - request, USB_TYPE_VENDOR | USB_DIR_IN, - value, index, data, size, 2000); - if (ret < 0) { - printk(KERN_INFO "m920x_read = error: %d\n", ret); - return ret; - } - - if (ret != size) { - deb("m920x_read = no data\n"); - return -EIO; - } - - return 0; -} - -static inline int m920x_write(struct usb_device *udev, u8 request, - u16 value, u16 index) -{ - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - request, USB_TYPE_VENDOR | USB_DIR_OUT, - value, index, NULL, 0, 2000); - - return ret; -} - -static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) -{ - int ret = 0, i, epi, flags = 0; - int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; - - /* Remote controller init. */ - if (d->props.rc.legacy.rc_query) { - deb("Initialising remote control\n"); - while (rc_seq->address) { - if ((ret = m920x_write(d->udev, M9206_CORE, - rc_seq->data, - rc_seq->address)) != 0) { - deb("Initialising remote control failed\n"); - return ret; - } - - rc_seq++; - } - - deb("Initialising remote control success\n"); - } - - for (i = 0; i < d->props.num_adapters; i++) - flags |= d->adapter[i].props.fe[0].caps; - - /* Some devices(Dposh) might crash if we attempt touch at all. */ - if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { - for (i = 0; i < d->props.num_adapters; i++) { - epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81; - - if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { - printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n"); - return -EINVAL; - } - - adap_enabled[epi] = 1; - } - - for (i = 0; i < M9206_MAX_ADAPTERS; i++) { - if (adap_enabled[i]) - continue; - - if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0) - return ret; - - if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0) - return ret; - } - } - - return ret; -} - -static int m920x_init_ep(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *alt; - - if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) { - deb("No alt found!\n"); - return -ENODEV; - } - - return usb_set_interface(udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); -} - -static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct m920x_state *m = d->priv; - int i, ret = 0; - u8 *rc_state; - - rc_state = kmalloc(2, GFP_KERNEL); - if (!rc_state) - return -ENOMEM; - - if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) - goto out; - - if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) - goto out; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) { - *event = d->props.rc.legacy.rc_map_table[i].keycode; - - switch(rc_state[0]) { - case 0x80: - *state = REMOTE_NO_KEY_PRESSED; - goto out; - - case 0x88: /* framing error or "invalid code" */ - case 0x99: - case 0xc0: - case 0xd8: - *state = REMOTE_NO_KEY_PRESSED; - m->rep_count = 0; - goto out; - - case 0x93: - case 0x92: - case 0x83: /* pinnacle PCTV310e */ - case 0x82: - m->rep_count = 0; - *state = REMOTE_KEY_PRESSED; - goto out; - - case 0x91: - case 0x81: /* pinnacle PCTV310e */ - /* prevent immediate auto-repeat */ - if (++m->rep_count > 2) - *state = REMOTE_KEY_REPEAT; - else - *state = REMOTE_NO_KEY_PRESSED; - goto out; - - default: - deb("Unexpected rc state %02x\n", rc_state[0]); - *state = REMOTE_NO_KEY_PRESSED; - goto out; - } - } - - if (rc_state[1] != 0) - deb("Unknown rc key %02x\n", rc_state[1]); - - *state = REMOTE_NO_KEY_PRESSED; - - out: - kfree(rc_state); - return ret; -} - -/* I2C */ -static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i, j; - int ret = 0; - - if (!num) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) { - /* For a 0 byte message, I think sending the address - * to index 0x80|0x40 would be the correct thing to - * do. However, zero byte messages are only used for - * probing, and since we don't know how to get the - * slave's ack, we can't probe. */ - ret = -ENOTSUPP; - goto unlock; - } - /* Send START & address/RW bit */ - if (!(msg[i].flags & I2C_M_NOSTART)) { - if ((ret = m920x_write(d->udev, M9206_I2C, - (msg[i].addr << 1) | - (msg[i].flags & I2C_M_RD ? 0x01 : 0), 0x80)) != 0) - goto unlock; - /* Should check for ack here, if we knew how. */ - } - if (msg[i].flags & I2C_M_RD) { - for (j = 0; j < msg[i].len; j++) { - /* Last byte of transaction? - * Send STOP, otherwise send ACK. */ - int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01; - - if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, - 0x20 | stop, - &msg[i].buf[j], 1)) != 0) - goto unlock; - } - } else { - for (j = 0; j < msg[i].len; j++) { - /* Last byte of transaction? Then send STOP. */ - int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00; - - if ((ret = m920x_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0) - goto unlock; - /* Should check for ack here too. */ - } - } - } - ret = num; - - unlock: - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 m920x_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm m920x_i2c_algo = { - .master_xfer = m920x_i2c_xfer, - .functionality = m920x_i2c_func, -}; - -/* pid filter */ -static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid) -{ - int ret = 0; - - if (pid >= 0x8000) - return -EINVAL; - - pid |= 0x8000; - - if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) - return ret; - - if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) - return ret; - - return ret; -} - -static int m920x_update_filters(struct dvb_usb_adapter *adap) -{ - struct m920x_state *m = adap->dev->priv; - int enabled = m->filtering_enabled[adap->id]; - int i, ret = 0, filter = 0; - int ep = adap->props.fe[0].stream.endpoint; - - for (i = 0; i < M9206_MAX_FILTERS; i++) - if (m->filters[adap->id][i] == 8192) - enabled = 0; - - /* Disable all filters */ - if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0) - return ret; - - for (i = 0; i < M9206_MAX_FILTERS; i++) - if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0) - return ret; - - /* Set */ - if (enabled) { - for (i = 0; i < M9206_MAX_FILTERS; i++) { - if (m->filters[adap->id][i] == 0) - continue; - - if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0) - return ret; - - filter++; - } - } - - return ret; -} - -static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct m920x_state *m = adap->dev->priv; - - m->filtering_enabled[adap->id] = onoff ? 1 : 0; - - return m920x_update_filters(adap); -} - -static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - struct m920x_state *m = adap->dev->priv; - - m->filters[adap->id][index] = onoff ? pid : 0; - - return m920x_update_filters(adap); -} - -static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw) -{ - u16 value, index, size; - u8 *read, *buff; - int i, pass, ret = 0; - - buff = kmalloc(65536, GFP_KERNEL); - if (buff == NULL) - return -ENOMEM; - - read = kmalloc(4, GFP_KERNEL); - if (!read) { - kfree(buff); - return -ENOMEM; - } - - if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) - goto done; - deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); - - if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) - goto done; - deb("%x\n", read[0]); - - for (pass = 0; pass < 2; pass++) { - for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { - value = get_unaligned_le16(fw->data + i); - i += sizeof(u16); - - index = get_unaligned_le16(fw->data + i); - i += sizeof(u16); - - size = get_unaligned_le16(fw->data + i); - i += sizeof(u16); - - if (pass == 1) { - /* Will stall if using fw->data ... */ - memcpy(buff, fw->data + i, size); - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), - M9206_FW, - USB_TYPE_VENDOR | USB_DIR_OUT, - value, index, buff, size, 20); - if (ret != size) { - deb("error while uploading fw!\n"); - ret = -EIO; - goto done; - } - msleep(3); - } - i += size; - } - if (i != fw->size) { - deb("bad firmware file!\n"); - ret = -EINVAL; - goto done; - } - } - - msleep(36); - - /* m920x will disconnect itself from the bus after this. */ - (void) m920x_write(udev, M9206_CORE, 0x01, M9206_FW_GO); - deb("firmware uploaded!\n"); - - done: - kfree(read); - kfree(buff); - - return ret; -} - -/* Callbacks for DVB USB */ -static int m920x_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - struct usb_host_interface *alt; - - alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1); - *cold = (alt == NULL) ? 1 : 0; - - return 0; -} - -/* demod configurations */ -static int m920x_mt352_demod_init(struct dvb_frontend *fe) -{ - int ret; - u8 config[] = { CONFIG, 0x3d }; - u8 clock[] = { CLOCK_CTL, 0x30 }; - u8 reset[] = { RESET, 0x80 }; - u8 adc_ctl[] = { ADC_CTL_1, 0x40 }; - u8 agc[] = { AGC_TARGET, 0x1c, 0x20 }; - u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 }; - u8 unk1[] = { 0x93, 0x1a }; - u8 unk2[] = { 0xb5, 0x7a }; - - deb("Demod init!\n"); - - if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0) - return ret; - if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0) - return ret; - if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0) - return ret; - if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0) - return ret; - if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0) - return ret; - if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0) - return ret; - if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0) - return ret; - if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0) - return ret; - - return 0; -} - -static struct mt352_config m920x_mt352_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .demod_init = m920x_mt352_demod_init, -}; - -static struct tda1004x_config m920x_tda10046_08_config = { - .demod_address = 0x08, - .invert = 0, - .invert_oclk = 0, - .ts_mode = TDA10046_TS_SERIAL, - .xtal_freq = TDA10046_XTAL_16M, - .if_freq = TDA10046_FREQ_045, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GPTRI, - .request_firmware = NULL, -}; - -static struct tda1004x_config m920x_tda10046_0b_config = { - .demod_address = 0x0b, - .invert = 0, - .invert_oclk = 0, - .ts_mode = TDA10046_TS_SERIAL, - .xtal_freq = TDA10046_XTAL_16M, - .if_freq = TDA10046_FREQ_045, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GPTRI, - .request_firmware = NULL, /* uses firmware EEPROM */ -}; - -/* tuner configurations */ -static struct qt1010_config m920x_qt1010_config = { - .i2c_address = 0x62 -}; - -/* Callbacks for DVB USB */ -static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - adap->fe_adap[0].fe = dvb_attach(mt352_attach, - &m920x_mt352_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) == NULL) - return -EIO; - - return 0; -} - -static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - adap->fe_adap[0].fe = dvb_attach(tda10046_attach, - &m920x_tda10046_08_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) == NULL) - return -EIO; - - return 0; -} - -static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - adap->fe_adap[0].fe = dvb_attach(tda10046_attach, - &m920x_tda10046_0b_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) == NULL) - return -EIO; - - return 0; -} - -static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) - return -ENODEV; - - return 0; -} - -static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) - return -ENODEV; - - return 0; -} - -static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) - return -ENODEV; - - return 0; -} - -static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); - return 0; -} - -/* device-specific initialization */ -static struct m920x_inits megasky_rc_init [] = { - { M9206_RC_INIT2, 0xa8 }, - { M9206_RC_INIT1, 0x51 }, - { } /* terminating entry */ -}; - -static struct m920x_inits tvwalkertwin_rc_init [] = { - { M9206_RC_INIT2, 0x00 }, - { M9206_RC_INIT1, 0xef }, - { 0xff28, 0x00 }, - { 0xff23, 0x00 }, - { 0xff21, 0x30 }, - { } /* terminating entry */ -}; - -static struct m920x_inits pinnacle310e_init[] = { - /* without these the tuner don't work */ - { 0xff20, 0x9b }, - { 0xff22, 0x70 }, - - /* rc settings */ - { 0xff50, 0x80 }, - { M9206_RC_INIT1, 0x00 }, - { M9206_RC_INIT2, 0xff }, - { } /* terminating entry */ -}; - -/* ir keymaps */ -static struct rc_map_table rc_map_megasky_table[] = { - { 0x0012, KEY_POWER }, - { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */ - { 0x0002, KEY_CHANNELUP }, - { 0x0005, KEY_CHANNELDOWN }, - { 0x0003, KEY_VOLUMEUP }, - { 0x0006, KEY_VOLUMEDOWN }, - { 0x0004, KEY_MUTE }, - { 0x0007, KEY_OK }, /* TS */ - { 0x0008, KEY_STOP }, - { 0x0009, KEY_MENU }, /* swap */ - { 0x000a, KEY_REWIND }, - { 0x001b, KEY_PAUSE }, - { 0x001f, KEY_FASTFORWARD }, - { 0x000c, KEY_RECORD }, - { 0x000d, KEY_CAMERA }, /* screenshot */ - { 0x000e, KEY_COFFEE }, /* "MTS" */ -}; - -static struct rc_map_table rc_map_tvwalkertwin_table[] = { - { 0x0001, KEY_ZOOM }, /* Full Screen */ - { 0x0002, KEY_CAMERA }, /* snapshot */ - { 0x0003, KEY_MUTE }, - { 0x0004, KEY_REWIND }, - { 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */ - { 0x0006, KEY_FASTFORWARD }, - { 0x0007, KEY_RECORD }, - { 0x0008, KEY_STOP }, - { 0x0009, KEY_TIME }, /* Timeshift */ - { 0x000c, KEY_COFFEE }, /* Recall */ - { 0x000e, KEY_CHANNELUP }, - { 0x0012, KEY_POWER }, - { 0x0015, KEY_MENU }, /* source */ - { 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */ - { 0x001a, KEY_CHANNELDOWN }, - { 0x001b, KEY_VOLUMEDOWN }, - { 0x001e, KEY_VOLUMEUP }, -}; - -static struct rc_map_table rc_map_pinnacle310e_table[] = { - { 0x16, KEY_POWER }, - { 0x17, KEY_FAVORITES }, - { 0x0f, KEY_TEXT }, - { 0x48, KEY_PROGRAM }, /* preview */ - { 0x1c, KEY_EPG }, - { 0x04, KEY_LIST }, /* record list */ - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, - { 0x15, KEY_0 }, - { 0x0c, KEY_CANCEL }, - { 0x4a, KEY_CLEAR }, - { 0x13, KEY_BACK }, - { 0x00, KEY_TAB }, - { 0x4b, KEY_UP }, - { 0x4e, KEY_LEFT }, - { 0x52, KEY_RIGHT }, - { 0x51, KEY_DOWN }, - { 0x4f, KEY_ENTER }, /* could also be KEY_OK */ - { 0x1e, KEY_VOLUMEUP }, - { 0x0a, KEY_VOLUMEDOWN }, - { 0x05, KEY_CHANNELUP }, - { 0x02, KEY_CHANNELDOWN }, - { 0x11, KEY_RECORD }, - { 0x14, KEY_PLAY }, - { 0x4c, KEY_PAUSE }, - { 0x1a, KEY_STOP }, - { 0x40, KEY_REWIND }, - { 0x12, KEY_FASTFORWARD }, - { 0x41, KEY_PREVIOUSSONG }, /* Replay */ - { 0x42, KEY_NEXTSONG }, /* Skip */ - { 0x54, KEY_CAMERA }, /* Capture */ -/* { 0x50, KEY_SAP }, */ /* Sap */ - { 0x47, KEY_CYCLEWINDOWS }, /* Pip */ - { 0x4d, KEY_SCREEN }, /* FullScreen */ - { 0x08, KEY_SUBTITLE }, - { 0x0e, KEY_MUTE }, -/* { 0x49, KEY_LR }, */ /* L/R */ - { 0x07, KEY_SLEEP }, /* Hibernate */ - { 0x08, KEY_VIDEO }, /* A/V */ - { 0x0e, KEY_MENU }, /* Recall */ - { 0x45, KEY_ZOOMIN }, - { 0x46, KEY_ZOOMOUT }, - { 0x18, KEY_RED }, /* Red */ - { 0x53, KEY_GREEN }, /* Green */ - { 0x5e, KEY_YELLOW }, /* Yellow */ - { 0x5f, KEY_BLUE }, /* Blue */ -}; - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties megasky_properties; -static struct dvb_usb_device_properties digivox_mini_ii_properties; -static struct dvb_usb_device_properties tvwalkertwin_properties; -static struct dvb_usb_device_properties dposh_properties; -static struct dvb_usb_device_properties pinnacle_pctv310e_properties; - -static int m920x_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d = NULL; - int ret; - struct m920x_inits *rc_init_seq = NULL; - int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; - - deb("Probing for m920x device at interface %d\n", bInterfaceNumber); - - if (bInterfaceNumber == 0) { - /* Single-tuner device, or first interface on - * multi-tuner device - */ - - ret = dvb_usb_device_init(intf, &megasky_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - rc_init_seq = megasky_rc_init; - goto found; - } - - ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - /* No remote control, so no rc_init_seq */ - goto found; - } - - /* This configures both tuners on the TV Walker Twin */ - ret = dvb_usb_device_init(intf, &tvwalkertwin_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - rc_init_seq = tvwalkertwin_rc_init; - goto found; - } - - ret = dvb_usb_device_init(intf, &dposh_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - /* Remote controller not supported yet. */ - goto found; - } - - ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - rc_init_seq = pinnacle310e_init; - goto found; - } - - return ret; - } else { - /* Another interface on a multi-tuner device */ - - /* The LifeView TV Walker Twin gets here, but struct - * tvwalkertwin_properties already configured both - * tuners, so there is nothing for us to do here - */ - } - - found: - if ((ret = m920x_init_ep(intf)) < 0) - return ret; - - if (d && (ret = m920x_init(d, rc_init_seq)) != 0) - return ret; - - return ret; -} - -static struct usb_device_id m920x_table [] = { - { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_MSI_DIGI_VOX_MINI_II) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) }, - { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) }, - { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, m920x_table); - -static struct dvb_usb_device_properties megasky_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-megasky-02.fw", - .download_firmware = m920x_firmware_download, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_megasky_table, - .rc_map_size = ARRAY_SIZE(rc_map_megasky_table), - .rc_query = m920x_rc_query, - }, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_mt352_frontend_attach, - .tuner_attach = m920x_qt1010_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "MSI Mega Sky 580 DVB-T USB2.0", - { &m920x_table[0], NULL }, - { NULL }, - } - } -}; - -static struct dvb_usb_device_properties digivox_mini_ii_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-digivox-02.fw", - .download_firmware = m920x_firmware_download, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_tda10046_08_frontend_attach, - .tuner_attach = m920x_tda8275_60_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 0x4000, - } - } - }, - }}, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "MSI DIGI VOX mini II DVB-T USB2.0", - { &m920x_table[1], NULL }, - { NULL }, - }, - } -}; - -/* LifeView TV Walker Twin support by Nick Andrew - * - * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A - * TDA10046 #0 is located at i2c address 0x08 - * TDA10046 #1 is located at i2c address 0x0b - * TDA8275A #0 is located at i2c address 0x60 - * TDA8275A #1 is located at i2c address 0x61 - */ -static struct dvb_usb_device_properties tvwalkertwin_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-tvwalkert.fw", - .download_firmware = m920x_firmware_download, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_tvwalkertwin_table, - .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table), - .rc_query = m920x_rc_query, - }, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 2, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_tda10046_08_frontend_attach, - .tuner_attach = m920x_tda8275_60_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }}, - }},{ - .num_frontends = 1, - .fe = {{ - - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_tda10046_0b_frontend_attach, - .tuner_attach = m920x_tda8275_61_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 512, - } - } - }}, - }, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { .name = "LifeView TV Walker Twin DVB-T USB2.0", - .cold_ids = { &m920x_table[2], NULL }, - .warm_ids = { &m920x_table[3], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties dposh_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dposh-01.fw", - .download_firmware = m920x_firmware_download, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - /* Hardware pid filters don't work with this device/firmware */ - - .frontend_attach = m920x_mt352_frontend_attach, - .tuner_attach = m920x_qt1010_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { .name = "Dposh DVB-T USB2.0", - .cold_ids = { &m920x_table[4], NULL }, - .warm_ids = { &m920x_table[5], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = NULL, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_pinnacle310e_table, - .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table), - .rc_query = m920x_rc_query, - }, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_mt352_frontend_attach, - .tuner_attach = m920x_fmd1216me_tuner_attach, - - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x84, - .u = { - .isoc = { - .framesperurb = 128, - .framesize = 564, - .interval = 1, - } - } - }, - }}, - } }, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "Pinnacle PCTV 310e", - { &m920x_table[6], NULL }, - { NULL }, - } - } -}; - -static struct usb_driver m920x_driver = { - .name = "dvb_usb_m920x", - .probe = m920x_probe, - .disconnect = dvb_usb_device_exit, - .id_table = m920x_table, -}; - -module_usb_driver(m920x_driver); - -MODULE_AUTHOR("Aapo Tahkola "); -MODULE_DESCRIPTION("DVB Driver for ULI M920x"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h deleted file mode 100644 index 3c061518ffc..00000000000 --- a/drivers/media/dvb/dvb-usb/m920x.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _DVB_USB_M920X_H_ -#define _DVB_USB_M920X_H_ - -#define DVB_USB_LOG_PREFIX "m920x" -#include "dvb-usb.h" - -#define deb(args...) dprintk(dvb_usb_m920x_debug,0x01,args) - -#define M9206_CORE 0x22 -#define M9206_RC_STATE 0xff51 -#define M9206_RC_KEY 0xff52 -#define M9206_RC_INIT1 0xff54 -#define M9206_RC_INIT2 0xff55 -#define M9206_FW_GO 0xff69 - -#define M9206_I2C 0x23 -#define M9206_FILTER 0x25 -#define M9206_FW 0x30 - -#define M9206_MAX_FILTERS 8 -#define M9206_MAX_ADAPTERS 4 - -/* -sequences found in logs: -[index value] -0x80 write addr -(0x00 out byte)* -0x40 out byte - -0x80 write addr -(0x00 out byte)* -0x80 read addr -(0x21 in byte)* -0x60 in byte - -this sequence works: -0x80 read addr -(0x21 in byte)* -0x60 in byte - -Guess at API of the I2C function: -I2C operation is done one byte at a time with USB control messages. The -index the messages is sent to is made up of a set of flags that control -the I2C bus state: -0x80: Send START condition. After a START condition, one would normally - always send the 7-bit slave I2C address as the 7 MSB, followed by - the read/write bit as the LSB. -0x40: Send STOP condition. This should be set on the last byte of an - I2C transaction. -0x20: Read a byte from the slave. As opposed to writing a byte to the - slave. The slave will normally not produce any data unless you - set the R/W bit to 1 when sending the slave's address after the - START condition. -0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read, - the master should send an ACK, that is pull SDA low during the 9th - clock cycle, after every byte but the last. This flags only makes - sense when bit 0x20 is set, indicating a read. - -What any other bits might mean, or how to get the slave's ACK/NACK -response to a write, is unknown. -*/ - -struct m920x_state { - u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS]; - int filtering_enabled[M9206_MAX_ADAPTERS]; - int rep_count; -}; - -/* Initialisation data for the m920x - */ - -struct m920x_inits { - u16 address; - u8 data; -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c deleted file mode 100644 index 6c55384e2fc..00000000000 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ /dev/null @@ -1,233 +0,0 @@ -/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2 - * DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_rc(args...) dprintk(debug,0x01,args) -#define deb_ee(args...) dprintk(debug,0x02,args) - -/* Hauppauge NOVA-T USB2 keys */ -static struct rc_map_table rc_map_haupp_table[] = { - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - { 0x1e0a, KEY_KPASTERISK }, - { 0x1e0b, KEY_RED }, - { 0x1e0c, KEY_RADIO }, - { 0x1e0d, KEY_MENU }, - { 0x1e0e, KEY_GRAVE }, /* # */ - { 0x1e0f, KEY_MUTE }, - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - { 0x1e12, KEY_CHANNEL }, - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VIDEO }, - { 0x1e19, KEY_AUDIO }, - { 0x1e1a, KEY_IMAGES }, - { 0x1e1b, KEY_EPG }, - { 0x1e1c, KEY_TV }, - { 0x1e1e, KEY_NEXT }, - { 0x1e1f, KEY_BACK }, - { 0x1e20, KEY_CHANNELUP }, - { 0x1e21, KEY_CHANNELDOWN }, - { 0x1e24, KEY_LAST }, /* Skip backwards */ - { 0x1e25, KEY_OK }, - { 0x1e29, KEY_BLUE}, - { 0x1e2e, KEY_GREEN }, - { 0x1e30, KEY_PAUSE }, - { 0x1e32, KEY_REWIND }, - { 0x1e34, KEY_FASTFORWARD }, - { 0x1e35, KEY_PLAY }, - { 0x1e36, KEY_STOP }, - { 0x1e37, KEY_RECORD }, - { 0x1e38, KEY_YELLOW }, - { 0x1e3b, KEY_GOTO }, - { 0x1e3d, KEY_POWER }, -}; - -/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key - * is delivered. No workaround yet, maybe a new firmware. - */ -static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; - u16 raw; - int i; - struct dibusb_device_state *st = d->priv; - - dvb_usb_generic_rw(d,cmd,2,key,5,0); - - *state = REMOTE_NO_KEY_PRESSED; - switch (key[0]) { - case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED: - raw = ((key[1] << 8) | key[2]) >> 3; - toggle = !!(raw & 0x800); - data = raw & 0x3f; - custom = (raw >> 6) & 0x1f; - - deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle); - - for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) { - if (rc5_data(&rc_map_haupp_table[i]) == data && - rc5_custom(&rc_map_haupp_table[i]) == custom) { - - deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]), - rc5_custom(&rc_map_haupp_table[i])); - - *event = rc_map_haupp_table[i].keycode; - *state = REMOTE_KEY_PRESSED; - if (st->old_toggle == toggle) { - if (st->last_repeat_count++ < 2) - *state = REMOTE_NO_KEY_PRESSED; - } else { - st->last_repeat_count = 0; - st->old_toggle = toggle; - } - break; - } - } - - break; - case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY: - default: - break; - } - - return 0; -} - -static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) -{ - int i; - u8 b; - - mac[0] = 0x00; - mac[1] = 0x0d; - mac[2] = 0xfe; - - /* this is a complete guess, but works for my box */ - for (i = 136; i < 139; i++) { - dibusb_read_eeprom_byte(d,i, &b); - - mac[5 - (i - 136)] = b; - } - - return 0; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties nova_t_properties; - -static int nova_t_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &nova_t_properties, - THIS_MODULE, NULL, adapter_nr); -} - -/* do not change the order of the ID table */ -static struct usb_device_id nova_t_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, nova_t_table); - -static struct dvb_usb_device_properties nova_t_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-nova-t-usb2-02.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .size_of_priv = sizeof(struct dibusb_device_state), - - .power_ctrl = dibusb2_0_power_ctrl, - .read_mac_address = nova_t_read_mac_address, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_haupp_table, - .rc_map_size = ARRAY_SIZE(rc_map_haupp_table), - .rc_query = nova_t_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Hauppauge WinTV-NOVA-T usb2", - { &nova_t_table[0], NULL }, - { &nova_t_table[1], NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver nova_t_driver = { - .name = "dvb_usb_nova_t_usb2", - .probe = nova_t_probe, - .disconnect = dvb_usb_device_exit, - .id_table = nova_t_table, -}; - -module_usb_driver(nova_t_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c deleted file mode 100644 index c8a95042dfb..00000000000 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ /dev/null @@ -1,583 +0,0 @@ -/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card -* -* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org) -* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de) -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the Free -* Software Foundation, version 2. -* -* see Documentation/dvb/README.dvb-usb for more information -*/ - -#define DVB_USB_LOG_PREFIX "opera" - -#include "dvb-usb.h" -#include "stv0299.h" - -#define OPERA_READ_MSG 0 -#define OPERA_WRITE_MSG 1 -#define OPERA_I2C_TUNER 0xd1 - -#define READ_FX2_REG_REQ 0xba -#define READ_MAC_ADDR 0x08 -#define OPERA_WRITE_FX2 0xbb -#define OPERA_TUNER_REQ 0xb1 -#define REG_1F_SYMBOLRATE_BYTE0 0x1f -#define REG_20_SYMBOLRATE_BYTE1 0x20 -#define REG_21_SYMBOLRATE_BYTE2 0x21 - -#define ADDR_B600_VOLTAGE_13V (0x02) -#define ADDR_B601_VOLTAGE_18V (0x03) -#define ADDR_B1A6_STREAM_CTRL (0x04) -#define ADDR_B880_READ_REMOTE (0x05) - -struct opera1_state { - u32 last_key_pressed; -}; -struct rc_map_opera_table { - u32 keycode; - u32 event; -}; - -static int dvb_usb_opera1_debug; -module_param_named(debug, dvb_usb_opera1_debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." - DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - - -static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value, - u8 * data, u16 len, int flags) -{ - int ret; - u8 tmp; - u8 *buf; - unsigned int pipe = (flags == OPERA_READ_MSG) ? - usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0); - u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; - - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (flags == OPERA_WRITE_MSG) - memcpy(buf, data, len); - ret = usb_control_msg(dev, pipe, request, - request_type | USB_TYPE_VENDOR, value, 0x0, - buf, len, 2000); - - if (request == OPERA_TUNER_REQ) { - tmp = buf[0]; - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR, - 0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) { - ret = 0; - goto out; - } - buf[0] = tmp; - } - if (flags == OPERA_READ_MSG) - memcpy(data, buf, len); -out: - kfree(buf); - return ret; -} - -/* I2C */ - -static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr, - u8 * buf, u16 len) -{ - int ret = 0; - u8 request; - u16 value; - - if (!dev) { - info("no usb_device"); - return -EINVAL; - } - if (mutex_lock_interruptible(&dev->usb_mutex) < 0) - return -EAGAIN; - - switch (addr>>1){ - case ADDR_B600_VOLTAGE_13V: - request=0xb6; - value=0x00; - break; - case ADDR_B601_VOLTAGE_18V: - request=0xb6; - value=0x01; - break; - case ADDR_B1A6_STREAM_CTRL: - request=0xb1; - value=0xa6; - break; - case ADDR_B880_READ_REMOTE: - request=0xb8; - value=0x80; - break; - default: - request=0xb1; - value=addr; - } - ret = opera1_xilinx_rw(dev->udev, request, - value, buf, len, - addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG); - - mutex_unlock(&dev->usb_mutex); - return ret; -} - -static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, tmp = 0; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if ((tmp = opera1_usb_i2c_msgxfer(d, - (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), - msg[i].buf, - msg[i].len - )) != msg[i].len) { - break; - } - if (dvb_usb_opera1_debug & 0x10) - info("sending i2c mesage %d %d", tmp, msg[i].len); - } - mutex_unlock(&d->i2c_mutex); - return num; -} - -static u32 opera1_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm opera1_i2c_algo = { - .master_xfer = opera1_i2c_xfer, - .functionality = opera1_i2c_func, -}; - -static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - static u8 command_13v[1]={0x00}; - static u8 command_18v[1]={0x01}; - struct i2c_msg msg[] = { - {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, - }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - if (voltage == SEC_VOLTAGE_18) { - msg[0].addr = ADDR_B601_VOLTAGE_18V; - msg[0].buf = command_18v; - } - i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); - return 0; -} - -static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, - u32 ratio) -{ - stv0299_writereg(fe, 0x13, 0x98); - stv0299_writereg(fe, 0x14, 0x95); - stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff); - stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff); - stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0); - return 0; - -} -static u8 opera1_inittab[] = { - 0x00, 0xa1, - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, - 0x05, 0x05, - 0x06, 0x02, - 0x07, 0x00, - 0x0b, 0x00, - 0x0c, 0x01, - 0x0d, 0x81, - 0x0e, 0x44, - 0x0f, 0x19, - 0x10, 0x3f, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x98, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0xeb, - 0x17, 0x00, - 0x18, 0x19, - 0x19, 0x8b, - 0x1a, 0x00, - 0x1b, 0x82, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - REG_1F_SYMBOLRATE_BYTE0, 0x06, - REG_20_SYMBOLRATE_BYTE1, 0x50, - REG_21_SYMBOLRATE_BYTE2, 0x10, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x37, - 0x25, 0xbc, - 0x26, 0x00, - 0x27, 0x00, - 0x28, 0x00, - 0x29, 0x1e, - 0x2a, 0x14, - 0x2b, 0x1f, - 0x2c, 0x09, - 0x2d, 0x0a, - 0x2e, 0x00, - 0x2f, 0x00, - 0x30, 0x00, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x13, - 0xff, 0xff, -}; - -static struct stv0299_config opera1_stv0299_config = { - .demod_address = 0xd0>>1, - .min_delay_ms = 100, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .inittab = opera1_inittab, - .set_symbol_rate = opera1_stv0299_set_symbol_rate, -}; - -static int opera1_frontend_attach(struct dvb_usb_adapter *d) -{ - d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config, - &d->dev->i2c_adap); - if ((d->fe_adap[0].fe) != NULL) { - d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage; - return 0; - } - info("not attached stv0299"); - return -EIO; -} - -static int opera1_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach( - dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1, - &adap->dev->i2c_adap, DVB_PLL_OPERA1 - ); - return 0; -} - -static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 val = onoff ? 0x01 : 0x00; - - if (dvb_usb_opera1_debug) - info("power %s", onoff ? "on" : "off"); - return opera1_xilinx_rw(d->udev, 0xb7, val, - &val, 1, OPERA_WRITE_MSG); -} - -static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - static u8 buf_start[2] = { 0xff, 0x03 }; - static u8 buf_stop[2] = { 0xff, 0x00 }; - struct i2c_msg start_tuner[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2}, - }; - if (dvb_usb_opera1_debug) - info("streaming %s", onoff ? "on" : "off"); - i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1); - return 0; -} - -static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - u8 b_pid[3]; - struct i2c_msg msg[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, - }; - if (dvb_usb_opera1_debug) - info("pidfilter index: %d pid: %d %s", index, pid, - onoff ? "on" : "off"); - b_pid[0] = (2 * index) + 4; - b_pid[1] = onoff ? (pid & 0xff) : (0x00); - b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00); - i2c_transfer(&adap->dev->i2c_adap, msg, 1); - return 0; -} - -static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) -{ - int u = 0x04; - u8 b_pid[3]; - struct i2c_msg msg[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, - }; - if (dvb_usb_opera1_debug) - info("%s hw-pidfilter", onoff ? "enable" : "disable"); - for (; u < 0x7e; u += 2) { - b_pid[0] = u; - b_pid[1] = 0; - b_pid[2] = 0x80; - i2c_transfer(&adap->dev->i2c_adap, msg, 1); - } - return 0; -} - -static struct rc_map_table rc_map_opera1_table[] = { - {0x5fa0, KEY_1}, - {0x51af, KEY_2}, - {0x5da2, KEY_3}, - {0x41be, KEY_4}, - {0x0bf5, KEY_5}, - {0x43bd, KEY_6}, - {0x47b8, KEY_7}, - {0x49b6, KEY_8}, - {0x05fa, KEY_9}, - {0x45ba, KEY_0}, - {0x09f6, KEY_CHANNELUP}, /*chanup */ - {0x1be5, KEY_CHANNELDOWN}, /*chandown */ - {0x5da3, KEY_VOLUMEDOWN}, /*voldown */ - {0x5fa1, KEY_VOLUMEUP}, /*volup */ - {0x07f8, KEY_SPACE}, /*tab */ - {0x1fe1, KEY_OK}, /*play ok */ - {0x1be4, KEY_ZOOM}, /*zoom */ - {0x59a6, KEY_MUTE}, /*mute */ - {0x5ba5, KEY_RADIO}, /*tv/f */ - {0x19e7, KEY_RECORD}, /*rec */ - {0x01fe, KEY_STOP}, /*Stop */ - {0x03fd, KEY_PAUSE}, /*pause */ - {0x03fc, KEY_SCREEN}, /*<- -> */ - {0x07f9, KEY_CAMERA}, /*capture */ - {0x47b9, KEY_ESC}, /*exit */ - {0x43bc, KEY_POWER2}, /*power */ -}; - -static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) -{ - struct opera1_state *opst = dev->priv; - u8 rcbuffer[32]; - const u16 startmarker1 = 0x10ed; - const u16 startmarker2 = 0x11ec; - struct i2c_msg read_remote[] = { - {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32}, - }; - int i = 0; - u32 send_key = 0; - - if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) { - for (i = 0; i < 32; i++) { - if (rcbuffer[i]) - send_key |= 1; - if (i < 31) - send_key = send_key << 1; - } - if (send_key & 0x8000) - send_key = (send_key << 1) | (send_key >> 15 & 0x01); - - if (send_key == 0xffff && opst->last_key_pressed != 0) { - *state = REMOTE_KEY_REPEAT; - *event = opst->last_key_pressed; - return 0; - } - for (; send_key != 0;) { - if (send_key >> 16 == startmarker2) { - break; - } else if (send_key >> 16 == startmarker1) { - send_key = - (send_key & 0xfffeffff) | (startmarker1 << 16); - break; - } else - send_key >>= 1; - } - - if (send_key == 0) - return 0; - - send_key = (send_key & 0xffff) | 0x0100; - - for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) { - if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_opera1_table[i].keycode; - opst->last_key_pressed = - rc_map_opera1_table[i].keycode; - break; - } - opst->last_key_pressed = 0; - } - } else - *state = REMOTE_NO_KEY_PRESSED; - return 0; -} - -static struct usb_device_id opera1_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, - {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, opera1_table); - -static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - u8 command[] = { READ_MAC_ADDR }; - opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); - opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); - return 0; -} -static int opera1_xilinx_load_firmware(struct usb_device *dev, - const char *filename) -{ - const struct firmware *fw = NULL; - u8 *b, *p; - int ret = 0, i,fpgasize=40; - u8 testval; - info("start downloading fpga firmware %s",filename); - - if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", - filename); - return ret; - } else { - p = kmalloc(fw->size, GFP_KERNEL); - opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG); - if (p != NULL && testval != 0x67) { - - u8 reset = 0, fpga_command = 0; - memcpy(p, fw->data, fw->size); - /* clear fpga ? */ - opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, - OPERA_WRITE_MSG); - for (i = 0; i < fw->size;) { - if ( (fw->size - i) size-i; - } - b = (u8 *) p + i; - if (opera1_xilinx_rw - (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize, - OPERA_WRITE_MSG) != fpgasize - ) { - err("error while transferring firmware"); - ret = -EINVAL; - break; - } - i = i + fpgasize; - } - /* restart the CPU */ - if (ret || opera1_xilinx_rw - (dev, 0xa0, 0xe600, &reset, 1, - OPERA_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - } - } - kfree(p); - release_firmware(fw); - return ret; -} - -static struct dvb_usb_device_properties opera1_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-opera-01.fw", - .size_of_priv = sizeof(struct opera1_state), - - .power_ctrl = opera1_power_ctrl, - .i2c_algo = &opera1_i2c_algo, - - .rc.legacy = { - .rc_map_table = rc_map_opera1_table, - .rc_map_size = ARRAY_SIZE(rc_map_opera1_table), - .rc_interval = 200, - .rc_query = opera1_rc_query, - }, - .read_mac_address = opera1_read_mac_address, - .generic_bulk_ctrl_endpoint = 0x00, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = opera1_frontend_attach, - .streaming_ctrl = opera1_streaming_ctrl, - .tuner_attach = opera1_tuner_attach, - .caps = - DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter = opera1_pid_filter, - .pid_filter_ctrl = opera1_pid_filter_control, - .pid_filter_count = 252, - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .num_device_descs = 1, - .devices = { - {"Opera1 DVB-S USB2.0", - {&opera1_table[0], NULL}, - {&opera1_table[1], NULL}, - }, - } -}; - -static int opera1_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - - if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && - udev->descriptor.idVendor == USB_VID_OPERA1 && - opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0 - ) { - return -EINVAL; - } - - if (0 != dvb_usb_device_init(intf, &opera1_properties, - THIS_MODULE, NULL, adapter_nr)) - return -EINVAL; - return 0; -} - -static struct usb_driver opera1_driver = { - .name = "opera1", - .probe = opera1_probe, - .disconnect = dvb_usb_device_exit, - .id_table = opera1_table, -}; - -module_usb_driver(opera1_driver); - -MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org"); -MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de"); -MODULE_DESCRIPTION("Driver for Opera1 DVB-S device"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c deleted file mode 100644 index 02e878577c3..00000000000 --- a/drivers/media/dvb/dvb-usb/pctv452e.c +++ /dev/null @@ -1,1063 +0,0 @@ -/* - * PCTV 452e DVB driver - * - * Copyright (c) 2006-2008 Dominik Kuhlen - * - * TT connect S2-3650-CI Common Interface support, MAC readout - * Copyright (C) 2008 Michael H. Schimek - * - * 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. - */ - -/* dvb usb framework */ -#define DVB_USB_LOG_PREFIX "pctv452e" -#include "dvb-usb.h" - -/* Demodulator */ -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -/* Tuner */ -#include "stb6100.h" -#include "stb6100_cfg.h" -/* FE Power */ -#include "lnbp22.h" - -#include "dvb_ca_en50221.h" -#include "ttpci-eeprom.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define ISOC_INTERFACE_ALTERNATIVE 3 - -#define SYNC_BYTE_OUT 0xaa -#define SYNC_BYTE_IN 0x55 - -/* guessed: (copied from ttusb-budget) */ -#define PCTV_CMD_RESET 0x15 -/* command to poll IR receiver */ -#define PCTV_CMD_IR 0x1b -/* command to send I2C */ -#define PCTV_CMD_I2C 0x31 - -#define I2C_ADDR_STB0899 (0xd0 >> 1) -#define I2C_ADDR_STB6100 (0xc0 >> 1) -#define I2C_ADDR_LNBP22 (0x10 >> 1) -#define I2C_ADDR_24C16 (0xa0 >> 1) -#define I2C_ADDR_24C64 (0xa2 >> 1) - - -/* pctv452e sends us this amount of data for each issued usb-command */ -#define PCTV_ANSWER_LEN 64 -/* Wait up to 1000ms for device */ -#define PCTV_TIMEOUT 1000 - - -#define PCTV_LED_GPIO STB0899_GPIO01 -#define PCTV_LED_GREEN 0x82 -#define PCTV_LED_ORANGE 0x02 - -#define ci_dbg(format, arg...) \ -do { \ - if (0) \ - printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ - ": " format "\n" , ## arg); \ -} while (0) - -enum { - TT3650_CMD_CI_TEST = 0x40, - TT3650_CMD_CI_RD_CTRL, - TT3650_CMD_CI_WR_CTRL, - TT3650_CMD_CI_RD_ATTR, - TT3650_CMD_CI_WR_ATTR, - TT3650_CMD_CI_RESET, - TT3650_CMD_CI_SET_VIDEO_PORT -}; - - -static struct stb0899_postproc pctv45e_postproc[] = { - { PCTV_LED_GPIO, STB0899_GPIOPULLUP }, - { 0, 0 } -}; - -/* - * stores all private variables for communication with the PCTV452e DVB-S2 - */ -struct pctv452e_state { - struct dvb_ca_en50221 ca; - struct mutex ca_mutex; - - u8 c; /* transaction counter, wraps around... */ - u8 initialized; /* set to 1 if 0x15 has been sent */ - u16 last_rc_key; -}; - -static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, - unsigned int write_len, unsigned int read_len) -{ - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - u8 buf[64]; - u8 id; - unsigned int rlen; - int ret; - - BUG_ON(NULL == data && 0 != (write_len | read_len)); - BUG_ON(write_len > 64 - 4); - BUG_ON(read_len > 64 - 4); - - id = state->c++; - - buf[0] = SYNC_BYTE_OUT; - buf[1] = id; - buf[2] = cmd; - buf[3] = write_len; - - memcpy(buf + 4, data, write_len); - - rlen = (read_len > 0) ? 64 : 0; - ret = dvb_usb_generic_rw(d, buf, 4 + write_len, - buf, rlen, /* delay_ms */ 0); - if (0 != ret) - goto failed; - - ret = -EIO; - if (SYNC_BYTE_IN != buf[0] || id != buf[1]) - goto failed; - - memcpy(data, buf + 4, read_len); - - return 0; - -failed: - err("CI error %d; %02X %02X %02X -> %*ph.", - ret, SYNC_BYTE_OUT, id, cmd, 3, buf); - - return ret; -} - -static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, - u8 cmd, u8 *data, unsigned int write_len, - unsigned int read_len) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - int ret; - - mutex_lock(&state->ca_mutex); - ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); - mutex_unlock(&state->ca_mutex); - - return ret; -} - -static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, int address) -{ - u8 buf[3]; - int ret; - - if (0 != slot) - return -EINVAL; - - buf[0] = (address >> 8) & 0x0F; - buf[1] = address; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); - - ci_dbg("%s %04x -> %d 0x%02x", - __func__, address, ret, buf[2]); - - if (ret < 0) - return ret; - - return buf[2]; -} - -static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, int address, u8 value) -{ - u8 buf[3]; - - ci_dbg("%s %d 0x%04x 0x%02x", - __func__, slot, address, value); - - if (0 != slot) - return -EINVAL; - - buf[0] = (address >> 8) & 0x0F; - buf[1] = address; - buf[2] = value; - - return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); -} - -static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address) -{ - u8 buf[2]; - int ret; - - if (0 != slot) - return -EINVAL; - - buf[0] = address & 3; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); - - ci_dbg("%s 0x%02x -> %d 0x%02x", - __func__, address, ret, buf[1]); - - if (ret < 0) - return ret; - - return buf[1]; -} - -static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address, - u8 value) -{ - u8 buf[2]; - - ci_dbg("%s %d 0x%02x 0x%02x", - __func__, slot, address, value); - - if (0 != slot) - return -EINVAL; - - buf[0] = address; - buf[1] = value; - - return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); -} - -static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, - int slot, - int enable) -{ - u8 buf[1]; - int ret; - - ci_dbg("%s %d %d", __func__, slot, enable); - - if (0 != slot) - return -EINVAL; - - enable = !!enable; - buf[0] = enable; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); - if (ret < 0) - return ret; - - if (enable != buf[0]) { - err("CI not %sabled.", enable ? "en" : "dis"); - return -EIO; - } - - return 0; -} - -static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - return tt3650_ci_set_video_port(ca, slot, /* enable */ 0); -} - -static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - return tt3650_ci_set_video_port(ca, slot, /* enable */ 1); -} - -static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - u8 buf[1]; - int ret; - - ci_dbg("%s %d", __func__, slot); - - if (0 != slot) - return -EINVAL; - - buf[0] = 0; - - mutex_lock(&state->ca_mutex); - - ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); - if (0 != ret) - goto failed; - - msleep(500); - - buf[0] = 1; - - ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); - if (0 != ret) - goto failed; - - msleep(500); - - buf[0] = 0; /* FTA */ - - ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); - - failed: - mutex_unlock(&state->ca_mutex); - - return ret; -} - -static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, - int slot, - int open) -{ - u8 buf[1]; - int ret; - - if (0 != slot) - return -EINVAL; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); - if (0 != ret) - return ret; - - if (1 == buf[0]) - return DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - - return 0; - -} - -static void tt3650_ci_uninit(struct dvb_usb_device *d) -{ - struct pctv452e_state *state; - - ci_dbg("%s", __func__); - - if (NULL == d) - return; - - state = (struct pctv452e_state *)d->priv; - if (NULL == state) - return; - - if (NULL == state->ca.data) - return; - - /* Error ignored. */ - tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0); - - dvb_ca_en50221_release(&state->ca); - - memset(&state->ca, 0, sizeof(state->ca)); -} - -static int tt3650_ci_init(struct dvb_usb_adapter *a) -{ - struct dvb_usb_device *d = a->dev; - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - int ret; - - ci_dbg("%s", __func__); - - mutex_init(&state->ca_mutex); - - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; - state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; - state->ca.read_cam_control = tt3650_ci_read_cam_control; - state->ca.write_cam_control = tt3650_ci_write_cam_control; - state->ca.slot_reset = tt3650_ci_slot_reset; - state->ca.slot_shutdown = tt3650_ci_slot_shutdown; - state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; - state->ca.poll_slot_status = tt3650_ci_poll_slot_status; - state->ca.data = d; - - ret = dvb_ca_en50221_init(&a->dvb_adap, - &state->ca, - /* flags */ 0, - /* n_slots */ 1); - if (0 != ret) { - err("Cannot initialize CI: Error %d.", ret); - memset(&state->ca, 0, sizeof(state->ca)); - return ret; - } - - info("CI initialized."); - - return 0; -} - -#define CMD_BUFFER_SIZE 0x28 -static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, - const u8 *snd_buf, u8 snd_len, - u8 *rcv_buf, u8 rcv_len) -{ - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - u8 buf[64]; - u8 id; - int ret; - - id = state->c++; - - ret = -EINVAL; - if (snd_len > 64 - 7 || rcv_len > 64 - 7) - goto failed; - - buf[0] = SYNC_BYTE_OUT; - buf[1] = id; - buf[2] = PCTV_CMD_I2C; - buf[3] = snd_len + 3; - buf[4] = addr << 1; - buf[5] = snd_len; - buf[6] = rcv_len; - - memcpy(buf + 7, snd_buf, snd_len); - - ret = dvb_usb_generic_rw(d, buf, 7 + snd_len, - buf, /* rcv_len */ 64, - /* delay_ms */ 0); - if (ret < 0) - goto failed; - - /* TT USB protocol error. */ - ret = -EIO; - if (SYNC_BYTE_IN != buf[0] || id != buf[1]) - goto failed; - - /* I2C device didn't respond as expected. */ - ret = -EREMOTEIO; - if (buf[5] < snd_len || buf[6] < rcv_len) - goto failed; - - memcpy(rcv_buf, buf + 7, rcv_len); - - return rcv_len; - -failed: - err("I2C error %d; %02X %02X %02X %02X %02X -> " - "%02X %02X %02X %02X %02X.", - ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len, - buf[0], buf[1], buf[4], buf[5], buf[6]); - - return ret; -} - -static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adapter); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; - int ret; - - if (msg[i].flags & I2C_M_RD) { - addr = msg[i].addr; - snd_buf = NULL; - snd_len = 0; - rcv_buf = msg[i].buf; - rcv_len = msg[i].len; - } else { - addr = msg[i].addr; - snd_buf = msg[i].buf; - snd_len = msg[i].len; - rcv_buf = NULL; - rcv_len = 0; - } - - ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, - rcv_len); - if (ret < rcv_len) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) -{ - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 }; - u8 rx[PCTV_ANSWER_LEN]; - int ret; - - info("%s: %d\n", __func__, i); - - if (!i) - return 0; - - if (state->initialized) - return 0; - - /* hmm where shoud this should go? */ - ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE); - if (ret != 0) - info("%s: Warning set interface returned: %d\n", - __func__, ret); - - /* this is a one-time initialization, dont know where to put */ - b0[1] = state->c++; - /* reset board */ - ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0); - if (ret) - return ret; - - b0[1] = state->c++; - b0[4] = 1; - /* reset board (again?) */ - ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0); - if (ret) - return ret; - - state->initialized = 1; - - return 0; -} - -static int pctv452e_rc_query(struct dvb_usb_device *d) -{ - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - u8 b[CMD_BUFFER_SIZE]; - u8 rx[PCTV_ANSWER_LEN]; - int ret, i; - u8 id = state->c++; - - /* prepare command header */ - b[0] = SYNC_BYTE_OUT; - b[1] = id; - b[2] = PCTV_CMD_IR; - b[3] = 0; - - /* send ir request */ - ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0); - if (ret != 0) - return ret; - - if (debug > 3) { - info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx); - for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) - info(" %02x", rx[i+3]); - - info("\n"); - } - - if ((rx[3] == 9) && (rx[12] & 0x01)) { - /* got a "press" event */ - state->last_rc_key = (rx[7] << 8) | rx[6]; - if (debug > 2) - info("%s: cmd=0x%02x sys=0x%02x\n", - __func__, rx[6], rx[7]); - - rc_keydown(d->rc_dev, state->last_rc_key, 0); - } else if (state->last_rc_key) { - rc_keyup(d->rc_dev); - state->last_rc_key = 0; - } - - return 0; -} - -static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - const u8 mem_addr[] = { 0x1f, 0xcc }; - u8 encoded_mac[20]; - int ret; - - ret = -EAGAIN; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - goto failed; - - ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16, - mem_addr + 1, /* snd_len */ 1, - encoded_mac, /* rcv_len */ 20); - if (-EREMOTEIO == ret) - /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a - byte write if /WC is low. */ - ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64, - mem_addr, 2, - encoded_mac, 20); - - mutex_unlock(&d->i2c_mutex); - - if (20 != ret) - goto failed; - - ret = ttpci_eeprom_decode_mac(mac, encoded_mac); - if (0 != ret) - goto failed; - - return 0; - -failed: - memset(mac, 0, 6); - - return ret; -} - -static const struct stb0899_s1_reg pctv452e_init_dev[] = { - { STB0899_DISCNTRL1, 0x26 }, - { STB0899_DISCNTRL2, 0x80 }, - { STB0899_DISRX_ST0, 0x04 }, - { STB0899_DISRX_ST1, 0x20 }, - { STB0899_DISPARITY, 0x00 }, - { STB0899_DISFIFO, 0x00 }, - { STB0899_DISF22, 0x99 }, - { STB0899_DISF22RX, 0x85 }, /* 0xa8 */ - { STB0899_ACRPRESC, 0x11 }, - { STB0899_ACRDIV1, 0x0a }, - { STB0899_ACRDIV2, 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG, 0x00 }, - { STB0899_MODECFG, 0x00 }, /* Inversion */ - { STB0899_IRQMSK_3, 0xf3 }, - { STB0899_IRQMSK_2, 0xfc }, - { STB0899_IRQMSK_1, 0xff }, - { STB0899_IRQMSK_0, 0xff }, - { STB0899_I2CCFG, 0x88 }, - { STB0899_I2CRPT, 0x58 }, - { STB0899_GPIO00CFG, 0x82 }, - { STB0899_GPIO01CFG, 0x82 }, /* LED: 0x02 green, 0x82 orange */ - { STB0899_GPIO02CFG, 0x82 }, - { STB0899_GPIO03CFG, 0x82 }, - { STB0899_GPIO04CFG, 0x82 }, - { STB0899_GPIO05CFG, 0x82 }, - { STB0899_GPIO06CFG, 0x82 }, - { STB0899_GPIO07CFG, 0x82 }, - { STB0899_GPIO08CFG, 0x82 }, - { STB0899_GPIO09CFG, 0x82 }, - { STB0899_GPIO10CFG, 0x82 }, - { STB0899_GPIO11CFG, 0x82 }, - { STB0899_GPIO12CFG, 0x82 }, - { STB0899_GPIO13CFG, 0x82 }, - { STB0899_GPIO14CFG, 0x82 }, - { STB0899_GPIO15CFG, 0x82 }, - { STB0899_GPIO16CFG, 0x82 }, - { STB0899_GPIO17CFG, 0x82 }, - { STB0899_GPIO18CFG, 0x82 }, - { STB0899_GPIO19CFG, 0x82 }, - { STB0899_GPIO20CFG, 0x82 }, - { STB0899_SDATCFG, 0xb8 }, - { STB0899_SCLTCFG, 0xba }, - { STB0899_AGCRFCFG, 0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */ - { STB0899_GPIO22, 0x82 }, - { STB0899_GPIO21, 0x91 }, - { STB0899_DIRCLKCFG, 0x82 }, - { STB0899_CLKOUT27CFG, 0x7e }, - { STB0899_STDBYCFG, 0x82 }, - { STB0899_CS0CFG, 0x82 }, - { STB0899_CS1CFG, 0x82 }, - { STB0899_DISEQCOCFG, 0x20 }, - { STB0899_NCOARSE, 0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */ - { STB0899_SYNTCTRL, 0x00 }, /* 0x00 CLKI, 0x02 XTALI */ - { STB0899_FILTCTRL, 0x00 }, - { STB0899_SYSCTRL, 0x00 }, - { STB0899_STOPCLK1, 0x20 }, /* orig: 0x00 budget-ci: 0x20 */ - { STB0899_STOPCLK2, 0x00 }, - { STB0899_INTBUFCTRL, 0x0a }, - { STB0899_AGC2I1, 0x00 }, - { STB0899_AGC2I2, 0x00 }, - { STB0899_AGCIQIN, 0x00 }, - { STB0899_TSTRES, 0x40 }, /* rjkm */ - { 0xffff, 0xff }, -}; - -static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = { - { STB0899_DEMOD, 0x00 }, - { STB0899_RCOMPC, 0xc9 }, - { STB0899_AGC1CN, 0x01 }, - { STB0899_AGC1REF, 0x10 }, - { STB0899_RTC, 0x23 }, - { STB0899_TMGCFG, 0x4e }, - { STB0899_AGC2REF, 0x34 }, - { STB0899_TLSR, 0x84 }, - { STB0899_CFD, 0xf7 }, - { STB0899_ACLC, 0x87 }, - { STB0899_BCLC, 0x94 }, - { STB0899_EQON, 0x41 }, - { STB0899_LDT, 0xf1 }, - { STB0899_LDT2, 0xe3 }, - { STB0899_EQUALREF, 0xb4 }, - { STB0899_TMGRAMP, 0x10 }, - { STB0899_TMGTHD, 0x30 }, - { STB0899_IDCCOMP, 0xfd }, - { STB0899_QDCCOMP, 0xff }, - { STB0899_POWERI, 0x0c }, - { STB0899_POWERQ, 0x0f }, - { STB0899_RCOMP, 0x6c }, - { STB0899_AGCIQIN, 0x80 }, - { STB0899_AGC2I1, 0x06 }, - { STB0899_AGC2I2, 0x00 }, - { STB0899_TLIR, 0x30 }, - { STB0899_RTF, 0x7f }, - { STB0899_DSTATUS, 0x00 }, - { STB0899_LDI, 0xbc }, - { STB0899_CFRM, 0xea }, - { STB0899_CFRL, 0x31 }, - { STB0899_NIRM, 0x2b }, - { STB0899_NIRL, 0x80 }, - { STB0899_ISYMB, 0x1d }, - { STB0899_QSYMB, 0xa6 }, - { STB0899_SFRH, 0x2f }, - { STB0899_SFRM, 0x68 }, - { STB0899_SFRL, 0x40 }, - { STB0899_SFRUPH, 0x2f }, - { STB0899_SFRUPM, 0x68 }, - { STB0899_SFRUPL, 0x40 }, - { STB0899_EQUAI1, 0x02 }, - { STB0899_EQUAQ1, 0xff }, - { STB0899_EQUAI2, 0x04 }, - { STB0899_EQUAQ2, 0x05 }, - { STB0899_EQUAI3, 0x02 }, - { STB0899_EQUAQ3, 0xfd }, - { STB0899_EQUAI4, 0x03 }, - { STB0899_EQUAQ4, 0x07 }, - { STB0899_EQUAI5, 0x08 }, - { STB0899_EQUAQ5, 0xf5 }, - { STB0899_DSTATUS2, 0x00 }, - { STB0899_VSTATUS, 0x00 }, - { STB0899_VERROR, 0x86 }, - { STB0899_IQSWAP, 0x2a }, - { STB0899_ECNT1M, 0x00 }, - { STB0899_ECNT1L, 0x00 }, - { STB0899_ECNT2M, 0x00 }, - { STB0899_ECNT2L, 0x00 }, - { STB0899_ECNT3M, 0x0a }, - { STB0899_ECNT3L, 0xad }, - { STB0899_FECAUTO1, 0x06 }, - { STB0899_FECM, 0x01 }, - { STB0899_VTH12, 0xb0 }, - { STB0899_VTH23, 0x7a }, - { STB0899_VTH34, 0x58 }, - { STB0899_VTH56, 0x38 }, - { STB0899_VTH67, 0x34 }, - { STB0899_VTH78, 0x24 }, - { STB0899_PRVIT, 0xff }, - { STB0899_VITSYNC, 0x19 }, - { STB0899_RSULC, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC, 0x42 }, - { STB0899_RSLLC, 0x41 }, - { STB0899_TSLPL, 0x12 }, - { STB0899_TSCFGH, 0x0c }, - { STB0899_TSCFGM, 0x00 }, - { STB0899_TSCFGL, 0x00 }, - { STB0899_TSOUT, 0x69 }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL, 0x00 }, - { STB0899_TSINHDELH, 0x02 }, - { STB0899_TSINHDELM, 0x00 }, - { STB0899_TSINHDELL, 0x00 }, - { STB0899_TSLLSTKM, 0x1b }, - { STB0899_TSLLSTKL, 0xb3 }, - { STB0899_TSULSTKM, 0x00 }, - { STB0899_TSULSTKL, 0x00 }, - { STB0899_PCKLENUL, 0xbc }, - { STB0899_PCKLENLL, 0xcc }, - { STB0899_RSPCKLEN, 0xbd }, - { STB0899_TSSTATUS, 0x90 }, - { STB0899_ERRCTRL1, 0xb6 }, - { STB0899_ERRCTRL2, 0x95 }, - { STB0899_ERRCTRL3, 0x8d }, - { STB0899_DMONMSK1, 0x27 }, - { STB0899_DMONMSK0, 0x03 }, - { STB0899_DEMAPVIT, 0x5c }, - { STB0899_PLPARM, 0x19 }, - { STB0899_PDELCTRL, 0x48 }, - { STB0899_PDELCTRL2, 0x00 }, - { STB0899_BBHCTRL1, 0x00 }, - { STB0899_BBHCTRL2, 0x00 }, - { STB0899_HYSTTHRESH, 0x77 }, - { STB0899_MATCSTM, 0x00 }, - { STB0899_MATCSTL, 0x00 }, - { STB0899_UPLCSTM, 0x00 }, - { STB0899_UPLCSTL, 0x00 }, - { STB0899_DFLCSTM, 0x00 }, - { STB0899_DFLCSTL, 0x00 }, - { STB0899_SYNCCST, 0x00 }, - { STB0899_SYNCDCSTM, 0x00 }, - { STB0899_SYNCDCSTL, 0x00 }, - { STB0899_ISI_ENTRY, 0x00 }, - { STB0899_ISI_BIT_EN, 0x00 }, - { STB0899_MATSTRM, 0xf0 }, - { STB0899_MATSTRL, 0x02 }, - { STB0899_UPLSTRM, 0x45 }, - { STB0899_UPLSTRL, 0x60 }, - { STB0899_DFLSTRM, 0xe3 }, - { STB0899_DFLSTRL, 0x00 }, - { STB0899_SYNCSTR, 0x47 }, - { STB0899_SYNCDSTRM, 0x05 }, - { STB0899_SYNCDSTRL, 0x18 }, - { STB0899_CFGPDELSTATUS1, 0x19 }, - { STB0899_CFGPDELSTATUS2, 0x2b }, - { STB0899_BBFERRORM, 0x00 }, - { STB0899_BBFERRORL, 0x01 }, - { STB0899_UPKTERRORM, 0x00 }, - { STB0899_UPKTERRORL, 0x00 }, - { 0xffff, 0xff }, -}; - -static struct stb0899_config stb0899_config = { - .init_dev = pctv452e_init_dev, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = pctv452e_init_s1_demod, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .demod_address = I2C_ADDR_STB0899, /* I2C Address */ - .block_sync_mode = STB0899_SYNC_FORCED, /* ? */ - - .xtal_freq = 27000000, /* Assume Hz ? */ - .inversion = IQ_SWAP_ON, /* ? */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .ts_output_mode = 0, /* Use parallel mode */ - .clock_polarity = 0, - .data_clk_parity = 0, - .fec_mode = 0, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL, - - /* helper for switching LED green/orange */ - .postproc = pctv45e_postproc -}; - -static struct stb6100_config stb6100_config = { - .tuner_address = I2C_ADDR_STB6100, - .refclock = 27000000 -}; - - -static struct i2c_algorithm pctv452e_i2c_algo = { - .master_xfer = pctv452e_i2c_xfer, - .functionality = pctv452e_i2c_func -}; - -static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) -{ - struct usb_device_id *id; - - a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config, - &a->dev->i2c_adap); - if (!a->fe_adap[0].fe) - return -ENODEV; - if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe, - &a->dev->i2c_adap)) == 0) - err("Cannot attach lnbp22\n"); - - id = a->dev->desc->warm_ids[0]; - if (USB_VID_TECHNOTREND == id->idVendor - && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) - /* Error ignored. */ - tt3650_ci_init(a); - - return 0; -} - -static int pctv452e_tuner_attach(struct dvb_usb_adapter *a) -{ - if (!a->fe_adap[0].fe) - return -ENODEV; - if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config, - &a->dev->i2c_adap) == 0) { - err("%s failed\n", __func__); - return -ENODEV; - } - - return 0; -} - -static struct usb_device_id pctv452e_usb_table[] = { - {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)}, - {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)}, - {USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)}, - {} -}; -MODULE_DEVICE_TABLE(usb, pctv452e_usb_table); - -static struct dvb_usb_device_properties pctv452e_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */ - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = sizeof(struct pctv452e_state), - - .power_ctrl = pctv452e_power_ctrl, - - .rc.core = { - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .allowed_protos = RC_TYPE_UNKNOWN, - .rc_query = pctv452e_rc_query, - .rc_interval = 100, - }, - - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - .frontend_attach = pctv452e_frontend_attach, - .tuner_attach = pctv452e_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 4, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1 - } - } - }, - } }, - } }, - - .i2c_algo = &pctv452e_i2c_algo, - - .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */ - - .num_device_descs = 1, - .devices = { - { .name = "PCTV HDTV USB", - .cold_ids = { NULL, NULL }, /* this is a warm only device */ - .warm_ids = { &pctv452e_usb_table[0], NULL } - }, - { 0 }, - } -}; - -static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */ - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = sizeof(struct pctv452e_state), - - .power_ctrl = pctv452e_power_ctrl, - .read_mac_address = pctv452e_read_mac_address, - - .rc.core = { - .rc_codes = RC_MAP_TT_1500, - .allowed_protos = RC_TYPE_UNKNOWN, - .rc_query = pctv452e_rc_query, - .rc_interval = 100, - }, - - .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - .frontend_attach = pctv452e_frontend_attach, - .tuner_attach = pctv452e_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 7, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1 - } - } - }, - - } }, - } }, - - .i2c_algo = &pctv452e_i2c_algo, - - .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/ - - .num_device_descs = 2, - .devices = { - { .name = "Technotrend TT Connect S2-3600", - .cold_ids = { NULL, NULL }, /* this is a warm only device */ - .warm_ids = { &pctv452e_usb_table[1], NULL } - }, - { .name = "Technotrend TT Connect S2-3650-CI", - .cold_ids = { NULL, NULL }, - .warm_ids = { &pctv452e_usb_table[2], NULL } - }, - { 0 }, - } -}; - -static void pctv452e_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - - tt3650_ci_uninit(d); - dvb_usb_device_exit(intf); -} - -static int pctv452e_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &pctv452e_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -ENODEV; -} - -static struct usb_driver pctv452e_usb_driver = { - .name = "pctv452e", - .probe = pctv452e_usb_probe, - .disconnect = pctv452e_usb_disconnect, - .id_table = pctv452e_usb_table, -}; - -module_usb_driver(pctv452e_usb_driver); - -MODULE_AUTHOR("Dominik Kuhlen "); -MODULE_AUTHOR("Andre Weidemann "); -MODULE_AUTHOR("Michael H. Schimek "); -MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c deleted file mode 100644 index acefaa89cc5..00000000000 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - * Linux driver for Technisat DVB-S/S2 USB 2.0 device - * - * Copyright (C) 2010 Patrick Boettcher, - * Kernel Labs Inc. PO Box 745, St James, NY 11780 - * - * Development was sponsored by Technisat Digital UK Limited, whose - * registered office is Witan Gate House 500 - 600 Witan Gate West, - * Milton Keynes, MK9 1SH - * - * 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. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND - * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR - * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER - * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, - * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR - * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the - * GNU General Public License for more details. - */ - -#define DVB_USB_LOG_PREFIX "technisat-usb2" -#include "dvb-usb.h" - -#include "stv6110x.h" -#include "stv090x.h" - -/* module parameters */ -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \ - DVB_USB_DEBUG_STATUS); - -/* disables all LED control command and - * also does not start the signal polling thread */ -static int disable_led_control; -module_param(disable_led_control, int, 0444); -MODULE_PARM_DESC(disable_led_control, - "disable LED control of the device " - "(default: 0 - LED control is active)."); - -/* device private data */ -struct technisat_usb2_state { - struct dvb_usb_device *dev; - struct delayed_work green_led_work; - u8 power_state; - - u16 last_scan_code; -}; - -/* debug print helpers */ -#define deb_info(args...) dprintk(debug, 0x01, args) -#define deb_eeprom(args...) dprintk(debug, 0x02, args) -#define deb_i2c(args...) dprintk(debug, 0x04, args) -#define deb_rc(args...) dprintk(debug, 0x08, args) - -/* vendor requests */ -#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3 -#define SET_FRONT_END_RESET_VENDOR_REQUEST 0xB4 -#define GET_VERSION_INFO_VENDOR_REQUEST 0xB5 -#define SET_GREEN_LED_VENDOR_REQUEST 0xB6 -#define SET_RED_LED_VENDOR_REQUEST 0xB7 -#define GET_IR_DATA_VENDOR_REQUEST 0xB8 -#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST 0xB9 -#define SET_USB_REENUMERATION 0xBA - -/* i2c-access methods */ -#define I2C_SPEED_100KHZ_BIT 0x40 - -#define I2C_STATUS_NAK 7 -#define I2C_STATUS_OK 8 - -static int technisat_usb2_i2c_access(struct usb_device *udev, - u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) -{ - u8 b[64]; - int ret, actual_length; - - deb_i2c("i2c-access: %02x, tx: ", device_addr); - debug_dump(tx, txlen, deb_i2c); - deb_i2c(" "); - - if (txlen > 62) { - err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)", - device_addr); - txlen = 62; - } - if (rxlen > 62) { - err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)", - device_addr); - txlen = 62; - } - - b[0] = I2C_SPEED_100KHZ_BIT; - b[1] = device_addr << 1; - - if (rx != NULL) { - b[0] |= rxlen; - b[1] |= 1; - } - - memcpy(&b[2], tx, txlen); - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x01), - b, 2 + txlen, - NULL, 1000); - - if (ret < 0) { - err("i2c-error: out failed %02x = %d", device_addr, ret); - return -ENODEV; - } - - ret = usb_bulk_msg(udev, - usb_rcvbulkpipe(udev, 0x01), - b, 64, &actual_length, 1000); - if (ret < 0) { - err("i2c-error: in failed %02x = %d", device_addr, ret); - return -ENODEV; - } - - if (b[0] != I2C_STATUS_OK) { - err("i2c-error: %02x = %d", device_addr, b[0]); - /* handle tuner-i2c-nak */ - if (!(b[0] == I2C_STATUS_NAK && - device_addr == 0x60 - /* && device_is_technisat_usb2 */)) - return -ENODEV; - } - - deb_i2c("status: %d, ", b[0]); - - if (rx != NULL) { - memcpy(rx, &b[2], rxlen); - - deb_i2c("rx (%d): ", rxlen); - debug_dump(rx, rxlen, deb_i2c); - } - - deb_i2c("\n"); - - return 0; -} - -static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - int ret = 0, i; - struct dvb_usb_device *d = i2c_get_adapdata(adap); - - /* Ensure nobody else hits the i2c bus while we're sending our - sequence of messages, (such as the remote control thread) */ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if (i+1 < num && msg[i+1].flags & I2C_M_RD) { - ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr, - msg[i].buf, msg[i].len, - msg[i+1].buf, msg[i+1].len); - if (ret != 0) - break; - i++; - } else { - ret = technisat_usb2_i2c_access(d->udev, msg[i].addr, - msg[i].buf, msg[i].len, - NULL, 0); - if (ret != 0) - break; - } - } - - if (ret == 0) - ret = i; - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm technisat_usb2_i2c_algo = { - .master_xfer = technisat_usb2_i2c_xfer, - .functionality = technisat_usb2_i2c_func, -}; - -#if 0 -static void technisat_usb2_frontend_reset(struct usb_device *udev) -{ - usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SET_FRONT_END_RESET_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 10, 0, - NULL, 0, 500); -} -#endif - -/* LED control */ -enum technisat_usb2_led_state { - LED_OFF, - LED_BLINK, - LED_ON, - LED_UNDEFINED -}; - -static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state) -{ - int ret; - - u8 led[8] = { - red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, - 0 - }; - - if (disable_led_control && state != LED_OFF) - return 0; - - switch (state) { - case LED_ON: - led[1] = 0x82; - break; - case LED_BLINK: - led[1] = 0x82; - if (red) { - led[2] = 0x02; - led[3] = 10; - led[4] = 10; - } else { - led[2] = 0xff; - led[3] = 50; - led[4] = 50; - } - led[5] = 1; - break; - - default: - case LED_OFF: - led[1] = 0x80; - break; - } - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, - led, sizeof(led), 500); - - mutex_unlock(&d->i2c_mutex); - return ret; -} - -static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green) -{ - int ret; - u8 b = 0; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - SET_LED_TIMER_DIVIDER_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - (red << 8) | green, 0, - &b, 1, 500); - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static void technisat_usb2_green_led_control(struct work_struct *work) -{ - struct technisat_usb2_state *state = - container_of(work, struct technisat_usb2_state, green_led_work.work); - struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe; - - if (state->power_state == 0) - goto schedule; - - if (fe != NULL) { - enum fe_status status; - - if (fe->ops.read_status(fe, &status) != 0) - goto schedule; - - if (status & FE_HAS_LOCK) { - u32 ber; - - if (fe->ops.read_ber(fe, &ber) != 0) - goto schedule; - - if (ber > 1000) - technisat_usb2_set_led(state->dev, 0, LED_BLINK); - else - technisat_usb2_set_led(state->dev, 0, LED_ON); - } else - technisat_usb2_set_led(state->dev, 0, LED_OFF); - } - -schedule: - schedule_delayed_work(&state->green_led_work, - msecs_to_jiffies(500)); -} - -/* method to find out whether the firmware has to be downloaded or not */ -static int technisat_usb2_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - int ret; - u8 version[3]; - - /* first select the interface */ - if (usb_set_interface(udev, 0, 1) != 0) - err("could not set alternate setting to 0"); - else - info("set alternate setting"); - - *cold = 0; /* by default do not download a firmware - just in case something is wrong */ - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - GET_VERSION_INFO_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_IN, - 0, 0, - version, sizeof(version), 500); - - if (ret < 0) - *cold = 1; - else { - info("firmware version: %d.%d", version[1], version[2]); - *cold = 0; - } - - return 0; -} - -/* power control */ -static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level) -{ - struct technisat_usb2_state *state = d->priv; - - state->power_state = level; - - if (disable_led_control) - return 0; - - /* green led is turned off in any case - will be turned on when tuning */ - technisat_usb2_set_led(d, 0, LED_OFF); - /* red led is turned on all the time */ - technisat_usb2_set_led(d, 1, LED_ON); - return 0; -} - -/* mac address reading - from the eeprom */ -#if 0 -static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d) -{ - u8 reg; - u8 b[16]; - int i, j; - - /* full EEPROM dump */ - for (j = 0; j < 256 * 4; j += 16) { - reg = j; - if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, ®, 1, b, 16) != 0) - break; - - deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg); - for (i = 0; i < 16; i++) - deb_eeprom("%02x ", b[i]); - deb_eeprom("\n"); - } -} -#endif - -static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length) -{ - u8 lrc = 0; - while (--length) - lrc ^= *b++; - return lrc; -} - -static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d, - u16 offset, u8 *b, u16 length, u8 tries) -{ - u8 bo = offset & 0xff; - struct i2c_msg msg[] = { - { - .addr = 0x50 | ((offset >> 8) & 0x3), - .buf = &bo, - .len = 1 - }, { - .addr = 0x50 | ((offset >> 8) & 0x3), - .flags = I2C_M_RD, - .buf = b, - .len = length - } - }; - - while (tries--) { - int status; - - if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) - break; - - status = - technisat_usb2_calc_lrc(b, length - 1) == b[length - 1]; - - if (status) - return 0; - } - - return -EREMOTEIO; -} - -#define EEPROM_MAC_START 0x3f8 -#define EEPROM_MAC_TOTAL 8 -static int technisat_usb2_read_mac_address(struct dvb_usb_device *d, - u8 mac[]) -{ - u8 buf[EEPROM_MAC_TOTAL]; - - if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START, - buf, EEPROM_MAC_TOTAL, 4) != 0) - return -ENODEV; - - memcpy(mac, buf, 6); - return 0; -} - -/* frontend attach */ -static int technisat_usb2_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - int i; - u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */ - - gpio[2] = 1; /* high - voltage ? */ - - switch (voltage) { - case SEC_VOLTAGE_13: - gpio[0] = 1; - break; - case SEC_VOLTAGE_18: - gpio[0] = 1; - gpio[1] = 1; - break; - default: - case SEC_VOLTAGE_OFF: - break; - } - - for (i = 0; i < 3; i++) - if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0) - return -EREMOTEIO; - return 0; -} - -static struct stv090x_config technisat_usb2_stv090x_config = { - .device = STV0903, - .demod_mode = STV090x_SINGLE, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 8000000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_DVBCI, - .ts1_clk = 13400000, - .ts1_tei = 1, - - .repeater_level = STV090x_RPTLEVEL_64, - - .tuner_bbgain = 6, -}; - -static struct stv6110x_config technisat_usb2_stv6110x_config = { - .addr = 0x60, - .refclk = 16000000, - .clk_div = 2, -}; - -static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) -{ - struct usb_device *udev = a->dev->udev; - int ret; - - a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, - &a->dev->i2c_adap, STV090x_DEMODULATOR_0); - - if (a->fe_adap[0].fe) { - struct stv6110x_devctl *ctl; - - ctl = dvb_attach(stv6110x_attach, - a->fe_adap[0].fe, - &technisat_usb2_stv6110x_config, - &a->dev->i2c_adap); - - if (ctl) { - technisat_usb2_stv090x_config.tuner_init = ctl->tuner_init; - technisat_usb2_stv090x_config.tuner_sleep = ctl->tuner_sleep; - technisat_usb2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - technisat_usb2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - technisat_usb2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - technisat_usb2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - technisat_usb2_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (a->fe_adap[0].fe->ops.init) - a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe); - - if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) - return -EAGAIN; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, - NULL, 0, 500); - mutex_unlock(&a->dev->i2c_mutex); - - if (ret != 0) - err("could not set IF_CLK to external"); - - a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage; - - /* if everything was successful assign a nice name to the frontend */ - strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name, - sizeof(a->fe_adap[0].fe->ops.info.name)); - } else { - dvb_frontend_detach(a->fe_adap[0].fe); - a->fe_adap[0].fe = NULL; - } - } - - technisat_usb2_set_led_timer(a->dev, 1, 1); - - return a->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -/* Remote control */ - -/* the device is giving providing raw IR-signals to the host mapping - * it only to one remote control is just the default implementation - */ -#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889 -#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US) - -#define FIRMWARE_CLOCK_TICK 83333 -#define FIRMWARE_CLOCK_DIVISOR 256 - -#define IR_PERCENT_TOLERANCE 15 - -#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) -#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR) - -#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) -#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR) - -#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) -#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) - -#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) -#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) - -static int technisat_usb2_get_ir(struct dvb_usb_device *d) -{ - u8 buf[62], *b; - int ret; - struct ir_raw_event ev; - - buf[0] = GET_IR_DATA_VENDOR_REQUEST; - buf[1] = 0x08; - buf[2] = 0x8f; - buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT; - buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - GET_IR_DATA_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, - buf, 5, 500); - if (ret < 0) - goto unlock; - - buf[1] = 0; - buf[2] = 0; - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - GET_IR_DATA_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_IN, - 0x8080, 0, - buf, sizeof(buf), 500); - -unlock: - mutex_unlock(&d->i2c_mutex); - - if (ret < 0) - return ret; - - if (ret == 1) - return 0; /* no key pressed */ - - /* decoding */ - b = buf+1; - -#if 0 - deb_rc("RC: %d ", ret); - debug_dump(b, ret, deb_rc); -#endif - - ev.pulse = 0; - while (1) { - ev.pulse = !ev.pulse; - ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000; - ir_raw_event_store(d->rc_dev, &ev); - - b++; - if (*b == 0xff) { - ev.pulse = 0; - ev.duration = 888888*2; - ir_raw_event_store(d->rc_dev, &ev); - break; - } - } - - ir_raw_event_handle(d->rc_dev); - - return 1; -} - -static int technisat_usb2_rc_query(struct dvb_usb_device *d) -{ - int ret = technisat_usb2_get_ir(d); - - if (ret < 0) - return ret; - - if (ret == 0) - return 0; - - if (!disable_led_control) - technisat_usb2_set_led(d, 1, LED_BLINK); - - return 0; -} - -/* DVB-USB and USB stuff follows */ -static struct usb_device_id technisat_usb2_id_table[] = { - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, - { 0 } /* Terminating entry */ -}; - -/* device description */ -static struct dvb_usb_device_properties technisat_usb2_devices = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .identify_state = technisat_usb2_identify_state, - .firmware = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw", - - .size_of_priv = sizeof(struct technisat_usb2_state), - - .i2c_algo = &technisat_usb2_i2c_algo, - - .power_ctrl = technisat_usb2_power_ctrl, - .read_mac_address = technisat_usb2_read_mac_address, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = technisat_usb2_frontend_attach, - - .stream = { - .type = USB_ISOC, - .count = 8, - .endpoint = 0x2, - .u = { - .isoc = { - .framesperurb = 32, - .framesize = 2048, - .interval = 3, - } - } - }, - }}, - .size_of_priv = 0, - }, - }, - - .num_device_descs = 1, - .devices = { - { "Technisat SkyStar USB HD (DVB-S/S2)", - { &technisat_usb2_id_table[0], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = 100, - .rc_codes = RC_MAP_TECHNISAT_USB2, - .module_name = "technisat-usb2", - .rc_query = technisat_usb2_rc_query, - .allowed_protos = RC_TYPE_ALL, - .driver_type = RC_DRIVER_IR_RAW, - } -}; - -static int technisat_usb2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *dev; - - if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE, - &dev, adapter_nr) != 0) - return -ENODEV; - - if (dev) { - struct technisat_usb2_state *state = dev->priv; - state->dev = dev; - - if (!disable_led_control) { - INIT_DELAYED_WORK(&state->green_led_work, - technisat_usb2_green_led_control); - schedule_delayed_work(&state->green_led_work, - msecs_to_jiffies(500)); - } - } - - return 0; -} - -static void technisat_usb2_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *dev = usb_get_intfdata(intf); - - /* work and stuff was only created when the device is is hot-state */ - if (dev != NULL) { - struct technisat_usb2_state *state = dev->priv; - if (state != NULL) - cancel_delayed_work_sync(&state->green_led_work); - } - - dvb_usb_device_exit(intf); -} - -static struct usb_driver technisat_usb2_driver = { - .name = "dvb_usb_technisat_usb2", - .probe = technisat_usb2_probe, - .disconnect = technisat_usb2_disconnect, - .id_table = technisat_usb2_id_table, -}; - -module_usb_driver(technisat_usb2_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c deleted file mode 100644 index e53a1061cb8..00000000000 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ /dev/null @@ -1,820 +0,0 @@ -/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones - * (e.g. Pinnacle 400e DVB-S USB2.0). - * - * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. - * - * TDA8263 + TDA10086 - * - * I2C addresses: - * 0x08 - LNBP21PD - LNB power supply - * 0x0e - TDA10086 - Demodulator - * 0x50 - FX2 eeprom - * 0x60 - TDA8263 - Tuner - * 0x78 ??? - * - * Copyright (c) 2002 Holger Waechtler - * Copyright (c) 2003 Felix Domke - * Copyright (C) 2005-6 Patrick Boettcher - * - * 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 - */ -#define DVB_USB_LOG_PREFIX "ttusb2" -#include "dvb-usb.h" - -#include "ttusb2.h" - -#include "tda826x.h" -#include "tda10086.h" -#include "tda1002x.h" -#include "tda10048.h" -#include "tda827x.h" -#include "lnbp21.h" -/* CA */ -#include "dvb_ca_en50221.h" - -/* debug */ -static int dvb_usb_ttusb2_debug; -#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) -module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); -static int dvb_usb_ttusb2_debug_ci; -module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644); -MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define ci_dbg(format, arg...) \ -do { \ - if (dvb_usb_ttusb2_debug_ci) \ - printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ - ": %s " format "\n" , __func__, ## arg); \ -} while (0) - -enum { - TT3650_CMD_CI_TEST = 0x40, - TT3650_CMD_CI_RD_CTRL, - TT3650_CMD_CI_WR_CTRL, - TT3650_CMD_CI_RD_ATTR, - TT3650_CMD_CI_WR_ATTR, - TT3650_CMD_CI_RESET, - TT3650_CMD_CI_SET_VIDEO_PORT -}; - -struct ttusb2_state { - struct dvb_ca_en50221 ca; - struct mutex ca_mutex; - u8 id; - u16 last_rc_key; -}; - -static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - struct ttusb2_state *st = d->priv; - u8 *s, *r = NULL; - int ret = 0; - - s = kzalloc(wlen+4, GFP_KERNEL); - if (!s) - return -ENOMEM; - - r = kzalloc(64, GFP_KERNEL); - if (!r) { - kfree(s); - return -ENOMEM; - } - - s[0] = 0xaa; - s[1] = ++st->id; - s[2] = cmd; - s[3] = wlen; - memcpy(&s[4],wbuf,wlen); - - ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); - - if (ret != 0 || - r[0] != 0x55 || - r[1] != s[1] || - r[2] != cmd || - (rlen > 0 && r[3] != rlen)) { - warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); - kfree(s); - kfree(r); - return -EIO; - } - - if (rlen > 0) - memcpy(rbuf, &r[4], rlen); - - kfree(s); - kfree(r); - - return 0; -} - -/* ci */ -static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) -{ - int ret; - u8 rx[60];/* (64 -4) */ - ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len); - if (!ret) - memcpy(data, rx, read_len); - return ret; -} - -static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) -{ - struct dvb_usb_device *d = ca->data; - struct ttusb2_state *state = d->priv; - int ret; - - mutex_lock(&state->ca_mutex); - ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); - mutex_unlock(&state->ca_mutex); - - return ret; -} - -static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - u8 buf[3]; - int ret = 0; - - if (slot) - return -EINVAL; - - buf[0] = (address >> 8) & 0x0F; - buf[1] = address; - - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); - - ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]); - - if (ret < 0) - return ret; - - return buf[2]; -} - -static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - u8 buf[3]; - - ci_dbg("%d 0x%04x 0x%02x", slot, address, value); - - if (slot) - return -EINVAL; - - buf[0] = (address >> 8) & 0x0F; - buf[1] = address; - buf[2] = value; - - return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); -} - -static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - u8 buf[2]; - int ret; - - if (slot) - return -EINVAL; - - buf[0] = address & 3; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); - - ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]); - - if (ret < 0) - return ret; - - return buf[1]; -} - -static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - u8 buf[2]; - - ci_dbg("%d 0x%02x 0x%02x", slot, address, value); - - if (slot) - return -EINVAL; - - buf[0] = address; - buf[1] = value; - - return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); -} - -static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable) -{ - u8 buf[1]; - int ret; - - ci_dbg("%d %d", slot, enable); - - if (slot) - return -EINVAL; - - buf[0] = enable; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); - if (ret < 0) - return ret; - - if (enable != buf[0]) { - err("CI not %sabled.", enable ? "en" : "dis"); - return -EIO; - } - - return 0; -} - -static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - return tt3650_ci_set_video_port(ca, slot, 0); -} - -static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - return tt3650_ci_set_video_port(ca, slot, 1); -} - -static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = ca->data; - struct ttusb2_state *state = d->priv; - u8 buf[1]; - int ret; - - ci_dbg("%d", slot); - - if (slot) - return -EINVAL; - - buf[0] = 0; - - mutex_lock(&state->ca_mutex); - - ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); - if (ret) - goto failed; - - msleep(500); - - buf[0] = 1; - - ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); - if (ret) - goto failed; - - msleep(500); - - buf[0] = 0; /* FTA */ - - ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); - - msleep(1100); - - failed: - mutex_unlock(&state->ca_mutex); - - return ret; -} - -static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - u8 buf[1]; - int ret; - - if (slot) - return -EINVAL; - - ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); - if (ret) - return ret; - - if (1 == buf[0]) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - } - return 0; -} - -static void tt3650_ci_uninit(struct dvb_usb_device *d) -{ - struct ttusb2_state *state; - - ci_dbg(""); - - if (NULL == d) - return; - - state = d->priv; - if (NULL == state) - return; - - if (NULL == state->ca.data) - return; - - dvb_ca_en50221_release(&state->ca); - - memset(&state->ca, 0, sizeof(state->ca)); -} - -static int tt3650_ci_init(struct dvb_usb_adapter *a) -{ - struct dvb_usb_device *d = a->dev; - struct ttusb2_state *state = d->priv; - int ret; - - ci_dbg(""); - - mutex_init(&state->ca_mutex); - - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; - state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; - state->ca.read_cam_control = tt3650_ci_read_cam_control; - state->ca.write_cam_control = tt3650_ci_write_cam_control; - state->ca.slot_reset = tt3650_ci_slot_reset; - state->ca.slot_shutdown = tt3650_ci_slot_shutdown; - state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; - state->ca.poll_slot_status = tt3650_ci_poll_slot_status; - state->ca.data = d; - - ret = dvb_ca_en50221_init(&a->dvb_adap, - &state->ca, - /* flags */ 0, - /* n_slots */ 1); - if (ret) { - err("Cannot initialize CI: Error %d.", ret); - memset(&state->ca, 0, sizeof(state->ca)); - return ret; - } - - info("CI initialized."); - - return 0; -} - -static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - static u8 obuf[60], ibuf[60]; - int i, write_read, read; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD); - read = msg[i].flags & I2C_M_RD; - - obuf[0] = (msg[i].addr << 1) | (write_read | read); - if (read) - obuf[1] = 0; - else - obuf[1] = msg[i].len; - - /* read request */ - if (write_read) - obuf[2] = msg[i+1].len; - else if (read) - obuf[2] = msg[i].len; - else - obuf[2] = 0; - - memcpy(&obuf[3], msg[i].buf, msg[i].len); - - if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) { - err("i2c transfer failed."); - break; - } - - if (write_read) { - memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len); - i++; - } else if (read) - memcpy(msg[i].buf, &ibuf[3], msg[i].len); - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ttusb2_i2c_algo = { - .master_xfer = ttusb2_i2c_xfer, - .functionality = ttusb2_i2c_func, -}; - -/* command to poll IR receiver (copied from pctv452e.c) */ -#define CMD_GET_IR_CODE 0x1b - -/* IR */ -static int tt3650_rc_query(struct dvb_usb_device *d) -{ - int ret; - u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */ - struct ttusb2_state *st = d->priv; - ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx)); - if (ret != 0) - return ret; - - if (rx[8] & 0x01) { - /* got a "press" event */ - st->last_rc_key = (rx[3] << 8) | rx[2]; - deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]); - rc_keydown(d->rc_dev, st->last_rc_key, 0); - } else if (st->last_rc_key) { - rc_keyup(d->rc_dev); - st->last_rc_key = 0; - } - - return 0; -} - - -/* Callbacks for DVB USB */ -static int ttusb2_identify_state (struct usb_device *udev, struct - dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, - int *cold) -{ - *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; - return 0; -} - -static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = onoff; - ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); - return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); -} - - -static struct tda10086_config tda10086_config = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct tda10023_config tda10023_config = { - .demod_address = 0x0c, - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .deltaf = 0xa511, -}; - -static struct tda10048_config tda10048_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_PARALLEL_OUTPUT, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_4000, - .dtv7_if_freq_khz = TDA10048_IF_4500, - .dtv8_if_freq_khz = TDA10048_IF_5000, - .clk_freq_khz = TDA10048_CLK_16000, - .no_firmware = 1, - .set_pll = true , - .pll_m = 5, - .pll_n = 3, - .pll_p = 0, -}; - -static struct tda827x_config tda827x_config = { - .config = 0, -}; - -static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev,0,3) < 0) - err("set interface to alts=3 failed"); - - if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { - deb_info("TDA10086 attach failed\n"); - return -ENODEV; - } - - return 0; -} - -static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable); -} - -static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 3) < 0) - err("set interface to alts=3 failed"); - - if (adap->fe_adap[0].fe == NULL) { - /* FE 0 DVB-C */ - adap->fe_adap[0].fe = dvb_attach(tda10023_attach, - &tda10023_config, &adap->dev->i2c_adap, 0x48); - - if (adap->fe_adap[0].fe == NULL) { - deb_info("TDA10023 attach failed\n"); - return -ENODEV; - } - tt3650_ci_init(adap); - } else { - adap->fe_adap[1].fe = dvb_attach(tda10048_attach, - &tda10048_config, &adap->dev->i2c_adap); - - if (adap->fe_adap[1].fe == NULL) { - deb_info("TDA10048 attach failed\n"); - return -ENODEV; - } - - /* tuner is behind TDA10023 I2C-gate */ - adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl; - - } - - return 0; -} - -static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - - /* MFE: select correct FE to attach tuner since that's called twice */ - if (adap->fe_adap[1].fe == NULL) - fe = adap->fe_adap[0].fe; - else - fe = adap->fe_adap[1].fe; - - /* attach tuner */ - if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) { - printk(KERN_ERR "%s: No tda827x found!\n", __func__); - return -ENODEV; - } - return 0; -} - -static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) -{ - if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { - deb_info("TDA8263 attach failed\n"); - return -ENODEV; - } - - if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) { - deb_info("LNBP21 attach failed\n"); - return -ENODEV; - } - return 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ttusb2_properties; -static struct dvb_usb_device_properties ttusb2_properties_s2400; -static struct dvb_usb_device_properties ttusb2_properties_ct3650; - -static void ttusb2_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - - tt3650_ci_uninit(d); - dvb_usb_device_exit(intf); -} - -static int ttusb2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &ttusb2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, - THIS_MODULE, NULL, adapter_nr)) - return 0; - return -ENODEV; -} - -static struct usb_device_id ttusb2_table [] = { - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2400) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_CT3650) }, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, ttusb2_table); - -static struct dvb_usb_device_properties ttusb2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-pctv-400e-01.fw", - - .size_of_priv = sizeof(struct ttusb2_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, - - .frontend_attach = ttusb2_frontend_tda10086_attach, - .tuner_attach = ttusb2_tuner_tda826x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - }}, - } - }, - - .power_ctrl = ttusb2_power_ctrl, - .identify_state = ttusb2_identify_state, - - .i2c_algo = &ttusb2_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 2, - .devices = { - { "Pinnacle 400e DVB-S USB2.0", - { &ttusb2_table[0], NULL }, - { NULL }, - }, - { "Pinnacle 450e DVB-S USB2.0", - { &ttusb2_table[1], NULL }, - { NULL }, - }, - } -}; - -static struct dvb_usb_device_properties ttusb2_properties_s2400 = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-tt-s2400-01.fw", - - .size_of_priv = sizeof(struct ttusb2_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = NULL, - - .frontend_attach = ttusb2_frontend_tda10086_attach, - .tuner_attach = ttusb2_tuner_tda826x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - }}, - } - }, - - .power_ctrl = ttusb2_power_ctrl, - .identify_state = ttusb2_identify_state, - - .i2c_algo = &ttusb2_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Technotrend TT-connect S-2400", - { &ttusb2_table[2], NULL }, - { NULL }, - }, - } -}; - -static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct ttusb2_state), - - .rc.core = { - .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ - .rc_codes = RC_MAP_TT_1500, - .rc_query = tt3650_rc_query, - .allowed_protos = RC_TYPE_UNKNOWN, - }, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 2, - .fe = {{ - .streaming_ctrl = NULL, - - .frontend_attach = ttusb2_frontend_tda10023_attach, - .tuner_attach = ttusb2_tuner_tda827x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - }, { - .streaming_ctrl = NULL, - - .frontend_attach = ttusb2_frontend_tda10023_attach, - .tuner_attach = ttusb2_tuner_tda827x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - }}, - }, - }, - - .power_ctrl = ttusb2_power_ctrl, - .identify_state = ttusb2_identify_state, - - .i2c_algo = &ttusb2_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Technotrend TT-connect CT-3650", - .warm_ids = { &ttusb2_table[3], NULL }, - }, - } -}; - -static struct usb_driver ttusb2_driver = { - .name = "dvb_usb_ttusb2", - .probe = ttusb2_probe, - .disconnect = ttusb2_usb_disconnect, - .id_table = ttusb2_table, -}; - -module_usb_driver(ttusb2_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h b/drivers/media/dvb/dvb-usb/ttusb2.h deleted file mode 100644 index 52a63af4089..00000000000 --- a/drivers/media/dvb/dvb-usb/ttusb2.h +++ /dev/null @@ -1,70 +0,0 @@ -/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones - * (e.g. Pinnacle 400e DVB-S USB2.0). - * - * Copyright (c) 2002 Holger Waechtler - * Copyright (c) 2003 Felix Domke - * Copyright (C) 2005-6 Patrick Boettcher - * - * 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_TTUSB2_H_ -#define _DVB_USB_TTUSB2_H_ - -/* TTUSB protocol - * - * always to messages (out/in) - * out message: - * 0xaa - * - * in message (complete block is always 0x40 bytes long) - * 0x55 - * - * id is incremented for each transaction - */ - -#define CMD_DSP_DOWNLOAD 0x13 -/* out data: [28] - * last block must be empty */ - -#define CMD_DSP_BOOT 0x14 -/* out data: nothing */ - -#define CMD_POWER 0x15 -/* out data: */ - -#define CMD_LNB 0x16 -/* out data: <18V=0,13V=1> */ - -#define CMD_GET_VERSION 0x17 -/* in data: [5] */ - -#define CMD_DISEQC 0x18 -/* out data: [cmdlen] */ - -#define CMD_PID_ENABLE 0x22 -/* out data: */ - -#define CMD_PID_DISABLE 0x23 -/* out data: */ - -#define CMD_FILTER_ENABLE 0x24 -/* out data: [12] [12] */ - -#define CMD_FILTER_DISABLE 0x25 -/* out data: */ - -#define CMD_GET_DSP_VERSION 0x26 -/* in data: [28] */ - -#define CMD_I2C_XFER 0x31 -/* out data: [sndlen] - * in data: [rcvlen] */ - -#define CMD_I2C_BITRATE 0x32 -/* out data: */ - -#endif diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c deleted file mode 100644 index 9b042292e78..00000000000 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ /dev/null @@ -1,151 +0,0 @@ -/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0 - * DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -#include "mt352.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int umt_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d }; - static u8 mt352_reset[] = { 0x50, 0x80 }; - static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 }; - static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 }; - - static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff }; - static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff }; - static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 }; - static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 }; - static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f }; - - static u8 mt352_acq_ctl[] = { 0x53, 0x50 }; - static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio)); - - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - - mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1)); - mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2)); - mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3)); - mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4)); - mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5)); - - mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl)); - mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1)); - - return 0; -} - -static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct mt352_config umt_config; - - memset(&umt_config,0,sizeof(struct mt352_config)); - umt_config.demod_init = umt_mt352_demod_init; - umt_config.demod_address = 0xf; - - adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); - - return 0; -} - -static int umt_tuner_attach (struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034); - return 0; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties umt_properties; - -static int umt_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &umt_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - return -EINVAL; -} - -/* do not change the order of the ID table */ -static struct usb_device_id umt_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, umt_table); - -static struct dvb_usb_device_properties umt_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-umt-010-02.fw", - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .frontend_attach = umt_mt352_frontend_attach, - .tuner_attach = umt_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = MAX_NO_URBS_FOR_DATA_STREAM, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb_power_ctrl, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Hanftek UMT-010 DVB-T USB2.0", - { &umt_table[0], NULL }, - { &umt_table[1], NULL }, - }, - } -}; - -static struct usb_driver umt_driver = { - .name = "dvb_usb_umt_010", - .probe = umt_probe, - .disconnect = dvb_usb_device_exit, - .id_table = umt_table, -}; - -module_usb_driver(umt_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c deleted file mode 100644 index d62ee0f5a16..00000000000 --- a/drivers/media/dvb/dvb-usb/usb-urb.c +++ /dev/null @@ -1,254 +0,0 @@ -/* usb-urb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file keeps functions for initializing and handling the - * BULK and ISOC USB data transfers in a generic way. - * Can be used for DVB-only and also, that's the plan, for - * Hybrid USB devices (analog and DVB). - */ -#include "dvb-usb-common.h" - -/* URB stuff for streaming */ -static void usb_urb_complete(struct urb *urb) -{ - struct usb_data_stream *stream = urb->context; - int ptype = usb_pipetype(urb->pipe); - int i; - u8 *b; - - deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", - ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", - urb->status,urb->actual_length,urb->transfer_buffer_length, - urb->number_of_packets,urb->error_count); - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - deb_ts("urb completition error %d.\n", urb->status); - break; - } - - b = (u8 *) urb->transfer_buffer; - switch (ptype) { - case PIPE_ISOCHRONOUS: - for (i = 0; i < urb->number_of_packets; i++) { - - if (urb->iso_frame_desc[i].status != 0) - deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); - else if (urb->iso_frame_desc[i].actual_length > 0) - stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); - - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - debug_dump(b,20,deb_uxfer); - break; - case PIPE_BULK: - if (urb->actual_length > 0) - stream->complete(stream, b, urb->actual_length); - break; - default: - err("unknown endpoint type in completition handler."); - return; - } - usb_submit_urb(urb,GFP_ATOMIC); -} - -int usb_urb_kill(struct usb_data_stream *stream) -{ - int i; - for (i = 0; i < stream->urbs_submitted; i++) { - deb_ts("killing URB no. %d.\n",i); - - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - return 0; -} - -int usb_urb_submit(struct usb_data_stream *stream) -{ - int i,ret; - for (i = 0; i < stream->urbs_initialized; i++) { - deb_ts("submitting URB no. %d\n",i); - if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { - err("could not submit URB no. %d - get them all back",i); - usb_urb_kill(stream); - return ret; - } - stream->urbs_submitted++; - } - return 0; -} - -static int usb_free_stream_buffers(struct usb_data_stream *stream) -{ - if (stream->state & USB_STATE_URB_BUF) { - while (stream->buf_num) { - stream->buf_num--; - deb_mem("freeing buffer %d\n",stream->buf_num); - usb_free_coherent(stream->udev, stream->buf_size, - stream->buf_list[stream->buf_num], - stream->dma_addr[stream->buf_num]); - } - } - - stream->state &= ~USB_STATE_URB_BUF; - - return 0; -} - -static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) -{ - stream->buf_num = 0; - stream->buf_size = size; - - deb_mem("all in all I will use %lu bytes for streaming\n",num*size); - - for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - deb_mem("allocating buffer %d\n",stream->buf_num); - if (( stream->buf_list[stream->buf_num] = - usb_alloc_coherent(stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]) ) == NULL) { - deb_mem("not enough memory for urb-buffer allocation.\n"); - usb_free_stream_buffers(stream); - return -ENOMEM; - } - deb_mem("buffer %d: %p (dma: %Lu)\n", - stream->buf_num, -stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); - memset(stream->buf_list[stream->buf_num],0,size); - stream->state |= USB_STATE_URB_BUF; - } - deb_mem("allocation successful\n"); - - return 0; -} - -static int usb_bulk_urb_init(struct usb_data_stream *stream) -{ - int i, j; - - if ((i = usb_allocate_stream_buffers(stream,stream->props.count, - stream->props.u.bulk.buffersize)) < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); - if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!.\n"); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - usb_fill_bulk_urb( stream->urb_list[i], stream->udev, - usb_rcvbulkpipe(stream->udev,stream->props.endpoint), - stream->buf_list[i], - stream->props.u.bulk.buffersize, - usb_urb_complete, stream); - - stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; - stream->urbs_initialized++; - } - return 0; -} - -static int usb_isoc_urb_init(struct usb_data_stream *stream) -{ - int i,j; - - if ((i = usb_allocate_stream_buffers(stream,stream->props.count, - stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - struct urb *urb; - int frame_offset = 0; - - stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); - if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!\n"); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - - urb = stream->urb_list[i]; - - urb->dev = stream->udev; - urb->context = stream; - urb->complete = usb_urb_complete; - urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = stream->props.u.isoc.interval; - urb->number_of_packets = stream->props.u.isoc.framesperurb; - urb->transfer_buffer_length = stream->buf_size; - urb->transfer_buffer = stream->buf_list[i]; - urb->transfer_dma = stream->dma_addr[i]; - - for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; - frame_offset += stream->props.u.isoc.framesize; - } - - stream->urbs_initialized++; - } - return 0; -} - -int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) -{ - if (stream == NULL || props == NULL) - return -EINVAL; - - memcpy(&stream->props, props, sizeof(*props)); - - usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); - - if (stream->complete == NULL) { - err("there is no data callback - this doesn't make sense."); - return -EINVAL; - } - - switch (stream->props.type) { - case USB_BULK: - return usb_bulk_urb_init(stream); - case USB_ISOC: - return usb_isoc_urb_init(stream); - default: - err("unknown URB-type for data transfer."); - return -EINVAL; - } -} - -int usb_urb_exit(struct usb_data_stream *stream) -{ - int i; - - usb_urb_kill(stream); - - for (i = 0; i < stream->urbs_initialized; i++) { - if (stream->urb_list[i] != NULL) { - deb_mem("freeing URB no. %d.\n",i); - /* free the URBs */ - usb_free_urb(stream->urb_list[i]); - } - } - stream->urbs_initialized = 0; - - usb_free_stream_buffers(stream); - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c deleted file mode 100644 index 5eab468dd90..00000000000 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ /dev/null @@ -1,379 +0,0 @@ -/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 - * DVB-S receiver. - * - * Copyright (C) 2005 Ralph Metzler - * Metzler Brothers Systementwicklung GbR - * - * Copyright (C) 2005 Patrick Boettcher - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * This file can be removed soon, after the DST-driver is rewritten to provice - * the frontend-controlling separately. - * - * 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 "vp702x.h" - -struct vp702x_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; - - struct dvb_frontend_ops ops; - - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone_mode; - - u8 lnb_buf[8]; - - u8 lock; - u8 sig; - u8 snr; - - unsigned long next_status_check; - unsigned long status_check_interval; -}; - -static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) -{ - struct vp702x_device_state *dst = st->d->priv; - u8 *buf; - - if (time_after(jiffies, st->next_status_check)) { - mutex_lock(&dst->buf_mutex); - buf = dst->buf; - - vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10); - st->lock = buf[4]; - - vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1); - st->snr = buf[0]; - - vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1); - st->sig = buf[0]; - - mutex_unlock(&dst->buf_mutex); - st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; - } - return 0; -} - -static u8 vp702x_chksum(u8 *buf,int f, int count) -{ - u8 s = 0; - int i; - for (i = f; i < f+count; i++) - s += buf[i]; - return ~s+1; -} - -static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - deb_fe("%s\n",__func__); - - if (st->lock == 0) - *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - *status = 0; - - if (*status & FE_HAS_LOCK) - st->status_check_interval = 1000; - else - st->status_check_interval = 250; - return 0; -} - -/* not supported by this Frontend */ -static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - *ber = 0; - return 0; -} - -/* not supported by this Frontend */ -static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - *unc = 0; - return 0; -} - -static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - - *strength = (st->sig << 8) | st->sig; - return 0; -} - -static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - u8 _snr; - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - - _snr = (st->snr & 0x1f) * 0xff / 0x1f; - *snr = (_snr << 8) | _snr; - return 0; -} - -static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - deb_fe("%s\n",__func__); - tune->min_delay_ms = 2000; - return 0; -} - -static int vp702x_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct vp702x_fe_state *st = fe->demodulator_priv; - struct vp702x_device_state *dst = st->d->priv; - u32 freq = fep->frequency/1000; - /*CalFrequency*/ -/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ - u64 sr; - u8 *cmd; - - mutex_lock(&dst->buf_mutex); - - cmd = dst->buf; - memset(cmd, 0, 10); - - cmd[0] = (freq >> 8) & 0x7f; - cmd[1] = freq & 0xff; - cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ - - sr = (u64) (fep->symbol_rate/1000) << 20; - do_div(sr,88000); - cmd[3] = (sr >> 12) & 0xff; - cmd[4] = (sr >> 4) & 0xff; - cmd[5] = (sr << 4) & 0xf0; - - deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", - fep->frequency, freq, freq, fep->symbol_rate, - (unsigned long) sr, (unsigned long) sr); - -/* if (fep->inversion == INVERSION_ON) - cmd[6] |= 0x80; */ - - if (st->voltage == SEC_VOLTAGE_18) - cmd[6] |= 0x40; - -/* if (fep->symbol_rate > 8000000) - cmd[6] |= 0x20; - - if (fep->frequency < 1531000) - cmd[6] |= 0x04; - - if (st->tone_mode == SEC_TONE_ON) - cmd[6] |= 0x01;*/ - - cmd[7] = vp702x_chksum(cmd,0,7); - - st->status_check_interval = 250; - st->next_status_check = jiffies; - - vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); - - if (cmd[2] == 0 && cmd[3] == 0) - deb_fe("tuning failed.\n"); - else - deb_fe("tuning succeeded.\n"); - - mutex_unlock(&dst->buf_mutex); - - return 0; -} - -static int vp702x_fe_init(struct dvb_frontend *fe) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - deb_fe("%s\n",__func__); - vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); - return 0; -} - -static int vp702x_fe_sleep(struct dvb_frontend *fe) -{ - deb_fe("%s\n",__func__); - return 0; -} - -static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) -{ - u8 *cmd; - struct vp702x_fe_state *st = fe->demodulator_priv; - struct vp702x_device_state *dst = st->d->priv; - - deb_fe("%s\n",__func__); - - if (m->msg_len > 4) - return -EINVAL; - - mutex_lock(&dst->buf_mutex); - - cmd = dst->buf; - cmd[1] = SET_DISEQC_CMD; - cmd[2] = m->msg_len; - memcpy(&cmd[3], m->msg, m->msg_len); - cmd[7] = vp702x_chksum(cmd, 0, 7); - - vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); - - if (cmd[2] == 0 && cmd[3] == 0) - deb_fe("diseqc cmd failed.\n"); - else - deb_fe("diseqc cmd succeeded.\n"); - - mutex_unlock(&dst->buf_mutex); - - return 0; -} - -static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) -{ - deb_fe("%s\n",__func__); - return 0; -} - -static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - struct vp702x_device_state *dst = st->d->priv; - u8 *buf; - - deb_fe("%s\n",__func__); - - st->tone_mode = tone; - - if (tone == SEC_TONE_ON) - st->lnb_buf[2] = 0x02; - else - st->lnb_buf[2] = 0x00; - - st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); - - mutex_lock(&dst->buf_mutex); - - buf = dst->buf; - memcpy(buf, st->lnb_buf, 8); - - vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); - if (buf[2] == 0 && buf[3] == 0) - deb_fe("set_tone cmd failed.\n"); - else - deb_fe("set_tone cmd succeeded.\n"); - - mutex_unlock(&dst->buf_mutex); - - return 0; -} - -static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t - voltage) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - struct vp702x_device_state *dst = st->d->priv; - u8 *buf; - deb_fe("%s\n",__func__); - - st->voltage = voltage; - - if (voltage != SEC_VOLTAGE_OFF) - st->lnb_buf[4] = 0x01; - else - st->lnb_buf[4] = 0x00; - - st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); - - mutex_lock(&dst->buf_mutex); - - buf = dst->buf; - memcpy(buf, st->lnb_buf, 8); - - vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); - if (buf[2] == 0 && buf[3] == 0) - deb_fe("set_voltage cmd failed.\n"); - else - deb_fe("set_voltage cmd succeeded.\n"); - - mutex_unlock(&dst->buf_mutex); - return 0; -} - -static void vp702x_fe_release(struct dvb_frontend* fe) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - kfree(st); -} - -static struct dvb_frontend_ops vp702x_fe_ops; - -struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) -{ - struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); - if (s == NULL) - goto error; - - s->d = d; - - memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - - s->lnb_buf[1] = SET_LNB_POWER; - s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ - - return &s->fe; -error: - return NULL; -} - - -static struct dvb_frontend_ops vp702x_fe_ops = { - .delsys = { SYS_DVBS }, - .info = { - .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | - FE_CAN_FEC_AUTO - }, - .release = vp702x_fe_release, - - .init = vp702x_fe_init, - .sleep = vp702x_fe_sleep, - - .set_frontend = vp702x_fe_set_frontend, - .get_tune_settings = vp702x_fe_get_tune_settings, - - .read_status = vp702x_fe_read_status, - .read_ber = vp702x_fe_read_ber, - .read_signal_strength = vp702x_fe_read_signal_strength, - .read_snr = vp702x_fe_read_snr, - .read_ucblocks = vp702x_fe_read_unc_blocks, - - .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, - .diseqc_send_burst = vp702x_fe_send_diseqc_burst, - .set_tone = vp702x_fe_set_tone, - .set_voltage = vp702x_fe_set_voltage, -}; diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c deleted file mode 100644 index 07c673a6e76..00000000000 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ /dev/null @@ -1,444 +0,0 @@ -/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S - * receiver. - * - * Copyright (C) 2005 Ralph Metzler - * Metzler Brothers Systementwicklung GbR - * - * Copyright (C) 2005 Patrick Boettcher - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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 "vp702x.h" -#include - -/* debug */ -int dvb_usb_vp702x_debug; -module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct vp702x_adapter_state { - int pid_filter_count; - int pid_filter_can_bypass; - u8 pid_filter_state; -}; - -static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req, - u16 value, u16 index, u8 *b, int blen) -{ - int ret; - - ret = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value, index, b, blen, - 2000); - - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else - ret = 0; - - - deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - return ret; -} - -int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - - mutex_lock(&d->usb_mutex); - ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen); - mutex_unlock(&d->usb_mutex); - - return ret; -} - -int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - if ((ret = usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value,index,b,blen, - 2000)) != blen) { - warn("usb out operation failed. (%d)",ret); - return -EIO; - } else - return 0; -} - -int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - - mutex_lock(&d->usb_mutex); - ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen); - mutex_unlock(&d->usb_mutex); - - return ret; -} - -int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec) -{ - int ret; - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen); - msleep(msec); - ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen); - - mutex_unlock(&d->usb_mutex); - return ret; -} - -static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, - int olen, u8 *i, int ilen, int msec) -{ - struct vp702x_device_state *st = d->priv; - int ret = 0; - u8 *buf; - int buflen = max(olen + 2, ilen + 1); - - ret = mutex_lock_interruptible(&st->buf_mutex); - if (ret < 0) - return ret; - - if (buflen > st->buf_len) { - buf = kmalloc(buflen, GFP_KERNEL); - if (!buf) { - mutex_unlock(&st->buf_mutex); - return -ENOMEM; - } - info("successfully reallocated a bigger buffer"); - kfree(st->buf); - st->buf = buf; - st->buf_len = buflen; - } else { - buf = st->buf; - } - - buf[0] = 0x00; - buf[1] = cmd; - memcpy(&buf[2], o, olen); - - ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec); - - if (ret == 0) - memcpy(i, &buf[1], ilen); - mutex_unlock(&st->buf_mutex); - - return ret; -} - -static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass) -{ - int ret; - struct vp702x_device_state *st = adap->dev->priv; - u8 *buf; - - mutex_lock(&st->buf_mutex); - - buf = st->buf; - memset(buf, 0, 16); - - ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, - 0, buf, 16); - mutex_unlock(&st->buf_mutex); - return ret; -} - -static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state) -{ - int ret; - struct vp702x_device_state *st = adap->dev->priv; - u8 *buf; - - mutex_lock(&st->buf_mutex); - - buf = st->buf; - memset(buf, 0, 16); - ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, - 0, buf, 16); - - mutex_unlock(&st->buf_mutex); - - return ret; -} - -static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff) -{ - struct vp702x_adapter_state *st = adap->priv; - struct vp702x_device_state *dst = adap->dev->priv; - u8 *buf; - - if (onoff) - st->pid_filter_state |= (1 << id); - else { - st->pid_filter_state &= ~(1 << id); - pid = 0xffff; - } - - id = 0x10 + id*2; - - vp702x_set_pld_state(adap, st->pid_filter_state); - - mutex_lock(&dst->buf_mutex); - - buf = dst->buf; - memset(buf, 0, 16); - vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16); - vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16); - - mutex_unlock(&dst->buf_mutex); - - return 0; -} - - -static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap) -{ - struct vp702x_adapter_state *st = adap->priv; - struct vp702x_device_state *dst = adap->dev->priv; - int i; - u8 *b; - - st->pid_filter_count = 8; - st->pid_filter_can_bypass = 1; - st->pid_filter_state = 0x00; - - vp702x_set_pld_mode(adap, 1); /* bypass */ - - for (i = 0; i < st->pid_filter_count; i++) - vp702x_set_pid(adap, 0xffff, i, 1); - - mutex_lock(&dst->buf_mutex); - b = dst->buf; - memset(b, 0, 10); - vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10); - vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10); - vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10); - mutex_unlock(&dst->buf_mutex); - /*vp702x_set_pld_mode(d, 0); // filter */ - - return 0; -} - -static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - return 0; -} - -/* keys for the enclosed remote control */ -static struct rc_map_table rc_map_vp702x_table[] = { - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, -}; - -/* remote control stuff (does not work with my box) */ -static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 *key; - int i; - -/* remove the following return to enabled remote querying */ - return 0; - - key = kmalloc(10, GFP_KERNEL); - if (!key) - return -ENOMEM; - - vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10); - - deb_rc("remote query key: %x %d\n",key[1],key[1]); - - if (key[1] == 0x44) { - *state = REMOTE_NO_KEY_PRESSED; - kfree(key); - return 0; - } - - for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++) - if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_vp702x_table[i].keycode; - break; - } - kfree(key); - return 0; -} - - -static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) -{ - u8 i, *buf; - struct vp702x_device_state *st = d->priv; - - mutex_lock(&st->buf_mutex); - buf = st->buf; - for (i = 6; i < 12; i++) - vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1); - - memcpy(mac, buf, 6); - mutex_unlock(&st->buf_mutex); - return 0; -} - -static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 buf[10] = { 0 }; - - vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); - - if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, - buf, 10, 10)) - return -EIO; - - buf[9] = '\0'; - info("system string: %s",&buf[1]); - - vp702x_init_pid_filter(adap); - - adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev); - vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); - - return 0; -} - -static struct dvb_usb_device_properties vp702x_properties; - -static int vp702x_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct vp702x_device_state *st; - int ret; - - ret = dvb_usb_device_init(intf, &vp702x_properties, - THIS_MODULE, &d, adapter_nr); - if (ret) - goto out; - - st = d->priv; - st->buf_len = 16; - st->buf = kmalloc(st->buf_len, GFP_KERNEL); - if (!st->buf) { - ret = -ENOMEM; - dvb_usb_device_exit(intf); - goto out; - } - mutex_init(&st->buf_mutex); - -out: - return ret; - -} - -static void vp702x_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - struct vp702x_device_state *st = d->priv; - mutex_lock(&st->buf_mutex); - kfree(st->buf); - mutex_unlock(&st->buf_mutex); - dvb_usb_device_exit(intf); -} - -static struct usb_device_id vp702x_usb_table [] = { - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, -// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, -// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, vp702x_usb_table); - -static struct dvb_usb_device_properties vp702x_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-vp702x-02.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct vp702x_device_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, - - .streaming_ctrl = vp702x_streaming_ctrl, - .frontend_attach = vp702x_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - .size_of_priv = sizeof(struct vp702x_adapter_state), - } - }, - .read_mac_address = vp702x_read_mac_addr, - - .rc.legacy = { - .rc_map_table = rc_map_vp702x_table, - .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table), - .rc_interval = 400, - .rc_query = vp702x_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", - .cold_ids = { &vp702x_usb_table[0], NULL }, - .warm_ids = { NULL }, - }, -/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", - .cold_ids = { &vp702x_usb_table[2], NULL }, - .warm_ids = { &vp702x_usb_table[3], NULL }, - }, -*/ { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vp702x_usb_driver = { - .name = "dvb_usb_vp702x", - .probe = vp702x_usb_probe, - .disconnect = vp702x_usb_disconnect, - .id_table = vp702x_usb_table, -}; - -module_usb_driver(vp702x_usb_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h deleted file mode 100644 index 20b90055e7a..00000000000 --- a/drivers/media/dvb/dvb-usb/vp702x.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef _DVB_USB_VP7021_H_ -#define _DVB_USB_VP7021_H_ - -#define DVB_USB_LOG_PREFIX "vp702x" -#include "dvb-usb.h" - -extern int dvb_usb_vp702x_debug; -#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args) -#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args) - -/* commands are read and written with USB control messages */ - -/* consecutive read/write operation */ -#define REQUEST_OUT 0xB2 -#define REQUEST_IN 0xB3 - -/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0 - * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer - * the returning buffer looks as follows - * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */ - -#define GET_TUNER_STATUS 0x05 -/* additional in buffer: - * 0 1 2 3 4 5 6 7 8 - * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */ - -#define GET_SYSTEM_STRING 0x06 -/* additional in buffer: - * 0 1 2 3 4 5 6 7 8 - * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */ - -#define SET_DISEQC_CMD 0x08 -/* additional out buffer: - * 0 1 2 3 4 - * len X1 X2 X3 X4 - * additional in buffer: - * 0 1 2 - * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */ - -#define SET_LNB_POWER 0x09 -/* additional out buffer: - * 0 1 2 - * 0x00 0xff 1 = on, 0 = off - * additional in buffer: - * 0 1 2 - * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */ - -#define GET_MAC_ADDRESS 0x0A -/* #define GET_MAC_ADDRESS 0x0B */ -/* additional in buffer: - * 0 1 2 3 4 5 6 7 8 - * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */ - -#define SET_PID_FILTER 0x11 -/* additional in buffer: - * 0 1 ... 14 15 16 - * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ - -/* request: 0xB2; i: 0; v: 0; - * b[0] != 0 -> tune and lock a channel - * 0 1 2 3 4 5 6 7 - * freq0 freq1 divstep srate0 srate1 srate2 flag chksum - */ - -/* one direction requests */ -#define READ_REMOTE_REQ 0xB4 -/* IN i: 0; v: 0; b[0] == request, b[1] == key */ - -#define READ_PID_NUMBER_REQ 0xB5 -/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */ - -#define WRITE_EEPROM_REQ 0xB6 -/* OUT i: offset; v: value to write; no extra buffer */ - -#define READ_EEPROM_REQ 0xB7 -/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ - -#define READ_STATUS 0xB8 -/* IN i: 0; v: 0; bufferlen 10 */ - -#define READ_TUNER_REG_REQ 0xB9 -/* IN i: 0; v: register; b[0] = value */ - -#define READ_FX2_REG_REQ 0xBA -/* IN i: offset; v: 0; b[0] = value */ - -#define WRITE_FX2_REG_REQ 0xBB -/* OUT i: offset; v: value to write; 1 byte extra buffer */ - -#define SET_TUNER_POWER_REQ 0xBC -/* IN i: 0 = power off, 1 = power on */ - -#define WRITE_TUNER_REG_REQ 0xBD -/* IN i: register, v: value to write, no extra buffer */ - -#define RESET_TUNER 0xBE -/* IN i: 0, v: 0, no extra buffer */ - -struct vp702x_device_state { - struct mutex buf_mutex; - int buf_len; - u8 *buf; -}; - - -extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); - -extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); -extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); - -#endif diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c deleted file mode 100644 index b8825b18c00..00000000000 --- a/drivers/media/dvb/dvb-usb/vp7045-fe.c +++ /dev/null @@ -1,190 +0,0 @@ -/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0 - * DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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 "vp7045.h" - -/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT - * - * Programming is hidden inside the firmware, so set_frontend is very easy. - * Even though there is a Firmware command that one can use to access the demod - * via its registers. This is used for status information. - */ - -struct vp7045_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; -}; - -static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u8 s0 = vp7045_read_reg(state->d,0x00), - s1 = vp7045_read_reg(state->d,0x01), - s3 = vp7045_read_reg(state->d,0x03); - - *status = 0; - if (s0 & (1 << 4)) - *status |= FE_HAS_CARRIER; - if (s0 & (1 << 1)) - *status |= FE_HAS_VITERBI; - if (s0 & (1 << 5)) - *status |= FE_HAS_LOCK; - if (s1 & (1 << 1)) - *status |= FE_HAS_SYNC; - if (s3 & (1 << 6)) - *status |= FE_HAS_SIGNAL; - - if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != - (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) - *status &= ~FE_HAS_LOCK; - - return 0; -} - -static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - *ber = (vp7045_read_reg(state->d, 0x0D) << 16) | - (vp7045_read_reg(state->d, 0x0E) << 8) | - vp7045_read_reg(state->d, 0x0F); - return 0; -} - -static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - *unc = (vp7045_read_reg(state->d, 0x10) << 8) | - vp7045_read_reg(state->d, 0x11); - return 0; -} - -static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) | - vp7045_read_reg(state->d, 0x15); - - *strength = ~signal; - return 0; -} - -static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u8 _snr = vp7045_read_reg(state->d, 0x09); - *snr = (_snr << 8) | _snr; - return 0; -} - -static int vp7045_fe_init(struct dvb_frontend* fe) -{ - return 0; -} - -static int vp7045_fe_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int vp7045_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct vp7045_fe_state *state = fe->demodulator_priv; - u8 buf[5]; - u32 freq = fep->frequency / 1000; - - buf[0] = (freq >> 16) & 0xff; - buf[1] = (freq >> 8) & 0xff; - buf[2] = freq & 0xff; - buf[3] = 0; - - switch (fep->bandwidth_hz) { - case 8000000: - buf[4] = 8; - break; - case 7000000: - buf[4] = 7; - break; - case 6000000: - buf[4] = 6; - break; - default: - return -EINVAL; - } - - vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200); - return 0; -} - -static void vp7045_fe_release(struct dvb_frontend* fe) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops vp7045_fe_ops; - -struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) -{ - struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL); - if (s == NULL) - goto error; - - s->d = d; - memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - - return &s->fe; -error: - return NULL; -} - - -static struct dvb_frontend_ops vp7045_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Twinhan VP7045/46 USB DVB-T", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 1000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = vp7045_fe_release, - - .init = vp7045_fe_init, - .sleep = vp7045_fe_sleep, - - .set_frontend = vp7045_fe_set_frontend, - .get_tune_settings = vp7045_fe_get_tune_settings, - - .read_status = vp7045_fe_read_status, - .read_ber = vp7045_fe_read_ber, - .read_signal_strength = vp7045_fe_read_signal_strength, - .read_snr = vp7045_fe_read_snr, - .read_ucblocks = vp7045_fe_read_unc_blocks, -}; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c deleted file mode 100644 index d750724132e..00000000000 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ /dev/null @@ -1,302 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver - * - DigitalNow TinyUSB2 DVB-t receiver - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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 "vp7045.h" - -/* debug */ -static int dvb_usb_vp7045_debug; -module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) - -int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) -{ - int ret = 0; - u8 *buf = d->priv; - - buf[0] = cmd; - - if (outlen > 19) - outlen = 19; - - if (inlen > 11) - inlen = 11; - - ret = mutex_lock_interruptible(&d->usb_mutex); - if (ret) - return ret; - - if (out != NULL && outlen > 0) - memcpy(&buf[1], out, outlen); - - deb_xfer("out buffer: "); - debug_dump(buf, outlen+1, deb_xfer); - - - if (usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev,0), - TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, - buf, 20, 2000) != 20) { - err("USB control message 'out' went wrong."); - ret = -EIO; - goto unlock; - } - - msleep(msec); - - if (usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev,0), - TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - buf, 12, 2000) != 12) { - err("USB control message 'in' went wrong."); - ret = -EIO; - goto unlock; - } - - deb_xfer("in buffer: "); - debug_dump(buf, 12, deb_xfer); - - if (in != NULL && inlen > 0) - memcpy(in, &buf[1], inlen); - -unlock: - mutex_unlock(&d->usb_mutex); - - return ret; -} - -u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg) -{ - u8 obuf[2] = { 0 },v; - obuf[1] = reg; - - vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30); - - return v; -} - -static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 v = onoff; - return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150); -} - -/* remote control stuff */ - -/* The keymapping struct. Somehow this should be loaded to the driver, but - * currently it is hardcoded. */ -static struct rc_map_table rc_map_vp7045_table[] = { - { 0x0016, KEY_POWER }, - { 0x0010, KEY_MUTE }, - { 0x0003, KEY_1 }, - { 0x0001, KEY_2 }, - { 0x0006, KEY_3 }, - { 0x0009, KEY_4 }, - { 0x001d, KEY_5 }, - { 0x001f, KEY_6 }, - { 0x000d, KEY_7 }, - { 0x0019, KEY_8 }, - { 0x001b, KEY_9 }, - { 0x0015, KEY_0 }, - { 0x0005, KEY_CHANNELUP }, - { 0x0002, KEY_CHANNELDOWN }, - { 0x001e, KEY_VOLUMEUP }, - { 0x000a, KEY_VOLUMEDOWN }, - { 0x0011, KEY_RECORD }, - { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x0014, KEY_PLAY }, - { 0x001a, KEY_STOP }, - { 0x0040, KEY_REWIND }, - { 0x0012, KEY_FASTFORWARD }, - { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x004c, KEY_PAUSE }, - { 0x004d, KEY_SCREEN }, /* Full screen mode. */ - { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x001c, KEY_EPG }, /* EPG */ - { 0x0000, KEY_TAB }, /* Tab */ - { 0x0048, KEY_INFO }, /* Preview */ - { 0x0004, KEY_LIST }, /* RecordList */ - { 0x000f, KEY_TEXT }, /* Teletext */ - { 0x0041, KEY_PREVIOUSSONG }, - { 0x0042, KEY_NEXTSONG }, - { 0x004b, KEY_UP }, - { 0x0051, KEY_DOWN }, - { 0x004e, KEY_LEFT }, - { 0x0052, KEY_RIGHT }, - { 0x004f, KEY_ENTER }, - { 0x0013, KEY_CANCEL }, - { 0x004a, KEY_CLEAR }, - { 0x0054, KEY_PRINT }, /* Capture */ - { 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */ - { 0x0008, KEY_VIDEO }, /* A/V */ - { 0x0007, KEY_SLEEP }, /* Hibernate */ - { 0x0045, KEY_ZOOM }, /* Zoom+ */ - { 0x0018, KEY_RED}, - { 0x0053, KEY_GREEN}, - { 0x005e, KEY_YELLOW}, - { 0x005f, KEY_BLUE} -}; - -static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key; - int i; - vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20); - - deb_rc("remote query key: %x %d\n",key,key); - - if (key == 0x44) { - *state = REMOTE_NO_KEY_PRESSED; - return 0; - } - - for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++) - if (rc5_data(&rc_map_vp7045_table[i]) == key) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_vp7045_table[i].keycode; - break; - } - return 0; -} - -static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset) -{ - int i = 0; - u8 v,br[2]; - for (i=0; i < len; i++) { - v = offset + i; - vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5); - buf[i] = br[1]; - } - deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i); - debug_dump(buf,i,deb_info); - return 0; -} - -static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) -{ - return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); -} - -static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 buf[255] = { 0 }; - - vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0); - buf[10] = '\0'; - deb_info("firmware says: %s ",buf); - - vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0); - buf[10] = '\0'; - deb_info("%s ",buf); - - vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0); - buf[10] = '\0'; - deb_info("v%s\n",buf); - -/* Dump the EEPROM */ -/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ - - adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev); - - return 0; -} - -static struct dvb_usb_device_properties vp7045_properties; - -static int vp7045_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &vp7045_properties, - THIS_MODULE, NULL, adapter_nr); -} - -static struct usb_device_id vp7045_usb_table [] = { - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, vp7045_usb_table); - -static struct dvb_usb_device_properties vp7045_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-vp7045-01.fw", - .size_of_priv = 20, - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .frontend_attach = vp7045_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }}, - } - }, - .power_ctrl = vp7045_power_ctrl, - .read_mac_address = vp7045_read_mac_addr, - - .rc.legacy = { - .rc_interval = 400, - .rc_map_table = rc_map_vp7045_table, - .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table), - .rc_query = vp7045_rc_query, - }, - - .num_device_descs = 2, - .devices = { - { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", - .cold_ids = { &vp7045_usb_table[0], NULL }, - .warm_ids = { &vp7045_usb_table[1], NULL }, - }, - { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", - .cold_ids = { &vp7045_usb_table[2], NULL }, - .warm_ids = { &vp7045_usb_table[3], NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vp7045_usb_driver = { - .name = "dvb_usb_vp7045", - .probe = vp7045_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = vp7045_usb_table, -}; - -module_usb_driver(vp7045_usb_driver); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h deleted file mode 100644 index cf5ec46f8bb..00000000000 --- a/drivers/media/dvb/dvb-usb/vp7045.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII - * USB2.0 DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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_VP7045_H_ -#define _DVB_USB_VP7045_H_ - -#define DVB_USB_LOG_PREFIX "vp7045" -#include "dvb-usb.h" - -/* vp7045 commands */ - -/* Twinhan Vendor requests */ -#define TH_COMMAND_IN 0xC0 -#define TH_COMMAND_OUT 0xC1 - -/* command bytes */ -#define TUNER_REG_READ 0x03 -#define TUNER_REG_WRITE 0x04 - -#define RC_VAL_READ 0x05 - #define RC_NO_KEY 0x44 - -#define SET_TUNER_POWER 0x06 -#define CHECK_TUNER_POWER 0x12 - #define Tuner_Power_ON 1 - #define Tuner_Power_OFF 0 - -#define GET_USB_SPEED 0x07 - -#define LOCK_TUNER_COMMAND 0x09 - -#define TUNER_SIGNAL_READ 0x0A - -/* FX2 eeprom */ -#define SET_EE_VALUE 0x10 -#define GET_EE_VALUE 0x11 - #define FX2_ID_ADDR 0x00 - #define VID_MSB_ADDR 0x02 - #define VID_LSB_ADDR 0x01 - #define PID_MSB_ADDR 0x04 - #define PID_LSB_ADDR 0x03 - #define MAC_0_ADDR 0x07 - #define MAC_1_ADDR 0x08 - #define MAC_2_ADDR 0x09 - #define MAC_3_ADDR 0x0a - #define MAC_4_ADDR 0x0b - #define MAC_5_ADDR 0x0c - -#define RESET_FX2 0x13 - -#define FW_VERSION_READ 0x0B -#define VENDOR_STRING_READ 0x0C -#define PRODUCT_STRING_READ 0x0D -#define FW_BCD_VERSION_READ 0x14 - -extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d); -extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec); -extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg); - -#endif diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig deleted file mode 100644 index bc6456eb2c4..00000000000 --- a/drivers/media/dvb/siano/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# -# Siano Mobile Silicon Digital TV device configuration -# - -config SMS_SIANO_MDTV - tristate "Siano SMS1xxx based MDTV receiver" - depends on DVB_CORE && RC_CORE && HAS_DMA - ---help--- - Choose Y or M here if you have MDTV receiver with a Siano chipset. - - To compile this driver as a module, choose M here - (The module will be called smsmdtv). - - Further documentation on this driver can be found on the WWW - at http://www.siano-ms.com/ - -if SMS_SIANO_MDTV -menu "Siano module components" - -# Hardware interfaces support - -config SMS_USB_DRV - tristate "USB interface support" - depends on DVB_CORE && USB - ---help--- - Choose if you would like to have Siano's support for USB interface - -config SMS_SDIO_DRV - tristate "SDIO interface support" - depends on DVB_CORE && MMC - ---help--- - Choose if you would like to have Siano's support for SDIO interface -endmenu -endif # SMS_SIANO_MDTV diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile deleted file mode 100644 index 14756bdb6ea..00000000000 --- a/drivers/media/dvb/siano/Makefile +++ /dev/null @@ -1,11 +0,0 @@ - -smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o - -obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o -obj-$(CONFIG_SMS_USB_DRV) += smsusb.o -obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o - -ccflags-y += -Idrivers/media/dvb-core - -ccflags-y += $(extra-cflags-y) $(extra-cflags-m) - diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c deleted file mode 100644 index 680c781c8dd..00000000000 --- a/drivers/media/dvb/siano/sms-cards.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Card-specific functions for the Siano SMS1xxx USB dongle - * - * Copyright (c) 2008 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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 "sms-cards.h" -#include "smsir.h" -#include - -static int sms_dbg; -module_param_named(cards_dbg, sms_dbg, int, 0644); -MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); - -static struct sms_board sms_boards[] = { - [SMS_BOARD_UNKNOWN] = { - .name = "Unknown board", - }, - [SMS1XXX_BOARD_SIANO_STELLAR] = { - .name = "Siano Stellar Digital Receiver", - .type = SMS_STELLAR, - }, - [SMS1XXX_BOARD_SIANO_NOVA_A] = { - .name = "Siano Nova A Digital Receiver", - .type = SMS_NOVA_A0, - }, - [SMS1XXX_BOARD_SIANO_NOVA_B] = { - .name = "Siano Nova B Digital Receiver", - .type = SMS_NOVA_B0, - }, - [SMS1XXX_BOARD_SIANO_VEGA] = { - .name = "Siano Vega Digital Receiver", - .type = SMS_VEGA, - }, - [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { - .name = "Hauppauge Catamount", - .type = SMS_STELLAR, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", - }, - [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { - .name = "Hauppauge Okemo-A", - .type = SMS_NOVA_A0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", - }, - [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { - .name = "Hauppauge Okemo-B", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", - }, - [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { - .name = "Hauppauge WinTV MiniStick", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .rc_codes = RC_MAP_HAUPPAUGE, - .board_cfg.leds_power = 26, - .board_cfg.led0 = 27, - .board_cfg.led1 = 28, - .board_cfg.ir = 9, - .led_power = 26, - .led_lo = 27, - .led_hi = 28, - }, - [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { - .name = "Hauppauge WinTV MiniCard", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .lna_ctrl = 29, - .board_cfg.foreign_lna0_ctrl = 29, - .rf_switch = 17, - .board_cfg.rf_switch_uhf = 17, - }, - [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { - .name = "Hauppauge WinTV MiniCard", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .lna_ctrl = -1, - }, - [SMS1XXX_BOARD_SIANO_NICE] = { - /* 11 */ - .name = "Siano Nice Digital Receiver", - .type = SMS_NOVA_B0, - }, - [SMS1XXX_BOARD_SIANO_VENICE] = { - /* 12 */ - .name = "Siano Venice Digital Receiver", - .type = SMS_VEGA, - }, -}; - -struct sms_board *sms_get_board(unsigned id) -{ - BUG_ON(id >= ARRAY_SIZE(sms_boards)); - - return &sms_boards[id]; -} -EXPORT_SYMBOL_GPL(sms_get_board); -static inline void sms_gpio_assign_11xx_default_led_config( - struct smscore_gpio_config *pGpioConfig) { - pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; - pGpioConfig->InputCharacteristics = - SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; - pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; - pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; - pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; -} - -int sms_board_event(struct smscore_device_t *coredev, - enum SMS_BOARD_EVENTS gevent) { - struct smscore_gpio_config MyGpioConfig; - - sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); - - switch (gevent) { - case BOARD_EVENT_POWER_INIT: /* including hotplug */ - break; /* BOARD_EVENT_BIND */ - - case BOARD_EVENT_POWER_SUSPEND: - break; /* BOARD_EVENT_POWER_SUSPEND */ - - case BOARD_EVENT_POWER_RESUME: - break; /* BOARD_EVENT_POWER_RESUME */ - - case BOARD_EVENT_BIND: - break; /* BOARD_EVENT_BIND */ - - case BOARD_EVENT_SCAN_PROG: - break; /* BOARD_EVENT_SCAN_PROG */ - case BOARD_EVENT_SCAN_COMP: - break; /* BOARD_EVENT_SCAN_COMP */ - case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: - break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ - case BOARD_EVENT_FE_LOCK: - break; /* BOARD_EVENT_FE_LOCK */ - case BOARD_EVENT_FE_UNLOCK: - break; /* BOARD_EVENT_FE_UNLOCK */ - case BOARD_EVENT_DEMOD_LOCK: - break; /* BOARD_EVENT_DEMOD_LOCK */ - case BOARD_EVENT_DEMOD_UNLOCK: - break; /* BOARD_EVENT_DEMOD_UNLOCK */ - case BOARD_EVENT_RECEPTION_MAX_4: - break; /* BOARD_EVENT_RECEPTION_MAX_4 */ - case BOARD_EVENT_RECEPTION_3: - break; /* BOARD_EVENT_RECEPTION_3 */ - case BOARD_EVENT_RECEPTION_2: - break; /* BOARD_EVENT_RECEPTION_2 */ - case BOARD_EVENT_RECEPTION_1: - break; /* BOARD_EVENT_RECEPTION_1 */ - case BOARD_EVENT_RECEPTION_LOST_0: - break; /* BOARD_EVENT_RECEPTION_LOST_0 */ - case BOARD_EVENT_MULTIPLEX_OK: - break; /* BOARD_EVENT_MULTIPLEX_OK */ - case BOARD_EVENT_MULTIPLEX_ERRORS: - break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ - - default: - sms_err("Unknown SMS board event"); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_event); - -static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) -{ - int lvl, ret; - u32 gpio; - struct smscore_config_gpio gpioconfig = { - .direction = SMS_GPIO_DIRECTION_OUTPUT, - .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, - .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, - .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, - .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, - }; - - if (pin == 0) - return -EINVAL; - - if (pin < 0) { - /* inverted gpio */ - gpio = pin * -1; - lvl = enable ? 0 : 1; - } else { - gpio = pin; - lvl = enable ? 1 : 0; - } - - ret = smscore_configure_gpio(coredev, gpio, &gpioconfig); - if (ret < 0) - return ret; - - return smscore_set_gpio(coredev, gpio, lvl); -} - -int sms_board_setup(struct smscore_device_t *coredev) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - /* turn off all LEDs */ - sms_set_gpio(coredev, board->led_power, 0); - sms_set_gpio(coredev, board->led_hi, 0); - sms_set_gpio(coredev, board->led_lo, 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - /* turn off LNA */ - sms_set_gpio(coredev, board->lna_ctrl, 0); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_setup); - -int sms_board_power(struct smscore_device_t *coredev, int onoff) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - /* power LED */ - sms_set_gpio(coredev, - board->led_power, onoff ? 1 : 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - /* LNA */ - if (!onoff) - sms_set_gpio(coredev, board->lna_ctrl, 0); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_power); - -int sms_board_led_feedback(struct smscore_device_t *coredev, int led) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - /* dont touch GPIO if LEDs are already set */ - if (smscore_led_state(coredev, -1) == led) - return 0; - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - sms_set_gpio(coredev, - board->led_lo, (led & SMS_LED_LO) ? 1 : 0); - sms_set_gpio(coredev, - board->led_hi, (led & SMS_LED_HI) ? 1 : 0); - - smscore_led_state(coredev, led); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_led_feedback); - -int sms_board_lna_control(struct smscore_device_t *coredev, int onoff) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled"); - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - sms_set_gpio(coredev, - board->rf_switch, onoff ? 1 : 0); - return sms_set_gpio(coredev, - board->lna_ctrl, onoff ? 1 : 0); - } - return -EINVAL; -} -EXPORT_SYMBOL_GPL(sms_board_lna_control); - -int sms_board_load_modules(int id) -{ - switch (id) { - case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B: - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - request_module("smsdvb"); - break; - default: - /* do nothing */ - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_load_modules); diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h deleted file mode 100644 index d8cdf756f7c..00000000000 --- a/drivers/media/dvb/siano/sms-cards.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Card-specific functions for the Siano SMS1xxx USB dongle - * - * Copyright (c) 2008 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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 __SMS_CARDS_H__ -#define __SMS_CARDS_H__ - -#include -#include "smscoreapi.h" -#include "smsir.h" - -#define SMS_BOARD_UNKNOWN 0 -#define SMS1XXX_BOARD_SIANO_STELLAR 1 -#define SMS1XXX_BOARD_SIANO_NOVA_A 2 -#define SMS1XXX_BOARD_SIANO_NOVA_B 3 -#define SMS1XXX_BOARD_SIANO_VEGA 4 -#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5 -#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 -#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 -#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 -#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 -#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 -#define SMS1XXX_BOARD_SIANO_NICE 11 -#define SMS1XXX_BOARD_SIANO_VENICE 12 - -struct sms_board_gpio_cfg { - int lna_vhf_exist; - int lna_vhf_ctrl; - int lna_uhf_exist; - int lna_uhf_ctrl; - int lna_uhf_d_ctrl; - int lna_sband_exist; - int lna_sband_ctrl; - int lna_sband_d_ctrl; - int foreign_lna0_ctrl; - int foreign_lna1_ctrl; - int foreign_lna2_ctrl; - int rf_switch_vhf; - int rf_switch_uhf; - int rf_switch_sband; - int leds_power; - int led0; - int led1; - int led2; - int led3; - int led4; - int ir; - int eeprom_wp; - int mrc_sense; - int mrc_pdn_resetn; - int mrc_gp0; /* mrcs spi int */ - int mrc_gp1; - int mrc_gp2; - int mrc_gp3; - int mrc_gp4; - int host_spi_gsp_ts_int; -}; - -struct sms_board { - enum sms_device_type_st type; - char *name, *fw[DEVICE_MODE_MAX]; - struct sms_board_gpio_cfg board_cfg; - char *rc_codes; /* Name of IR codes table */ - - /* gpios */ - int led_power, led_hi, led_lo, lna_ctrl, rf_switch; -}; - -struct sms_board *sms_get_board(unsigned id); - -extern struct smscore_device_t *coredev; - -enum SMS_BOARD_EVENTS { - BOARD_EVENT_POWER_INIT, - BOARD_EVENT_POWER_SUSPEND, - BOARD_EVENT_POWER_RESUME, - BOARD_EVENT_BIND, - BOARD_EVENT_SCAN_PROG, - BOARD_EVENT_SCAN_COMP, - BOARD_EVENT_EMERGENCY_WARNING_SIGNAL, - BOARD_EVENT_FE_LOCK, - BOARD_EVENT_FE_UNLOCK, - BOARD_EVENT_DEMOD_LOCK, - BOARD_EVENT_DEMOD_UNLOCK, - BOARD_EVENT_RECEPTION_MAX_4, - BOARD_EVENT_RECEPTION_3, - BOARD_EVENT_RECEPTION_2, - BOARD_EVENT_RECEPTION_1, - BOARD_EVENT_RECEPTION_LOST_0, - BOARD_EVENT_MULTIPLEX_OK, - BOARD_EVENT_MULTIPLEX_ERRORS -}; - -int sms_board_event(struct smscore_device_t *coredev, - enum SMS_BOARD_EVENTS gevent); - -int sms_board_setup(struct smscore_device_t *coredev); - -#define SMS_LED_OFF 0 -#define SMS_LED_LO 1 -#define SMS_LED_HI 2 -int sms_board_led_feedback(struct smscore_device_t *coredev, int led); -int sms_board_power(struct smscore_device_t *coredev, int onoff); -int sms_board_lna_control(struct smscore_device_t *coredev, int onoff); - -extern int sms_board_load_modules(int id); - -#endif /* __SMS_CARDS_H__ */ diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c deleted file mode 100644 index 9cc55546cc3..00000000000 --- a/drivers/media/dvb/siano/smscoreapi.c +++ /dev/null @@ -1,1637 +0,0 @@ -/* - * Siano core API module - * - * This file contains implementation for the interface to sms core component - * - * author: Uri Shkolnik - * - * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "smscoreapi.h" -#include "sms-cards.h" -#include "smsir.h" -#include "smsendian.h" - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -struct smscore_device_notifyee_t { - struct list_head entry; - hotplug_t hotplug; -}; - -struct smscore_idlist_t { - struct list_head entry; - int id; - int data_type; -}; - -struct smscore_client_t { - struct list_head entry; - struct smscore_device_t *coredev; - void *context; - struct list_head idlist; - onresponse_t onresponse_handler; - onremove_t onremove_handler; -}; - -void smscore_set_board_id(struct smscore_device_t *core, int id) -{ - core->board_id = id; -} - -int smscore_led_state(struct smscore_device_t *core, int led) -{ - if (led >= 0) - core->led_state = led; - return core->led_state; -} -EXPORT_SYMBOL_GPL(smscore_set_board_id); - -int smscore_get_board_id(struct smscore_device_t *core) -{ - return core->board_id; -} -EXPORT_SYMBOL_GPL(smscore_get_board_id); - -struct smscore_registry_entry_t { - struct list_head entry; - char devpath[32]; - int mode; - enum sms_device_type_st type; -}; - -static struct list_head g_smscore_notifyees; -static struct list_head g_smscore_devices; -static struct mutex g_smscore_deviceslock; - -static struct list_head g_smscore_registry; -static struct mutex g_smscore_registrylock; - -static int default_mode = 4; - -module_param(default_mode, int, 0644); -MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); - -static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) -{ - struct smscore_registry_entry_t *entry; - struct list_head *next; - - kmutex_lock(&g_smscore_registrylock); - for (next = g_smscore_registry.next; - next != &g_smscore_registry; - next = next->next) { - entry = (struct smscore_registry_entry_t *) next; - if (!strcmp(entry->devpath, devpath)) { - kmutex_unlock(&g_smscore_registrylock); - return entry; - } - } - entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL); - if (entry) { - entry->mode = default_mode; - strcpy(entry->devpath, devpath); - list_add(&entry->entry, &g_smscore_registry); - } else - sms_err("failed to create smscore_registry."); - kmutex_unlock(&g_smscore_registrylock); - return entry; -} - -int smscore_registry_getmode(char *devpath) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - return entry->mode; - else - sms_err("No registry found."); - - return default_mode; -} -EXPORT_SYMBOL_GPL(smscore_registry_getmode); - -static enum sms_device_type_st smscore_registry_gettype(char *devpath) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - return entry->type; - else - sms_err("No registry found."); - - return -1; -} - -void smscore_registry_setmode(char *devpath, int mode) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - entry->mode = mode; - else - sms_err("No registry found."); -} - -static void smscore_registry_settype(char *devpath, - enum sms_device_type_st type) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - entry->type = type; - else - sms_err("No registry found."); -} - - -static void list_add_locked(struct list_head *new, struct list_head *head, - spinlock_t *lock) -{ - unsigned long flags; - - spin_lock_irqsave(lock, flags); - - list_add(new, head); - - spin_unlock_irqrestore(lock, flags); -} - -/** - * register a client callback that called when device plugged in/unplugged - * NOTE: if devices exist callback is called immediately for each device - * - * @param hotplug callback - * - * @return 0 on success, <0 on error. - */ -int smscore_register_hotplug(hotplug_t hotplug) -{ - struct smscore_device_notifyee_t *notifyee; - struct list_head *next, *first; - int rc = 0; - - kmutex_lock(&g_smscore_deviceslock); - - notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), - GFP_KERNEL); - if (notifyee) { - /* now notify callback about existing devices */ - first = &g_smscore_devices; - for (next = first->next; - next != first && !rc; - next = next->next) { - struct smscore_device_t *coredev = - (struct smscore_device_t *) next; - rc = hotplug(coredev, coredev->device, 1); - } - - if (rc >= 0) { - notifyee->hotplug = hotplug; - list_add(¬ifyee->entry, &g_smscore_notifyees); - } else - kfree(notifyee); - } else - rc = -ENOMEM; - - kmutex_unlock(&g_smscore_deviceslock); - - return rc; -} -EXPORT_SYMBOL_GPL(smscore_register_hotplug); - -/** - * unregister a client callback that called when device plugged in/unplugged - * - * @param hotplug callback - * - */ -void smscore_unregister_hotplug(hotplug_t hotplug) -{ - struct list_head *next, *first; - - kmutex_lock(&g_smscore_deviceslock); - - first = &g_smscore_notifyees; - - for (next = first->next; next != first;) { - struct smscore_device_notifyee_t *notifyee = - (struct smscore_device_notifyee_t *) next; - next = next->next; - - if (notifyee->hotplug == hotplug) { - list_del(¬ifyee->entry); - kfree(notifyee); - } - } - - kmutex_unlock(&g_smscore_deviceslock); -} -EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); - -static void smscore_notify_clients(struct smscore_device_t *coredev) -{ - struct smscore_client_t *client; - - /* the client must call smscore_unregister_client from remove handler */ - while (!list_empty(&coredev->clients)) { - client = (struct smscore_client_t *) coredev->clients.next; - client->onremove_handler(client->context); - } -} - -static int smscore_notify_callbacks(struct smscore_device_t *coredev, - struct device *device, int arrival) -{ - struct smscore_device_notifyee_t *elem; - int rc = 0; - - /* note: must be called under g_deviceslock */ - - list_for_each_entry(elem, &g_smscore_notifyees, entry) { - rc = elem->hotplug(coredev, device, arrival); - if (rc < 0) - break; - } - - return rc; -} - -static struct -smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, - dma_addr_t common_buffer_phys) -{ - struct smscore_buffer_t *cb = - kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); - if (!cb) { - sms_info("kmalloc(...) failed"); - return NULL; - } - - cb->p = buffer; - cb->offset_in_common = buffer - (u8 *) common_buffer; - cb->phys = common_buffer_phys + cb->offset_in_common; - - return cb; -} - -/** - * creates coredev object for a device, prepares buffers, - * creates buffer mappings, notifies registered hotplugs about new device. - * - * @param params device pointer to struct with device specific parameters - * and handlers - * @param coredev pointer to a value that receives created coredev object - * - * @return 0 on success, <0 on error. - */ -int smscore_register_device(struct smsdevice_params_t *params, - struct smscore_device_t **coredev) -{ - struct smscore_device_t *dev; - u8 *buffer; - - dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); - if (!dev) { - sms_info("kzalloc(...) failed"); - return -ENOMEM; - } - - /* init list entry so it could be safe in smscore_unregister_device */ - INIT_LIST_HEAD(&dev->entry); - - /* init queues */ - INIT_LIST_HEAD(&dev->clients); - INIT_LIST_HEAD(&dev->buffers); - - /* init locks */ - spin_lock_init(&dev->clientslock); - spin_lock_init(&dev->bufferslock); - - /* init completion events */ - init_completion(&dev->version_ex_done); - init_completion(&dev->data_download_done); - init_completion(&dev->trigger_done); - init_completion(&dev->init_device_done); - init_completion(&dev->reload_start_done); - init_completion(&dev->resume_done); - init_completion(&dev->gpio_configuration_done); - init_completion(&dev->gpio_set_level_done); - init_completion(&dev->gpio_get_level_done); - init_completion(&dev->ir_init_done); - - /* Buffer management */ - init_waitqueue_head(&dev->buffer_mng_waitq); - - /* alloc common buffer */ - dev->common_buffer_size = params->buffer_size * params->num_buffers; - dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, - &dev->common_buffer_phys, - GFP_KERNEL | GFP_DMA); - if (!dev->common_buffer) { - smscore_unregister_device(dev); - return -ENOMEM; - } - - /* prepare dma buffers */ - for (buffer = dev->common_buffer; - dev->num_buffers < params->num_buffers; - dev->num_buffers++, buffer += params->buffer_size) { - struct smscore_buffer_t *cb = - smscore_createbuffer(buffer, dev->common_buffer, - dev->common_buffer_phys); - if (!cb) { - smscore_unregister_device(dev); - return -ENOMEM; - } - - smscore_putbuffer(dev, cb); - } - - sms_info("allocated %d buffers", dev->num_buffers); - - dev->mode = DEVICE_MODE_NONE; - dev->context = params->context; - dev->device = params->device; - dev->setmode_handler = params->setmode_handler; - dev->detectmode_handler = params->detectmode_handler; - dev->sendrequest_handler = params->sendrequest_handler; - dev->preload_handler = params->preload_handler; - dev->postload_handler = params->postload_handler; - - dev->device_flags = params->flags; - strcpy(dev->devpath, params->devpath); - - smscore_registry_settype(dev->devpath, params->device_type); - - /* add device to devices list */ - kmutex_lock(&g_smscore_deviceslock); - list_add(&dev->entry, &g_smscore_devices); - kmutex_unlock(&g_smscore_deviceslock); - - *coredev = dev; - - sms_info("device %p created", dev); - - return 0; -} -EXPORT_SYMBOL_GPL(smscore_register_device); - - -static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, - void *buffer, size_t size, struct completion *completion) { - int rc = coredev->sendrequest_handler(coredev->context, buffer, size); - if (rc < 0) { - sms_info("sendrequest returned error %d", rc); - return rc; - } - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? - 0 : -ETIME; -} - -/** - * Starts & enables IR operations - * - * @return 0 on success, < 0 on error. - */ -static int smscore_init_ir(struct smscore_device_t *coredev) -{ - int ir_io; - int rc; - void *buffer; - - coredev->ir.dev = NULL; - ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; - if (ir_io) {/* only if IR port exist we use IR sub-module */ - sms_info("IR loading"); - rc = sms_ir_init(coredev); - - if (rc != 0) - sms_err("Error initialization DTV IR sub-module"); - else { - buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + - SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST2 *msg = - (struct SmsMsgData_ST2 *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, - MSG_SMS_START_IR_REQ, - sizeof(struct SmsMsgData_ST2)); - msg->msgData[0] = coredev->ir.controller; - msg->msgData[1] = coredev->ir.timeout; - - smsendian_handle_tx_message( - (struct SmsMsgHdr_ST2 *)msg); - rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader. msgLength, - &coredev->ir_init_done); - - kfree(buffer); - } else - sms_err - ("Sending IR initialization message failed"); - } - } else - sms_info("IR port has not been detected"); - - return 0; -} - -/** - * sets initial device mode and notifies client hotplugs that device is ready - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return 0 on success, <0 on error. - */ -int smscore_start_device(struct smscore_device_t *coredev) -{ - int rc = smscore_set_device_mode( - coredev, smscore_registry_getmode(coredev->devpath)); - if (rc < 0) { - sms_info("set device mode faile , rc %d", rc); - return rc; - } - - kmutex_lock(&g_smscore_deviceslock); - - rc = smscore_notify_callbacks(coredev, coredev->device, 1); - smscore_init_ir(coredev); - - sms_info("device %p started, rc %d", coredev, rc); - - kmutex_unlock(&g_smscore_deviceslock); - - return rc; -} -EXPORT_SYMBOL_GPL(smscore_start_device); - - -static int smscore_load_firmware_family2(struct smscore_device_t *coredev, - void *buffer, size_t size) -{ - struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; - struct SmsMsgHdr_ST *msg; - u32 mem_address; - u8 *payload = firmware->Payload; - int rc = 0; - firmware->StartAddress = le32_to_cpu(firmware->StartAddress); - firmware->Length = le32_to_cpu(firmware->Length); - - mem_address = firmware->StartAddress; - - sms_info("loading FW to addr 0x%x size %d", - mem_address, firmware->Length); - if (coredev->preload_handler) { - rc = coredev->preload_handler(coredev->context); - if (rc < 0) - return rc; - } - - /* PAGE_SIZE buffer shall be enough and dma aligned */ - msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); - if (!msg) - return -ENOMEM; - - if (coredev->mode != DEVICE_MODE_NONE) { - sms_debug("sending reload command."); - SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, - sizeof(struct SmsMsgHdr_ST)); - rc = smscore_sendrequest_and_wait(coredev, msg, - msg->msgLength, - &coredev->reload_start_done); - mem_address = *(u32 *) &payload[20]; - } - - while (size && rc >= 0) { - struct SmsDataDownload_ST *DataMsg = - (struct SmsDataDownload_ST *) msg; - int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); - - SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, - (u16)(sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) + payload_size)); - - DataMsg->MemAddr = mem_address; - memcpy(DataMsg->Payload, payload, payload_size); - - if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && - (coredev->mode == DEVICE_MODE_NONE)) - rc = coredev->sendrequest_handler( - coredev->context, DataMsg, - DataMsg->xMsgHeader.msgLength); - else - rc = smscore_sendrequest_and_wait( - coredev, DataMsg, - DataMsg->xMsgHeader.msgLength, - &coredev->data_download_done); - - payload += payload_size; - size -= payload_size; - mem_address += payload_size; - } - - if (rc >= 0) { - if (coredev->mode == DEVICE_MODE_NONE) { - struct SmsMsgData_ST *TriggerMsg = - (struct SmsMsgData_ST *) msg; - - SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, - sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) * 5); - - TriggerMsg->msgData[0] = firmware->StartAddress; - /* Entry point */ - TriggerMsg->msgData[1] = 5; /* Priority */ - TriggerMsg->msgData[2] = 0x200; /* Stack size */ - TriggerMsg->msgData[3] = 0; /* Parameter */ - TriggerMsg->msgData[4] = 4; /* Task ID */ - - if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { - rc = coredev->sendrequest_handler( - coredev->context, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength); - msleep(100); - } else - rc = smscore_sendrequest_and_wait( - coredev, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength, - &coredev->trigger_done); - } else { - SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = coredev->sendrequest_handler(coredev->context, - msg, msg->msgLength); - } - msleep(500); - } - - sms_debug("rc=%d, postload=%p ", rc, - coredev->postload_handler); - - kfree(msg); - - return ((rc >= 0) && coredev->postload_handler) ? - coredev->postload_handler(coredev->context) : - rc; -} - -/** - * loads specified firmware into a buffer and calls device loadfirmware_handler - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param filename null-terminated string specifies firmware file name - * @param loadfirmware_handler device handler that loads firmware - * - * @return 0 on success, <0 on error. - */ -static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, - char *filename, - loadfirmware_t loadfirmware_handler) -{ - int rc = -ENOENT; - const struct firmware *fw; - u8 *fw_buffer; - - if (loadfirmware_handler == NULL && !(coredev->device_flags & - SMS_DEVICE_FAMILY2)) - return -EINVAL; - - rc = request_firmware(&fw, filename, coredev->device); - if (rc < 0) { - sms_info("failed to open \"%s\"", filename); - return rc; - } - sms_info("read FW %s, size=%zd", filename, fw->size); - fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), - GFP_KERNEL | GFP_DMA); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - - rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? - smscore_load_firmware_family2(coredev, - fw_buffer, - fw->size) : - loadfirmware_handler(coredev->context, - fw_buffer, fw->size); - - kfree(fw_buffer); - } else { - sms_info("failed to allocate firmware buffer"); - rc = -ENOMEM; - } - - release_firmware(fw); - - return rc; -} - -/** - * notifies all clients registered with the device, notifies hotplugs, - * frees all buffers and coredev object - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return 0 on success, <0 on error. - */ -void smscore_unregister_device(struct smscore_device_t *coredev) -{ - struct smscore_buffer_t *cb; - int num_buffers = 0; - int retry = 0; - - kmutex_lock(&g_smscore_deviceslock); - - /* Release input device (IR) resources */ - sms_ir_exit(coredev); - - smscore_notify_clients(coredev); - smscore_notify_callbacks(coredev, NULL, 0); - - /* at this point all buffers should be back - * onresponse must no longer be called */ - - while (1) { - while (!list_empty(&coredev->buffers)) { - cb = (struct smscore_buffer_t *) coredev->buffers.next; - list_del(&cb->entry); - kfree(cb); - num_buffers++; - } - if (num_buffers == coredev->num_buffers) - break; - if (++retry > 10) { - sms_info("exiting although " - "not all buffers released."); - break; - } - - sms_info("waiting for %d buffer(s)", - coredev->num_buffers - num_buffers); - msleep(100); - } - - sms_info("freed %d buffers", num_buffers); - - if (coredev->common_buffer) - dma_free_coherent(NULL, coredev->common_buffer_size, - coredev->common_buffer, coredev->common_buffer_phys); - - if (coredev->fw_buf != NULL) - kfree(coredev->fw_buf); - - list_del(&coredev->entry); - kfree(coredev); - - kmutex_unlock(&g_smscore_deviceslock); - - sms_info("device %p destroyed", coredev); -} -EXPORT_SYMBOL_GPL(smscore_unregister_device); - -static int smscore_detect_mode(struct smscore_device_t *coredev) -{ - void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - struct SmsMsgHdr_ST *msg = - (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); - int rc; - - if (!buffer) - return -ENOMEM; - - SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, - &coredev->version_ex_done); - if (rc == -ETIME) { - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); - - if (wait_for_completion_timeout(&coredev->resume_done, - msecs_to_jiffies(5000))) { - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->msgLength, - &coredev->version_ex_done); - if (rc < 0) - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " - "second try, rc %d", rc); - } else - rc = -ETIME; - } - - kfree(buffer); - - return rc; -} - -static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { - /*Stellar NOVA A0 Nova B0 VEGA*/ - /*DVBT*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*DVBH*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*TDMB*/ - {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, - /*DABIP*/ - {"none", "none", "none", "none"}, - /*BDA*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*ISDBT*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*ISDBTBDA*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*CMMB*/ - {"none", "none", "none", "cmmb_vega_12mhz.inp"} -}; - -static inline char *sms_get_fw_name(struct smscore_device_t *coredev, - int mode, enum sms_device_type_st type) -{ - char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; - return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; -} - -/** - * calls device handler to change mode of operation - * NOTE: stellar/usb may disconnect when changing mode - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param mode requested mode of operation - * - * @return 0 on success, <0 on error. - */ -int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) -{ - void *buffer; - int rc = 0; - enum sms_device_type_st type; - - sms_debug("set device mode to %d", mode); - if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { - sms_err("invalid mode specified %d", mode); - return -EINVAL; - } - - smscore_registry_setmode(coredev->devpath, mode); - - if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { - rc = smscore_detect_mode(coredev); - if (rc < 0) { - sms_err("mode detect failed %d", rc); - return rc; - } - } - - if (coredev->mode == mode) { - sms_info("device mode %d already set", mode); - return 0; - } - - if (!(coredev->modes_supported & (1 << mode))) { - char *fw_filename; - - type = smscore_registry_gettype(coredev->devpath); - fw_filename = sms_get_fw_name(coredev, mode, type); - - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - if (rc < 0) { - sms_warn("error %d loading firmware: %s, " - "trying again with default firmware", - rc, fw_filename); - - /* try again with the default firmware */ - fw_filename = smscore_fw_lkup[mode][type]; - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - - if (rc < 0) { - sms_warn("error %d loading " - "firmware: %s", rc, - fw_filename); - return rc; - } - } - sms_log("firmware download success: %s", fw_filename); - } else - sms_info("mode %d supported by running " - "firmware", mode); - - buffer = kmalloc(sizeof(struct SmsMsgData_ST) + - SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST *msg = - (struct SmsMsgData_ST *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); - msg->msgData[0] = mode; - - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->xMsgHeader.msgLength, - &coredev->init_device_done); - - kfree(buffer); - } else { - sms_err("Could not allocate buffer for " - "init device message."); - rc = -ENOMEM; - } - } else { - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid mode specified %d", mode); - return -EINVAL; - } - - smscore_registry_setmode(coredev->devpath, mode); - - if (coredev->detectmode_handler) - coredev->detectmode_handler(coredev->context, - &coredev->mode); - - if (coredev->mode != mode && coredev->setmode_handler) - rc = coredev->setmode_handler(coredev->context, mode); - } - - if (rc >= 0) { - coredev->mode = mode; - coredev->device_flags &= ~SMS_DEVICE_NOT_READY; - } - - if (rc < 0) - sms_err("return error code %d.", rc); - return rc; -} - -/** - * calls device handler to get current mode of operation - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return current mode - */ -int smscore_get_device_mode(struct smscore_device_t *coredev) -{ - return coredev->mode; -} -EXPORT_SYMBOL_GPL(smscore_get_device_mode); - -/** - * find client by response id & type within the clients list. - * return client handle or NULL. - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param data_type client data type (SMS_DONT_CARE for all types) - * @param id client id (SMS_DONT_CARE for all id) - * - */ -static struct -smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, - int data_type, int id) -{ - struct list_head *first; - struct smscore_client_t *client; - unsigned long flags; - struct list_head *firstid; - struct smscore_idlist_t *client_id; - - spin_lock_irqsave(&coredev->clientslock, flags); - first = &coredev->clients; - list_for_each_entry(client, first, entry) { - firstid = &client->idlist; - list_for_each_entry(client_id, firstid, entry) { - if ((client_id->id == id) && - (client_id->data_type == data_type || - (client_id->data_type == 0))) - goto found; - } - } - client = NULL; -found: - spin_unlock_irqrestore(&coredev->clientslock, flags); - return client; -} - -/** - * find client by response id/type, call clients onresponse handler - * return buffer to pool on error - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param cb pointer to response buffer descriptor - * - */ -void smscore_onresponse(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p - + cb->offset); - struct smscore_client_t *client; - int rc = -EBUSY; - static unsigned long last_sample_time; /* = 0; */ - static int data_total; /* = 0; */ - unsigned long time_now = jiffies_to_msecs(jiffies); - - if (!last_sample_time) - last_sample_time = time_now; - - if (time_now - last_sample_time > 10000) { - sms_debug("\ndata rate %d bytes/secs", - (int)((data_total * 1000) / - (time_now - last_sample_time))); - - last_sample_time = time_now; - data_total = 0; - } - - data_total += cb->size; - /* Do we need to re-route? */ - if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || - (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { - if (coredev->mode == DEVICE_MODE_DVBT_BDA) - phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; - } - - - client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); - - /* If no client registered for type & id, - * check for control client where type is not registered */ - if (client) - rc = client->onresponse_handler(client->context, cb); - - if (rc < 0) { - switch (phdr->msgType) { - case MSG_SMS_GET_VERSION_EX_RES: - { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) phdr; - sms_debug("MSG_SMS_GET_VERSION_EX_RES " - "id %d prots 0x%x ver %d.%d", - ver->FirmwareId, ver->SupportedProtocols, - ver->RomVersionMajor, ver->RomVersionMinor); - - coredev->mode = ver->FirmwareId == 255 ? - DEVICE_MODE_NONE : ver->FirmwareId; - coredev->modes_supported = ver->SupportedProtocols; - - complete(&coredev->version_ex_done); - break; - } - case MSG_SMS_INIT_DEVICE_RES: - sms_debug("MSG_SMS_INIT_DEVICE_RES"); - complete(&coredev->init_device_done); - break; - case MSG_SW_RELOAD_START_RES: - sms_debug("MSG_SW_RELOAD_START_RES"); - complete(&coredev->reload_start_done); - break; - case MSG_SMS_DATA_DOWNLOAD_RES: - complete(&coredev->data_download_done); - break; - case MSG_SW_RELOAD_EXEC_RES: - sms_debug("MSG_SW_RELOAD_EXEC_RES"); - break; - case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: - sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); - complete(&coredev->trigger_done); - break; - case MSG_SMS_SLEEP_RESUME_COMP_IND: - complete(&coredev->resume_done); - break; - case MSG_SMS_GPIO_CONFIG_EX_RES: - sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); - complete(&coredev->gpio_configuration_done); - break; - case MSG_SMS_GPIO_SET_LEVEL_RES: - sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); - complete(&coredev->gpio_set_level_done); - break; - case MSG_SMS_GPIO_GET_LEVEL_RES: - { - u32 *msgdata = (u32 *) phdr; - coredev->gpio_get_res = msgdata[1]; - sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", - coredev->gpio_get_res); - complete(&coredev->gpio_get_level_done); - break; - } - case MSG_SMS_START_IR_RES: - complete(&coredev->ir_init_done); - break; - case MSG_SMS_IR_SAMPLES_IND: - sms_ir_event(coredev, - (const char *) - ((char *)phdr - + sizeof(struct SmsMsgHdr_ST)), - (int)phdr->msgLength - - sizeof(struct SmsMsgHdr_ST)); - break; - - default: - break; - } - smscore_putbuffer(coredev, cb); - } -} -EXPORT_SYMBOL_GPL(smscore_onresponse); - -/** - * return pointer to next free buffer descriptor from core pool - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return pointer to descriptor on success, NULL on error. - */ - -struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) -{ - struct smscore_buffer_t *cb = NULL; - unsigned long flags; - - spin_lock_irqsave(&coredev->bufferslock, flags); - if (!list_empty(&coredev->buffers)) { - cb = (struct smscore_buffer_t *) coredev->buffers.next; - list_del(&cb->entry); - } - spin_unlock_irqrestore(&coredev->bufferslock, flags); - return cb; -} - -struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) -{ - struct smscore_buffer_t *cb = NULL; - - wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev))); - - return cb; -} -EXPORT_SYMBOL_GPL(smscore_getbuffer); - -/** - * return buffer descriptor to a pool - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param cb pointer buffer descriptor - * - */ -void smscore_putbuffer(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) { - wake_up_interruptible(&coredev->buffer_mng_waitq); - list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); -} -EXPORT_SYMBOL_GPL(smscore_putbuffer); - -static int smscore_validate_client(struct smscore_device_t *coredev, - struct smscore_client_t *client, - int data_type, int id) -{ - struct smscore_idlist_t *listentry; - struct smscore_client_t *registered_client; - - if (!client) { - sms_err("bad parameter."); - return -EINVAL; - } - registered_client = smscore_find_client(coredev, data_type, id); - if (registered_client == client) - return 0; - - if (registered_client) { - sms_err("The msg ID already registered to another client."); - return -EEXIST; - } - listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); - if (!listentry) { - sms_err("Can't allocate memory for client id."); - return -ENOMEM; - } - listentry->id = id; - listentry->data_type = data_type; - list_add_locked(&listentry->entry, &client->idlist, - &coredev->clientslock); - return 0; -} - -/** - * creates smsclient object, check that id is taken by another client - * - * @param coredev pointer to a coredev object from clients hotplug - * @param initial_id all messages with this id would be sent to this client - * @param data_type all messages of this type would be sent to this client - * @param onresponse_handler client handler that is called to - * process incoming messages - * @param onremove_handler client handler that is called when device is removed - * @param context client-specific context - * @param client pointer to a value that receives created smsclient object - * - * @return 0 on success, <0 on error. - */ -int smscore_register_client(struct smscore_device_t *coredev, - struct smsclient_params_t *params, - struct smscore_client_t **client) -{ - struct smscore_client_t *newclient; - /* check that no other channel with same parameters exists */ - if (smscore_find_client(coredev, params->data_type, - params->initial_id)) { - sms_err("Client already exist."); - return -EEXIST; - } - - newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); - if (!newclient) { - sms_err("Failed to allocate memory for client."); - return -ENOMEM; - } - - INIT_LIST_HEAD(&newclient->idlist); - newclient->coredev = coredev; - newclient->onresponse_handler = params->onresponse_handler; - newclient->onremove_handler = params->onremove_handler; - newclient->context = params->context; - list_add_locked(&newclient->entry, &coredev->clients, - &coredev->clientslock); - smscore_validate_client(coredev, newclient, params->data_type, - params->initial_id); - *client = newclient; - sms_debug("%p %d %d", params->context, params->data_type, - params->initial_id); - - return 0; -} -EXPORT_SYMBOL_GPL(smscore_register_client); - -/** - * frees smsclient object and all subclients associated with it - * - * @param client pointer to smsclient object returned by - * smscore_register_client - * - */ -void smscore_unregister_client(struct smscore_client_t *client) -{ - struct smscore_device_t *coredev = client->coredev; - unsigned long flags; - - spin_lock_irqsave(&coredev->clientslock, flags); - - - while (!list_empty(&client->idlist)) { - struct smscore_idlist_t *identry = - (struct smscore_idlist_t *) client->idlist.next; - list_del(&identry->entry); - kfree(identry); - } - - sms_info("%p", client->context); - - list_del(&client->entry); - kfree(client); - - spin_unlock_irqrestore(&coredev->clientslock, flags); -} -EXPORT_SYMBOL_GPL(smscore_unregister_client); - -/** - * verifies that source id is not taken by another client, - * calls device handler to send requests to the device - * - * @param client pointer to smsclient object returned by - * smscore_register_client - * @param buffer pointer to a request buffer - * @param size size (in bytes) of request buffer - * - * @return 0 on success, <0 on error. - */ -int smsclient_sendrequest(struct smscore_client_t *client, - void *buffer, size_t size) -{ - struct smscore_device_t *coredev; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; - int rc; - - if (client == NULL) { - sms_err("Got NULL client"); - return -EINVAL; - } - - coredev = client->coredev; - - /* check that no other channel with same id exists */ - if (coredev == NULL) { - sms_err("Got NULL coredev"); - return -EINVAL; - } - - rc = smscore_validate_client(client->coredev, client, 0, - phdr->msgSrcId); - if (rc < 0) - return rc; - - return coredev->sendrequest_handler(coredev->context, buffer, size); -} -EXPORT_SYMBOL_GPL(smsclient_sendrequest); - - -/* old GPIO managements implementation */ -int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, - struct smscore_config_gpio *pinconfig) -{ - struct { - struct SmsMsgHdr_ST hdr; - u32 data[6]; - } msg; - - if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - msg.hdr.msgLength = sizeof(msg); - - msg.data[0] = pin; - msg.data[1] = pinconfig->pullupdown; - - /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ - msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; - - switch (pinconfig->outputdriving) { - case SMS_GPIO_OUTPUTDRIVING_16mA: - msg.data[3] = 7; /* Nova - 16mA */ - break; - case SMS_GPIO_OUTPUTDRIVING_12mA: - msg.data[3] = 5; /* Nova - 11mA */ - break; - case SMS_GPIO_OUTPUTDRIVING_8mA: - msg.data[3] = 3; /* Nova - 7mA */ - break; - case SMS_GPIO_OUTPUTDRIVING_4mA: - default: - msg.data[3] = 2; /* Nova - 4mA */ - break; - } - - msg.data[4] = pinconfig->direction; - msg.data[5] = 0; - } else /* TODO: SMS_DEVICE_FAMILY1 */ - return -EINVAL; - - return coredev->sendrequest_handler(coredev->context, - &msg, sizeof(msg)); -} - -int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) -{ - struct { - struct SmsMsgHdr_ST hdr; - u32 data[3]; - } msg; - - if (pin > MAX_GPIO_PIN_NUMBER) - return -EINVAL; - - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - msg.hdr.msgLength = sizeof(msg); - - msg.data[0] = pin; - msg.data[1] = level ? 1 : 0; - msg.data[2] = 0; - - return coredev->sendrequest_handler(coredev->context, - &msg, sizeof(msg)); -} - -/* new GPIO management implementation */ -static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, - u32 *pGroupNum, u32 *pGroupCfg) { - - *pGroupCfg = 1; - - if (PinNum <= 1) { - *pTranslatedPinNum = 0; - *pGroupNum = 9; - *pGroupCfg = 2; - } else if (PinNum >= 2 && PinNum <= 6) { - *pTranslatedPinNum = 2; - *pGroupNum = 0; - *pGroupCfg = 2; - } else if (PinNum >= 7 && PinNum <= 11) { - *pTranslatedPinNum = 7; - *pGroupNum = 1; - } else if (PinNum >= 12 && PinNum <= 15) { - *pTranslatedPinNum = 12; - *pGroupNum = 2; - *pGroupCfg = 3; - } else if (PinNum == 16) { - *pTranslatedPinNum = 16; - *pGroupNum = 23; - } else if (PinNum >= 17 && PinNum <= 24) { - *pTranslatedPinNum = 17; - *pGroupNum = 3; - } else if (PinNum == 25) { - *pTranslatedPinNum = 25; - *pGroupNum = 6; - } else if (PinNum >= 26 && PinNum <= 28) { - *pTranslatedPinNum = 26; - *pGroupNum = 4; - } else if (PinNum == 29) { - *pTranslatedPinNum = 29; - *pGroupNum = 5; - *pGroupCfg = 2; - } else if (PinNum == 30) { - *pTranslatedPinNum = 30; - *pGroupNum = 8; - } else if (PinNum == 31) { - *pTranslatedPinNum = 31; - *pGroupNum = 17; - } else - return -1; - - *pGroupCfg <<= 24; - - return 0; -} - -int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig) { - - u32 totalLen; - u32 TranslatedPinNum = 0; - u32 GroupNum = 0; - u32 ElectricChar; - u32 groupCfg; - void *buffer; - int rc; - - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[6]; - } *pMsg; - - - if (PinNum > MAX_GPIO_PIN_NUMBER) - return -EINVAL; - - if (pGpioConfig == NULL) - return -EINVAL; - - totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); - - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - - if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; - if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, - &groupCfg) != 0) { - rc = -EINVAL; - goto free; - } - - pMsg->msgData[1] = TranslatedPinNum; - pMsg->msgData[2] = GroupNum; - ElectricChar = (pGpioConfig->PullUpDown) - | (pGpioConfig->InputCharacteristics << 2) - | (pGpioConfig->OutputSlewRate << 3) - | (pGpioConfig->OutputDriving << 4); - pMsg->msgData[3] = ElectricChar; - pMsg->msgData[4] = pGpioConfig->Direction; - pMsg->msgData[5] = groupCfg; - } else { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - pMsg->msgData[1] = pGpioConfig->PullUpDown; - pMsg->msgData[2] = pGpioConfig->OutputSlewRate; - pMsg->msgData[3] = pGpioConfig->OutputDriving; - pMsg->msgData[4] = pGpioConfig->Direction; - pMsg->msgData[5] = 0; - } - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, - &coredev->gpio_configuration_done); - - if (rc != 0) { - if (rc == -ETIME) - sms_err("smscore_gpio_configure timeout"); - else - sms_err("smscore_gpio_configure error"); - } -free: - kfree(buffer); - - return rc; -} - -int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel) { - - u32 totalLen; - int rc; - void *buffer; - - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[3]; /* keep it 3 ! */ - } *pMsg; - - if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER)) - return -EINVAL; - - totalLen = sizeof(struct SmsMsgHdr_ST) + - (3 * sizeof(u32)); /* keep it 3 ! */ - - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = NewLevel; - - /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, - &coredev->gpio_set_level_done); - - if (rc != 0) { - if (rc == -ETIME) - sms_err("smscore_gpio_set_level timeout"); - else - sms_err("smscore_gpio_set_level error"); - } - kfree(buffer); - - return rc; -} - -int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, - u8 *level) { - - u32 totalLen; - int rc; - void *buffer; - - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[2]; - } *pMsg; - - - if (PinNum > MAX_GPIO_PIN_NUMBER) - return -EINVAL; - - totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); - - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = 0; - - /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, - &coredev->gpio_get_level_done); - - if (rc != 0) { - if (rc == -ETIME) - sms_err("smscore_gpio_get_level timeout"); - else - sms_err("smscore_gpio_get_level error"); - } - kfree(buffer); - - /* Its a race between other gpio_get_level() and the copy of the single - * global 'coredev->gpio_get_res' to the function's variable 'level' - */ - *level = coredev->gpio_get_res; - - return rc; -} - -static int __init smscore_module_init(void) -{ - int rc = 0; - - INIT_LIST_HEAD(&g_smscore_notifyees); - INIT_LIST_HEAD(&g_smscore_devices); - kmutex_init(&g_smscore_deviceslock); - - INIT_LIST_HEAD(&g_smscore_registry); - kmutex_init(&g_smscore_registrylock); - - return rc; -} - -static void __exit smscore_module_exit(void) -{ - kmutex_lock(&g_smscore_deviceslock); - while (!list_empty(&g_smscore_notifyees)) { - struct smscore_device_notifyee_t *notifyee = - (struct smscore_device_notifyee_t *) - g_smscore_notifyees.next; - - list_del(¬ifyee->entry); - kfree(notifyee); - } - kmutex_unlock(&g_smscore_deviceslock); - - kmutex_lock(&g_smscore_registrylock); - while (!list_empty(&g_smscore_registry)) { - struct smscore_registry_entry_t *entry = - (struct smscore_registry_entry_t *) - g_smscore_registry.next; - - list_del(&entry->entry); - kfree(entry); - } - kmutex_unlock(&g_smscore_registrylock); - - sms_debug(""); -} - -module_init(smscore_module_init); -module_exit(smscore_module_exit); - -MODULE_DESCRIPTION("Siano MDTV Core module"); -MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h deleted file mode 100644 index c592ae09039..00000000000 --- a/drivers/media/dvb/siano/smscoreapi.h +++ /dev/null @@ -1,775 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat - -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, see . - -****************************************************************/ - -#ifndef __SMS_CORE_API_H__ -#define __SMS_CORE_API_H__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "smsir.h" - -#define kmutex_init(_p_) mutex_init(_p_) -#define kmutex_lock(_p_) mutex_lock(_p_) -#define kmutex_trylock(_p_) mutex_trylock(_p_) -#define kmutex_unlock(_p_) mutex_unlock(_p_) - -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) -#define SMS_ALLOC_ALIGNMENT 128 -#define SMS_DMA_ALIGNMENT 16 -#define SMS_ALIGN_ADDRESS(addr) \ - ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) - -#define SMS_DEVICE_FAMILY2 1 -#define SMS_ROM_NO_RESPONSE 2 -#define SMS_DEVICE_NOT_READY 0x8000000 - -enum sms_device_type_st { - SMS_STELLAR = 0, - SMS_NOVA_A0, - SMS_NOVA_B0, - SMS_VEGA, - SMS_NUM_OF_DEVICE_TYPES -}; - -struct smscore_device_t; -struct smscore_client_t; -struct smscore_buffer_t; - -typedef int (*hotplug_t)(struct smscore_device_t *coredev, - struct device *device, int arrival); - -typedef int (*setmode_t)(void *context, int mode); -typedef void (*detectmode_t)(void *context, int *mode); -typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); -typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); -typedef int (*preload_t)(void *context); -typedef int (*postload_t)(void *context); - -typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); -typedef void (*onremove_t)(void *context); - -struct smscore_buffer_t { - /* public members, once passed to clients can be changed freely */ - struct list_head entry; - int size; - int offset; - - /* private members, read-only for clients */ - void *p; - dma_addr_t phys; - unsigned long offset_in_common; -}; - -struct smsdevice_params_t { - struct device *device; - - int buffer_size; - int num_buffers; - - char devpath[32]; - unsigned long flags; - - setmode_t setmode_handler; - detectmode_t detectmode_handler; - sendrequest_t sendrequest_handler; - preload_t preload_handler; - postload_t postload_handler; - - void *context; - enum sms_device_type_st device_type; -}; - -struct smsclient_params_t { - int initial_id; - int data_type; - onresponse_t onresponse_handler; - onremove_t onremove_handler; - void *context; -}; - -struct smscore_device_t { - struct list_head entry; - - struct list_head clients; - struct list_head subclients; - spinlock_t clientslock; - - struct list_head buffers; - spinlock_t bufferslock; - int num_buffers; - - void *common_buffer; - int common_buffer_size; - dma_addr_t common_buffer_phys; - - void *context; - struct device *device; - - char devpath[32]; - unsigned long device_flags; - - setmode_t setmode_handler; - detectmode_t detectmode_handler; - sendrequest_t sendrequest_handler; - preload_t preload_handler; - postload_t postload_handler; - - int mode, modes_supported; - - /* host <--> device messages */ - struct completion version_ex_done, data_download_done, trigger_done; - struct completion init_device_done, reload_start_done, resume_done; - struct completion gpio_configuration_done, gpio_set_level_done; - struct completion gpio_get_level_done, ir_init_done; - - /* Buffer management */ - wait_queue_head_t buffer_mng_waitq; - - /* GPIO */ - int gpio_get_res; - - /* Target hardware board */ - int board_id; - - /* Firmware */ - u8 *fw_buf; - u32 fw_buf_size; - - /* Infrared (IR) */ - struct ir_t ir; - - int led_state; -}; - -/* GPIO definitions for antenna frequency domain control (SMS8021) */ -#define SMS_ANTENNA_GPIO_0 1 -#define SMS_ANTENNA_GPIO_1 0 - -#define BW_8_MHZ 0 -#define BW_7_MHZ 1 -#define BW_6_MHZ 2 -#define BW_5_MHZ 3 -#define BW_ISDBT_1SEG 4 -#define BW_ISDBT_3SEG 5 - -#define MSG_HDR_FLAG_SPLIT_MSG 4 - -#define MAX_GPIO_PIN_NUMBER 31 - -#define HIF_TASK 11 -#define SMS_HOST_LIB 150 -#define DVBT_BDA_CONTROL_MSG_ID 201 - -#define SMS_MAX_PAYLOAD_SIZE 240 -#define SMS_TUNE_TIMEOUT 500 - -#define MSG_SMS_GPIO_CONFIG_REQ 507 -#define MSG_SMS_GPIO_CONFIG_RES 508 -#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 -#define MSG_SMS_GPIO_SET_LEVEL_RES 510 -#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 -#define MSG_SMS_GPIO_GET_LEVEL_RES 512 -#define MSG_SMS_RF_TUNE_REQ 561 -#define MSG_SMS_RF_TUNE_RES 562 -#define MSG_SMS_INIT_DEVICE_REQ 578 -#define MSG_SMS_INIT_DEVICE_RES 579 -#define MSG_SMS_ADD_PID_FILTER_REQ 601 -#define MSG_SMS_ADD_PID_FILTER_RES 602 -#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 -#define MSG_SMS_REMOVE_PID_FILTER_RES 604 -#define MSG_SMS_DAB_CHANNEL 607 -#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 -#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 -#define MSG_SMS_GET_STATISTICS_RES 616 -#define MSG_SMS_GET_STATISTICS_REQ 615 -#define MSG_SMS_HO_PER_SLICES_IND 630 -#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 -#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 -#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 -#define MSG_SMS_DATA_DOWNLOAD_REQ 660 -#define MSG_SMS_DATA_DOWNLOAD_RES 661 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 -#define MSG_SMS_GET_VERSION_EX_REQ 668 -#define MSG_SMS_GET_VERSION_EX_RES 669 -#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 -#define MSG_SMS_I2C_SET_FREQ_REQ 685 -#define MSG_SMS_GENERIC_I2C_REQ 687 -#define MSG_SMS_GENERIC_I2C_RES 688 -#define MSG_SMS_DVBT_BDA_DATA 693 -#define MSG_SW_RELOAD_REQ 697 -#define MSG_SMS_DATA_MSG 699 -#define MSG_SW_RELOAD_START_REQ 702 -#define MSG_SW_RELOAD_START_RES 703 -#define MSG_SW_RELOAD_EXEC_REQ 704 -#define MSG_SW_RELOAD_EXEC_RES 705 -#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 -#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 -#define MSG_SMS_GPIO_CONFIG_EX_RES 713 -#define MSG_SMS_ISDBT_TUNE_REQ 776 -#define MSG_SMS_ISDBT_TUNE_RES 777 -#define MSG_SMS_TRANSMISSION_IND 782 -#define MSG_SMS_START_IR_REQ 800 -#define MSG_SMS_START_IR_RES 801 -#define MSG_SMS_IR_SAMPLES_IND 802 -#define MSG_SMS_SIGNAL_DETECTED_IND 827 -#define MSG_SMS_NO_SIGNAL_IND 828 - -#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ - (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ - (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ -} while (0) - -#define SMS_INIT_MSG(ptr, type, len) \ - SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) - -enum SMS_DVB3_EVENTS { - DVB3_EVENT_INIT = 0, - DVB3_EVENT_SLEEP, - DVB3_EVENT_HOTPLUG, - DVB3_EVENT_FE_LOCK, - DVB3_EVENT_FE_UNLOCK, - DVB3_EVENT_UNC_OK, - DVB3_EVENT_UNC_ERR -}; - -enum SMS_DEVICE_MODE { - DEVICE_MODE_NONE = -1, - DEVICE_MODE_DVBT = 0, - DEVICE_MODE_DVBH, - DEVICE_MODE_DAB_TDMB, - DEVICE_MODE_DAB_TDMB_DABIP, - DEVICE_MODE_DVBT_BDA, - DEVICE_MODE_ISDBT, - DEVICE_MODE_ISDBT_BDA, - DEVICE_MODE_CMMB, - DEVICE_MODE_RAW_TUNER, - DEVICE_MODE_MAX, -}; - -struct SmsMsgHdr_ST { - u16 msgType; - u8 msgSrcId; - u8 msgDstId; - u16 msgLength; /* Length of entire message, including header */ - u16 msgFlags; -}; - -struct SmsMsgData_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[1]; -}; - -struct SmsMsgData_ST2 { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[2]; -}; - -struct SmsDataDownload_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 MemAddr; - u8 Payload[SMS_MAX_PAYLOAD_SIZE]; -}; - -struct SmsVersionRes_ST { - struct SmsMsgHdr_ST xMsgHeader; - - u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ - u8 Step; /* 0 - Step A */ - u8 MetalFix; /* 0 - Metal 0 */ - - /* FirmwareId 0xFF if ROM, otherwise the - * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ - u8 FirmwareId; - /* SupportedProtocols Bitwise OR combination of - * supported protocols */ - u8 SupportedProtocols; - - u8 VersionMajor; - u8 VersionMinor; - u8 VersionPatch; - u8 VersionFieldPatch; - - u8 RomVersionMajor; - u8 RomVersionMinor; - u8 RomVersionPatch; - u8 RomVersionFieldPatch; - - u8 TextLabel[34]; -}; - -struct SmsFirmware_ST { - u32 CheckSum; - u32 Length; - u32 StartAddress; - u8 Payload[1]; -}; - -/* Statistics information returned as response for - * SmsHostApiGetStatistics_Req */ -struct SMSHOSTLIB_STATISTICS_ST { - u32 Reserved; /* Reserved */ - - /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - /* Reception quality */ - s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ - u32 TS_PER; /* Transport stream PER, - 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ - u32 MFER; /* DVB-H frame error rate in percentage, - 0xFFFFFFFF indicate N/A, valid only for DVB-H */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - - /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ - u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, - for DVB-T/H FFT mode carriers in Kilos */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, - valid only for DVB-T/H */ - u32 GuardInterval; /* Guard Interval from - SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, - valid only for DVB-T/H */ - u32 LPCodeRate; /* Low Priority Code Rate from - SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, - valid only for DVB-T/H */ - u32 Constellation; /* Constellation from - SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ - - /* Burst parameters, valid only for DVB-H */ - u32 BurstSize; /* Current burst size in bytes, - valid only for DVB-H */ - u32 BurstDuration; /* Current burst duration in mSec, - valid only for DVB-H */ - u32 BurstCycleTime; /* Current burst cycle time in mSec, - valid only for DVB-H */ - u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, - as calculated by demodulator, valid only for DVB-H */ - u32 NumOfRows; /* Number of rows in MPE table, - valid only for DVB-H */ - u32 NumOfPaddCols; /* Number of padding columns in MPE table, - valid only for DVB-H */ - u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, - valid only for DVB-H */ - u32 ErrorTSPackets; /* Number of erroneous - transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include - errors after MPE RS decoding */ - u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors - after MPE RS decoding */ - u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were - corrected by MPE RS decoding */ - /* Common params */ - u32 BERErrorCount; /* Number of errornous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ - - /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ - - /* DAB/T-DMB */ - u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ - - /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; - if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - - u32 NumMPEReceived; /* DVB-H, Num MPE section received */ - - u32 ReservedFields[10]; /* Reserved */ -}; - -struct SmsMsgStatisticsInfo_ST { - u32 RequestResult; - - struct SMSHOSTLIB_STATISTICS_ST Stat; - - /* Split the calc of the SNR in DAB */ - u32 Signal; /* dB */ - u32 Noise; /* dB */ - -}; - -struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { - /* Per-layer information */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, - * 255 means layer does not exist */ - u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, - * 255 means layer does not exist */ - u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 BERErrorCount; /* Post Viterbi Error Bits Count */ - u32 BERBitCount; /* Post Viterbi Total Bits Count */ - u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 TILdepthI; /* Time interleaver depth I parameter, - * 255 means layer does not exist */ - u32 NumberOfSegments; /* Number of segments in layer A, - * 255 means layer does not exist */ - u32 TMCCErrors; /* TMCC errors */ -}; - -struct SMSHOSTLIB_STATISTICS_ISDBT_ST { - u32 StatisticsType; /* Enumerator identifying the type of the - * structure. Values are the same as - * SMSHOSTLIB_DEVICE_MODES_E - * - * This field MUST always be first in any - * statistics structure */ - - u32 FullSize; /* Total size of the structure returned by the modem. - * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ - - /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - /* Reception quality */ - s32 SNR; /* dB */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in Hz */ - - /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* ISDB-T transmission mode */ - u32 ModemState; /* 0 - Acquisition, 1 - Locked */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ - u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ - u32 NumOfLayers; /* Number of ISDB-T layers in the network */ - - /* Per-layer information */ - /* Layers A, B and C */ - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; - /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ - - /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ -}; - -struct PID_STATISTICS_DATA_S { - struct PID_BURST_S { - u32 size; - u32 padding_cols; - u32 punct_cols; - u32 duration; - u32 cycle; - u32 calc_cycle; - } burst; - - u32 tot_tbl_cnt; - u32 invalid_tbl_cnt; - u32 tot_cor_tbl; -}; - -struct PID_DATA_S { - u32 pid; - u32 num_rows; - struct PID_STATISTICS_DATA_S pid_statistics; -}; - -#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) -#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) -#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ - if (_stat.TransmissionMode == 0) \ - _stat.TransmissionMode = 2; \ - else if (_stat.TransmissionMode == 1) \ - _stat.TransmissionMode = 8; \ - else \ - _stat.TransmissionMode = 4; - -struct TRANSMISSION_STATISTICS_S { - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* FFT mode carriers in Kilos */ - u32 GuardInterval; /* Guard Interval from - SMSHOSTLIB_GUARD_INTERVALS_ET */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 LPCodeRate; /* Low Priority Code Rate from - SMSHOSTLIB_CODE_RATE_ET */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ - u32 Constellation; /* Constellation from - SMSHOSTLIB_CONSTELLATION_ET */ - - /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; - if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ -}; - -struct RECEPTION_STATISTICS_S { - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ - s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ - u32 TS_PER; /* Transport stream PER, - 0xFFFFFFFF indicate N/A */ - u32 MFER; /* DVB-H frame error rate in percentage, - 0xFFFFFFFF indicate N/A, valid only for DVB-H */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - u32 ErrorTSPackets; /* Number of erroneous - transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - - s32 MRC_SNR; /* dB */ - s32 MRC_RSSI; /* dBm */ - s32 MRC_InBandPwr; /* In band power in dBM */ -}; - - -/* Statistics information returned as response for - * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ -struct SMSHOSTLIB_STATISTICS_DVB_S { - /* Reception */ - struct RECEPTION_STATISTICS_S ReceptionData; - - /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S TransmissionData; - - /* Burst parameters, valid only for DVB-H */ -#define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; -}; - -struct SRVM_SIGNAL_STATUS_S { - u32 result; - u32 snr; - u32 tsPackets; - u32 etsPackets; - u32 constellation; - u32 hpCode; - u32 tpsSrvIndLP; - u32 tpsSrvIndHP; - u32 cellId; - u32 reason; - - s32 inBandPower; - u32 requestId; -}; - -struct SMSHOSTLIB_I2C_REQ_ST { - u32 DeviceAddress; /* I2c device address */ - u32 WriteCount; /* number of bytes to write */ - u32 ReadCount; /* number of bytes to read */ - u8 Data[1]; -}; - -struct SMSHOSTLIB_I2C_RES_ST { - u32 Status; /* non-zero value in case of failure */ - u32 ReadCount; /* number of bytes read */ - u8 Data[1]; -}; - - -struct smscore_config_gpio { -#define SMS_GPIO_DIRECTION_INPUT 0 -#define SMS_GPIO_DIRECTION_OUTPUT 1 - u8 direction; - -#define SMS_GPIO_PULLUPDOWN_NONE 0 -#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 -#define SMS_GPIO_PULLUPDOWN_PULLUP 2 -#define SMS_GPIO_PULLUPDOWN_KEEPER 3 - u8 pullupdown; - -#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 -#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 - u8 inputcharacteristics; - -#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 -#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 - u8 outputslewrate; - -#define SMS_GPIO_OUTPUTDRIVING_4mA 0 -#define SMS_GPIO_OUTPUTDRIVING_8mA 1 -#define SMS_GPIO_OUTPUTDRIVING_12mA 2 -#define SMS_GPIO_OUTPUTDRIVING_16mA 3 - u8 outputdriving; -}; - -struct smscore_gpio_config { -#define SMS_GPIO_DIRECTION_INPUT 0 -#define SMS_GPIO_DIRECTION_OUTPUT 1 - u8 Direction; - -#define SMS_GPIO_PULL_UP_DOWN_NONE 0 -#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 -#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 -#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 - u8 PullUpDown; - -#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 -#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 - u8 InputCharacteristics; - -#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ - - -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ - u8 OutputSlewRate; - -#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ - -#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ - u8 OutputDriving; -}; - -extern void smscore_registry_setmode(char *devpath, int mode); -extern int smscore_registry_getmode(char *devpath); - -extern int smscore_register_hotplug(hotplug_t hotplug); -extern void smscore_unregister_hotplug(hotplug_t hotplug); - -extern int smscore_register_device(struct smsdevice_params_t *params, - struct smscore_device_t **coredev); -extern void smscore_unregister_device(struct smscore_device_t *coredev); - -extern int smscore_start_device(struct smscore_device_t *coredev); -extern int smscore_load_firmware(struct smscore_device_t *coredev, - char *filename, - loadfirmware_t loadfirmware_handler); - -extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); -extern int smscore_get_device_mode(struct smscore_device_t *coredev); - -extern int smscore_register_client(struct smscore_device_t *coredev, - struct smsclient_params_t *params, - struct smscore_client_t **client); -extern void smscore_unregister_client(struct smscore_client_t *client); - -extern int smsclient_sendrequest(struct smscore_client_t *client, - void *buffer, size_t size); -extern void smscore_onresponse(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb); - -extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); -extern int smscore_map_common_buffer(struct smscore_device_t *coredev, - struct vm_area_struct *vma); -extern int smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, char *filename); -extern int smscore_send_fw_file(struct smscore_device_t *coredev, - u8 *ufwbuf, int size); - -extern -struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); -extern void smscore_putbuffer(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb); - -/* old GPIO management */ -int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, - struct smscore_config_gpio *pinconfig); -int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); - -/* new GPIO management */ -extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig); -extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel); -extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, - u8 *level); - -void smscore_set_board_id(struct smscore_device_t *core, int id); -int smscore_get_board_id(struct smscore_device_t *core); - -int smscore_led_state(struct smscore_device_t *core, int led); - - -/* ------------------------------------------------------------------------ */ - -#define DBG_INFO 1 -#define DBG_ADV 2 - -#define sms_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define dprintk(kern, lvl, fmt, arg...) do {\ - if (sms_dbg & lvl) \ - sms_printk(kern, fmt, ##arg); } while (0) - -#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) -#define sms_err(fmt, arg...) \ - sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) -#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) -#define sms_info(fmt, arg...) \ - dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) -#define sms_debug(fmt, arg...) \ - dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) - - -#endif /* __SMS_CORE_API_H__ */ diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c deleted file mode 100644 index aa77e54a8fa..00000000000 --- a/drivers/media/dvb/siano/smsdvb.c +++ /dev/null @@ -1,1078 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2008, Uri Shkolnik - -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, see . - -****************************************************************/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" - -#include "smscoreapi.h" -#include "smsendian.h" -#include "sms-cards.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct smsdvb_client_t { - struct list_head entry; - - struct smscore_device_t *coredev; - struct smscore_client_t *smsclient; - - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dvb_frontend frontend; - - fe_status_t fe_status; - - struct completion tune_done; - - struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; - int event_fe_state; - int event_unc_state; -}; - -static struct list_head g_smsdvb_clients; -static struct mutex g_smsdvb_clientslock; - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -/* Events that may come from DVB v3 adapter */ -static void sms_board_dvb3_event(struct smsdvb_client_t *client, - enum SMS_DVB3_EVENTS event) { - - struct smscore_device_t *coredev = client->coredev; - switch (event) { - case DVB3_EVENT_INIT: - sms_debug("DVB3_EVENT_INIT"); - sms_board_event(coredev, BOARD_EVENT_BIND); - break; - case DVB3_EVENT_SLEEP: - sms_debug("DVB3_EVENT_SLEEP"); - sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); - break; - case DVB3_EVENT_HOTPLUG: - sms_debug("DVB3_EVENT_HOTPLUG"); - sms_board_event(coredev, BOARD_EVENT_POWER_INIT); - break; - case DVB3_EVENT_FE_LOCK: - if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { - client->event_fe_state = DVB3_EVENT_FE_LOCK; - sms_debug("DVB3_EVENT_FE_LOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_LOCK); - } - break; - case DVB3_EVENT_FE_UNLOCK: - if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { - client->event_fe_state = DVB3_EVENT_FE_UNLOCK; - sms_debug("DVB3_EVENT_FE_UNLOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); - } - break; - case DVB3_EVENT_UNC_OK: - if (client->event_unc_state != DVB3_EVENT_UNC_OK) { - client->event_unc_state = DVB3_EVENT_UNC_OK; - sms_debug("DVB3_EVENT_UNC_OK"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); - } - break; - case DVB3_EVENT_UNC_ERR: - if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { - client->event_unc_state = DVB3_EVENT_UNC_ERR; - sms_debug("DVB3_EVENT_UNC_ERR"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); - } - break; - - default: - sms_err("Unknown dvb3 api event"); - break; - } -} - - -static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ST *p) -{ - if (sms_dbg & 2) { - printk(KERN_DEBUG "Reserved = %d", p->Reserved); - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "BER = %d", p->BER); - printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); - printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); - printk(KERN_DEBUG "MFER = %d", p->MFER); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); - printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); - printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); - printk(KERN_DEBUG "Constellation = %d", p->Constellation); - printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); - printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); - printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); - printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); - printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); - printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); - printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); - printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); - printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); - printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); - printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); - printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); - printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); - printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - printk(KERN_DEBUG "PreBER = %d", p->PreBER); - printk(KERN_DEBUG "CellId = %d", p->CellId); - printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); - printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); - printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); - } - - pReceptionData->IsDemodLocked = p->IsDemodLocked; - - pReceptionData->SNR = p->SNR; - pReceptionData->BER = p->BER; - pReceptionData->BERErrorCount = p->BERErrorCount; - pReceptionData->InBandPwr = p->InBandPwr; - pReceptionData->ErrorTSPackets = p->ErrorTSPackets; -}; - - -static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) -{ - int i; - - if (sms_dbg & 2) { - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - - for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); - } - } - - pReceptionData->IsDemodLocked = p->IsDemodLocked; - - pReceptionData->SNR = p->SNR; - pReceptionData->InBandPwr = p->InBandPwr; - - pReceptionData->ErrorTSPackets = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - for (i = 0; i < 3; i++) { - pReceptionData->BER += p->LayerInfo[i].BER; - pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount; - pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets; - } -} - -static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) -{ - struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) - + cb->offset); - u32 *pMsgData = (u32 *) phdr + 1; - /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ - bool is_status_update = false; - - smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); - - switch (phdr->msgType) { - case MSG_SMS_DVBT_BDA_DATA: - dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), - cb->size - sizeof(struct SmsMsgHdr_ST)); - break; - - case MSG_SMS_RF_TUNE_RES: - case MSG_SMS_ISDBT_TUNE_RES: - complete(&client->tune_done); - break; - - case MSG_SMS_SIGNAL_DETECTED_IND: - sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); - client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; - is_status_update = true; - break; - - case MSG_SMS_NO_SIGNAL_IND: - sms_info("MSG_SMS_NO_SIGNAL_IND"); - client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; - is_status_update = true; - break; - - case MSG_SMS_TRANSMISSION_IND: { - sms_info("MSG_SMS_TRANSMISSION_IND"); - - pMsgData++; - memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, - sizeof(struct TRANSMISSION_STATISTICS_S)); - - /* Mo need to correct guard interval - * (as opposed to old statistics message). - */ - CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); - CORRECT_STAT_TRANSMISSON_MODE( - client->sms_stat_dvb.TransmissionData); - is_status_update = true; - break; - } - case MSG_SMS_HO_PER_SLICES_IND: { - struct RECEPTION_STATISTICS_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - struct SRVM_SIGNAL_STATUS_S SignalStatusData; - - /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ - pMsgData++; - SignalStatusData.result = pMsgData[0]; - SignalStatusData.snr = pMsgData[1]; - SignalStatusData.inBandPower = (s32) pMsgData[2]; - SignalStatusData.tsPackets = pMsgData[3]; - SignalStatusData.etsPackets = pMsgData[4]; - SignalStatusData.constellation = pMsgData[5]; - SignalStatusData.hpCode = pMsgData[6]; - SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; - SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; - SignalStatusData.cellId = pMsgData[9] & 0xFFFF; - SignalStatusData.reason = pMsgData[10]; - SignalStatusData.requestId = pMsgData[11]; - pReceptionData->IsRfLocked = pMsgData[16]; - pReceptionData->IsDemodLocked = pMsgData[17]; - pReceptionData->ModemState = pMsgData[12]; - pReceptionData->SNR = pMsgData[1]; - pReceptionData->BER = pMsgData[13]; - pReceptionData->RSSI = pMsgData[14]; - CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); - - pReceptionData->InBandPwr = (s32) pMsgData[2]; - pReceptionData->CarrierOffset = (s32) pMsgData[15]; - pReceptionData->TotalTSPackets = pMsgData[3]; - pReceptionData->ErrorTSPackets = pMsgData[4]; - - /* TS PER */ - if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) - > 0) { - pReceptionData->TS_PER = (SignalStatusData.etsPackets - * 100) / (SignalStatusData.tsPackets - + SignalStatusData.etsPackets); - } else { - pReceptionData->TS_PER = 0; - } - - pReceptionData->BERBitCount = pMsgData[18]; - pReceptionData->BERErrorCount = pMsgData[19]; - - pReceptionData->MRC_SNR = pMsgData[20]; - pReceptionData->MRC_InBandPwr = pMsgData[21]; - pReceptionData->MRC_RSSI = pMsgData[22]; - - is_status_update = true; - break; - } - case MSG_SMS_GET_STATISTICS_RES: { - union { - struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; - struct SmsMsgStatisticsInfo_ST dvb; - } *p = (void *) (phdr + 1); - struct RECEPTION_STATISTICS_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - - sms_info("MSG_SMS_GET_STATISTICS_RES"); - - is_status_update = true; - - switch (smscore_get_device_mode(client->coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt); - break; - default: - smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat); - } - if (!pReceptionData->IsDemodLocked) { - pReceptionData->SNR = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - pReceptionData->InBandPwr = 0; - pReceptionData->ErrorTSPackets = 0; - } - - complete(&client->tune_done); - break; - } - default: - sms_info("Unhandled message %d", phdr->msgType); - - } - smscore_putbuffer(client->coredev, cb); - - if (is_status_update) { - if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER - | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); - if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets - == 0) - sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); - else - sms_board_dvb3_event(client, - DVB3_EVENT_UNC_ERR); - - } else { - if (client->sms_stat_dvb.ReceptionData.IsRfLocked) - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - client->fe_status = 0; - sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); - } - } - - return 0; -} - -static void smsdvb_unregister_client(struct smsdvb_client_t *client) -{ - /* must be called under clientslock */ - - list_del(&client->entry); - - smscore_unregister_client(client->smsclient); - dvb_unregister_frontend(&client->frontend); - dvb_dmxdev_release(&client->dmxdev); - dvb_dmx_release(&client->demux); - dvb_unregister_adapter(&client->adapter); - kfree(client); -} - -static void smsdvb_onremove(void *context) -{ - kmutex_lock(&g_smsdvb_clientslock); - - smsdvb_unregister_client((struct smsdvb_client_t *) context); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -static int smsdvb_start_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("add pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("remove pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, - void *buffer, size_t size, - struct completion *completion) -{ - int rc; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); - rc = smsclient_sendrequest(client->smsclient, buffer, size); - if (rc < 0) - return rc; - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(2000)) ? - 0 : -ETIME; -} - -static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) -{ - int rc; - struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, - DVBT_BDA_CONTROL_MSG_ID, - HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; - - rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - return rc; -} - -static inline int led_feedback(struct smsdvb_client_t *client) -{ - if (client->fe_status & FE_HAS_LOCK) - return sms_board_led_feedback(client->coredev, - (client->sms_stat_dvb.ReceptionData.BER - == 0) ? SMS_LED_HI : SMS_LED_LO); - else - return sms_board_led_feedback(client->coredev, SMS_LED_OFF); -} - -static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *stat = client->fe_status; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ber = client->sms_stat_dvb.ReceptionData.BER; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - int rc; - - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) - *strength = 0; - else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) - *strength = 100; - else - *strength = - (client->sms_stat_dvb.ReceptionData.InBandPwr - + 95) * 3 / 2; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *snr = client->sms_stat_dvb.ReceptionData.SNR; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; - - led_feedback(client); - - return rc; -} - -static int smsdvb_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - sms_debug(""); - - tune->min_delay_ms = 400; - tune->step_size = 250000; - tune->max_drift = 0; - return 0; -} - -static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[3]; - } Msg; - - int ret; - - client->fe_status = FE_HAS_SIGNAL; - client->event_fe_state = -1; - client->event_unc_state = -1; - fe->dtv_property_cache.delivery_system = SYS_DVBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - - sms_info("%s: freq %d band %d", __func__, c->frequency, - c->bandwidth_hz); - - switch (c->bandwidth_hz / 1000000) { - case 8: - Msg.Data[1] = BW_8_MHZ; - break; - case 7: - Msg.Data[1] = BW_7_MHZ; - break; - case 6: - Msg.Data[1] = BW_6_MHZ; - break; - case 0: - return -EOPNOTSUPP; - default: - return -EINVAL; - } - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didn't lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[4]; - } Msg; - - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - - if (c->isdbt_sb_segment_idx == -1) - c->isdbt_sb_segment_idx = 0; - - switch (c->isdbt_sb_segment_count) { - case 3: - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 1: - Msg.Data[1] = BW_ISDBT_1SEG; - break; - case 0: /* AUTO */ - switch (c->bandwidth_hz / 1000000) { - case 8: - case 7: - c->isdbt_sb_segment_count = 3; - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 6: - c->isdbt_sb_segment_count = 1; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - default: /* Assumes 6 MHZ bw */ - c->isdbt_sb_segment_count = 1; - c->bandwidth_hz = 6000; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - } - break; - default: - sms_info("Segment count %d not supported", c->isdbt_sb_segment_count); - return -EINVAL; - } - - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - Msg.Data[3] = c->isdbt_sb_segment_idx; - - sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, - c->frequency, c->isdbt_sb_segment_count, - c->isdbt_sb_segment_idx); - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_set_frontend(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - return smsdvb_dvbt_set_frontend(fe); - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - return smsdvb_isdbt_set_frontend(fe); - default: - return -EINVAL; - } -} - -static int smsdvb_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - struct TRANSMISSION_STATISTICS_S *td = - &client->sms_stat_dvb.TransmissionData; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - fep->frequency = td->Frequency; - - switch (td->Bandwidth) { - case 6: - fep->bandwidth_hz = 6000000; - break; - case 7: - fep->bandwidth_hz = 7000000; - break; - case 8: - fep->bandwidth_hz = 8000000; - break; - } - - switch (td->TransmissionMode) { - case 2: - fep->transmission_mode = TRANSMISSION_MODE_2K; - break; - case 8: - fep->transmission_mode = TRANSMISSION_MODE_8K; - } - - switch (td->GuardInterval) { - case 0: - fep->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - fep->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - fep->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - fep->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - switch (td->CodeRate) { - case 0: - fep->code_rate_HP = FEC_1_2; - break; - case 1: - fep->code_rate_HP = FEC_2_3; - break; - case 2: - fep->code_rate_HP = FEC_3_4; - break; - case 3: - fep->code_rate_HP = FEC_5_6; - break; - case 4: - fep->code_rate_HP = FEC_7_8; - break; - } - - switch (td->LPCodeRate) { - case 0: - fep->code_rate_LP = FEC_1_2; - break; - case 1: - fep->code_rate_LP = FEC_2_3; - break; - case 2: - fep->code_rate_LP = FEC_3_4; - break; - case 3: - fep->code_rate_LP = FEC_5_6; - break; - case 4: - fep->code_rate_LP = FEC_7_8; - break; - } - - switch (td->Constellation) { - case 0: - fep->modulation = QPSK; - break; - case 1: - fep->modulation = QAM_16; - break; - case 2: - fep->modulation = QAM_64; - break; - } - - switch (td->Hierarchy) { - case 0: - fep->hierarchy = HIERARCHY_NONE; - break; - case 1: - fep->hierarchy = HIERARCHY_1; - break; - case 2: - fep->hierarchy = HIERARCHY_2; - break; - case 3: - fep->hierarchy = HIERARCHY_4; - break; - } - - fep->inversion = INVERSION_AUTO; - break; - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - fep->frequency = td->Frequency; - fep->bandwidth_hz = 6000000; - /* todo: retrive the other parameters */ - break; - default: - return -EINVAL; - } - - return 0; -} - -static int smsdvb_init(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_power(client->coredev, 1); - - sms_board_dvb3_event(client, DVB3_EVENT_INIT); - return 0; -} - -static int smsdvb_sleep(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - sms_board_power(client->coredev, 0); - - sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); - - return 0; -} - -static void smsdvb_release(struct dvb_frontend *fe) -{ - /* do nothing */ -} - -static struct dvb_frontend_ops smsdvb_fe_ops = { - .info = { - .name = "Siano Mobile Digital MDTV Receiver", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = smsdvb_release, - - .set_frontend = smsdvb_set_frontend, - .get_frontend = smsdvb_get_frontend, - .get_tune_settings = smsdvb_get_tune_settings, - - .read_status = smsdvb_read_status, - .read_ber = smsdvb_read_ber, - .read_signal_strength = smsdvb_read_signal_strength, - .read_snr = smsdvb_read_snr, - .read_ucblocks = smsdvb_read_ucblocks, - - .init = smsdvb_init, - .sleep = smsdvb_sleep, -}; - -static int smsdvb_hotplug(struct smscore_device_t *coredev, - struct device *device, int arrival) -{ - struct smsclient_params_t params; - struct smsdvb_client_t *client; - int rc; - - /* device removal handled by onremove callback */ - if (!arrival) - return 0; - client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); - if (!client) { - sms_err("kmalloc() failed"); - return -ENOMEM; - } - - /* register dvb adapter */ - rc = dvb_register_adapter(&client->adapter, - sms_get_board( - smscore_get_board_id(coredev))->name, - THIS_MODULE, device, adapter_nr); - if (rc < 0) { - sms_err("dvb_register_adapter() failed %d", rc); - goto adapter_error; - } - - /* init dvb demux */ - client->demux.dmx.capabilities = DMX_TS_FILTERING; - client->demux.filternum = 32; /* todo: nova ??? */ - client->demux.feednum = 32; - client->demux.start_feed = smsdvb_start_feed; - client->demux.stop_feed = smsdvb_stop_feed; - - rc = dvb_dmx_init(&client->demux); - if (rc < 0) { - sms_err("dvb_dmx_init failed %d", rc); - goto dvbdmx_error; - } - - /* init dmxdev */ - client->dmxdev.filternum = 32; - client->dmxdev.demux = &client->demux.dmx; - client->dmxdev.capabilities = 0; - - rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); - if (rc < 0) { - sms_err("dvb_dmxdev_init failed %d", rc); - goto dmxdev_error; - } - - /* init and register frontend */ - memcpy(&client->frontend.ops, &smsdvb_fe_ops, - sizeof(struct dvb_frontend_ops)); - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - client->frontend.ops.delsys[0] = SYS_DVBT; - break; - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - client->frontend.ops.delsys[0] = SYS_ISDBT; - break; - } - - rc = dvb_register_frontend(&client->adapter, &client->frontend); - if (rc < 0) { - sms_err("frontend registration failed %d", rc); - goto frontend_error; - } - - params.initial_id = 1; - params.data_type = MSG_SMS_DVBT_BDA_DATA; - params.onresponse_handler = smsdvb_onresponse; - params.onremove_handler = smsdvb_onremove; - params.context = client; - - rc = smscore_register_client(coredev, ¶ms, &client->smsclient); - if (rc < 0) { - sms_err("smscore_register_client() failed %d", rc); - goto client_error; - } - - client->coredev = coredev; - - init_completion(&client->tune_done); - - kmutex_lock(&g_smsdvb_clientslock); - - list_add(&client->entry, &g_smsdvb_clients); - - kmutex_unlock(&g_smsdvb_clientslock); - - client->event_fe_state = -1; - client->event_unc_state = -1; - sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); - - sms_info("success"); - sms_board_setup(coredev); - - return 0; - -client_error: - dvb_unregister_frontend(&client->frontend); - -frontend_error: - dvb_dmxdev_release(&client->dmxdev); - -dmxdev_error: - dvb_dmx_release(&client->demux); - -dvbdmx_error: - dvb_unregister_adapter(&client->adapter); - -adapter_error: - kfree(client); - return rc; -} - -static int __init smsdvb_module_init(void) -{ - int rc; - - INIT_LIST_HEAD(&g_smsdvb_clients); - kmutex_init(&g_smsdvb_clientslock); - - rc = smscore_register_hotplug(smsdvb_hotplug); - - sms_debug(""); - - return rc; -} - -static void __exit smsdvb_module_exit(void) -{ - smscore_unregister_hotplug(smsdvb_hotplug); - - kmutex_lock(&g_smsdvb_clientslock); - - while (!list_empty(&g_smsdvb_clients)) - smsdvb_unregister_client( - (struct smsdvb_client_t *) g_smsdvb_clients.next); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -module_init(smsdvb_module_init); -module_exit(smsdvb_module_exit); - -MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); -MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c deleted file mode 100644 index e2657c2f010..00000000000 --- a/drivers/media/dvb/siano/smsendian.c +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************** - - Siano Mobile Silicon, Inc. - MDTV receiver kernel modules. - Copyright (C) 2006-2009, Uri Shkolnik - - 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, see . - - ****************************************************************/ - -#include -#include - -#include "smsendian.h" -#include "smscoreapi.h" - -void smsendian_handle_tx_message(void *buffer) -{ -#ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; - int i; - int msgWords; - - switch (msg->xMsgHeader.msgType) { - case MSG_SMS_DATA_DOWNLOAD_REQ: - { - msg->msgData[0] = le32_to_cpu(msg->msgData[0]); - break; - } - - default: - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; - - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); - - break; - } -#endif /* __BIG_ENDIAN */ -} -EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); - -void smsendian_handle_rx_message(void *buffer) -{ -#ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; - int i; - int msgWords; - - switch (msg->xMsgHeader.msgType) { - case MSG_SMS_GET_VERSION_EX_RES: - { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) msg; - ver->ChipModel = le16_to_cpu(ver->ChipModel); - break; - } - - case MSG_SMS_DVBT_BDA_DATA: - case MSG_SMS_DAB_CHANNEL: - case MSG_SMS_DATA_MSG: - { - break; - } - - default: - { - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; - - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); - - break; - } - } -#endif /* __BIG_ENDIAN */ -} -EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); - -void smsendian_handle_message_header(void *msg) -{ -#ifdef __BIG_ENDIAN - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; - - phdr->msgType = le16_to_cpu(phdr->msgType); - phdr->msgLength = le16_to_cpu(phdr->msgLength); - phdr->msgFlags = le16_to_cpu(phdr->msgFlags); -#endif /* __BIG_ENDIAN */ -} -EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/dvb/siano/smsendian.h deleted file mode 100644 index 1624d6fd367..00000000000 --- a/drivers/media/dvb/siano/smsendian.h +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2009, Uri Shkolnik - -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, see . - -****************************************************************/ - -#ifndef __SMS_ENDIAN_H__ -#define __SMS_ENDIAN_H__ - -#include - -extern void smsendian_handle_tx_message(void *buffer); -extern void smsendian_handle_rx_message(void *buffer); -extern void smsendian_handle_message_header(void *msg); - -#endif /* __SMS_ENDIAN_H__ */ - diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c deleted file mode 100644 index 37bc5c4b8ad..00000000000 --- a/drivers/media/dvb/siano/smsir.c +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************** - - Siano Mobile Silicon, Inc. - MDTV receiver kernel modules. - Copyright (C) 2006-2009, Uri Shkolnik - - Copyright (c) 2010 - Mauro Carvalho Chehab - - Ported the driver to use rc-core - - IR raw event decoding is now done at rc-core - - Code almost re-written - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (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, see . - - ****************************************************************/ - - -#include -#include - -#include "smscoreapi.h" -#include "smsir.h" -#include "sms-cards.h" - -#define MODULE_NAME "smsmdtv" - -void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) -{ - int i; - const s32 *samples = (const void *)buf; - - for (i = 0; i < len >> 2; i++) { - DEFINE_IR_RAW_EVENT(ev); - - ev.duration = abs(samples[i]) * 1000; /* Convert to ns */ - ev.pulse = (samples[i] > 0) ? false : true; - - ir_raw_event_store(coredev->ir.dev, &ev); - } - ir_raw_event_handle(coredev->ir.dev); -} - -int sms_ir_init(struct smscore_device_t *coredev) -{ - int err; - int board_id = smscore_get_board_id(coredev); - struct rc_dev *dev; - - sms_log("Allocating rc device"); - dev = rc_allocate_device(); - if (!dev) { - sms_err("Not enough memory"); - return -ENOMEM; - } - - coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ - coredev->ir.timeout = IR_DEFAULT_TIMEOUT; - sms_log("IR port %d, timeout %d ms", - coredev->ir.controller, coredev->ir.timeout); - - snprintf(coredev->ir.name, sizeof(coredev->ir.name), - "SMS IR (%s)", sms_get_board(board_id)->name); - - strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); - strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); - - dev->input_name = coredev->ir.name; - dev->input_phys = coredev->ir.phys; - dev->dev.parent = coredev->device; - -#if 0 - /* TODO: properly initialize the parameters bellow */ - dev->input_id.bustype = BUS_USB; - dev->input_id.version = 1; - dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); -#endif - - dev->priv = coredev; - dev->driver_type = RC_DRIVER_IR_RAW; - dev->allowed_protos = RC_TYPE_ALL; - dev->map_name = sms_get_board(board_id)->rc_codes; - dev->driver_name = MODULE_NAME; - - sms_log("Input device (IR) %s is set for key events", dev->input_name); - - err = rc_register_device(dev); - if (err < 0) { - sms_err("Failed to register device"); - rc_free_device(dev); - return err; - } - - coredev->ir.dev = dev; - return 0; -} - -void sms_ir_exit(struct smscore_device_t *coredev) -{ - if (coredev->ir.dev) - rc_unregister_device(coredev->ir.dev); - - sms_log(""); -} diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h deleted file mode 100644 index ae92b3a8587..00000000000 --- a/drivers/media/dvb/siano/smsir.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2009, Uri Shkolnik - - Copyright (c) 2010 - Mauro Carvalho Chehab - - Ported the driver to use rc-core - - IR raw event decoding is now done at rc-core - - Code almost re-written - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(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, see . - -****************************************************************/ - -#ifndef __SMS_IR_H__ -#define __SMS_IR_H__ - -#include -#include - -#define IR_DEFAULT_TIMEOUT 100 - -struct smscore_device_t; - -struct ir_t { - struct rc_dev *dev; - char name[40]; - char phys[32]; - - char *rc_codes; - u64 protocol; - - u32 timeout; - u32 controller; -}; - -int sms_ir_init(struct smscore_device_t *coredev); -void sms_ir_exit(struct smscore_device_t *coredev); -void sms_ir_event(struct smscore_device_t *coredev, - const char *buf, int len); - -#endif /* __SMS_IR_H__ */ - diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c deleted file mode 100644 index d6f3f100699..00000000000 --- a/drivers/media/dvb/siano/smssdio.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * smssdio.c - Siano 1xxx SDIO interface driver - * - * Copyright 2008 Pierre Ossman - * - * Based on code by Siano Mobile Silicon, Inc., - * Copyright (C) 2006-2008, Uri Shkolnik - * - * 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 hardware is a bit odd in that all transfers should be done - * to/from the SMSSDIO_DATA register, yet the "increase address" bit - * always needs to be set. - * - * Also, buffers from the card are always aligned to 128 byte - * boundaries. - */ - -/* - * General cleanup notes: - * - * - only typedefs should be name *_t - * - * - use ERR_PTR and friends for smscore_register_device() - * - * - smscore_getbuffer should zero fields - * - * Fix stop command - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "smscoreapi.h" -#include "sms-cards.h" - -/* Registers */ - -#define SMSSDIO_DATA 0x00 -#define SMSSDIO_INT 0x04 -#define SMSSDIO_BLOCK_SIZE 128 - -static const struct sdio_device_id smssdio_ids[] __devinitconst = { - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), - .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), - .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0), - .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0), - .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), - .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(sdio, smssdio_ids); - -struct smssdio_device { - struct sdio_func *func; - - struct smscore_device_t *coredev; - - struct smscore_buffer_t *split_cb; -}; - -/*******************************************************************/ -/* Siano core callbacks */ -/*******************************************************************/ - -static int smssdio_sendrequest(void *context, void *buffer, size_t size) -{ - int ret = 0; - struct smssdio_device *smsdev; - - smsdev = context; - - sdio_claim_host(smsdev->func); - - while (size >= smsdev->func->cur_blksize) { - ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, - buffer, smsdev->func->cur_blksize); - if (ret) - goto out; - - buffer += smsdev->func->cur_blksize; - size -= smsdev->func->cur_blksize; - } - - if (size) { - ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, - buffer, size); - } - -out: - sdio_release_host(smsdev->func); - - return ret; -} - -/*******************************************************************/ -/* SDIO callbacks */ -/*******************************************************************/ - -static void smssdio_interrupt(struct sdio_func *func) -{ - int ret; - - struct smssdio_device *smsdev; - struct smscore_buffer_t *cb; - struct SmsMsgHdr_ST *hdr; - size_t size; - - smsdev = sdio_get_drvdata(func); - - /* - * The interrupt register has no defined meaning. It is just - * a way of turning of the level triggered interrupt. - */ - (void)sdio_readb(func, SMSSDIO_INT, &ret); - if (ret) { - sms_err("Unable to read interrupt register!\n"); - return; - } - - if (smsdev->split_cb == NULL) { - cb = smscore_getbuffer(smsdev->coredev); - if (!cb) { - sms_err("Unable to allocate data buffer!\n"); - return; - } - - ret = sdio_memcpy_fromio(smsdev->func, - cb->p, - SMSSDIO_DATA, - SMSSDIO_BLOCK_SIZE); - if (ret) { - sms_err("Error %d reading initial block!\n", ret); - return; - } - - hdr = cb->p; - - if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { - smsdev->split_cb = cb; - return; - } - - if (hdr->msgLength > smsdev->func->cur_blksize) - size = hdr->msgLength - smsdev->func->cur_blksize; - else - size = 0; - } else { - cb = smsdev->split_cb; - hdr = cb->p; - - size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); - - smsdev->split_cb = NULL; - } - - if (size) { - void *buffer; - - buffer = cb->p + (hdr->msgLength - size); - size = ALIGN(size, SMSSDIO_BLOCK_SIZE); - - BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); - - /* - * First attempt to transfer all of it in one go... - */ - ret = sdio_memcpy_fromio(smsdev->func, - buffer, - SMSSDIO_DATA, - size); - if (ret && ret != -EINVAL) { - smscore_putbuffer(smsdev->coredev, cb); - sms_err("Error %d reading data from card!\n", ret); - return; - } - - /* - * ..then fall back to one block at a time if that is - * not possible... - * - * (we have to do this manually because of the - * problem with the "increase address" bit) - */ - if (ret == -EINVAL) { - while (size) { - ret = sdio_memcpy_fromio(smsdev->func, - buffer, SMSSDIO_DATA, - smsdev->func->cur_blksize); - if (ret) { - smscore_putbuffer(smsdev->coredev, cb); - sms_err("Error %d reading " - "data from card!\n", ret); - return; - } - - buffer += smsdev->func->cur_blksize; - if (size > smsdev->func->cur_blksize) - size -= smsdev->func->cur_blksize; - else - size = 0; - } - } - } - - cb->size = hdr->msgLength; - cb->offset = 0; - - smscore_onresponse(smsdev->coredev, cb); -} - -static int __devinit smssdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret; - - int board_id; - struct smssdio_device *smsdev; - struct smsdevice_params_t params; - - board_id = id->driver_data; - - smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL); - if (!smsdev) - return -ENOMEM; - - smsdev->func = func; - - memset(¶ms, 0, sizeof(struct smsdevice_params_t)); - - params.device = &func->dev; - params.buffer_size = 0x5000; /* ?? */ - params.num_buffers = 22; /* ?? */ - params.context = smsdev; - - snprintf(params.devpath, sizeof(params.devpath), - "sdio\\%s", sdio_func_id(func)); - - params.sendrequest_handler = smssdio_sendrequest; - - params.device_type = sms_get_board(board_id)->type; - - if (params.device_type != SMS_STELLAR) - params.flags |= SMS_DEVICE_FAMILY2; - else { - /* - * FIXME: Stellar needs special handling... - */ - ret = -ENODEV; - goto free; - } - - ret = smscore_register_device(¶ms, &smsdev->coredev); - if (ret < 0) - goto free; - - smscore_set_board_id(smsdev->coredev, board_id); - - sdio_claim_host(func); - - ret = sdio_enable_func(func); - if (ret) - goto release; - - ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE); - if (ret) - goto disable; - - ret = sdio_claim_irq(func, smssdio_interrupt); - if (ret) - goto disable; - - sdio_set_drvdata(func, smsdev); - - sdio_release_host(func); - - ret = smscore_start_device(smsdev->coredev); - if (ret < 0) - goto reclaim; - - return 0; - -reclaim: - sdio_claim_host(func); - sdio_release_irq(func); -disable: - sdio_disable_func(func); -release: - sdio_release_host(func); - smscore_unregister_device(smsdev->coredev); -free: - kfree(smsdev); - - return ret; -} - -static void smssdio_remove(struct sdio_func *func) -{ - struct smssdio_device *smsdev; - - smsdev = sdio_get_drvdata(func); - - /* FIXME: racy! */ - if (smsdev->split_cb) - smscore_putbuffer(smsdev->coredev, smsdev->split_cb); - - smscore_unregister_device(smsdev->coredev); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_disable_func(func); - sdio_release_host(func); - - kfree(smsdev); -} - -static struct sdio_driver smssdio_driver = { - .name = "smssdio", - .id_table = smssdio_ids, - .probe = smssdio_probe, - .remove = smssdio_remove, -}; - -/*******************************************************************/ -/* Module functions */ -/*******************************************************************/ - -static int __init smssdio_module_init(void) -{ - int ret = 0; - - printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n"); - printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n"); - - ret = sdio_register_driver(&smssdio_driver); - - return ret; -} - -static void __exit smssdio_module_exit(void) -{ - sdio_unregister_driver(&smssdio_driver); -} - -module_init(smssdio_module_init); -module_exit(smssdio_module_exit); - -MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver"); -MODULE_AUTHOR("Pierre Ossman"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c deleted file mode 100644 index 664e460f247..00000000000 --- a/drivers/media/dvb/siano/smsusb.c +++ /dev/null @@ -1,568 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat - -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, see . - -****************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "smscoreapi.h" -#include "sms-cards.h" -#include "smsendian.h" - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -#define USB1_BUFFER_SIZE 0x1000 -#define USB2_BUFFER_SIZE 0x4000 - -#define MAX_BUFFERS 50 -#define MAX_URBS 10 - -struct smsusb_device_t; - -struct smsusb_urb_t { - struct smscore_buffer_t *cb; - struct smsusb_device_t *dev; - - struct urb urb; -}; - -struct smsusb_device_t { - struct usb_device *udev; - struct smscore_device_t *coredev; - - struct smsusb_urb_t surbs[MAX_URBS]; - - int response_alignment; - int buffer_size; -}; - -static int smsusb_submit_urb(struct smsusb_device_t *dev, - struct smsusb_urb_t *surb); - -static void smsusb_onresponse(struct urb *urb) -{ - struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; - struct smsusb_device_t *dev = surb->dev; - - if (urb->status == -ESHUTDOWN) { - sms_err("error, urb status %d (-ESHUTDOWN), %d bytes", - urb->status, urb->actual_length); - return; - } - - if ((urb->actual_length > 0) && (urb->status == 0)) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; - - smsendian_handle_message_header(phdr); - if (urb->actual_length >= phdr->msgLength) { - surb->cb->size = phdr->msgLength; - - if (dev->response_alignment && - (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) { - - surb->cb->offset = - dev->response_alignment + - ((phdr->msgFlags >> 8) & 3); - - /* sanity check */ - if (((int) phdr->msgLength + - surb->cb->offset) > urb->actual_length) { - sms_err("invalid response " - "msglen %d offset %d " - "size %d", - phdr->msgLength, - surb->cb->offset, - urb->actual_length); - goto exit_and_resubmit; - } - - /* move buffer pointer and - * copy header to its new location */ - memcpy((char *) phdr + surb->cb->offset, - phdr, sizeof(struct SmsMsgHdr_ST)); - } else - surb->cb->offset = 0; - - smscore_onresponse(dev->coredev, surb->cb); - surb->cb = NULL; - } else { - sms_err("invalid response " - "msglen %d actual %d", - phdr->msgLength, urb->actual_length); - } - } else - sms_err("error, urb status %d, %d bytes", - urb->status, urb->actual_length); - - -exit_and_resubmit: - smsusb_submit_urb(dev, surb); -} - -static int smsusb_submit_urb(struct smsusb_device_t *dev, - struct smsusb_urb_t *surb) -{ - if (!surb->cb) { - surb->cb = smscore_getbuffer(dev->coredev); - if (!surb->cb) { - sms_err("smscore_getbuffer(...) returned NULL"); - return -ENOMEM; - } - } - - usb_fill_bulk_urb( - &surb->urb, - dev->udev, - usb_rcvbulkpipe(dev->udev, 0x81), - surb->cb->p, - dev->buffer_size, - smsusb_onresponse, - surb - ); - surb->urb.transfer_dma = surb->cb->phys; - surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - return usb_submit_urb(&surb->urb, GFP_ATOMIC); -} - -static void smsusb_stop_streaming(struct smsusb_device_t *dev) -{ - int i; - - for (i = 0; i < MAX_URBS; i++) { - usb_kill_urb(&dev->surbs[i].urb); - - if (dev->surbs[i].cb) { - smscore_putbuffer(dev->coredev, dev->surbs[i].cb); - dev->surbs[i].cb = NULL; - } - } -} - -static int smsusb_start_streaming(struct smsusb_device_t *dev) -{ - int i, rc; - - for (i = 0; i < MAX_URBS; i++) { - rc = smsusb_submit_urb(dev, &dev->surbs[i]); - if (rc < 0) { - sms_err("smsusb_submit_urb(...) failed"); - smsusb_stop_streaming(dev); - break; - } - } - - return rc; -} - -static int smsusb_sendrequest(void *context, void *buffer, size_t size) -{ - struct smsusb_device_t *dev = (struct smsusb_device_t *) context; - int dummy; - - smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); - return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), - buffer, size, &dummy, 1000); -} - -static char *smsusb1_fw_lkup[] = { - "dvbt_stellar_usb.inp", - "dvbh_stellar_usb.inp", - "tdmb_stellar_usb.inp", - "none", - "dvbt_bda_stellar_usb.inp", -}; - -static inline char *sms_get_fw_name(int mode, int board_id) -{ - char **fw = sms_get_board(board_id)->fw; - return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode]; -} - -static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) -{ - const struct firmware *fw; - u8 *fw_buffer; - int rc, dummy; - char *fw_filename; - - if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid firmware id specified %d", id); - return -EINVAL; - } - - fw_filename = sms_get_fw_name(id, board_id); - - rc = request_firmware(&fw, fw_filename, &udev->dev); - if (rc < 0) { - sms_warn("failed to open \"%s\" mode %d, " - "trying again with default firmware", fw_filename, id); - - fw_filename = smsusb1_fw_lkup[id]; - rc = request_firmware(&fw, fw_filename, &udev->dev); - if (rc < 0) { - sms_warn("failed to open \"%s\" mode %d", - fw_filename, id); - - return rc; - } - } - - fw_buffer = kmalloc(fw->size, GFP_KERNEL); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - - rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), - fw_buffer, fw->size, &dummy, 1000); - - sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc); - - kfree(fw_buffer); - } else { - sms_err("failed to allocate firmware buffer"); - rc = -ENOMEM; - } - sms_info("read FW %s, size=%zd", fw_filename, fw->size); - - release_firmware(fw); - - return rc; -} - -static void smsusb1_detectmode(void *context, int *mode) -{ - char *product_string = - ((struct smsusb_device_t *) context)->udev->product; - - *mode = DEVICE_MODE_NONE; - - if (!product_string) { - product_string = "none"; - sms_err("product string not found"); - } else if (strstr(product_string, "DVBH")) - *mode = 1; - else if (strstr(product_string, "BDA")) - *mode = 4; - else if (strstr(product_string, "DVBT")) - *mode = 0; - else if (strstr(product_string, "TDMB")) - *mode = 2; - - sms_info("%d \"%s\"", *mode, product_string); -} - -static int smsusb1_setmode(void *context, int mode) -{ - struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; - - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid firmware id specified %d", mode); - return -EINVAL; - } - - return smsusb_sendrequest(context, &Msg, sizeof(Msg)); -} - -static void smsusb_term_device(struct usb_interface *intf) -{ - struct smsusb_device_t *dev = usb_get_intfdata(intf); - - if (dev) { - smsusb_stop_streaming(dev); - - /* unregister from smscore */ - if (dev->coredev) - smscore_unregister_device(dev->coredev); - - sms_info("device %p destroyed", dev); - kfree(dev); - } - - usb_set_intfdata(intf, NULL); -} - -static int smsusb_init_device(struct usb_interface *intf, int board_id) -{ - struct smsdevice_params_t params; - struct smsusb_device_t *dev; - int i, rc; - - /* create device object */ - dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); - if (!dev) { - sms_err("kzalloc(sizeof(struct smsusb_device_t) failed"); - return -ENOMEM; - } - - memset(¶ms, 0, sizeof(params)); - usb_set_intfdata(intf, dev); - dev->udev = interface_to_usbdev(intf); - - params.device_type = sms_get_board(board_id)->type; - - switch (params.device_type) { - case SMS_STELLAR: - dev->buffer_size = USB1_BUFFER_SIZE; - - params.setmode_handler = smsusb1_setmode; - params.detectmode_handler = smsusb1_detectmode; - break; - default: - sms_err("Unspecified sms device type!"); - /* fall-thru */ - case SMS_NOVA_A0: - case SMS_NOVA_B0: - case SMS_VEGA: - dev->buffer_size = USB2_BUFFER_SIZE; - dev->response_alignment = - le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - - sizeof(struct SmsMsgHdr_ST); - - params.flags |= SMS_DEVICE_FAMILY2; - break; - } - - params.device = &dev->udev->dev; - params.buffer_size = dev->buffer_size; - params.num_buffers = MAX_BUFFERS; - params.sendrequest_handler = smsusb_sendrequest; - params.context = dev; - usb_make_path(dev->udev, params.devpath, sizeof(params.devpath)); - - /* register in smscore */ - rc = smscore_register_device(¶ms, &dev->coredev); - if (rc < 0) { - sms_err("smscore_register_device(...) failed, rc %d", rc); - smsusb_term_device(intf); - return rc; - } - - smscore_set_board_id(dev->coredev, board_id); - - /* initialize urbs */ - for (i = 0; i < MAX_URBS; i++) { - dev->surbs[i].dev = dev; - usb_init_urb(&dev->surbs[i].urb); - } - - sms_info("smsusb_start_streaming(...)."); - rc = smsusb_start_streaming(dev); - if (rc < 0) { - sms_err("smsusb_start_streaming(...) failed"); - smsusb_term_device(intf); - return rc; - } - - rc = smscore_start_device(dev->coredev); - if (rc < 0) { - sms_err("smscore_start_device(...) failed"); - smsusb_term_device(intf); - return rc; - } - - sms_info("device %p created", dev); - - return rc; -} - -static int __devinit smsusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - char devpath[32]; - int i, rc; - - rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); - rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); - - if (intf->num_altsetting > 0) { - rc = usb_set_interface( - udev, intf->cur_altsetting->desc.bInterfaceNumber, 0); - if (rc < 0) { - sms_err("usb_set_interface failed, rc %d", rc); - return rc; - } - } - - sms_info("smsusb_probe %d", - intf->cur_altsetting->desc.bInterfaceNumber); - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) - sms_info("endpoint %d %02x %02x %d", i, - intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, - intf->cur_altsetting->endpoint[i].desc.bmAttributes, - intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - - if ((udev->actconfig->desc.bNumInterfaces == 2) && - (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { - sms_err("rom interface 0 is not used"); - return -ENODEV; - } - - if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { - snprintf(devpath, sizeof(devpath), "usb\\%d-%s", - udev->bus->busnum, udev->devpath); - sms_info("stellar device was found."); - return smsusb1_load_firmware( - udev, smscore_registry_getmode(devpath), - id->driver_info); - } - - rc = smsusb_init_device(intf, id->driver_info); - sms_info("rc %d", rc); - sms_board_load_modules(id->driver_info); - return rc; -} - -static void smsusb_disconnect(struct usb_interface *intf) -{ - smsusb_term_device(intf); -} - -static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct smsusb_device_t *dev = usb_get_intfdata(intf); - printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event); - smsusb_stop_streaming(dev); - return 0; -} - -static int smsusb_resume(struct usb_interface *intf) -{ - int rc, i; - struct smsusb_device_t *dev = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); - - printk(KERN_INFO "%s: Entering.\n", __func__); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); - - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) - printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, - intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, - intf->cur_altsetting->endpoint[i].desc.bmAttributes, - intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - - if (intf->num_altsetting > 0) { - rc = usb_set_interface(udev, - intf->cur_altsetting->desc. - bInterfaceNumber, 0); - if (rc < 0) { - printk(KERN_INFO "%s usb_set_interface failed, " - "rc %d\n", __func__, rc); - return rc; - } - } - - smsusb_start_streaming(dev); - return 0; -} - -static const struct usb_device_id smsusb_id_table[] __devinitconst = { - { USB_DEVICE(0x187f, 0x0010), - .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, - { USB_DEVICE(0x187f, 0x0100), - .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, - { USB_DEVICE(0x187f, 0x0200), - .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, - { USB_DEVICE(0x187f, 0x0201), - .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B }, - { USB_DEVICE(0x187f, 0x0300), - .driver_info = SMS1XXX_BOARD_SIANO_VEGA }, - { USB_DEVICE(0x2040, 0x1700), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT }, - { USB_DEVICE(0x2040, 0x1800), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, - { USB_DEVICE(0x2040, 0x1801), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, - { USB_DEVICE(0x2040, 0x2000), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2009), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 }, - { USB_DEVICE(0x2040, 0x200a), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2010), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2011), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2019), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x5500), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5510), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5520), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5530), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5580), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5590), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x187f, 0x0202), - .driver_info = SMS1XXX_BOARD_SIANO_NICE }, - { USB_DEVICE(0x187f, 0x0301), - .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, - { USB_DEVICE(0x2040, 0xb900), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb910), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb980), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb990), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc000), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc010), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc080), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc090), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc0a0), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xf5a0), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { } /* Terminating entry */ - }; - -MODULE_DEVICE_TABLE(usb, smsusb_id_table); - -static struct usb_driver smsusb_driver = { - .name = "smsusb", - .probe = smsusb_probe, - .disconnect = smsusb_disconnect, - .id_table = smsusb_id_table, - - .suspend = smsusb_suspend, - .resume = smsusb_resume, -}; - -module_usb_driver(smsusb_driver); - -MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); -MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig deleted file mode 100644 index 2663ae39b88..00000000000 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config DVB_TTUSB_BUDGET - tristate "Technotrend/Hauppauge Nova-USB devices" - depends on DVB_CORE && USB && I2C && PCI - select DVB_CX22700 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - help - Support for external USB adapters designed by Technotrend and - produced by Hauppauge, shipped under the brand name 'Nova-USB'. - - These devices don't have a MPEG decoder built in, so you need - an external software decoder to watch TV. - - Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile deleted file mode 100644 index f47bbf62dcd..00000000000 --- a/drivers/media/dvb/ttusb-budget/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c deleted file mode 100644 index 5b682cc4c81..00000000000 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ /dev/null @@ -1,1816 +0,0 @@ -/* - * TTUSB DVB driver - * - * Copyright (c) 2002 Holger Waechtler - * Copyright (c) 2003 Felix Domke - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "ves1820.h" -#include "cx22700.h" -#include "tda1004x.h" -#include "stv0299.h" -#include "tda8083.h" -#include "stv0297.h" -#include "lnbp21.h" - -#include -#include -#include - -/* - TTUSB_HWSECTIONS: - the DSP supports filtering in hardware, however, since the "muxstream" - is a bit braindead (no matching channel masks or no matching filter mask), - we won't support this - yet. it doesn't event support negative filters, - so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just - parse TS data. USB bandwidth will be a problem when having large - datastreams, especially for dvb-net, but hey, that's not my problem. - - TTUSB_DISEQC, TTUSB_TONE: - let the STC do the diseqc/tone stuff. this isn't supported at least with - my TTUSB, so let it undef'd unless you want to implement another - frontend. never tested. - - debug: - define it to > 3 for really hardcore debugging. you probably don't want - this unless the device doesn't load at all. > 2 for bandwidth statistics. -*/ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0) - -#define ISO_BUF_COUNT 4 -#define FRAMES_PER_ISO_BUF 4 -#define ISO_FRAME_SIZE 912 -#define TTUSB_MAXCHANNEL 32 -#ifdef TTUSB_HWSECTIONS -#define TTUSB_MAXFILTER 16 /* ??? */ -#endif - -#define TTUSB_REV_2_2 0x22 -#define TTUSB_BUDGET_NAME "ttusb_stc_fw" - -/** - * since we're casting (struct ttusb*) <-> (struct dvb_demux*) around - * the dvb_demux field must be the first in struct!! - */ -struct ttusb { - struct dvb_demux dvb_demux; - struct dmxdev dmxdev; - struct dvb_net dvbnet; - - /* and one for USB access. */ - struct mutex semi2c; - struct mutex semusb; - - struct dvb_adapter adapter; - struct usb_device *dev; - - struct i2c_adapter i2c_adap; - - int disconnecting; - int iso_streaming; - - unsigned int bulk_out_pipe; - unsigned int bulk_in_pipe; - unsigned int isoc_in_pipe; - - void *iso_buffer; - dma_addr_t iso_dma_handle; - - struct urb *iso_urb[ISO_BUF_COUNT]; - - int running_feed_count; - int last_channel; - int last_filter; - - u8 c; /* transaction counter, wraps around... */ - fe_sec_tone_mode_t tone; - fe_sec_voltage_t voltage; - - int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack - u8 mux_npacks; - u8 muxpack[256 + 8]; - int muxpack_ptr, muxpack_len; - - int insync; - - int cc; /* MuxCounter - will increment on EVERY MUX PACKET */ - /* (including stuffing. yes. really.) */ - - u8 last_result[32]; - - int revision; - - struct dvb_frontend* fe; -}; - -/* ugly workaround ... don't know why it's necessary to read */ -/* all result codes. */ - -static int ttusb_cmd(struct ttusb *ttusb, - const u8 * data, int len, int needresult) -{ - int actual_len; - int err; - int i; - - if (debug >= 3) { - printk(KERN_DEBUG ">"); - for (i = 0; i < len; ++i) - printk(KERN_CONT " %02x", data[i]); - printk(KERN_CONT "\n"); - } - - if (mutex_lock_interruptible(&ttusb->semusb) < 0) - return -EAGAIN; - - err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe, - (u8 *) data, len, &actual_len, 1000); - if (err != 0) { - dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n", - __func__, err); - mutex_unlock(&ttusb->semusb); - return err; - } - if (actual_len != len) { - dprintk("%s: only wrote %d of %d bytes\n", __func__, - actual_len, len); - mutex_unlock(&ttusb->semusb); - return -1; - } - - err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe, - ttusb->last_result, 32, &actual_len, 1000); - - if (err != 0) { - printk("%s: failed, receive error %d\n", __func__, - err); - mutex_unlock(&ttusb->semusb); - return err; - } - - if (debug >= 3) { - actual_len = ttusb->last_result[3] + 4; - printk(KERN_DEBUG "<"); - for (i = 0; i < actual_len; ++i) - printk(KERN_CONT " %02x", ttusb->last_result[i]); - printk(KERN_CONT "\n"); - } - - if (!needresult) - mutex_unlock(&ttusb->semusb); - return 0; -} - -static int ttusb_result(struct ttusb *ttusb, u8 * data, int len) -{ - memcpy(data, ttusb->last_result, len); - mutex_unlock(&ttusb->semusb); - return 0; -} - -static int ttusb_i2c_msg(struct ttusb *ttusb, - u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf, - u8 rcv_len) -{ - u8 b[0x28]; - u8 id = ++ttusb->c; - int i, err; - - if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7) - return -EINVAL; - - b[0] = 0xaa; - b[1] = id; - b[2] = 0x31; - b[3] = snd_len + 3; - b[4] = addr << 1; - b[5] = snd_len; - b[6] = rcv_len; - - for (i = 0; i < snd_len; i++) - b[7 + i] = snd_buf[i]; - - err = ttusb_cmd(ttusb, b, snd_len + 7, 1); - - if (err) - return -EREMOTEIO; - - err = ttusb_result(ttusb, b, 0x20); - - /* check if the i2c transaction was successful */ - if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO; - - if (rcv_len > 0) { - - if (err || b[0] != 0x55 || b[1] != id) { - dprintk - ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ", - __func__, err, id); - return -EREMOTEIO; - } - - for (i = 0; i < rcv_len; i++) - rcv_buf[i] = b[7 + i]; - } - - return rcv_len; -} - -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) -{ - struct ttusb *ttusb = i2c_get_adapdata(adapter); - int i = 0; - int inc; - - if (mutex_lock_interruptible(&ttusb->semi2c) < 0) - return -EAGAIN; - - while (i < num) { - u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; - int err; - - if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) { - addr = msg[i].addr; - snd_buf = msg[i].buf; - snd_len = msg[i].len; - rcv_buf = msg[i + 1].buf; - rcv_len = msg[i + 1].len; - inc = 2; - } else { - addr = msg[i].addr; - snd_buf = msg[i].buf; - snd_len = msg[i].len; - rcv_buf = NULL; - rcv_len = 0; - inc = 1; - } - - err = ttusb_i2c_msg(ttusb, addr, - snd_buf, snd_len, rcv_buf, rcv_len); - - if (err < rcv_len) { - dprintk("%s: i == %i\n", __func__, i); - break; - } - - i += inc; - } - - mutex_unlock(&ttusb->semi2c); - return i; -} - -static int ttusb_boot_dsp(struct ttusb *ttusb) -{ - const struct firmware *fw; - int i, err; - u8 b[40]; - - err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin", - &ttusb->dev->dev); - if (err) { - printk(KERN_ERR "ttusb-budget: failed to request firmware\n"); - return err; - } - - /* BootBlock */ - b[0] = 0xaa; - b[2] = 0x13; - b[3] = 28; - - /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ - /* 32 is max packet size, no messages should be splitted. */ - for (i = 0; i < fw->size; i += 28) { - memcpy(&b[4], &fw->data[i], 28); - - b[1] = ++ttusb->c; - - err = ttusb_cmd(ttusb, b, 32, 0); - if (err) - goto done; - } - - /* last block ... */ - b[1] = ++ttusb->c; - b[2] = 0x13; - b[3] = 0; - - err = ttusb_cmd(ttusb, b, 4, 0); - if (err) - goto done; - - /* BootEnd */ - b[1] = ++ttusb->c; - b[2] = 0x14; - b[3] = 0; - - err = ttusb_cmd(ttusb, b, 4, 0); - - done: - release_firmware(fw); - if (err) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } - - return err; -} - -static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type, - int pid) -{ - int err; - /* SetChannel */ - u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type, - (pid >> 8) & 0xff, pid & 0xff - }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} - -static int ttusb_del_channel(struct ttusb *ttusb, int channel_id) -{ - int err; - /* DelChannel */ - u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} - -#ifdef TTUSB_HWSECTIONS -static int ttusb_set_filter(struct ttusb *ttusb, int filter_id, - int associated_chan, u8 filter[8], u8 mask[8]) -{ - int err; - /* SetFilter */ - u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan, - filter[0], filter[1], filter[2], filter[3], - filter[4], filter[5], filter[6], filter[7], - filter[8], filter[9], filter[10], filter[11], - mask[0], mask[1], mask[2], mask[3], - mask[4], mask[5], mask[6], mask[7], - mask[8], mask[9], mask[10], mask[11] - }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} - -static int ttusb_del_filter(struct ttusb *ttusb, int filter_id) -{ - int err; - /* DelFilter */ - u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} -#endif - -static int ttusb_init_controller(struct ttusb *ttusb) -{ - u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 }; - u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 }; - u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 }; - /* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */ - u8 b3[] = - { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e }; - u8 b4[] = - { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e }; - - u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 }; - u8 get_dsp_version[0x20] = - { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 }; - int err; - - /* reset board */ - if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0))) - return err; - - /* reset board (again?) */ - if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0))) - return err; - - ttusb_boot_dsp(ttusb); - - /* set i2c bit rate */ - if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0))) - return err; - - if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1))) - return err; - - err = ttusb_result(ttusb, b4, sizeof(b4)); - - if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1))) - return err; - - if ((err = ttusb_result(ttusb, get_version, sizeof(get_version)))) - return err; - - dprintk("%s: stc-version: %c%c%c%c%c\n", __func__, - get_version[4], get_version[5], get_version[6], - get_version[7], get_version[8]); - - if (memcmp(get_version + 4, "V 0.0", 5) && - memcmp(get_version + 4, "V 1.1", 5) && - memcmp(get_version + 4, "V 2.1", 5) && - memcmp(get_version + 4, "V 2.2", 5)) { - printk - ("%s: unknown STC version %c%c%c%c%c, please report!\n", - __func__, get_version[4], get_version[5], - get_version[6], get_version[7], get_version[8]); - } - - ttusb->revision = ((get_version[6] - '0') << 4) | - (get_version[8] - '0'); - - err = - ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1); - if (err) - return err; - - err = - ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version)); - if (err) - return err; - printk("%s: dsp-version: %c%c%c\n", __func__, - get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]); - return 0; -} - -#ifdef TTUSB_DISEQC -static int ttusb_send_diseqc(struct dvb_frontend* fe, - const struct dvb_diseqc_master_cmd *cmd) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; - - int err; - - b[3] = 4 + 2 + cmd->msg_len; - b[4] = 0xFF; /* send diseqc master, not burst */ - b[5] = cmd->msg_len; - - memcpy(b + 5, cmd->msg, cmd->msg_len); - - /* Diseqc */ - if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } - - return err; -} -#endif - -static int ttusb_update_lnb(struct ttusb *ttusb) -{ - u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, - ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1, - ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1 - }; - int err; - - /* SetLNB */ - if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } - - return err; -} - -static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - - ttusb->voltage = voltage; - return ttusb_update_lnb(ttusb); -} - -#ifdef TTUSB_TONE -static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - - ttusb->tone = tone; - return ttusb_update_lnb(ttusb); -} -#endif - - -#if 0 -static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) -{ - u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq }; - int err, actual_len; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - if (err) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } -} -#endif - -/*****************************************************************************/ - -#ifdef TTUSB_HWSECTIONS -static void ttusb_handle_ts_data(struct ttusb_channel *channel, - const u8 * data, int len); -static void ttusb_handle_sec_data(struct ttusb_channel *channel, - const u8 * data, int len); -#endif - -static int numpkt, numts, numstuff, numsec, numinvalid; -static unsigned long lastj; - -static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, - int len) -{ - u16 csum = 0, cc; - int i; - for (i = 0; i < len; i += 2) - csum ^= le16_to_cpup((__le16 *) (muxpack + i)); - if (csum) { - printk("%s: muxpack with incorrect checksum, ignoring\n", - __func__); - numinvalid++; - return; - } - - cc = (muxpack[len - 4] << 8) | muxpack[len - 3]; - cc &= 0x7FFF; - if ((cc != ttusb->cc) && (ttusb->cc != -1)) - printk("%s: cc discontinuity (%d frames missing)\n", - __func__, (cc - ttusb->cc) & 0x7FFF); - ttusb->cc = (cc + 1) & 0x7FFF; - if (muxpack[0] & 0x80) { -#ifdef TTUSB_HWSECTIONS - /* section data */ - int pusi = muxpack[0] & 0x40; - int channel = muxpack[0] & 0x1F; - int payload = muxpack[1]; - const u8 *data = muxpack + 2; - /* check offset flag */ - if (muxpack[0] & 0x20) - data++; - - ttusb_handle_sec_data(ttusb->channel + channel, data, - payload); - data += payload; - - if ((!!(ttusb->muxpack[0] & 0x20)) ^ - !!(ttusb->muxpack[1] & 1)) - data++; -#warning TODO: pusi - printk("cc: %04x\n", (data[0] << 8) | data[1]); -#endif - numsec++; - } else if (muxpack[0] == 0x47) { -#ifdef TTUSB_HWSECTIONS - /* we have TS data here! */ - int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2]; - int channel; - for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) - if (ttusb->channel[channel].active - && (pid == ttusb->channel[channel].pid)) - ttusb_handle_ts_data(ttusb->channel + - channel, muxpack, - 188); -#endif - numts++; - dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1); - } else if (muxpack[0] != 0) { - numinvalid++; - printk("illegal muxpack type %02x\n", muxpack[0]); - } else - numstuff++; -} - -static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) -{ - int maxwork = 1024; - while (len) { - if (!(maxwork--)) { - printk("%s: too much work\n", __func__); - break; - } - - switch (ttusb->mux_state) { - case 0: - case 1: - case 2: - len--; - if (*data++ == 0xAA) - ++ttusb->mux_state; - else { - ttusb->mux_state = 0; - if (ttusb->insync) { - dprintk("%s: %02x\n", - __func__, data[-1]); - printk(KERN_INFO "%s: lost sync.\n", - __func__); - ttusb->insync = 0; - } - } - break; - case 3: - ttusb->insync = 1; - len--; - ttusb->mux_npacks = *data++; - ++ttusb->mux_state; - ttusb->muxpack_ptr = 0; - /* maximum bytes, until we know the length */ - ttusb->muxpack_len = 2; - break; - case 4: - { - int avail; - avail = len; - if (avail > - (ttusb->muxpack_len - - ttusb->muxpack_ptr)) - avail = - ttusb->muxpack_len - - ttusb->muxpack_ptr; - memcpy(ttusb->muxpack + ttusb->muxpack_ptr, - data, avail); - ttusb->muxpack_ptr += avail; - BUG_ON(ttusb->muxpack_ptr > 264); - data += avail; - len -= avail; - /* determine length */ - if (ttusb->muxpack_ptr == 2) { - if (ttusb->muxpack[0] & 0x80) { - ttusb->muxpack_len = - ttusb->muxpack[1] + 2; - if (ttusb-> - muxpack[0] & 0x20) - ttusb-> - muxpack_len++; - if ((!! - (ttusb-> - muxpack[0] & 0x20)) ^ - !!(ttusb-> - muxpack[1] & 1)) - ttusb-> - muxpack_len++; - ttusb->muxpack_len += 4; - } else if (ttusb->muxpack[0] == - 0x47) - ttusb->muxpack_len = - 188 + 4; - else if (ttusb->muxpack[0] == 0x00) - ttusb->muxpack_len = - ttusb->muxpack[1] + 2 + - 4; - else { - dprintk - ("%s: invalid state: first byte is %x\n", - __func__, - ttusb->muxpack[0]); - ttusb->mux_state = 0; - } - } - - /** - * if length is valid and we reached the end: - * goto next muxpack - */ - if ((ttusb->muxpack_ptr >= 2) && - (ttusb->muxpack_ptr == - ttusb->muxpack_len)) { - ttusb_process_muxpack(ttusb, - ttusb-> - muxpack, - ttusb-> - muxpack_ptr); - ttusb->muxpack_ptr = 0; - /* maximum bytes, until we know the length */ - ttusb->muxpack_len = 2; - - /** - * no muxpacks left? - * return to search-sync state - */ - if (!ttusb->mux_npacks--) { - ttusb->mux_state = 0; - break; - } - } - break; - } - default: - BUG(); - break; - } - } -} - -static void ttusb_iso_irq(struct urb *urb) -{ - struct ttusb *ttusb = urb->context; - struct usb_iso_packet_descriptor *d; - u8 *data; - int len, i; - - if (!ttusb->iso_streaming) - return; - -#if 0 - printk("%s: status %d, errcount == %d, length == %i\n", - __func__, - urb->status, urb->error_count, urb->actual_length); -#endif - - if (!urb->status) { - for (i = 0; i < urb->number_of_packets; ++i) { - numpkt++; - if (time_after_eq(jiffies, lastj + HZ)) { - dprintk("frames/s: %lu (ts: %d, stuff %d, " - "sec: %d, invalid: %d, all: %d)\n", - numpkt * HZ / (jiffies - lastj), - numts, numstuff, numsec, numinvalid, - numts + numstuff + numsec + numinvalid); - numts = numstuff = numsec = numinvalid = 0; - lastj = jiffies; - numpkt = 0; - } - d = &urb->iso_frame_desc[i]; - data = urb->transfer_buffer + d->offset; - len = d->actual_length; - d->actual_length = 0; - d->status = 0; - ttusb_process_frame(ttusb, data, len); - } - } - usb_submit_urb(urb, GFP_ATOMIC); -} - -static void ttusb_free_iso_urbs(struct ttusb *ttusb) -{ - int i; - - for (i = 0; i < ISO_BUF_COUNT; i++) - if (ttusb->iso_urb[i]) - usb_free_urb(ttusb->iso_urb[i]); - - pci_free_consistent(NULL, - ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT, ttusb->iso_buffer, - ttusb->iso_dma_handle); -} - -static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) -{ - int i; - - ttusb->iso_buffer = pci_alloc_consistent(NULL, - ISO_FRAME_SIZE * - FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT, - &ttusb->iso_dma_handle); - - if (!ttusb->iso_buffer) { - dprintk("%s: pci_alloc_consistent - not enough memory\n", - __func__); - return -ENOMEM; - } - - memset(ttusb->iso_buffer, 0, - ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); - - for (i = 0; i < ISO_BUF_COUNT; i++) { - struct urb *urb; - - if (! - (urb = - usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { - ttusb_free_iso_urbs(ttusb); - return -ENOMEM; - } - - ttusb->iso_urb[i] = urb; - } - - return 0; -} - -static void ttusb_stop_iso_xfer(struct ttusb *ttusb) -{ - int i; - - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_kill_urb(ttusb->iso_urb[i]); - - ttusb->iso_streaming = 0; -} - -static int ttusb_start_iso_xfer(struct ttusb *ttusb) -{ - int i, j, err, buffer_offset = 0; - - if (ttusb->iso_streaming) { - printk("%s: iso xfer already running!\n", __func__); - return 0; - } - - ttusb->cc = -1; - ttusb->insync = 0; - ttusb->mux_state = 0; - - for (i = 0; i < ISO_BUF_COUNT; i++) { - int frame_offset = 0; - struct urb *urb = ttusb->iso_urb[i]; - - urb->dev = ttusb->dev; - urb->context = ttusb; - urb->complete = ttusb_iso_irq; - urb->pipe = ttusb->isoc_in_pipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = FRAMES_PER_ISO_BUF; - urb->transfer_buffer_length = - ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; - urb->transfer_buffer = ttusb->iso_buffer + buffer_offset; - buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; - - for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; - frame_offset += ISO_FRAME_SIZE; - } - } - - for (i = 0; i < ISO_BUF_COUNT; i++) { - if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) { - ttusb_stop_iso_xfer(ttusb); - printk - ("%s: failed urb submission (%i: err = %i)!\n", - __func__, i, err); - return err; - } - } - - ttusb->iso_streaming = 1; - - return 0; -} - -#ifdef TTUSB_HWSECTIONS -static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, - int len) -{ - dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0); -} - -static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, - int len) -{ -// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; -#error TODO: handle ugly stuff -// dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0); -} -#endif - -static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; - int feed_type = 1; - - dprintk("ttusb_start_feed\n"); - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - break; - case DMX_TYPE_SEC: - break; - default: - return -EINVAL; - } - - if (dvbdmxfeed->type == DMX_TYPE_TS) { - switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: - break; - default: - return -EINVAL; - } - } - -#ifdef TTUSB_HWSECTIONS -#error TODO: allocate filters - if (dvbdmxfeed->type == DMX_TYPE_TS) { - feed_type = 1; - } else if (dvbdmxfeed->type == DMX_TYPE_SEC) { - feed_type = 2; - } -#endif - - ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid); - - if (0 == ttusb->running_feed_count++) - ttusb_start_iso_xfer(ttusb); - - return 0; -} - -static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; - - ttusb_del_channel(ttusb, dvbdmxfeed->index); - - if (--ttusb->running_feed_count == 0) - ttusb_stop_iso_xfer(ttusb); - - return 0; -} - -static int ttusb_setup_interfaces(struct ttusb *ttusb) -{ - usb_set_interface(ttusb->dev, 1, 1); - - ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); - ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1); - ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2); - - return 0; -} - -#if 0 -static u8 stc_firmware[8192]; - -static int stc_open(struct inode *inode, struct file *file) -{ - struct ttusb *ttusb = file->private_data; - int addr; - - for (addr = 0; addr < 8192; addr += 16) { - u8 snd_buf[2] = { addr >> 8, addr & 0xFF }; - ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr, - 16); - } - - return 0; -} - -static ssize_t stc_read(struct file *file, char *buf, size_t count, - loff_t *offset) -{ - return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192); -} - -static int stc_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static const struct file_operations stc_fops = { - .owner = THIS_MODULE, - .read = stc_read, - .open = stc_open, - .release = stc_release, -}; -#endif - -static u32 functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - - - -static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 data[4]; - struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; - u32 div; - - div = (p->frequency + 36166667) / 166667; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | 0x85; - data[3] = p->frequency < 592000000 ? 0x40 : 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct cx22700_config alps_tdmb7_config = { - .demod_address = 0x43, -}; - - - - - -static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; - msleep(1); - - // disable the mc44BC374c (do not check for errors) - tuner_msg.addr = 0x65; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { - i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); - } - - return 0; -} - -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = p->frequency + 36130000; - if (tuner_frequency < 87000000) return -EINVAL; - else if (tuner_frequency < 130000000) cp = 3; - else if (tuner_frequency < 160000000) cp = 5; - else if (tuner_frequency < 200000000) cp = 6; - else if (tuner_frequency < 290000000) cp = 3; - else if (tuner_frequency < 420000000) cp = 5; - else if (tuner_frequency < 480000000) cp = 6; - else if (tuner_frequency < 620000000) cp = 3; - else if (tuner_frequency < 830000000) cp = 5; - else if (tuner_frequency < 895000000) cp = 7; - else return -EINVAL; - - // determine band - if (p->frequency < 49000000) - return -EINVAL; - else if (p->frequency < 159000000) - band = 1; - else if (p->frequency < 444000000) - band = 2; - else if (p->frequency < 861000000) - band = 4; - else return -EINVAL; - - // setup PLL filter - switch (p->bandwidth_hz) { - case 6000000: - tda1004x_writereg(fe, 0x0C, 0); - filter = 0; - break; - - case 7000000: - tda1004x_writereg(fe, 0x0C, 0); - filter = 0; - break; - - case 8000000: - tda1004x_writereg(fe, 0x0C, 0xFF); - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - - return request_firmware(fw, name, &ttusb->dev->dev); -} - -static struct tda1004x_config philips_tdm1316l_config = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static u8 alps_bsbe1_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x92, - 0xff, 0xff -}; - -static u8 alps_bsru6_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x52, - 0xff, 0xff -}; - -static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; - bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; - bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; - bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; - bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; - bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; - bclk = 0x51; - } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - - return 0; -} - -static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((p->frequency < 950000) || (p->frequency > 2150000)) - return -EINVAL; - - div = (p->frequency + (125 - 1)) / 125; /* round correctly */ - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; - buf[3] = 0xC4; - - if (p->frequency > 1530000) - buf[3] = 0xC0; - - /* BSBE1 wants XCE bit set */ - if (ttusb->revision == TTUSB_REV_2_2) - buf[3] |= 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct stv0299_config alps_stv0299_config = { - .demod_address = 0x68, - .inittab = alps_bsru6_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = alps_stv0299_set_symbol_rate, -}; - -static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - div = p->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x8e; - buf[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct tda8083_config ttusb_novas_grundig_29504_491_config = { - - .demod_address = 0x68, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusb* ttusb = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (p->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - -static u8 read_pwm(struct ttusb* ttusb) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - - -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; - u8 tuner_buf[5]; - struct i2c_msg tuner_msg = {.addr = 0x60, - .flags = 0, - .buf = tuner_buf, - .len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = p->frequency; - if (tuner_frequency < 87000000) {return -EINVAL;} - else if (tuner_frequency < 130000000) {cp = 3; band = 1;} - else if (tuner_frequency < 160000000) {cp = 5; band = 1;} - else if (tuner_frequency < 200000000) {cp = 6; band = 1;} - else if (tuner_frequency < 290000000) {cp = 3; band = 2;} - else if (tuner_frequency < 420000000) {cp = 5; band = 2;} - else if (tuner_frequency < 480000000) {cp = 6; band = 2;} - else if (tuner_frequency < 620000000) {cp = 3; band = 4;} - else if (tuner_frequency < 830000000) {cp = 5; band = 4;} - else if (tuner_frequency < 895000000) {cp = 7; band = 4;} - else {return -EINVAL;} - - // assume PLL filter should always be 8MHz for the moment. - filter = 1; - - // calculate divisor - // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz - tuner_frequency = ((p->frequency + 36125000) / 62500); - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xc8; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - tuner_buf[4] = 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { - printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n"); - return -EIO; - } - - msleep(50); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { - printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n"); - return -EIO; - } - - msleep(1); - - return 0; -} - -static u8 dvbc_philips_tdm1316l_inittab[] = { - 0x80, 0x21, - 0x80, 0x20, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x20, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0xff, - 0x4b, 0x7f, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x00, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x00, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x4b, - 0xc1, 0x00, - 0xc2, 0x00, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x38, - 0x62, 0x0a, - 0x53, 0x13, - 0x59, 0x08, - 0x55, 0x00, - 0x56, 0x40, - 0x57, 0x08, - 0x58, 0x3d, - 0x88, 0x10, - 0xa0, 0x00, - 0xa0, 0x00, - 0xa0, 0x00, - 0xa0, 0x04, - 0xff, 0xff, -}; - -static struct stv0297_config dvbc_philips_tdm1316l_config = { - .demod_address = 0x1c, - .inittab = dvbc_philips_tdm1316l_inittab, - .invert = 0, -}; - -static void frontend_init(struct ttusb* ttusb) -{ - switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) { - case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059)) - // try the stv0299 based first - ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params; - - if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1 - alps_stv0299_config.inittab = alps_bsbe1_inittab; - dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0); - } else { // ALPS BSRU6 - ttusb->fe->ops.set_voltage = ttusb_set_voltage; - } - break; - } - - // Grundig 29504-491 - ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params; - ttusb->fe->ops.set_voltage = ttusb_set_voltage; - break; - } - break; - - case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) - ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - break; - } - - ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) - // try the ALPS TDMB7 first - ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params; - break; - } - - // Philips td1316 - ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - } - - if (ttusb->fe == NULL) { - printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", - le16_to_cpu(ttusb->dev->descriptor.idVendor), - le16_to_cpu(ttusb->dev->descriptor.idProduct)); - } else { - if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) { - printk("dvb-ttusb-budget: Frontend registration failed!\n"); - dvb_frontend_detach(ttusb->fe); - ttusb->fe = NULL; - } - } -} - - - -static struct i2c_algorithm ttusb_dec_algo = { - .master_xfer = master_xfer, - .functionality = functionality, -}; - -static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev; - struct ttusb *ttusb; - int result; - - dprintk("%s: TTUSB DVB connected\n", __func__); - - udev = interface_to_usbdev(intf); - - if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV; - - if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL))) - return -ENOMEM; - - ttusb->dev = udev; - ttusb->c = 0; - ttusb->mux_state = 0; - mutex_init(&ttusb->semi2c); - - mutex_lock(&ttusb->semi2c); - - mutex_init(&ttusb->semusb); - - ttusb_setup_interfaces(ttusb); - - result = ttusb_alloc_iso_urbs(ttusb); - if (result < 0) { - dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__); - mutex_unlock(&ttusb->semi2c); - kfree(ttusb); - return result; - } - - if (ttusb_init_controller(ttusb)) - printk("ttusb_init_controller: error\n"); - - mutex_unlock(&ttusb->semi2c); - - result = dvb_register_adapter(&ttusb->adapter, - "Technotrend/Hauppauge Nova-USB", - THIS_MODULE, &udev->dev, adapter_nr); - if (result < 0) { - ttusb_free_iso_urbs(ttusb); - kfree(ttusb); - return result; - } - ttusb->adapter.priv = ttusb; - - /* i2c */ - memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); - strcpy(ttusb->i2c_adap.name, "TTUSB DEC"); - - i2c_set_adapdata(&ttusb->i2c_adap, ttusb); - - ttusb->i2c_adap.algo = &ttusb_dec_algo; - ttusb->i2c_adap.algo_data = NULL; - ttusb->i2c_adap.dev.parent = &udev->dev; - - result = i2c_add_adapter(&ttusb->i2c_adap); - if (result) - goto err_unregister_adapter; - - memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); - - ttusb->dvb_demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING; - ttusb->dvb_demux.priv = NULL; -#ifdef TTUSB_HWSECTIONS - ttusb->dvb_demux.filternum = TTUSB_MAXFILTER; -#else - ttusb->dvb_demux.filternum = 32; -#endif - ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; - ttusb->dvb_demux.start_feed = ttusb_start_feed; - ttusb->dvb_demux.stop_feed = ttusb_stop_feed; - ttusb->dvb_demux.write_to_decoder = NULL; - - result = dvb_dmx_init(&ttusb->dvb_demux); - if (result < 0) { - printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); - result = -ENODEV; - goto err_i2c_del_adapter; - } -//FIXME dmxdev (nur WAS?) - ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; - ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; - ttusb->dmxdev.capabilities = 0; - - result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter); - if (result < 0) { - printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", - result); - result = -ENODEV; - goto err_release_dmx; - } - - if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { - printk("ttusb_dvb: dvb_net_init failed!\n"); - result = -ENODEV; - goto err_release_dmxdev; - } - - usb_set_intfdata(intf, (void *) ttusb); - - frontend_init(ttusb); - - return 0; - -err_release_dmxdev: - dvb_dmxdev_release(&ttusb->dmxdev); -err_release_dmx: - dvb_dmx_release(&ttusb->dvb_demux); -err_i2c_del_adapter: - i2c_del_adapter(&ttusb->i2c_adap); -err_unregister_adapter: - dvb_unregister_adapter (&ttusb->adapter); - return result; -} - -static void ttusb_disconnect(struct usb_interface *intf) -{ - struct ttusb *ttusb = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - ttusb->disconnecting = 1; - - ttusb_stop_iso_xfer(ttusb); - - ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx); - dvb_net_release(&ttusb->dvbnet); - dvb_dmxdev_release(&ttusb->dmxdev); - dvb_dmx_release(&ttusb->dvb_demux); - if (ttusb->fe != NULL) { - dvb_unregister_frontend(ttusb->fe); - dvb_frontend_detach(ttusb->fe); - } - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter(&ttusb->adapter); - - ttusb_free_iso_urbs(ttusb); - - kfree(ttusb); - - dprintk("%s: TTUSB DVB disconnected\n", __func__); -} - -static struct usb_device_id ttusb_table[] = { - {USB_DEVICE(0xb48, 0x1003)}, - {USB_DEVICE(0xb48, 0x1004)}, - {USB_DEVICE(0xb48, 0x1005)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, ttusb_table); - -static struct usb_driver ttusb_driver = { - .name = "ttusb", - .probe = ttusb_probe, - .disconnect = ttusb_disconnect, - .id_table = ttusb_table, -}; - -module_usb_driver(ttusb_driver); - -MODULE_AUTHOR("Holger Waechtler "); -MODULE_DESCRIPTION("TTUSB DVB Driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("ttusb-budget/dspbootcode.bin"); diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig deleted file mode 100644 index 290254ab06d..00000000000 --- a/drivers/media/dvb/ttusb-dec/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config DVB_TTUSB_DEC - tristate "Technotrend/Hauppauge USB DEC devices" - depends on DVB_CORE && USB && INPUT && PCI - select CRC32 - help - Support for external USB adapters designed by Technotrend and - produced by Hauppauge, shipped under the brand name 'DEC2000-t' - and 'DEC3000-s'. - - Even if these devices have a MPEG decoder built in, they transmit - only compressed MPEG data over the USB bus, so you need - an external software decoder to watch TV on your computer. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware dec2000t", - "/Documentation/dvb/get_dvb_firmware dec2540t", - "/Documentation/dvb/get_dvb_firmware dec3000s", - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - - Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile deleted file mode 100644 index 5352740d235..00000000000 --- a/drivers/media/dvb/ttusb-dec/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o - -ccflags-y += -Idrivers/media/dvb-core/ diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c deleted file mode 100644 index 504c8123033..00000000000 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ /dev/null @@ -1,1764 +0,0 @@ -/* - * TTUSB DEC Driver - * - * Copyright (C) 2003-2004 Alex Woods - * IR support by Peter Beutner - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_filter.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "ttusbdecfe.h" - -static int debug; -static int output_pva; -static int enable_rc; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); -module_param(output_pva, int, 0444); -MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)"); -module_param(enable_rc, int, 0644); -MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk if (debug) printk - -#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" - -#define COMMAND_PIPE 0x03 -#define RESULT_PIPE 0x04 -#define IN_PIPE 0x08 -#define OUT_PIPE 0x07 -#define IRQ_PIPE 0x0A - -#define COMMAND_PACKET_SIZE 0x3c -#define ARM_PACKET_SIZE 0x1000 -#define IRQ_PACKET_SIZE 0x8 - -#define ISO_BUF_COUNT 0x04 -#define FRAMES_PER_ISO_BUF 0x04 -#define ISO_FRAME_SIZE 0x0380 - -#define MAX_PVA_LENGTH 6144 - -enum ttusb_dec_model { - TTUSB_DEC2000T, - TTUSB_DEC2540T, - TTUSB_DEC3000S -}; - -enum ttusb_dec_packet_type { - TTUSB_DEC_PACKET_PVA, - TTUSB_DEC_PACKET_SECTION, - TTUSB_DEC_PACKET_EMPTY -}; - -enum ttusb_dec_interface { - TTUSB_DEC_INTERFACE_INITIAL, - TTUSB_DEC_INTERFACE_IN, - TTUSB_DEC_INTERFACE_OUT -}; - -struct ttusb_dec { - enum ttusb_dec_model model; - char *model_name; - char *firmware_name; - int can_playback; - - /* DVB bits */ - struct dvb_adapter adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dmx_frontend frontend; - struct dvb_net dvb_net; - struct dvb_frontend* fe; - - u16 pid[DMX_PES_OTHER]; - - /* USB bits */ - struct usb_device *udev; - u8 trans_count; - unsigned int command_pipe; - unsigned int result_pipe; - unsigned int in_pipe; - unsigned int out_pipe; - unsigned int irq_pipe; - enum ttusb_dec_interface interface; - struct mutex usb_mutex; - - void *irq_buffer; - struct urb *irq_urb; - dma_addr_t irq_dma_handle; - void *iso_buffer; - dma_addr_t iso_dma_handle; - struct urb *iso_urb[ISO_BUF_COUNT]; - int iso_stream_count; - struct mutex iso_mutex; - - u8 packet[MAX_PVA_LENGTH + 4]; - enum ttusb_dec_packet_type packet_type; - int packet_state; - int packet_length; - int packet_payload_length; - u16 next_packet_id; - - int pva_stream_count; - int filter_stream_count; - - struct dvb_filter_pes2ts a_pes2ts; - struct dvb_filter_pes2ts v_pes2ts; - - u8 v_pes[16 + MAX_PVA_LENGTH]; - int v_pes_length; - int v_pes_postbytes; - - struct list_head urb_frame_list; - struct tasklet_struct urb_tasklet; - spinlock_t urb_frame_list_lock; - - struct dvb_demux_filter *audio_filter; - struct dvb_demux_filter *video_filter; - struct list_head filter_info_list; - spinlock_t filter_info_list_lock; - - struct input_dev *rc_input_dev; - char rc_phys[64]; - - int active; /* Loaded successfully */ -}; - -struct urb_frame { - u8 data[ISO_FRAME_SIZE]; - int length; - struct list_head urb_frame_list; -}; - -struct filter_info { - u8 stream_id; - struct dvb_demux_filter *filter; - struct list_head filter_info_list; -}; - -static u16 rc_keys[] = { - KEY_POWER, - KEY_MUTE, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_0, - KEY_CHANNELUP, - KEY_VOLUMEDOWN, - KEY_OK, - KEY_VOLUMEUP, - KEY_CHANNELDOWN, - KEY_PREVIOUS, - KEY_ESC, - KEY_RED, - KEY_GREEN, - KEY_YELLOW, - KEY_BLUE, - KEY_OPTION, - KEY_M, - KEY_RADIO -}; - -static void ttusb_dec_set_model(struct ttusb_dec *dec, - enum ttusb_dec_model model); - -static void ttusb_dec_handle_irq( struct urb *urb) -{ - struct ttusb_dec * dec = urb->context; - char *buffer = dec->irq_buffer; - int retval; - - switch(urb->status) { - case 0: /*success*/ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - case -ETIME: - /* this urb is dead, cleanup */ - dprintk("%s:urb shutting down with status: %d\n", - __func__, urb->status); - return; - default: - dprintk("%s:nonzero status received: %d\n", - __func__,urb->status); - goto exit; - } - - if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) { - /* IR - Event */ - /* this is an fact a bit too simple implementation; - * the box also reports a keyrepeat signal - * (with buffer[3] == 0x40) in an intervall of ~100ms. - * But to handle this correctly we had to imlemenent some - * kind of timer which signals a 'key up' event if no - * keyrepeat signal is received for lets say 200ms. - * this should/could be added later ... - * for now lets report each signal as a key down and up*/ - dprintk("%s:rc signal:%d\n", __func__, buffer[4]); - input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); - input_sync(dec->rc_input_dev); - input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); - input_sync(dec->rc_input_dev); - } - -exit: retval = usb_submit_urb(urb, GFP_ATOMIC); - if(retval) - printk("%s - usb_commit_urb failed with result: %d\n", - __func__, retval); -} - -static u16 crc16(u16 crc, const u8 *buf, size_t len) -{ - u16 tmp; - - while (len--) { - crc ^= *buf++; - crc ^= (u8)crc >> 4; - tmp = (u8)crc; - crc ^= (tmp ^ (tmp << 1)) << 4; - } - return crc; -} - -static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]) -{ - int result, actual_len, i; - u8 *b; - - dprintk("%s\n", __func__); - - b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); - if (!b) - return -ENOMEM; - - if ((result = mutex_lock_interruptible(&dec->usb_mutex))) { - kfree(b); - printk("%s: Failed to lock usb mutex.\n", __func__); - return result; - } - - b[0] = 0xaa; - b[1] = ++dec->trans_count; - b[2] = command; - b[3] = param_length; - - if (params) - memcpy(&b[4], params, param_length); - - if (debug) { - printk("%s: command: ", __func__); - for (i = 0; i < param_length + 4; i++) - printk("0x%02X ", b[i]); - printk("\n"); - } - - result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - COMMAND_PACKET_SIZE + 4, &actual_len, 1000); - - if (result) { - printk("%s: command bulk message failed: error %d\n", - __func__, result); - mutex_unlock(&dec->usb_mutex); - kfree(b); - return result; - } - - result = usb_bulk_msg(dec->udev, dec->result_pipe, b, - COMMAND_PACKET_SIZE + 4, &actual_len, 1000); - - if (result) { - printk("%s: result bulk message failed: error %d\n", - __func__, result); - mutex_unlock(&dec->usb_mutex); - kfree(b); - return result; - } else { - if (debug) { - printk("%s: result: ", __func__); - for (i = 0; i < actual_len; i++) - printk("0x%02X ", b[i]); - printk("\n"); - } - - if (result_length) - *result_length = b[3]; - if (cmd_result && b[3] > 0) - memcpy(cmd_result, &b[4], b[3]); - - mutex_unlock(&dec->usb_mutex); - - kfree(b); - return 0; - } -} - -static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, - unsigned int *model, unsigned int *version) -{ - u8 c[COMMAND_PACKET_SIZE]; - int c_length; - int result; - __be32 tmp; - - dprintk("%s\n", __func__); - - result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); - if (result) - return result; - - if (c_length >= 0x0c) { - if (mode != NULL) { - memcpy(&tmp, c, 4); - *mode = ntohl(tmp); - } - if (model != NULL) { - memcpy(&tmp, &c[4], 4); - *model = ntohl(tmp); - } - if (version != NULL) { - memcpy(&tmp, &c[8], 4); - *version = ntohl(tmp); - } - return 0; - } else { - return -1; - } -} - -static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) -{ - struct ttusb_dec *dec = priv; - - dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, - &dec->audio_filter->feed->feed.ts, - DMX_OK); - - return 0; -} - -static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) -{ - struct ttusb_dec *dec = priv; - - dec->video_filter->feed->cb.ts(data, 188, NULL, 0, - &dec->video_filter->feed->feed.ts, - DMX_OK); - - return 0; -} - -static void ttusb_dec_set_pids(struct ttusb_dec *dec) -{ - u8 b[] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff }; - - __be16 pcr = htons(dec->pid[DMX_PES_PCR]); - __be16 audio = htons(dec->pid[DMX_PES_AUDIO]); - __be16 video = htons(dec->pid[DMX_PES_VIDEO]); - - dprintk("%s\n", __func__); - - memcpy(&b[0], &pcr, 2); - memcpy(&b[2], &audio, 2); - memcpy(&b[4], &video, 2); - - ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); - - dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], - ttusb_dec_audio_pes2ts_cb, dec); - dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], - ttusb_dec_video_pes2ts_cb, dec); - dec->v_pes_length = 0; - dec->v_pes_postbytes = 0; -} - -static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) -{ - if (length < 8) { - printk("%s: packet too short - discarding\n", __func__); - return; - } - - if (length > 8 + MAX_PVA_LENGTH) { - printk("%s: packet too long - discarding\n", __func__); - return; - } - - switch (pva[2]) { - - case 0x01: { /* VideoStream */ - int prebytes = pva[5] & 0x03; - int postbytes = (pva[5] & 0x0c) >> 2; - __be16 v_pes_payload_length; - - if (output_pva) { - dec->video_filter->feed->cb.ts(pva, length, NULL, 0, - &dec->video_filter->feed->feed.ts, DMX_OK); - return; - } - - if (dec->v_pes_postbytes > 0 && - dec->v_pes_postbytes == prebytes) { - memcpy(&dec->v_pes[dec->v_pes_length], - &pva[12], prebytes); - - dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length + prebytes, 1); - } - - if (pva[5] & 0x10) { - dec->v_pes[7] = 0x80; - dec->v_pes[8] = 0x05; - - dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5); - dec->v_pes[10] = ((pva[8] & 0x3f) << 2) | - ((pva[9] & 0xc0) >> 6); - dec->v_pes[11] = 0x01 | - ((pva[9] & 0x3f) << 2) | - ((pva[10] & 0x80) >> 6); - dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | - ((pva[11] & 0xc0) >> 7); - dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1); - - memcpy(&dec->v_pes[14], &pva[12 + prebytes], - length - 12 - prebytes); - dec->v_pes_length = 14 + length - 12 - prebytes; - } else { - dec->v_pes[7] = 0x00; - dec->v_pes[8] = 0x00; - - memcpy(&dec->v_pes[9], &pva[8], length - 8); - dec->v_pes_length = 9 + length - 8; - } - - dec->v_pes_postbytes = postbytes; - - if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && - dec->v_pes[10 + dec->v_pes[8]] == 0x00 && - dec->v_pes[11 + dec->v_pes[8]] == 0x01) - dec->v_pes[6] = 0x84; - else - dec->v_pes[6] = 0x80; - - v_pes_payload_length = htons(dec->v_pes_length - 6 + - postbytes); - memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); - - if (postbytes == 0) - dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length, 1); - - break; - } - - case 0x02: /* MainAudioStream */ - if (output_pva) { - dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, - &dec->audio_filter->feed->feed.ts, DMX_OK); - return; - } - - dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8, - pva[5] & 0x10); - break; - - default: - printk("%s: unknown PVA type: %02x.\n", __func__, - pva[2]); - break; - } -} - -static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, - int length) -{ - struct list_head *item; - struct filter_info *finfo; - struct dvb_demux_filter *filter = NULL; - unsigned long flags; - u8 sid; - - sid = packet[1]; - spin_lock_irqsave(&dec->filter_info_list_lock, flags); - for (item = dec->filter_info_list.next; item != &dec->filter_info_list; - item = item->next) { - finfo = list_entry(item, struct filter_info, filter_info_list); - if (finfo->stream_id == sid) { - filter = finfo->filter; - break; - } - } - spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); - - if (filter) - filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, - &filter->filter, DMX_OK); -} - -static void ttusb_dec_process_packet(struct ttusb_dec *dec) -{ - int i; - u16 csum = 0; - u16 packet_id; - - if (dec->packet_length % 2) { - printk("%s: odd sized packet - discarding\n", __func__); - return; - } - - for (i = 0; i < dec->packet_length; i += 2) - csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]); - - if (csum) { - printk("%s: checksum failed - discarding\n", __func__); - return; - } - - packet_id = dec->packet[dec->packet_length - 4] << 8; - packet_id += dec->packet[dec->packet_length - 3]; - - if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { - printk("%s: warning: lost packets between %u and %u\n", - __func__, dec->next_packet_id - 1, packet_id); - } - - if (packet_id == 0xffff) - dec->next_packet_id = 0x8000; - else - dec->next_packet_id = packet_id + 1; - - switch (dec->packet_type) { - case TTUSB_DEC_PACKET_PVA: - if (dec->pva_stream_count) - ttusb_dec_process_pva(dec, dec->packet, - dec->packet_payload_length); - break; - - case TTUSB_DEC_PACKET_SECTION: - if (dec->filter_stream_count) - ttusb_dec_process_filter(dec, dec->packet, - dec->packet_payload_length); - break; - - case TTUSB_DEC_PACKET_EMPTY: - break; - } -} - -static void swap_bytes(u8 *b, int length) -{ - u8 c; - - length -= length % 2; - for (; length; b += 2, length -= 2) { - c = *b; - *b = *(b + 1); - *(b + 1) = c; - } -} - -static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, - int length) -{ - swap_bytes(b, length); - - while (length) { - switch (dec->packet_state) { - - case 0: - case 1: - case 2: - if (*b++ == 0xaa) - dec->packet_state++; - else - dec->packet_state = 0; - - length--; - break; - - case 3: - if (*b == 0x00) { - dec->packet_state++; - dec->packet_length = 0; - } else if (*b != 0xaa) { - dec->packet_state = 0; - } - - b++; - length--; - break; - - case 4: - dec->packet[dec->packet_length++] = *b++; - - if (dec->packet_length == 2) { - if (dec->packet[0] == 'A' && - dec->packet[1] == 'V') { - dec->packet_type = - TTUSB_DEC_PACKET_PVA; - dec->packet_state++; - } else if (dec->packet[0] == 'S') { - dec->packet_type = - TTUSB_DEC_PACKET_SECTION; - dec->packet_state++; - } else if (dec->packet[0] == 0x00) { - dec->packet_type = - TTUSB_DEC_PACKET_EMPTY; - dec->packet_payload_length = 2; - dec->packet_state = 7; - } else { - printk("%s: unknown packet type: " - "%02x%02x\n", __func__, - dec->packet[0], dec->packet[1]); - dec->packet_state = 0; - } - } - - length--; - break; - - case 5: - dec->packet[dec->packet_length++] = *b++; - - if (dec->packet_type == TTUSB_DEC_PACKET_PVA && - dec->packet_length == 8) { - dec->packet_state++; - dec->packet_payload_length = 8 + - (dec->packet[6] << 8) + - dec->packet[7]; - } else if (dec->packet_type == - TTUSB_DEC_PACKET_SECTION && - dec->packet_length == 5) { - dec->packet_state++; - dec->packet_payload_length = 5 + - ((dec->packet[3] & 0x0f) << 8) + - dec->packet[4]; - } - - length--; - break; - - case 6: { - int remainder = dec->packet_payload_length - - dec->packet_length; - - if (length >= remainder) { - memcpy(dec->packet + dec->packet_length, - b, remainder); - dec->packet_length += remainder; - b += remainder; - length -= remainder; - dec->packet_state++; - } else { - memcpy(&dec->packet[dec->packet_length], - b, length); - dec->packet_length += length; - length = 0; - } - - break; - } - - case 7: { - int tail = 4; - - dec->packet[dec->packet_length++] = *b++; - - if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && - dec->packet_payload_length % 2) - tail++; - - if (dec->packet_length == - dec->packet_payload_length + tail) { - ttusb_dec_process_packet(dec); - dec->packet_state = 0; - } - - length--; - break; - } - - default: - printk("%s: illegal packet state encountered.\n", - __func__); - dec->packet_state = 0; - } - } -} - -static void ttusb_dec_process_urb_frame_list(unsigned long data) -{ - struct ttusb_dec *dec = (struct ttusb_dec *)data; - struct list_head *item; - struct urb_frame *frame; - unsigned long flags; - - while (1) { - spin_lock_irqsave(&dec->urb_frame_list_lock, flags); - if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { - frame = list_entry(item, struct urb_frame, - urb_frame_list); - list_del(&frame->urb_frame_list); - } else { - spin_unlock_irqrestore(&dec->urb_frame_list_lock, - flags); - return; - } - spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); - - ttusb_dec_process_urb_frame(dec, frame->data, frame->length); - kfree(frame); - } -} - -static void ttusb_dec_process_urb(struct urb *urb) -{ - struct ttusb_dec *dec = urb->context; - - if (!urb->status) { - int i; - - for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { - struct usb_iso_packet_descriptor *d; - u8 *b; - int length; - struct urb_frame *frame; - - d = &urb->iso_frame_desc[i]; - b = urb->transfer_buffer + d->offset; - length = d->actual_length; - - if ((frame = kmalloc(sizeof(struct urb_frame), - GFP_ATOMIC))) { - unsigned long flags; - - memcpy(frame->data, b, length); - frame->length = length; - - spin_lock_irqsave(&dec->urb_frame_list_lock, - flags); - list_add_tail(&frame->urb_frame_list, - &dec->urb_frame_list); - spin_unlock_irqrestore(&dec->urb_frame_list_lock, - flags); - - tasklet_schedule(&dec->urb_tasklet); - } - } - } else { - /* -ENOENT is expected when unlinking urbs */ - if (urb->status != -ENOENT) - dprintk("%s: urb error: %d\n", __func__, - urb->status); - } - - if (dec->iso_stream_count) - usb_submit_urb(urb, GFP_ATOMIC); -} - -static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) -{ - int i, j, buffer_offset = 0; - - dprintk("%s\n", __func__); - - for (i = 0; i < ISO_BUF_COUNT; i++) { - int frame_offset = 0; - struct urb *urb = dec->iso_urb[i]; - - urb->dev = dec->udev; - urb->context = dec; - urb->complete = ttusb_dec_process_urb; - urb->pipe = dec->in_pipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = FRAMES_PER_ISO_BUF; - urb->transfer_buffer_length = ISO_FRAME_SIZE * - FRAMES_PER_ISO_BUF; - urb->transfer_buffer = dec->iso_buffer + buffer_offset; - buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; - - for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; - frame_offset += ISO_FRAME_SIZE; - } - } -} - -static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - if (mutex_lock_interruptible(&dec->iso_mutex)) - return; - - dec->iso_stream_count--; - - if (!dec->iso_stream_count) { - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_kill_urb(dec->iso_urb[i]); - } - - mutex_unlock(&dec->iso_mutex); -} - -/* Setting the interface of the DEC tends to take down the USB communications - * for a short period, so it's important not to call this function just before - * trying to talk to it. - */ -static int ttusb_dec_set_interface(struct ttusb_dec *dec, - enum ttusb_dec_interface interface) -{ - int result = 0; - u8 b[] = { 0x05 }; - - if (interface != dec->interface) { - switch (interface) { - case TTUSB_DEC_INTERFACE_INITIAL: - result = usb_set_interface(dec->udev, 0, 0); - break; - case TTUSB_DEC_INTERFACE_IN: - result = ttusb_dec_send_command(dec, 0x80, sizeof(b), - b, NULL, NULL); - if (result) - return result; - result = usb_set_interface(dec->udev, 0, 8); - break; - case TTUSB_DEC_INTERFACE_OUT: - result = usb_set_interface(dec->udev, 0, 1); - break; - } - - if (result) - return result; - - dec->interface = interface; - } - - return 0; -} - -static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) -{ - int i, result; - - dprintk("%s\n", __func__); - - if (mutex_lock_interruptible(&dec->iso_mutex)) - return -EAGAIN; - - if (!dec->iso_stream_count) { - ttusb_dec_setup_urbs(dec); - - dec->packet_state = 0; - dec->v_pes_postbytes = 0; - dec->next_packet_id = 0; - - for (i = 0; i < ISO_BUF_COUNT; i++) { - if ((result = usb_submit_urb(dec->iso_urb[i], - GFP_ATOMIC))) { - printk("%s: failed urb submission %d: " - "error %d\n", __func__, i, result); - - while (i) { - usb_kill_urb(dec->iso_urb[i - 1]); - i--; - } - - mutex_unlock(&dec->iso_mutex); - return result; - } - } - } - - dec->iso_stream_count++; - - mutex_unlock(&dec->iso_mutex); - - return 0; -} - -static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ttusb_dec *dec = dvbdmx->priv; - u8 b0[] = { 0x05 }; - int result = 0; - - dprintk("%s\n", __func__); - - dprintk(" ts_type:"); - - if (dvbdmxfeed->ts_type & TS_DECODER) - dprintk(" TS_DECODER"); - - if (dvbdmxfeed->ts_type & TS_PACKET) - dprintk(" TS_PACKET"); - - if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) - dprintk(" TS_PAYLOAD_ONLY"); - - dprintk("\n"); - - switch (dvbdmxfeed->pes_type) { - - case DMX_TS_PES_VIDEO: - dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); - dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; - dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; - dec->video_filter = dvbdmxfeed->filter; - ttusb_dec_set_pids(dec); - break; - - case DMX_TS_PES_AUDIO: - dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); - dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; - dec->audio_filter = dvbdmxfeed->filter; - ttusb_dec_set_pids(dec); - break; - - case DMX_TS_PES_TELETEXT: - dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); - return -ENOSYS; - - case DMX_TS_PES_PCR: - dprintk(" pes_type: DMX_TS_PES_PCR\n"); - dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; - ttusb_dec_set_pids(dec); - break; - - case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); - return -ENOSYS; - - default: - dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); - return -EINVAL; - - } - - result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); - if (result) - return result; - - dec->pva_stream_count++; - return ttusb_dec_start_iso_xfer(dec); -} - -static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb_dec *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00 }; - __be16 pid; - u8 c[COMMAND_PACKET_SIZE]; - int c_length; - int result; - struct filter_info *finfo; - unsigned long flags; - u8 x = 1; - - dprintk("%s\n", __func__); - - pid = htons(dvbdmxfeed->pid); - memcpy(&b0[0], &pid, 2); - memcpy(&b0[4], &x, 1); - memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); - - result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, - &c_length, c); - - if (!result) { - if (c_length == 2) { - if (!(finfo = kmalloc(sizeof(struct filter_info), - GFP_ATOMIC))) - return -ENOMEM; - - finfo->stream_id = c[1]; - finfo->filter = dvbdmxfeed->filter; - - spin_lock_irqsave(&dec->filter_info_list_lock, flags); - list_add_tail(&finfo->filter_info_list, - &dec->filter_info_list); - spin_unlock_irqrestore(&dec->filter_info_list_lock, - flags); - - dvbdmxfeed->priv = finfo; - - dec->filter_stream_count++; - return ttusb_dec_start_iso_xfer(dec); - } - - return -EAGAIN; - } else - return result; -} - -static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - - dprintk("%s\n", __func__); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); - - switch (dvbdmxfeed->type) { - - case DMX_TYPE_TS: - return ttusb_dec_start_ts_feed(dvbdmxfeed); - break; - - case DMX_TYPE_SEC: - return ttusb_dec_start_sec_feed(dvbdmxfeed); - break; - - default: - dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); - return -EINVAL; - - } -} - -static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb_dec *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00 }; - - ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); - - dec->pva_stream_count--; - - ttusb_dec_stop_iso_xfer(dec); - - return 0; -} - -static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb_dec *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00, 0x00 }; - struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; - unsigned long flags; - - b0[1] = finfo->stream_id; - spin_lock_irqsave(&dec->filter_info_list_lock, flags); - list_del(&finfo->filter_info_list); - spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); - kfree(finfo); - ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); - - dec->filter_stream_count--; - - ttusb_dec_stop_iso_xfer(dec); - - return 0; -} - -static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - dprintk("%s\n", __func__); - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - return ttusb_dec_stop_ts_feed(dvbdmxfeed); - break; - - case DMX_TYPE_SEC: - return ttusb_dec_stop_sec_feed(dvbdmxfeed); - break; - } - - return 0; -} - -static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_free_urb(dec->iso_urb[i]); - - pci_free_consistent(NULL, - ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT), - dec->iso_buffer, dec->iso_dma_handle); -} - -static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - dec->iso_buffer = pci_alloc_consistent(NULL, - ISO_FRAME_SIZE * - (FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT), - &dec->iso_dma_handle); - - if (!dec->iso_buffer) { - dprintk("%s: pci_alloc_consistent - not enough memory\n", - __func__); - return -ENOMEM; - } - - memset(dec->iso_buffer, 0, - ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); - - for (i = 0; i < ISO_BUF_COUNT; i++) { - struct urb *urb; - - if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { - ttusb_dec_free_iso_urbs(dec); - return -ENOMEM; - } - - dec->iso_urb[i] = urb; - } - - ttusb_dec_setup_urbs(dec); - - return 0; -} - -static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) -{ - spin_lock_init(&dec->urb_frame_list_lock); - INIT_LIST_HEAD(&dec->urb_frame_list); - tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list, - (unsigned long)dec); -} - -static int ttusb_init_rc( struct ttusb_dec *dec) -{ - struct input_dev *input_dev; - u8 b[] = { 0x00, 0x01 }; - int i; - int err; - - usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); - strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - input_dev->name = "ttusb_dec remote control"; - input_dev->phys = dec->rc_phys; - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->keycodesize = sizeof(u16); - input_dev->keycodemax = 0x1a; - input_dev->keycode = rc_keys; - - for (i = 0; i < ARRAY_SIZE(rc_keys); i++) - set_bit(rc_keys[i], input_dev->keybit); - - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; - } - - dec->rc_input_dev = input_dev; - if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) - printk("%s: usb_submit_urb failed\n",__func__); - /* enable irq pipe */ - ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); - - return 0; -} - -static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) -{ - dprintk("%s\n", __func__); - - dec->v_pes[0] = 0x00; - dec->v_pes[1] = 0x00; - dec->v_pes[2] = 0x01; - dec->v_pes[3] = 0xe0; -} - -static int ttusb_dec_init_usb(struct ttusb_dec *dec) -{ - dprintk("%s\n", __func__); - - mutex_init(&dec->usb_mutex); - mutex_init(&dec->iso_mutex); - - dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); - dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); - dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); - dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); - dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); - - if(enable_rc) { - dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if(!dec->irq_urb) { - return -ENOMEM; - } - dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, - GFP_ATOMIC, &dec->irq_dma_handle); - if(!dec->irq_buffer) { - usb_free_urb(dec->irq_urb); - return -ENOMEM; - } - usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, - dec->irq_buffer, IRQ_PACKET_SIZE, - ttusb_dec_handle_irq, dec, 1); - dec->irq_urb->transfer_dma = dec->irq_dma_handle; - dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - } - - return ttusb_dec_alloc_iso_urbs(dec); -} - -static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) -{ - int i, j, actual_len, result, size, trans_count; - u8 b0[] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x61, 0x00 }; - u8 b1[] = { 0x61 }; - u8 *b; - char idstring[21]; - const u8 *firmware = NULL; - size_t firmware_size = 0; - u16 firmware_csum = 0; - __be16 firmware_csum_ns; - __be32 firmware_size_nl; - u32 crc32_csum, crc32_check; - __be32 tmp; - const struct firmware *fw_entry = NULL; - - dprintk("%s\n", __func__); - - if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { - printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", - __func__, dec->firmware_name); - return 1; - } - - firmware = fw_entry->data; - firmware_size = fw_entry->size; - - if (firmware_size < 60) { - printk("%s: firmware size too small for DSP code (%zu < 60).\n", - __func__, firmware_size); - release_firmware(fw_entry); - return -1; - } - - /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored - at offset 56 of file, so use it to check if the firmware file is - valid. */ - crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; - memcpy(&tmp, &firmware[56], 4); - crc32_check = ntohl(tmp); - if (crc32_csum != crc32_check) { - printk("%s: crc32 check of DSP code failed (calculated " - "0x%08x != 0x%08x in file), file invalid.\n", - __func__, crc32_csum, crc32_check); - release_firmware(fw_entry); - return -1; - } - memcpy(idstring, &firmware[36], 20); - idstring[20] = '\0'; - printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); - - firmware_size_nl = htonl(firmware_size); - memcpy(b0, &firmware_size_nl, 4); - firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; - firmware_csum_ns = htons(firmware_csum); - memcpy(&b0[6], &firmware_csum_ns, 2); - - result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); - - if (result) { - release_firmware(fw_entry); - return result; - } - - trans_count = 0; - j = 0; - - b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); - if (b == NULL) { - release_firmware(fw_entry); - return -ENOMEM; - } - - for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { - size = firmware_size - i; - if (size > COMMAND_PACKET_SIZE) - size = COMMAND_PACKET_SIZE; - - b[j + 0] = 0xaa; - b[j + 1] = trans_count++; - b[j + 2] = 0xf0; - b[j + 3] = size; - memcpy(&b[j + 4], &firmware[i], size); - - j += COMMAND_PACKET_SIZE + 4; - - if (j >= ARM_PACKET_SIZE) { - result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - ARM_PACKET_SIZE, &actual_len, - 100); - j = 0; - } else if (size < COMMAND_PACKET_SIZE) { - result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - j - COMMAND_PACKET_SIZE + size, - &actual_len, 100); - } - } - - result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); - - release_firmware(fw_entry); - kfree(b); - - return result; -} - -static int ttusb_dec_init_stb(struct ttusb_dec *dec) -{ - int result; - unsigned int mode = 0, model = 0, version = 0; - - dprintk("%s\n", __func__); - - result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); - - if (!result) { - if (!mode) { - if (version == 0xABCDEFAB) - printk(KERN_INFO "ttusb_dec: no version " - "info in Firmware\n"); - else - printk(KERN_INFO "ttusb_dec: Firmware " - "%x.%02x%c%c\n", - version >> 24, (version >> 16) & 0xff, - (version >> 8) & 0xff, version & 0xff); - - result = ttusb_dec_boot_dsp(dec); - if (result) - return result; - else - return 1; - } else { - /* We can't trust the USB IDs that some firmwares - give the box */ - switch (model) { - case 0x00070001: - case 0x00070008: - case 0x0007000c: - ttusb_dec_set_model(dec, TTUSB_DEC3000S); - break; - case 0x00070009: - case 0x00070013: - ttusb_dec_set_model(dec, TTUSB_DEC2000T); - break; - case 0x00070011: - ttusb_dec_set_model(dec, TTUSB_DEC2540T); - break; - default: - printk(KERN_ERR "%s: unknown model returned " - "by firmware (%08x) - please report\n", - __func__, model); - return -1; - break; - } - - if (version >= 0x01770000) - dec->can_playback = 1; - - return 0; - } - } - else - return result; -} - -static int ttusb_dec_init_dvb(struct ttusb_dec *dec) -{ - int result; - - dprintk("%s\n", __func__); - - if ((result = dvb_register_adapter(&dec->adapter, - dec->model_name, THIS_MODULE, - &dec->udev->dev, - adapter_nr)) < 0) { - printk("%s: dvb_register_adapter failed: error %d\n", - __func__, result); - - return result; - } - - dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - - dec->demux.priv = (void *)dec; - dec->demux.filternum = 31; - dec->demux.feednum = 31; - dec->demux.start_feed = ttusb_dec_start_feed; - dec->demux.stop_feed = ttusb_dec_stop_feed; - dec->demux.write_to_decoder = NULL; - - if ((result = dvb_dmx_init(&dec->demux)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); - - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - dec->dmxdev.filternum = 32; - dec->dmxdev.demux = &dec->demux.dmx; - dec->dmxdev.capabilities = 0; - - if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { - printk("%s: dvb_dmxdev_init failed: error %d\n", - __func__, result); - - dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - dec->frontend.source = DMX_FRONTEND_0; - - if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, - &dec->frontend)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); - - dvb_dmxdev_release(&dec->dmxdev); - dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, - &dec->frontend)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); - - dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); - dvb_dmxdev_release(&dec->dmxdev); - dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); - - return 0; -} - -static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) -{ - dprintk("%s\n", __func__); - - dvb_net_release(&dec->dvb_net); - dec->demux.dmx.close(&dec->demux.dmx); - dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); - dvb_dmxdev_release(&dec->dmxdev); - dvb_dmx_release(&dec->demux); - if (dec->fe) { - dvb_unregister_frontend(dec->fe); - if (dec->fe->ops.release) - dec->fe->ops.release(dec->fe); - } - dvb_unregister_adapter(&dec->adapter); -} - -static void ttusb_dec_exit_rc(struct ttusb_dec *dec) -{ - - dprintk("%s\n", __func__); - /* we have to check whether the irq URB is already submitted. - * As the irq is submitted after the interface is changed, - * this is the best method i figured out. - * Any others?*/ - if (dec->interface == TTUSB_DEC_INTERFACE_IN) - usb_kill_urb(dec->irq_urb); - - usb_free_urb(dec->irq_urb); - - usb_free_coherent(dec->udev,IRQ_PACKET_SIZE, - dec->irq_buffer, dec->irq_dma_handle); - - if (dec->rc_input_dev) { - input_unregister_device(dec->rc_input_dev); - dec->rc_input_dev = NULL; - } -} - - -static void ttusb_dec_exit_usb(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - dec->iso_stream_count = 0; - - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_kill_urb(dec->iso_urb[i]); - - ttusb_dec_free_iso_urbs(dec); -} - -static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) -{ - struct list_head *item; - struct urb_frame *frame; - - tasklet_kill(&dec->urb_tasklet); - - while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { - frame = list_entry(item, struct urb_frame, urb_frame_list); - list_del(&frame->urb_frame_list); - kfree(frame); - } -} - -static void ttusb_dec_init_filters(struct ttusb_dec *dec) -{ - INIT_LIST_HEAD(&dec->filter_info_list); - spin_lock_init(&dec->filter_info_list_lock); -} - -static void ttusb_dec_exit_filters(struct ttusb_dec *dec) -{ - struct list_head *item; - struct filter_info *finfo; - - while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { - finfo = list_entry(item, struct filter_info, filter_info_list); - list_del(&finfo->filter_info_list); - kfree(finfo); - } -} - -static int fe_send_command(struct dvb_frontend* fe, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]) -{ - struct ttusb_dec* dec = fe->dvb->priv; - return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); -} - -static struct ttusbdecfe_config fe_config = { - .send_command = fe_send_command -}; - -static int ttusb_dec_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev; - struct ttusb_dec *dec; - - dprintk("%s\n", __func__); - - udev = interface_to_usbdev(intf); - - if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { - printk("%s: couldn't allocate memory.\n", __func__); - return -ENOMEM; - } - - usb_set_intfdata(intf, (void *)dec); - - switch (id->idProduct) { - case 0x1006: - ttusb_dec_set_model(dec, TTUSB_DEC3000S); - break; - - case 0x1008: - ttusb_dec_set_model(dec, TTUSB_DEC2000T); - break; - - case 0x1009: - ttusb_dec_set_model(dec, TTUSB_DEC2540T); - break; - } - - dec->udev = udev; - - if (ttusb_dec_init_usb(dec)) - return 0; - if (ttusb_dec_init_stb(dec)) { - ttusb_dec_exit_usb(dec); - return 0; - } - ttusb_dec_init_dvb(dec); - - dec->adapter.priv = dec; - switch (id->idProduct) { - case 0x1006: - dec->fe = ttusbdecfe_dvbs_attach(&fe_config); - break; - - case 0x1008: - case 0x1009: - dec->fe = ttusbdecfe_dvbt_attach(&fe_config); - break; - } - - if (dec->fe == NULL) { - printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", - le16_to_cpu(dec->udev->descriptor.idVendor), - le16_to_cpu(dec->udev->descriptor.idProduct)); - } else { - if (dvb_register_frontend(&dec->adapter, dec->fe)) { - printk("budget-ci: Frontend registration failed!\n"); - if (dec->fe->ops.release) - dec->fe->ops.release(dec->fe); - dec->fe = NULL; - } - } - - ttusb_dec_init_v_pes(dec); - ttusb_dec_init_filters(dec); - ttusb_dec_init_tasklet(dec); - - dec->active = 1; - - ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); - - if (enable_rc) - ttusb_init_rc(dec); - - return 0; -} - -static void ttusb_dec_disconnect(struct usb_interface *intf) -{ - struct ttusb_dec *dec = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - dprintk("%s\n", __func__); - - if (dec->active) { - ttusb_dec_exit_tasklet(dec); - ttusb_dec_exit_filters(dec); - if(enable_rc) - ttusb_dec_exit_rc(dec); - ttusb_dec_exit_usb(dec); - ttusb_dec_exit_dvb(dec); - } - - kfree(dec); -} - -static void ttusb_dec_set_model(struct ttusb_dec *dec, - enum ttusb_dec_model model) -{ - dec->model = model; - - switch (model) { - case TTUSB_DEC2000T: - dec->model_name = "DEC2000-t"; - dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; - break; - - case TTUSB_DEC2540T: - dec->model_name = "DEC2540-t"; - dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; - break; - - case TTUSB_DEC3000S: - dec->model_name = "DEC3000-s"; - dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; - break; - } -} - -static struct usb_device_id ttusb_dec_table[] = { - {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ - /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ - {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ - {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ - {} -}; - -static struct usb_driver ttusb_dec_driver = { - .name = "ttusb-dec", - .probe = ttusb_dec_probe, - .disconnect = ttusb_dec_disconnect, - .id_table = ttusb_dec_table, -}; - -module_usb_driver(ttusb_dec_driver); - -MODULE_AUTHOR("Alex Woods "); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, ttusb_dec_table); diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c deleted file mode 100644 index 5c45c9d0712..00000000000 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * TTUSB DEC Frontend Driver - * - * Copyright (C) 2003-2004 Alex Woods - * - * 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 "dvb_frontend.h" -#include "ttusbdecfe.h" - - -#define LOF_HI 10600000 -#define LOF_LO 9750000 - -struct ttusbdecfe_state { - - /* configuration settings */ - const struct ttusbdecfe_config* config; - - struct dvb_frontend frontend; - - u8 hi_band; - u8 voltage; -}; - - -static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; -} - - -static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - struct ttusbdecfe_state* state = fe->demodulator_priv; - u8 b[] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - u8 result[4]; - int len, ret; - - *status=0; - - ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); - if(ret) - return ret; - - if(len != 4) { - printk(KERN_ERR "%s: unexpected reply\n", __func__); - return -EIO; - } - - switch(result[3]) { - case 1: /* not tuned yet */ - case 2: /* no signal/no lock*/ - break; - case 3: /* signal found and locked*/ - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - case 4: - *status = FE_TIMEDOUT; - break; - default: - pr_info("%s: returned unknown value: %d\n", - __func__, result[3]); - return -EIO; - } - - return 0; -} - -static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - u8 b[] = { 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff }; - - __be32 freq = htonl(p->frequency / 1000); - memcpy(&b[4], &freq, sizeof (u32)); - state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); - - return 0; -} - -static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, - struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 1500; - /* Drift compensation makes no sense for DVB-T */ - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - - u8 b[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - __be32 freq; - __be32 sym_rate; - __be32 band; - __be32 lnb_voltage; - - freq = htonl(p->frequency + - (state->hi_band ? LOF_HI : LOF_LO)); - memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->symbol_rate); - memcpy(&b[12], &sym_rate, sizeof(u32)); - band = htonl(state->hi_band ? LOF_HI : LOF_LO); - memcpy(&b[24], &band, sizeof(u32)); - lnb_voltage = htonl(state->voltage); - memcpy(&b[28], &lnb_voltage, sizeof(u32)); - - state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); - - return 0; -} - -static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - u8 b[] = { 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; - - memcpy(&b[4], cmd->msg, cmd->msg_len); - - state->config->send_command(fe, 0x72, - sizeof(b) - (6 - cmd->msg_len), b, - NULL, NULL); - - return 0; -} - - -static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - - state->hi_band = (SEC_TONE_ON == tone); - - return 0; -} - - -static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - state->voltage = 13; - break; - case SEC_VOLTAGE_18: - state->voltage = 18; - break; - default: - return -EINVAL; - } - - return 0; -} - -static void ttusbdecfe_release(struct dvb_frontend* fe) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; - -struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) -{ - struct ttusbdecfe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - /* setup the state */ - state->config = config; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; - -struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) -{ - struct ttusbdecfe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - /* setup the state */ - state->config = config; - state->voltage = 0; - state->hi_band = 0; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_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 = ttusbdecfe_release, - - .set_frontend = ttusbdecfe_dvbt_set_frontend, - - .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, - - .read_status = ttusbdecfe_dvbt_read_status, -}; - -static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { - .delsys = { SYS_DVBS }, - .info = { - .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, - .symbol_rate_min = 1000000, /* guessed */ - .symbol_rate_max = 45000000, /* guessed */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = ttusbdecfe_release, - - .set_frontend = ttusbdecfe_dvbs_set_frontend, - - .read_status = ttusbdecfe_dvbs_read_status, - - .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, - .set_voltage = ttusbdecfe_dvbs_set_voltage, - .set_tone = ttusbdecfe_dvbs_set_tone, -}; - -MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); -MODULE_AUTHOR("Alex Woods/Andrew de Quincey"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ttusbdecfe_dvbt_attach); -EXPORT_SYMBOL(ttusbdecfe_dvbs_attach); diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h b/drivers/media/dvb/ttusb-dec/ttusbdecfe.h deleted file mode 100644 index 15ccc3d1a20..00000000000 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * TTUSB DEC Driver - * - * Copyright (C) 2003-2004 Alex Woods - * - * 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 TTUSBDECFE_H -#define TTUSBDECFE_H - -#include - -struct ttusbdecfe_config -{ - int (*send_command)(struct dvb_frontend* fe, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]); -}; - -extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config); - -extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config); - -#endif // TTUSBDECFE_H diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig new file mode 100644 index 00000000000..70b1708db05 --- /dev/null +++ b/drivers/media/usb/Kconfig @@ -0,0 +1,18 @@ +# +# USB media device configuration +# + +menuconfig MEDIA_USB_DRIVERS + bool "Supported DVB USB Adapters" + depends on USB + default y + +if MEDIA_USB_DRIVERS && DVB_CORE && I2C + +source "drivers/media/usb/dvb-usb/Kconfig" +source "drivers/media/usb/dvb-usb-v2/Kconfig" +source "drivers/media/usb/ttusb-budget/Kconfig" +source "drivers/media/usb/ttusb-dec/Kconfig" +source "drivers/media/usb/siano/Kconfig" + +endif diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile new file mode 100644 index 00000000000..44e29f340eb --- /dev/null +++ b/drivers/media/usb/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the USB media device drivers +# + +# DVB USB-only drivers +obj-y := ttusb-dec/ ttusb-budget/ dvb-usb/ dvb-usb-v2/ siano/ diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig new file mode 100644 index 00000000000..276374fbaf4 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -0,0 +1,146 @@ +config DVB_USB_V2 + tristate "Support for various USB DVB devices v2" + depends on DVB_CORE && USB && I2C && RC_CORE + help + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. + + Almost every USB device needs a firmware, please look into + . + + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a USB DVB device. + +config DVB_USB_CYPRESS_FIRMWARE + tristate "Cypress firmware helper routines" + depends on DVB_USB_V2 + +config DVB_USB_AF9015 + tristate "Afatech AF9015 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_AF9013 + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver + +config DVB_USB_AF9035 + tristate "Afatech AF9035 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_AF9033 + select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9035 based DVB USB receiver. + +config DVB_USB_ANYSEE + tristate "Anysee DVB-T/C USB2.0 support" + depends on DVB_USB_V2 + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_CXD2820R if !DVB_FE_CUSTOMISE + help + Say Y here to support the Anysee E30, Anysee E30 Plus or + Anysee E30 C Plus DVB USB2.0 receiver. + +config DVB_USB_AU6610 + tristate "Alcor Micro AU6610 USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. + +config DVB_USB_AZ6007 + tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" + depends on DVB_USB_V2 + select DVB_USB_CYPRESS_FIRMWARE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE + help + Say Y here to support the AZ6007 receivers like Terratec H7. + +config DVB_USB_CE6230 + tristate "Intel CE6230 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 + 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_EC168 + tristate "E3C EC168 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_EC100 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. + +config DVB_USB_GL861 + tristate "Genesys Logic GL861 USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 + receiver with USB ID 0db0:5581. + +config DVB_USB_IT913X + tristate "ITE IT913X DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_IT913X_FE + help + Say Y here to support the ITE IT913X DVB-T USB2.0 + +config DVB_USB_LME2510 + tristate "LME DM04/QQBOX DVB-S USB2.0 support" + depends on DVB_USB_V2 + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_IX2505V if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_M88RS2000 if !DVB_FE_CUSTOMISE + help + Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 + +config DVB_USB_MXL111SF + tristate "MxL111SF DTV USB2.0 support" + depends on DVB_USB_V2 + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_LG2160 if !DVB_FE_CUSTOMISE + select VIDEO_TVEEPROM + help + Say Y here to support the MxL111SF USB2.0 DTV receiver. + +config DVB_USB_RTL28XXU + tristate "Realtek RTL28xxU DVB USB support" + depends on DVB_USB_V2 && EXPERIMENTAL + select DVB_RTL2830 + select DVB_RTL2832 + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Realtek RTL28xxU DVB USB receiver. + diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile new file mode 100644 index 00000000000..24248b3acd4 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -0,0 +1,48 @@ +dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o +obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o + +dvb_usb_cypress_firmware-objs = cypress_firmware.o +obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o + +dvb-usb-af9015-objs = af9015.o +obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o + +dvb-usb-af9035-objs = af9035.o +obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o + +dvb-usb-anysee-objs = anysee.o +obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o + +dvb-usb-au6610-objs = au6610.o +obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o + +dvb-usb-az6007-objs = az6007.o +obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o + +dvb-usb-ce6230-objs = ce6230.o +obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o + +dvb-usb-ec168-objs = ec168.o +obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o + +dvb-usb-it913x-objs = it913x.o +obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o + +dvb-usb-lmedm04-objs = lmedm04.o +obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o + +dvb-usb-gl861-objs = gl861.o +obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o + +dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o +obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o + +dvb-usb-rtl28xxu-objs = rtl28xxu.o +obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o + +ccflags-y += -I$(srctree)/drivers/media/dvb-core +ccflags-y += -I$(srctree)/drivers/media/dvb-frontends +ccflags-y += -I$(srctree)/drivers/media/common/tuners + diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c new file mode 100644 index 00000000000..e77429b37a7 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -0,0 +1,1434 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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 "af9015.h" + +static int dvb_usb_af9015_debug; +module_param_named(debug, dvb_usb_af9015_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +static int dvb_usb_af9015_remote; +module_param_named(remote, dvb_usb_af9015_remote, int, 0644); +MODULE_PARM_DESC(remote, "select remote"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +{ +#define BUF_LEN 63 +#define REQ_HDR_LEN 8 /* send header size */ +#define ACK_HDR_LEN 2 /* rece header size */ + struct af9015_state *state = d_to_priv(d); + int ret, wlen, rlen; + u8 buf[BUF_LEN]; + u8 write = 1; + + buf[0] = req->cmd; + buf[1] = state->seq++; + buf[2] = req->i2c_addr; + buf[3] = req->addr >> 8; + buf[4] = req->addr & 0xff; + buf[5] = req->mbox; + buf[6] = req->addr_len; + buf[7] = req->data_len; + + switch (req->cmd) { + case GET_CONFIG: + case READ_MEMORY: + case RECONNECT_USB: + write = 0; + break; + case READ_I2C: + write = 0; + buf[2] |= 0x01; /* set I2C direction */ + case WRITE_I2C: + buf[0] = READ_WRITE_I2C; + break; + case WRITE_MEMORY: + if (((req->addr & 0xff00) == 0xff00) || + ((req->addr & 0xff00) == 0xae00)) + buf[0] = WRITE_VIRTUAL_MEMORY; + case WRITE_VIRTUAL_MEMORY: + case COPY_FIRMWARE: + case DOWNLOAD_FIRMWARE: + case BOOT: + break; + default: + err("unknown command:%d", req->cmd); + ret = -1; + goto error; + } + + /* buffer overflow check */ + if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || + (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { + err("too much data; cmd:%d len:%d", req->cmd, req->data_len); + ret = -EINVAL; + goto error; + } + + /* write receives seq + status = 2 bytes + read receives seq + status + data = 2 + N bytes */ + wlen = REQ_HDR_LEN; + rlen = ACK_HDR_LEN; + if (write) { + wlen += req->data_len; + memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); + } else { + rlen += req->data_len; + } + + /* no ack for these packets */ + if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) + rlen = 0; + + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); + if (ret) + goto error; + + /* check status */ + if (rlen && buf[1]) { + err("command failed:%d", buf[1]); + ret = -1; + goto error; + } + + /* read request, copy returned data to return buf */ + if (!write) + memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); +error: + return ret; +} + +static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, + u8 len) +{ + struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) +{ + struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) +{ + return af9015_write_regs(d, addr, &val, 1); +} + +static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) +{ + return af9015_read_regs(d, addr, val, 1); +} + +static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 val) +{ + struct af9015_state *state = d_to_priv(d); + struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; + + if (addr == state->af9013_config[0].i2c_addr || + addr == state->af9013_config[1].i2c_addr) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 *val) +{ + struct af9015_state *state = d_to_priv(d); + struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; + + if (addr == state->af9013_config[0].i2c_addr || + addr == state->af9013_config[1].i2c_addr) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +{ + int ret; + u8 val, mask = 0x01; + + ret = af9015_read_reg(d, addr, &val); + if (ret) + return ret; + + mask <<= bit; + if (op) { + /* set bit */ + val |= mask; + } else { + /* clear bit */ + mask ^= 0xff; + val &= mask; + } + + return af9015_write_reg(d, addr, val); +} + +static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 1); +} + +static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 0); +} + +static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct af9015_state *state = d_to_priv(d); + int ret = 0, i = 0; + u16 addr; + u8 uninitialized_var(mbox), addr_len; + struct req_t req; + +/* +The bus lock is needed because there is two tuners both using same I2C-address. +Due to that the only way to select correct tuner is use demodulator I2C-gate. + +................................................ +. AF9015 includes integrated AF9013 demodulator. +. ____________ ____________ . ____________ +.| uC | | demod | . | tuner | +.|------------| |------------| . |------------| +.| AF9015 | | AF9013/5 | . | MXL5003 | +.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | +.| | | | addr 0x38 | . | addr 0xc6 | +.|____________| | |____________| . |____________| +.................|.............................. + | ____________ ____________ + | | demod | | tuner | + | |------------| |------------| + | | AF9013 | | MXL5003 | + +----I2C-------|-----/ -----|-------I2C-------| | + | addr 0x3a | | addr 0xc6 | + |____________| |____________| +*/ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (msg[i].addr == state->af9013_config[0].i2c_addr || + msg[i].addr == state->af9013_config[1].i2c_addr) { + addr = msg[i].buf[0] << 8; + addr += msg[i].buf[1]; + mbox = msg[i].buf[2]; + addr_len = 3; + } else { + addr = msg[i].buf[0]; + addr_len = 1; + /* mbox is don't care in that case */ + } + + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].len > 3 || msg[i+1].len > 61) { + ret = -EOPNOTSUPP; + goto error; + } + if (msg[i].addr == state->af9013_config[0].i2c_addr) + req.cmd = READ_MEMORY; + else + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 2; + } else if (msg[i].flags & I2C_M_RD) { + if (msg[i].len > 61) { + ret = -EOPNOTSUPP; + goto error; + } + if (msg[i].addr == state->af9013_config[0].i2c_addr) { + ret = -EINVAL; + goto error; + } + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len; + req.data = &msg[i].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } else { + if (msg[i].len > 21) { + ret = -EOPNOTSUPP; + goto error; + } + if (msg[i].addr == state->af9013_config[0].i2c_addr) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len-addr_len; + req.data = &msg[i].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 af9015_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9015_i2c_algo = { + .master_xfer = af9015_i2c_xfer, + .functionality = af9015_i2c_func, +}; + +static int af9015_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 reply; + struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; + + ret = af9015_ctrl_msg(d, &req); + if (ret) + return ret; + + deb_info("%s: reply:%02x\n", __func__, reply); + if (reply == 0x02) + ret = WARM; + else + ret = COLD; + + return ret; +} + +static int af9015_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + struct af9015_state *state = d_to_priv(d); + int i, len, remaining, ret; + struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; + u16 checksum = 0; + + deb_info("%s:\n", __func__); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + state->firmware_size = fw->size; + state->firmware_checksum = checksum; + + #define FW_ADDR 0x5100 /* firmware start address */ + #define LEN_MAX 55 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + + req.data_len = len; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.addr = FW_ADDR + fw->size - remaining; + + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("firmware download failed:%d", ret); + goto error; + } + } + + /* firmware loaded, request boot */ + req.cmd = BOOT; + req.data_len = 0; + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("firmware boot failed:%d", ret); + goto error; + } + +error: + return ret; +} + +/* hash (and dump) eeprom */ +static int af9015_eeprom_hash(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + static const unsigned int eeprom_size = 256; + unsigned int reg; + u8 val, *eeprom; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + eeprom = kmalloc(eeprom_size, GFP_KERNEL); + if (eeprom == NULL) + return -ENOMEM; + + for (reg = 0; reg < eeprom_size; reg++) { + req.addr = reg; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto free; + + eeprom[reg] = val; + } + + if (dvb_usb_af9015_debug & 0x01) + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, + eeprom_size); + + BUG_ON(eeprom_size % 4); + + state->eeprom_sum = 0; + for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { + state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; + state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); + } + + deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum); + + ret = 0; +free: + kfree(eeprom); + return ret; +} + +static int af9015_read_config(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u8 val, i, offset = 0; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + deb_info("%s:\n", __func__); + + /* IR remote controller */ + req.addr = AF9015_EEPROM_IR_MODE; + /* first message will timeout often due to possible hw bug */ + for (i = 0; i < 4; i++) { + ret = af9015_ctrl_msg(d, &req); + if (!ret) + break; + } + if (ret) + goto error; + + ret = af9015_eeprom_hash(d); + if (ret) + goto error; + + deb_info("%s: IR mode=%d\n", __func__, val); + state->ir_mode = val; + + /* TS mode - one or two receivers */ + req.addr = AF9015_EEPROM_TS_MODE; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->dual_mode = val; + deb_info("%s: TS mode=%d\n", __func__, state->dual_mode); + + /* disable 2nd adapter because we don't have PID-filters */ + if (d->udev->speed == USB_SPEED_FULL) + state->dual_mode = 0; + + if (state->dual_mode) { + /* read 2nd demodulator I2C address */ + req.addr = AF9015_EEPROM_DEMOD2_I2C; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[1].i2c_addr = val; + } + + for (i = 0; i < state->dual_mode + 1; i++) { + if (i == 1) + offset = AF9015_EEPROM_OFFSET; + /* xtal */ + req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + switch (val) { + case 0: + state->af9013_config[i].clock = 28800000; + break; + case 1: + state->af9013_config[i].clock = 20480000; + break; + case 2: + state->af9013_config[i].clock = 28000000; + break; + case 3: + state->af9013_config[i].clock = 25000000; + break; + }; + deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, + val, state->af9013_config[i].clock); + + /* IF frequency */ + req.addr = AF9015_EEPROM_IF1H + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[i].if_frequency = val << 8; + + req.addr = AF9015_EEPROM_IF1L + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[i].if_frequency += val; + state->af9013_config[i].if_frequency *= 1000; + deb_info("%s: [%d] IF frequency=%d\n", __func__, i, + state->af9013_config[i].if_frequency); + + /* MT2060 IF1 */ + req.addr = AF9015_EEPROM_MT2060_IF1H + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + state->mt2060_if1[i] = val << 8; + req.addr = AF9015_EEPROM_MT2060_IF1L + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + state->mt2060_if1[i] += val; + deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, + state->mt2060_if1[i]); + + /* tuner */ + req.addr = AF9015_EEPROM_TUNER_ID1 + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + switch (val) { + case AF9013_TUNER_ENV77H11D5: + case AF9013_TUNER_MT2060: + case AF9013_TUNER_QT1010: + case AF9013_TUNER_UNKNOWN: + case AF9013_TUNER_MT2060_2: + case AF9013_TUNER_TDA18271: + case AF9013_TUNER_QT1010A: + case AF9013_TUNER_TDA18218: + state->af9013_config[i].spec_inv = 1; + break; + case AF9013_TUNER_MXL5003D: + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + case AF9013_TUNER_MXL5007T: + state->af9013_config[i].spec_inv = 0; + break; + case AF9013_TUNER_MC44S803: + state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; + state->af9013_config[i].spec_inv = 1; + break; + default: + warn("tuner id=%d not supported, please report!", val); + return -ENODEV; + }; + + state->af9013_config[i].tuner = val; + deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); + } + +error: + if (ret) + err("eeprom read failed=%d", ret); + + /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM + content :-( Override some wrong values here. Ditto for the + AVerTV Red HD+ (A850T) device. */ + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && + ((le16_to_cpu(d->udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850) || + (le16_to_cpu(d->udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850T))) { + deb_info("%s: AverMedia A850: overriding config\n", __func__); + /* disable dual mode */ + state->dual_mode = 0; + + /* set correct IF */ + state->af9013_config[0].if_frequency = 4570000; + } + + return ret; +} + +static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, + struct usb_data_stream_properties *stream) +{ + deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id); + + if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL) + stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; + + return 0; +} + +static int af9015_get_adapter_count(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + return state->dual_mode + 1; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->set_frontend[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->read_status[fe_to_adap(fe)->id](fe, status); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_init(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->init[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_sleep(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->sleep[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override tuner callbacks for resource locking */ +static int af9015_tuner_init(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->tuner_init[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override tuner callbacks for resource locking */ +static int af9015_tuner_sleep(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +static int af9015_copy_firmware(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u8 fw_params[4]; + u8 val, i; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), + fw_params }; + deb_info("%s:\n", __func__); + + fw_params[0] = state->firmware_size >> 8; + fw_params[1] = state->firmware_size & 0xff; + fw_params[2] = state->firmware_checksum >> 8; + fw_params[3] = state->firmware_checksum & 0xff; + + /* wait 2nd demodulator ready */ + msleep(100); + + ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + /* set I2C master clock to fast (to speed up firmware copy) */ + ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ + if (ret) + goto error; + + msleep(50); + + /* copy firmware */ + ret = af9015_ctrl_msg(d, &req); + if (ret) + err("firmware copy cmd failed:%d", ret); + deb_info("%s: firmware copy done\n", __func__); + + /* set I2C master clock back to normal */ + ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + if (ret) + goto error; + + /* request boot firmware */ + ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0xe205, 1); + deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); + if (ret) + goto error; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0x98be, &val); + deb_info("%s: firmware status cmd status:%d fw status:%02x\n", + __func__, ret, val); + if (ret) + goto error; + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error: +exit: + return ret; +} + +static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct af9015_state *state = adap_to_priv(adap); + + if (adap->id == 0) { + state->af9013_config[0].ts_mode = AF9013_TS_USB; + memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); + state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; + state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; + } else if (adap->id == 1) { + state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; + memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); + state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; + state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; + + /* copy firmware to 2nd demodulator */ + if (state->dual_mode) { + ret = af9015_copy_firmware(adap_to_d(adap)); + if (ret) { + err("firmware copy to 2nd frontend " \ + "failed, will disable it"); + state->dual_mode = 0; + return -ENODEV; + } + } else { + return -ENODEV; + } + } + + /* attach demodulator */ + adap->fe[0] = dvb_attach(af9013_attach, + &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); + + /* + * AF9015 firmware does not like if it gets interrupted by I2C adapter + * request on some critical phases. During normal operation I2C adapter + * is used only 2nd demodulator and tuner on dual tuner devices. + * Override demodulator callbacks and use mutex for limit access to + * those "critical" paths to keep AF9015 happy. + */ + if (adap->fe[0]) { + state->set_frontend[adap->id] = + adap->fe[0]->ops.set_frontend; + adap->fe[0]->ops.set_frontend = + af9015_af9013_set_frontend; + + state->read_status[adap->id] = + adap->fe[0]->ops.read_status; + adap->fe[0]->ops.read_status = + af9015_af9013_read_status; + + state->init[adap->id] = adap->fe[0]->ops.init; + adap->fe[0]->ops.init = af9015_af9013_init; + + state->sleep[adap->id] = adap->fe[0]->ops.sleep; + adap->fe[0]->ops.sleep = af9015_af9013_sleep; + } + + return adap->fe[0] == NULL ? -ENODEV : 0; +} + +static struct mt2060_config af9015_mt2060_config = { + .i2c_address = 0xc0, + .clock_out = 0, +}; + +static struct qt1010_config af9015_qt1010_config = { + .i2c_address = 0xc4, +}; + +static struct tda18271_config af9015_tda18271_config = { + .gate = TDA18271_GATE_DIGITAL, + .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, +}; + +static struct mxl5005s_config af9015_mxl5003_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mxl5005s_config af9015_mxl5005_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mc44s803_config af9015_mc44s803_config = { + .i2c_address = 0xc0, + .dig_out = 1, +}; + +static struct tda18218_config af9015_tda18218_config = { + .i2c_address = 0xc0, + .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ +}; + +static struct mxl5007t_config af9015_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_4_57_MHZ, +}; + +static int af9015_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct af9015_state *state = adap_to_priv(adap); + int ret; + deb_info("%s:\n", __func__); + + switch (state->af9013_config[adap->id].tuner) { + case AF9013_TUNER_MT2060: + case AF9013_TUNER_MT2060_2: + ret = dvb_attach(mt2060_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, + state->mt2060_if1[adap->id]) + == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_QT1010: + case AF9013_TUNER_QT1010A: + ret = dvb_attach(qt1010_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_qt1010_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18271: + ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, + &adap_to_d(adap)->i2c_adap, + &af9015_tda18271_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18218: + ret = dvb_attach(tda18218_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_tda18218_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5003D: + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_mxl5003_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_mxl5005_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_ENV77H11D5: + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, + &adap_to_d(adap)->i2c_adap, + DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MC44S803: + ret = dvb_attach(mc44s803_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_mc44s803_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5007T: + ret = dvb_attach(mxl5007t_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_UNKNOWN: + default: + ret = -ENODEV; + err("Unknown tuner id:%d", + state->af9013_config[adap->id].tuner); + } + + if (adap->fe[0]->ops.tuner_ops.init) { + state->tuner_init[adap->id] = + adap->fe[0]->ops.tuner_ops.init; + adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; + } + + if (adap->fe[0]->ops.tuner_ops.sleep) { + state->tuner_sleep[adap->id] = + adap->fe[0]->ops.tuner_ops.sleep; + adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; + } + + return ret; +} + +static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) + ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0); + else + ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0); + + return ret; +} + +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret; + u8 idx; + + deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", + __func__, index, pid, onoff); + + ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff)); + if (ret) + goto error; + + ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8)); + if (ret) + goto error; + + idx = ((index & 0x1f) | (1 << 5)); + ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx); + +error: + return ret; +} + +static int af9015_init_endpoint(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u16 frame_size; + u8 packet_size; + deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); + + if (d->udev->speed == USB_SPEED_FULL) { + frame_size = TS_USB11_FRAME_SIZE/4; + packet_size = TS_USB11_MAX_PACKET_SIZE/4; + } else { + frame_size = TS_USB20_FRAME_SIZE/4; + packet_size = TS_USB20_MAX_PACKET_SIZE/4; + } + + ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ + if (ret) + goto error; + } + ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ + if (ret) + goto error; + } + /* EP4 xfer length */ + ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); + if (ret) + goto error; + /* EP5 xfer length */ + ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ + if (ret) + goto error; + } + + /* enable / disable mp2if2 */ + if (state->dual_mode) + ret = af9015_set_reg_bit(d, 0xd50b, 0); + else + ret = af9015_clear_reg_bit(d, 0xd50b, 0); + +error: + if (ret) + err("endpoint init failed:%d", ret); + return ret; +} + +static int af9015_init(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + deb_info("%s:\n", __func__); + + mutex_init(&state->fe_mutex); + + /* init RC canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + ret = af9015_init_endpoint(d); + if (ret) + goto error; + +error: + return ret; +} + +struct af9015_rc_setup { + unsigned int id; + char *rc_codes; +}; + +static char *af9015_rc_setup_match(unsigned int id, + const struct af9015_rc_setup *table) +{ + for (; table->rc_codes; table++) + if (table->id == id) + return table->rc_codes; + return NULL; +} + +static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { + { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, + { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, + { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, + { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, + { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, + { } +}; + +static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { + { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, + { 0xa3703d00, RC_MAP_ALINK_DTU_M }, + { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ + { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ + { } +}; + +static int af9015_rc_query(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u8 buf[17]; + + deb_info("%s:\n", __func__); + + /* read registers needed to detect remote controller code */ + ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); + if (ret) + goto error; + + /* If any of these are non-zero, assume invalid data */ + if (buf[1] || buf[2] || buf[3]) + return ret; + + /* Check for repeat of previous code */ + if ((state->rc_repeat != buf[6] || buf[0]) && + !memcmp(&buf[12], state->rc_last, 4)) { + deb_rc("%s: key repeated\n", __func__); + rc_keydown(d->rc_dev, state->rc_keycode, 0); + state->rc_repeat = buf[6]; + return ret; + } + + /* Only process key if canary killed */ + if (buf[16] != 0xff && buf[0] != 0x01) { + deb_rc("%s: key pressed %*ph\n", __func__, 4, buf + 12); + + /* Reset the canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + /* Remember this key */ + memcpy(state->rc_last, &buf[12], 4); + if (buf[14] == (u8) ~buf[15]) { + if (buf[12] == (u8) ~buf[13]) { + /* NEC */ + state->rc_keycode = buf[12] << 8 | buf[14]; + } else { + /* NEC extended*/ + state->rc_keycode = buf[12] << 16 | + buf[13] << 8 | buf[14]; + } + } else { + /* 32 bit NEC */ + state->rc_keycode = buf[12] << 24 | buf[13] << 16 | + buf[14] << 8 | buf[15]; + } + rc_keydown(d->rc_dev, state->rc_keycode, 0); + } else { + deb_rc("%s: no key press\n", __func__); + /* Invalidate last keypress */ + /* Not really needed, but helps with debug */ + state->rc_last[2] = state->rc_last[3]; + } + + state->rc_repeat = buf[6]; + state->rc_failed = false; + +error: + if (ret) { + err("%s: failed:%d", __func__, ret); + + /* allow random errors as dvb-usb will stop polling on error */ + if (!state->rc_failed) + ret = 0; + + state->rc_failed = true; + } + + return ret; +} + +static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + struct af9015_state *state = d_to_priv(d); + u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); + + if (state->ir_mode == AF9015_IR_MODE_DISABLED) + return 0; + + /* try to load remote based module param */ + if (!rc->map_name) + rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, + af9015_rc_setup_modparam); + + /* try to load remote based eeprom hash */ + if (!rc->map_name) + rc->map_name = af9015_rc_setup_match(state->eeprom_sum, + af9015_rc_setup_hashes); + + /* try to load remote based USB iManufacturer string */ + if (!rc->map_name && vid == USB_VID_AFATECH) { + /* Check USB manufacturer and product strings and try + to determine correct remote in case of chip vendor + reference IDs are used. + DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ + char manufacturer[10]; + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(d->udev, d->udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + if (!strcmp("MSI", manufacturer)) { + /* iManufacturer 1 MSI + iProduct 2 MSI K-VOX */ + rc->map_name = af9015_rc_setup_match( + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + af9015_rc_setup_modparam); + } + } + + /* load empty to enable rc */ + if (!rc->map_name) + rc->map_name = RC_MAP_EMPTY; + + rc->allowed_protos = RC_TYPE_NEC; + rc->query = af9015_rc_query; + rc->interval = 500; + + return 0; +} + +/* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ +static struct dvb_usb_device_properties af9015_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct af9015_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9015_identify_state, + .firmware = "dvb-usb-af9015.fw", + .download_firmware = af9015_download_firmware, + + .i2c_algo = &af9015_i2c_algo, + .read_config = af9015_read_config, + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .init = af9015_init, + .get_rc_config = af9015_get_rc_config, + .get_stream_config = af9015_get_stream_config, + + .get_adapter_count = af9015_get_adapter_count, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), + }, + }, +}; + +static const struct usb_device_id af9015_id_table[] = { + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, + &af9015_props, "Afatech AF9015 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, + &af9015_props, "Afatech AF9015 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, + &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) }, + { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, + &af9015_props, "Pinnacle PCTV 71e", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, + &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, + &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) }, + { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, + &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, + &af9015_props, "TerraTec Cinergy T USB XE", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, + &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, + &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) }, + { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, + &af9015_props, "Xtensions XD-380", NULL) }, + { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, + &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, + &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) }, + { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, + &af9015_props, "Telestar Starstick 2", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, + &af9015_props, "AVerMedia A309", NULL) }, + { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, + &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, + &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, + &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, + &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, + &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, + &af9015_props, "KWorld Digial MC-810", NULL) }, + { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, + &af9015_props, "Genius TVGo DVB-T03", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, + &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, + &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, + &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, + &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, + &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, + &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, + &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, + &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, + &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, + &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, + &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, + &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) }, + { } +}; +MODULE_DEVICE_TABLE(usb, af9015_id_table); + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9015_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = af9015_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(af9015_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Afatech AF9015 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h new file mode 100644 index 00000000000..c6b304d962a --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -0,0 +1,170 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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 AF9015_H +#define AF9015_H + +#include +#include "dvb_usb.h" +#include "af9013.h" +#include "dvb-pll.h" +#include "mt2060.h" +#include "qt1010.h" +#include "tda18271.h" +#include "mxl5005s.h" +#include "mc44s803.h" +#include "tda18218.h" +#include "mxl5007t.h" + +#define DVB_USB_LOG_PREFIX "af9015" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif + +#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) +#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) + +#undef err +#define err(format, arg...) \ + printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) \ + printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. + We use smaller - about 1/4 from the original, 5 and 87. */ +#define TS_PACKET_SIZE 188 + +#define TS_USB20_PACKET_COUNT 87 +#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) + +#define TS_USB11_PACKET_COUNT 5 +#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) + +#define TS_USB20_MAX_PACKET_SIZE 512 +#define TS_USB11_MAX_PACKET_SIZE 64 + +#define AF9015_I2C_EEPROM 0xa0 +#define AF9015_I2C_DEMOD 0x38 +#define AF9015_USB_TIMEOUT 2000 + +/* EEPROM locations */ +#define AF9015_EEPROM_IR_MODE 0x18 +#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 +#define AF9015_EEPROM_TS_MODE 0x31 +#define AF9015_EEPROM_DEMOD2_I2C 0x32 + +#define AF9015_EEPROM_SAW_BW1 0x35 +#define AF9015_EEPROM_XTAL_TYPE1 0x36 +#define AF9015_EEPROM_SPEC_INV1 0x37 +#define AF9015_EEPROM_IF1L 0x38 +#define AF9015_EEPROM_IF1H 0x39 +#define AF9015_EEPROM_MT2060_IF1L 0x3a +#define AF9015_EEPROM_MT2060_IF1H 0x3b +#define AF9015_EEPROM_TUNER_ID1 0x3c + +#define AF9015_EEPROM_SAW_BW2 0x45 +#define AF9015_EEPROM_XTAL_TYPE2 0x46 +#define AF9015_EEPROM_SPEC_INV2 0x47 +#define AF9015_EEPROM_IF2L 0x48 +#define AF9015_EEPROM_IF2H 0x49 +#define AF9015_EEPROM_MT2060_IF2L 0x4a +#define AF9015_EEPROM_MT2060_IF2H 0x4b +#define AF9015_EEPROM_TUNER_ID2 0x4c + +#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) + +struct req_t { + u8 cmd; /* [0] */ + /* seq */ /* [1] */ + u8 i2c_addr; /* [2] */ + u16 addr; /* [3|4] */ + u8 mbox; /* [5] */ + u8 addr_len; /* [6] */ + u8 data_len; /* [7] */ + u8 *data; +}; + +enum af9015_cmd { + GET_CONFIG = 0x10, + DOWNLOAD_FIRMWARE = 0x11, + BOOT = 0x13, + READ_MEMORY = 0x20, + WRITE_MEMORY = 0x21, + READ_WRITE_I2C = 0x22, + COPY_FIRMWARE = 0x23, + RECONNECT_USB = 0x5a, + WRITE_VIRTUAL_MEMORY = 0x26, + GET_IR_CODE = 0x27, + READ_I2C, + WRITE_I2C, +}; + +enum af9015_ir_mode { + AF9015_IR_MODE_DISABLED = 0, + AF9015_IR_MODE_HID, + AF9015_IR_MODE_RLC, + AF9015_IR_MODE_RC6, + AF9015_IR_MODE_POLLING, /* just guess */ +}; + +struct af9015_state { + u8 ir_mode; + u8 rc_repeat; + u32 rc_keycode; + u8 rc_last[4]; + bool rc_failed; + u8 dual_mode; + u8 seq; /* packet sequence number */ + u16 mt2060_if1[2]; + u16 firmware_size; + u16 firmware_checksum; + u32 eeprom_sum; + struct af9013_config af9013_config[2]; + + /* for demod callback override */ + int (*set_frontend[2]) (struct dvb_frontend *fe); + int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); + int (*init[2]) (struct dvb_frontend *fe); + int (*sleep[2]) (struct dvb_frontend *fe); + int (*tuner_init[2]) (struct dvb_frontend *fe); + int (*tuner_sleep[2]) (struct dvb_frontend *fe); + struct mutex fe_mutex; +}; + +enum af9015_remote { + AF9015_REMOTE_NONE = 0, +/* 1 */ AF9015_REMOTE_A_LINK_DTU_M, + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + AF9015_REMOTE_MYGICTV_U718, + AF9015_REMOTE_DIGITTRADE_DVB_T, +/* 5 */ AF9015_REMOTE_AVERMEDIA_KS, +}; + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c new file mode 100644 index 00000000000..bb90b877d07 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -0,0 +1,1086 @@ +/* + * Afatech AF9035 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "af9035.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static u16 af9035_checksum(const u8 *buf, size_t len) +{ + size_t i; + u16 checksum = 0; + + for (i = 1; i < len; i++) { + if (i % 2) + checksum += buf[i] << 8; + else + checksum += buf[i]; + } + checksum = ~checksum; + + return checksum; +} + +static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) +{ +#define BUF_LEN 64 +#define REQ_HDR_LEN 4 /* send header size */ +#define ACK_HDR_LEN 3 /* rece header size */ +#define CHECKSUM_LEN 2 +#define USB_TIMEOUT 2000 + struct state *state = d_to_priv(d); + int ret, wlen, rlen; + u8 buf[BUF_LEN]; + u16 checksum, tmp_checksum; + + /* buffer overflow check */ + if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || + req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { + pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, + req->wlen, req->rlen); + return -EINVAL; + } + + buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; + buf[1] = req->mbox; + buf[2] = req->cmd; + buf[3] = state->seq++; + memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen); + + wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN; + rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; + + /* calc and add checksum */ + checksum = af9035_checksum(buf, buf[0] - 1); + buf[buf[0] - 1] = (checksum >> 8); + buf[buf[0] - 0] = (checksum & 0xff); + + /* no ack for these packets */ + if (req->cmd == CMD_FW_DL) + rlen = 0; + + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); + if (ret) + goto err; + + /* no ack for those packets */ + if (req->cmd == CMD_FW_DL) + goto exit; + + /* verify checksum */ + checksum = af9035_checksum(buf, rlen - 2); + tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1]; + if (tmp_checksum != checksum) { + pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n", + KBUILD_MODNAME, req->cmd, tmp_checksum, + checksum); + ret = -EIO; + goto err; + } + + /* check status */ + if (buf[2]) { + pr_debug("%s: command=%02x failed fw error=%d\n", __func__, + req->cmd, buf[2]); + ret = -EIO; + goto err; + } + + /* read request, copy returned data to return buf */ + if (req->rlen) + memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); + +exit: + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* write multiple registers */ +static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) +{ + u8 wbuf[6 + len]; + u8 mbox = (reg >> 16) & 0xff; + struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; + + wbuf[0] = len; + wbuf[1] = 2; + wbuf[2] = 0; + wbuf[3] = 0; + wbuf[4] = (reg >> 8) & 0xff; + wbuf[5] = (reg >> 0) & 0xff; + memcpy(&wbuf[6], val, len); + + return af9035_ctrl_msg(d, &req); +} + +/* read multiple registers */ +static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) +{ + u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; + u8 mbox = (reg >> 16) & 0xff; + struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; + + return af9035_ctrl_msg(d, &req); +} + +/* write single register */ +static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) +{ + return af9035_wr_regs(d, reg, &val, 1); +} + +/* read single register */ +static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) +{ + return af9035_rd_regs(d, reg, val, 1); +} + +/* write single register with mask */ +static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = af9035_rd_regs(d, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return af9035_wr_regs(d, reg, &val, 1); +} + +static int af9035_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct state *state = d_to_priv(d); + int ret; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + /* + * I2C sub header is 5 bytes long. Meaning of those bytes are: + * 0: data len + * 1: I2C addr << 1 + * 2: reg addr len + * byte 3 and 4 can be used as reg addr + * 3: reg addr MSB + * used when reg addr len is set to 2 + * 4: reg addr LSB + * used when reg addr len is set to 1 or 2 + * + * For the simplify we do not use register addr at all. + * NOTE: As a firmware knows tuner type there is very small possibility + * there could be some tuner I2C hacks done by firmware and this may + * lead problems if firmware expects those bytes are used. + */ + if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + if (msg[0].len > 40 || msg[1].len > 40) { + /* TODO: correct limits > 40 */ + ret = -EOPNOTSUPP; + } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { + /* integrated demod */ + u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; + ret = af9035_rd_regs(d, reg, &msg[1].buf[0], + msg[1].len); + } else { + /* I2C */ + u8 buf[5 + msg[0].len]; + struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), + buf, msg[1].len, msg[1].buf }; + buf[0] = msg[1].len; + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + ret = af9035_ctrl_msg(d, &req); + } + } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + if (msg[0].len > 40) { + /* TODO: correct limits > 40 */ + ret = -EOPNOTSUPP; + } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { + /* integrated demod */ + u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; + ret = af9035_wr_regs(d, reg, &msg[0].buf[3], + msg[0].len - 3); + } else { + /* I2C */ + u8 buf[5 + msg[0].len]; + struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, + 0, NULL }; + buf[0] = msg[0].len; + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + ret = af9035_ctrl_msg(d, &req); + } + } else { + /* + * We support only two kind of I2C transactions: + * 1) 1 x read + 1 x write + * 2) 1 x write + */ + ret = -EOPNOTSUPP; + } + + mutex_unlock(&d->i2c_mutex); + + if (ret < 0) + return ret; + else + return num; +} + +static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9035_i2c_algo = { + .master_xfer = af9035_i2c_master_xfer, + .functionality = af9035_i2c_functionality, +}; + +static int af9035_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 wbuf[1] = { 1 }; + u8 rbuf[4]; + struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, + sizeof(rbuf), rbuf }; + + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + pr_debug("%s: reply=%*ph\n", __func__, 4, rbuf); + if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) + ret = WARM; + else + ret = COLD; + + return ret; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret, i, j, len; + u8 wbuf[1]; + u8 rbuf[4]; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + u8 hdr_core; + u16 hdr_addr, hdr_data_len, hdr_checksum; + #define MAX_DATA 58 + #define HDR_SIZE 7 + + /* + * Thanks to Daniel Glöckner about that info! + * + * byte 0: MCS 51 core + * There are two inside the AF9035 (1=Link and 2=OFDM) with separate + * address spaces + * byte 1-2: Big endian destination address + * byte 3-4: Big endian number of data bytes following the header + * byte 5-6: Big endian header checksum, apparently ignored by the chip + * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) + */ + + for (i = fw->size; i > HDR_SIZE;) { + hdr_core = fw->data[fw->size - i + 0]; + hdr_addr = fw->data[fw->size - i + 1] << 8; + hdr_addr |= fw->data[fw->size - i + 2] << 0; + hdr_data_len = fw->data[fw->size - i + 3] << 8; + hdr_data_len |= fw->data[fw->size - i + 4] << 0; + hdr_checksum = fw->data[fw->size - i + 5] << 8; + hdr_checksum |= fw->data[fw->size - i + 6] << 0; + + pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", + __func__, hdr_core, hdr_addr, hdr_data_len, + hdr_checksum); + + if (((hdr_core != 1) && (hdr_core != 2)) || + (hdr_data_len > i)) { + pr_debug("%s: bad firmware\n", __func__); + break; + } + + /* download begin packet */ + req.cmd = CMD_FW_DL_BEGIN; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + /* download firmware packet(s) */ + for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { + len = j; + if (len > MAX_DATA) + len = MAX_DATA; + req_fw_dl.wlen = len; + req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + + HDR_SIZE + hdr_data_len - j]; + ret = af9035_ctrl_msg(d, &req_fw_dl); + if (ret < 0) + goto err; + } + + /* download end packet */ + req.cmd = CMD_FW_DL_END; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + i -= hdr_data_len + HDR_SIZE; + + pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); + } + + /* firmware loaded, request boot */ + req.cmd = CMD_FW_BOOT; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + /* ensure firmware starts */ + wbuf[0] = 1; + ret = af9035_ctrl_msg(d, &req_fw_ver); + if (ret < 0) + goto err; + + if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { + pr_err("%s: firmware did not run\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware_it9135(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret, i, i_prev; + u8 wbuf[1]; + u8 rbuf[4]; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + #define HDR_SIZE 7 + + /* + * There seems to be following firmware header. Meaning of bytes 0-3 + * is unknown. + * + * 0: 3 + * 1: 0, 1 + * 2: 0 + * 3: 1, 2, 3 + * 4: addr MSB + * 5: addr LSB + * 6: count of data bytes ? + */ + + for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { + if (i == fw->size || + (fw->data[i + 0] == 0x03 && + (fw->data[i + 1] == 0x00 || + fw->data[i + 1] == 0x01) && + fw->data[i + 2] == 0x00)) { + req_fw_dl.wlen = i - i_prev; + req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; + i_prev = i; + ret = af9035_ctrl_msg(d, &req_fw_dl); + if (ret < 0) + goto err; + + pr_debug("%s: data uploaded=%d\n", __func__, i); + } + } + + /* firmware loaded, request boot */ + req.cmd = CMD_FW_BOOT; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + /* ensure firmware starts */ + wbuf[0] = 1; + ret = af9035_ctrl_msg(d, &req_fw_ver); + if (ret < 0) + goto err; + + if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { + pr_err("%s: firmware did not run\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_read_config(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i, eeprom_shift = 0; + u8 tmp; + u16 tmp16; + + /* check if there is dual tuners */ + ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); + if (ret < 0) + goto err; + + state->dual_mode = tmp; + pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode); + + for (i = 0; i < state->dual_mode + 1; i++) { + /* tuner */ + ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + state->af9033_config[i].tuner = tmp; + pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); + + switch (tmp) { + case AF9033_TUNER_TUA9001: + case AF9033_TUNER_FC0011: + case AF9033_TUNER_MXL5007T: + case AF9033_TUNER_TDA18218: + state->af9033_config[i].spec_inv = 1; + break; + default: + pr_info("%s: tuner ID=%02x not supported, please " \ + "report!", KBUILD_MODNAME, tmp); + }; + + /* tuner IF frequency */ + ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + tmp16 = tmp; + + ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + tmp16 |= tmp << 8; + + pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); + + eeprom_shift = 0x10; /* shift for the 2nd tuner params */ + } + + /* get demod clock */ + ret = af9035_rd_reg(d, 0x00d800, &tmp); + if (ret < 0) + goto err; + + tmp = (tmp >> 0) & 0x0f; + + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) + state->af9033_config[i].clock = clock_lut[tmp]; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_read_config_it9135(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i; + u8 tmp; + + state->dual_mode = false; + + /* get demod clock */ + ret = af9035_rd_reg(d, 0x00d800, &tmp); + if (ret < 0) + goto err; + + tmp = (tmp >> 0) & 0x0f; + + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) + state->af9033_config[i].clock = clock_lut_it9135[tmp]; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + int ret; + + switch (cmd) { + case FC0011_FE_CALLBACK_POWER: + /* Tuner enable */ + ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); + if (ret < 0) + goto err; + + /* LED */ + ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); + if (ret < 0) + goto err; + + usleep_range(10000, 50000); + break; + case FC0011_FE_CALLBACK_RESET: + ret = af9035_wr_reg(d, 0xd8e9, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0xd8e8, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0xd8e7, 1); + if (ret < 0) + goto err; + + usleep_range(10000, 20000); + + ret = af9035_wr_reg(d, 0xd8e7, 0); + if (ret < 0) + goto err; + + usleep_range(10000, 20000); + break; + default: + ret = -EINVAL; + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) +{ + struct state *state = d_to_priv(d); + + switch (state->af9033_config[0].tuner) { + case AF9033_TUNER_FC0011: + return af9035_fc0011_tuner_callback(d, cmd, arg); + default: + break; + } + + return -ENODEV; +} + +static int af9035_frontend_callback(void *adapter_priv, int component, + int cmd, int arg) +{ + struct i2c_adapter *adap = adapter_priv; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + switch (component) { + case DVB_FRONTEND_COMPONENT_TUNER: + return af9035_tuner_callback(d, cmd, arg); + default: + break; + } + + return -EINVAL; +} + +static int af9035_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + + if (!state->af9033_config[adap->id].tuner) { + /* unsupported tuner */ + ret = -ENODEV; + goto err; + } + + if (adap->id == 0) { + state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; + state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; + + ret = af9035_wr_reg(d, 0x00417f, + state->af9033_config[1].i2c_addr); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0x00d81a, + state->dual_mode); + if (ret < 0) + goto err; + } + + /* attach demodulator */ + adap->fe[0] = dvb_attach(af9033_attach, + &state->af9033_config[adap->id], &d->i2c_adap); + if (adap->fe[0] == NULL) { + ret = -ENODEV; + goto err; + } + + /* disable I2C-gate */ + adap->fe[0]->ops.i2c_gate_ctrl = NULL; + adap->fe[0]->callback = af9035_frontend_callback; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static struct tua9001_config af9035_tua9001_config = { + .i2c_addr = 0x60, +}; + +static const struct fc0011_config af9035_fc0011_config = { + .i2c_address = 0x60, +}; + +static struct mxl5007t_config af9035_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_4_57_MHZ, + .invert_if = 0, + .loop_thru_enable = 0, + .clk_out_enable = 0, + .clk_out_amp = MxL_CLKOUT_AMP_0_94V, +}; + +static struct tda18218_config af9035_tda18218_config = { + .i2c_address = 0x60, + .i2c_wr_max = 21, +}; + +static int af9035_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + struct dvb_frontend *fe; + + switch (state->af9033_config[adap->id].tuner) { + case AF9033_TUNER_TUA9001: + /* AF9035 gpiot3 = TUA9001 RESETN + AF9035 gpiot2 = TUA9001 RXEN */ + + /* configure gpiot2 and gpiot2 as output */ + ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01); + if (ret < 0) + goto err; + + /* reset tuner */ + ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01); + if (ret < 0) + goto err; + + usleep_range(2000, 20000); + + ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01); + if (ret < 0) + goto err; + + /* activate tuner RX */ + /* TODO: use callback for TUA9001 RXEN */ + ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01); + if (ret < 0) + goto err; + + /* attach tuner */ + fe = dvb_attach(tua9001_attach, adap->fe[0], + &d->i2c_adap, &af9035_tua9001_config); + break; + case AF9033_TUNER_FC0011: + fe = dvb_attach(fc0011_attach, adap->fe[0], + &d->i2c_adap, &af9035_fc0011_config); + break; + case AF9033_TUNER_MXL5007T: + ret = af9035_wr_reg(d, 0x00d8e0, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8e1, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8df, 0); + if (ret < 0) + goto err; + + msleep(30); + + ret = af9035_wr_reg(d, 0x00d8df, 1); + if (ret < 0) + goto err; + + msleep(300); + + ret = af9035_wr_reg(d, 0x00d8c0, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8c1, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8bf, 0); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8b4, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8b5, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8b3, 1); + if (ret < 0) + goto err; + + /* attach tuner */ + fe = dvb_attach(mxl5007t_attach, adap->fe[0], + &d->i2c_adap, 0x60, &af9035_mxl5007t_config); + break; + case AF9033_TUNER_TDA18218: + /* attach tuner */ + fe = dvb_attach(tda18218_attach, adap->fe[0], + &d->i2c_adap, &af9035_tda18218_config); + break; + default: + fe = NULL; + } + + if (fe == NULL) { + ret = -ENODEV; + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_init(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i; + u16 frame_size = 87 * 188 / 4; + u8 packet_size = 512 / 4; + struct reg_val_mask tab[] = { + { 0x80f99d, 0x01, 0x01 }, + { 0x80f9a4, 0x01, 0x01 }, + { 0x00dd11, 0x00, 0x20 }, + { 0x00dd11, 0x00, 0x40 }, + { 0x00dd13, 0x00, 0x20 }, + { 0x00dd13, 0x00, 0x40 }, + { 0x00dd11, 0x20, 0x20 }, + { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0c, packet_size, 0xff}, + { 0x00dd11, state->dual_mode << 6, 0x40 }, + { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0d, packet_size, 0xff }, + { 0x80f9a3, 0x00, 0x01 }, + { 0x80f9cd, 0x00, 0x01 }, + { 0x80f99d, 0x00, 0x01 }, + { 0x80f9a4, 0x00, 0x01 }, + }; + + pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", + __func__, d->udev->speed, frame_size, packet_size); + + /* init endpoints */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret < 0) + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_rc_query(struct dvb_usb_device *d) +{ + unsigned int key; + unsigned char b[4]; + int ret; + struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; + + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + if ((b[2] + b[3]) == 0xff) { + if ((b[0] + b[1]) == 0xff) { + /* NEC */ + key = b[0] << 8 | b[2]; + } else { + /* ext. NEC */ + key = b[0] << 16 | b[1] << 8 | b[2]; + } + } else { + key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; + } + + rc_keydown(d->rc_dev, key, 0); + +err: + /* ignore errors */ + return 0; +} + +static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + int ret; + u8 tmp; + + ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); + if (ret < 0) + goto err; + + pr_debug("%s: ir_mode=%02x\n", __func__, tmp); + + /* don't activate rc if in HID mode or if not available */ + if (tmp == 5) { + ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); + if (ret < 0) + goto err; + + pr_debug("%s: ir_type=%02x\n", __func__, tmp); + + switch (tmp) { + case 0: /* NEC */ + default: + rc->allowed_protos = RC_TYPE_NEC; + break; + case 1: /* RC6 */ + rc->allowed_protos = RC_TYPE_RC6; + break; + } + + rc->query = af9035_rc_query; + rc->interval = 500; + + /* load empty to enable rc */ + if (!rc->map_name) + rc->map_name = RC_MAP_EMPTY; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ +static const struct dvb_usb_device_properties af9035_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9035_identify_state, + .firmware = "dvb-usb-af9035-02.fw", + .download_firmware = af9035_download_firmware, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config, + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .init = af9035_init, + .get_rc_config = af9035_get_rc_config, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), + }, + }, +}; + +static const struct dvb_usb_device_properties it9135_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9035_identify_state, + .firmware = "dvb-usb-it9135-01.fw", + .download_firmware = af9035_download_firmware_it9135, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config_it9135, + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .init = af9035_init, + .get_rc_config = af9035_get_rc_config, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), + }, + }, +}; + +static const struct usb_device_id af9035_id_table[] = { + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK, + &af9035_props, "TerraTec Cinergy T Stick", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835, + &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835, + &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR, + &af9035_props, "AVerMedia Twinstar (A825)", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, af9035_id_table); + +static struct usb_driver af9035_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = af9035_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(af9035_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Afatech AF9035 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h new file mode 100644 index 00000000000..59ff69ede0f --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -0,0 +1,111 @@ +/* + * Afatech AF9035 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9035_H +#define AF9035_H + +#include "dvb_usb.h" +#include "af9033.h" +#include "tua9001.h" +#include "fc0011.h" +#include "mxl5007t.h" +#include "tda18218.h" + +struct reg_val { + u32 reg; + u8 val; +}; + +struct reg_val_mask { + u32 reg; + u8 val; + u8 mask; +}; + +struct usb_req { + u8 cmd; + u8 mbox; + u8 wlen; + u8 *wbuf; + u8 rlen; + u8 *rbuf; +}; + +struct state { + u8 seq; /* packet sequence number */ + bool dual_mode; + + struct af9033_config af9033_config[2]; +}; + +u32 clock_lut[] = { + 20480000, /* FPGA */ + 16384000, /* 16.38 MHz */ + 20480000, /* 20.48 MHz */ + 36000000, /* 36.00 MHz */ + 30000000, /* 30.00 MHz */ + 26000000, /* 26.00 MHz */ + 28000000, /* 28.00 MHz */ + 32000000, /* 32.00 MHz */ + 34000000, /* 34.00 MHz */ + 24000000, /* 24.00 MHz */ + 22000000, /* 22.00 MHz */ + 12000000, /* 12.00 MHz */ +}; + +u32 clock_lut_it9135[] = { + 12000000, /* 12.00 MHz */ + 20480000, /* 20.48 MHz */ + 36000000, /* 36.00 MHz */ + 30000000, /* 30.00 MHz */ + 26000000, /* 26.00 MHz */ + 28000000, /* 28.00 MHz */ + 32000000, /* 32.00 MHz */ + 34000000, /* 34.00 MHz */ + 24000000, /* 24.00 MHz */ + 22000000, /* 22.00 MHz */ +}; + +/* EEPROM locations */ +#define EEPROM_IR_MODE 0x430d +#define EEPROM_DUAL_MODE 0x4326 +#define EEPROM_IR_TYPE 0x4329 +#define EEPROM_1_IFFREQ_L 0x432d +#define EEPROM_1_IFFREQ_H 0x432e +#define EEPROM_1_TUNER_ID 0x4331 +#define EEPROM_2_IFFREQ_L 0x433d +#define EEPROM_2_IFFREQ_H 0x433e +#define EEPROM_2_TUNER_ID 0x4341 + +/* USB commands */ +#define CMD_MEM_RD 0x00 +#define CMD_MEM_WR 0x01 +#define CMD_I2C_RD 0x02 +#define CMD_I2C_WR 0x03 +#define CMD_IR_GET 0x18 +#define CMD_FW_DL 0x21 +#define CMD_FW_QUERYINFO 0x22 +#define CMD_FW_BOOT 0x23 +#define CMD_FW_DL_BEGIN 0x24 +#define CMD_FW_DL_END 0x25 +#define CMD_FW_SCATTER_WR 0x29 + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c new file mode 100644 index 00000000000..fb3829a73d2 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -0,0 +1,1324 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * 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. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#include "anysee.h" +#include "dvb-pll.h" +#include "tda1002x.h" +#include "mt352.h" +#include "mt352_priv.h" +#include "zl10353.h" +#include "tda18212.h" +#include "cx24116.h" +#include "stv0900.h" +#include "stv6110.h" +#include "isl6423.h" +#include "cxd2820r.h" + +/* debug */ +static int dvb_usb_anysee_debug; +module_param_named(debug, dvb_usb_anysee_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static DEFINE_MUTEX(anysee_usb_mutex); + +static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, + u8 *rbuf, u8 rlen) +{ + struct anysee_state *state = d_to_priv(d); + int act_len, ret, i; + u8 buf[64]; + + memcpy(&buf[0], sbuf, slen); + buf[60] = state->seq++; + + mutex_lock(&anysee_usb_mutex); + + deb_xfer(">>> "); + debug_dump(buf, slen, deb_xfer); + + /* We need receive one message more after dvb_usb_generic_rw due + to weird transaction flow, which is 1 x send + 2 x receive. */ + ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf)); + if (ret) + goto error_unlock; + + /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 + * (EPIPE, Broken pipe). Function supports currently msleep() as a + * parameter but I would not like to use it, since according to + * Documentation/timers/timers-howto.txt it should not be used such + * short, under < 20ms, sleeps. Repeating failed message would be + * better choice as not to add unwanted delays... + * Fixing that correctly is one of those or both; + * 1) use repeat if possible + * 2) add suitable delay + */ + + /* get answer, retry few times if error returned */ + for (i = 0; i < 3; i++) { + /* receive 2nd answer */ + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf), + &act_len, 2000); + + if (ret) { + deb_info("%s: recv bulk message failed: %d", + __func__, ret); + } else { + deb_xfer("<<< "); + debug_dump(buf, rlen, deb_xfer); + + if (buf[63] != 0x4f) + deb_info("%s: cmd failed\n", __func__); + + break; + } + } + + if (ret) { + /* all retries failed, it is fatal */ + err("%s: recv bulk message failed: %d", __func__, ret); + goto error_unlock; + } + + /* read request, copy returned data to return buf */ + if (rbuf && rlen) + memcpy(rbuf, buf, rlen); + +error_unlock: + mutex_unlock(&anysee_usb_mutex); + + return ret; +} + +static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +{ + u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; + int ret; + ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); + return ret; +} + +static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) +{ + u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +/* write single register with mask */ +static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return anysee_write_reg(d, reg, val); +} + +/* read single register with mask */ +static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, + u8 mask) +{ + int ret, i; + u8 tmp; + + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) +{ + u8 buf[] = {CMD_GET_HW_INFO}; + return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); +} + +static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0); +} + +static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; + deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +/* I2C */ +static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, inc, i = 0; + u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */ + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].len > 2 || msg[i+1].len > 60) { + ret = -EOPNOTSUPP; + break; + } + buf[0] = CMD_I2C_READ; + buf[1] = (msg[i].addr << 1) | 0x01; + buf[2] = msg[i].buf[0]; + buf[3] = msg[i].buf[1]; + buf[4] = msg[i].len-1; + buf[5] = msg[i+1].len; + ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf, + msg[i+1].len); + inc = 2; + } else { + if (msg[i].len > 48) { + ret = -EOPNOTSUPP; + break; + } + buf[0] = CMD_I2C_WRITE; + buf[1] = (msg[i].addr << 1); + buf[2] = msg[i].len; + buf[3] = 0x01; + memcpy(&buf[4], msg[i].buf, msg[i].len); + ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0); + inc = 1; + } + if (ret) + break; + + i += inc; + } + + mutex_unlock(&d->i2c_mutex); + + return ret ? ret : i; +} + +static u32 anysee_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm anysee_i2c_algo = { + .master_xfer = anysee_master_xfer, + .functionality = anysee_i2c_func, +}; + +static int anysee_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +/* Callbacks for DVB USB */ +static struct tda10023_config anysee_tda10023_config = { + .demod_address = (0x1a >> 1), + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .deltaf = 0xfeeb, +}; + +static struct mt352_config anysee_mt352_config = { + .demod_address = (0x1e >> 1), + .demod_init = anysee_mt352_demod_init, +}; + +static struct zl10353_config anysee_zl10353_config = { + .demod_address = (0x1e >> 1), + .parallel_ts = 1, +}; + +static struct zl10353_config anysee_zl10353_tda18212_config2 = { + .demod_address = (0x1e >> 1), + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .if2 = 41500, +}; + +static struct zl10353_config anysee_zl10353_tda18212_config = { + .demod_address = (0x18 >> 1), + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .if2 = 41500, +}; + +static struct tda10023_config anysee_tda10023_tda18212_config = { + .demod_address = (0x1a >> 1), + .xtal = 16000000, + .pll_m = 12, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, + .deltaf = 0xba02, +}; + +static struct tda18212_config anysee_tda18212_config = { + .i2c_address = (0xc0 >> 1), + .if_dvbt_6 = 4150, + .if_dvbt_7 = 4150, + .if_dvbt_8 = 4150, + .if_dvbc = 5000, +}; + +static struct tda18212_config anysee_tda18212_config2 = { + .i2c_address = 0x60 /* (0xc0 >> 1) */, + .if_dvbt_6 = 3550, + .if_dvbt_7 = 3700, + .if_dvbt_8 = 4150, + .if_dvbt2_6 = 3250, + .if_dvbt2_7 = 4000, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, +}; + +static struct cx24116_config anysee_cx24116_config = { + .demod_address = (0xaa >> 1), + .mpg_clk_pos_pol = 0x00, + .i2c_wr_max = 48, +}; + +static struct stv0900_config anysee_stv0900_config = { + .demod_address = (0xd0 >> 1), + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1, /* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config anysee_stv6110_config = { + .i2c_address = (0xc0 >> 1), + .mclk = 16000000, + .clk_div = 1, +}; + +static struct isl6423_config anysee_isl6423_config = { + .current_max = SEC_CURRENT_800m, + .curlim = SEC_CURRENT_LIM_OFF, + .mod_extern = 1, + .addr = (0x10 >> 1), +}; + +static struct cxd2820r_config anysee_cxd2820r_config = { + .i2c_address = 0x6d, /* (0xda >> 1) */ + .ts_mode = 0x38, +}; + +/* + * New USB device strings: Mfr=1, Product=2, SerialNumber=0 + * Manufacturer: AMT.CO.KR + * + * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=???????? + * PCB: ? + * parts: DNOS404ZH102A(MT352, DTT7579(?)) + * + * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)" + * PCB: PCB 507T (rev1.61) + * parts: DNOS404ZH103A(ZL10353, DTT7579(?)) + * OEA=0a OEB=00 OEC=00 OED=ff OEE=00 + * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00 + * + * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee" + * PCB: 507CD (rev1.1) + * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01 + * IOD[0] ZL10353 1=enabled + * IOA[7] TS 0=enabled + * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not) + * + * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)" + * PCB: 507DC (rev0.2) + * parts: TDA10023, DTOS403IH102B TM, CST56I01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01 + * IOD[0] TDA10023 1=enabled + * + * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)" + * PCB: 507SI (rev2.1) + * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe + * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01 + * IOD[0] CX24116 1=enabled + * + * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" + * PCB: 507FA (rev0.4) + * parts: TDA10023, DTOS403IH102B TM, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 + * IOD[5] TDA10023 1=enabled + * IOE[0] tuner 1=enabled + * + * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" + * PCB: 507FA (rev1.1) + * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 + * DVB-C: + * IOD[5] TDA10023 1=enabled + * IOE[0] tuner 1=enabled + * DVB-T: + * IOD[0] ZL10353 1=enabled + * IOE[0] tuner 0=enabled + * tuner is behind ZL10353 I2C-gate + * + * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" + * PCB: 508TC (rev0.6) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)" + * PCB: 508S2 (rev0.7) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + * + * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" + * PCB: 508T2C (rev0.3) + * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] CXD2820R 1=enabled + * + * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" + * PCB: 508PTC (rev0.5) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * PCB: 508PS2 (rev0.4) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + */ + +static int anysee_read_config(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + int ret; + u8 hw_info[3]; + + /* + * Check which hardware we have. + * We must do this call two times to get reliable values (hw/fw bug). + */ + ret = anysee_get_hw_info(d, hw_info); + if (ret) + goto error; + + ret = anysee_get_hw_info(d, hw_info); + if (ret) + goto error; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d hardware id:%d", + hw_info[1], hw_info[2], hw_info[0]); + + state->hw = hw_info[0]; +error: + return ret; +} + +/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ +static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + /* enable / disable tuner access on IOE[4] */ + return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10); +} + +static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct anysee_state *state = fe_to_priv(fe); + struct dvb_usb_device *d = fe_to_d(fe); + int ret; + + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + /* no frontend sleep control */ + if (onoff == 0) + return 0; + + switch (state->hw) { + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + if (fe->id == 0) { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-C tuner on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* enable DVB-T tuner on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); + if (ret) + goto error; + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + if (fe->id == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); + if (ret) + goto error; + } + + break; + default: + ret = 0; + } + +error: + return ret; +} + +static int anysee_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct anysee_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + u8 tmp; + struct i2c_msg msg[2] = { + { + .addr = anysee_tda18212_config.i2c_address, + .flags = 0, + .len = 1, + .buf = "\x00", + }, { + .addr = anysee_tda18212_config.i2c_address, + .flags = I2C_M_RD, + .len = 1, + .buf = &tmp, + } + }; + + switch (state->hw) { + case ANYSEE_HW_507T: /* 2 */ + /* E30 */ + + /* attach demod */ + adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, + &d->i2c_adap); + if (adap->fe[0]) + break; + + /* attach demod */ + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &d->i2c_adap); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* enable transport stream on IOA[7] */ + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &d->i2c_adap); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* enable DVB-C demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_config, &d->i2c_adap, 0x48); + + break; + case ANYSEE_HW_507SI: /* 11 */ + /* E30 S2 Plus */ + + /* enable DVB-S/S2 demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, + &d->i2c_adap); + + break; + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + /* enable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10); + if (ret) + goto error; + + /* probe TDA18212 */ + tmp = 0; + ret = i2c_transfer(&d->i2c_adap, msg, 2); + if (ret == 2 && tmp == 0xc7) + deb_info("%s: TDA18212 found\n", __func__); + else + tmp = 0; + + /* disable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10); + if (ret) + goto error; + + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &d->i2c_adap, 0x48); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[0]) + adap->fe[0]->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } else { + /* PLL config */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_config, + &d->i2c_adap, 0x48); + } + + /* break out if first frontend attaching fails */ + if (!adap->fe[0]) + break; + + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config2, + &d->i2c_adap); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[1]) + adap->fe[1]->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } else { + /* PLL config */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_config, + &d->i2c_adap); + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &d->i2c_adap, 0x48); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[0]) + adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; + + /* break out if first frontend attaching fails */ + if (!adap->fe[0]) + break; + + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); + if (ret) + goto error; + + /* attach demod */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &d->i2c_adap); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[1]) + adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; + + state->has_ci = true; + + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ + /* E7 S2 */ + /* E7 PS2 */ + + /* enable DVB-S/S2 demod on IOE[5] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(stv0900_attach, + &anysee_stv0900_config, &d->i2c_adap, 0); + + state->has_ci = true; + + break; + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* enable DVB-T/T2/C demod on IOE[5] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(cxd2820r_attach, + &anysee_cxd2820r_config, &d->i2c_adap); + + state->has_ci = true; + + break; + } + + if (!adap->fe[0]) { + /* we have no frontend :-( */ + ret = -ENODEV; + err("Unsupported Anysee version. " \ + "Please report the ."); + } +error: + return ret; +} + +static int anysee_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct anysee_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + struct dvb_frontend *fe; + int ret; + deb_info("%s: adap=%d\n", __func__, adap->id); + + switch (state->hw) { + case ANYSEE_HW_507T: /* 2 */ + /* E30 */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, + DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), + &d->i2c_adap, DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + break; + case ANYSEE_HW_507SI: /* 11 */ + /* E30 S2 Plus */ + + /* attach LNB controller */ + fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap, + &anysee_isl6423_config); + + break; + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + /* Try first attach TDA18212 silicon tuner on IOE[4], if that + * fails attach old simple PLL. */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(tda18212_attach, adap->fe[1], + &d->i2c_adap, &anysee_tda18212_config); + break; + } else if (fe) { + break; + } + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], + (0xc0 >> 1), &d->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config); + + if (fe) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(tda18212_attach, adap->fe[1], + &d->i2c_adap, &anysee_tda18212_config); + } + + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ + /* E7 S2 */ + /* E7 PS2 */ + + /* attach tuner */ + fe = dvb_attach(stv6110_attach, adap->fe[0], + &anysee_stv6110_config, &d->i2c_adap); + + if (fe) { + /* attach LNB controller */ + fe = dvb_attach(isl6423_attach, adap->fe[0], + &d->i2c_adap, &anysee_isl6423_config); + } + + break; + + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config2); + + break; + default: + fe = NULL; + } + + if (fe) + ret = 0; + else + ret = -ENODEV; + + return ret; +} + +static int anysee_rc_query(struct dvb_usb_device *d) +{ + u8 buf[] = {CMD_GET_IR_CODE}; + u8 ircode[2]; + int ret; + + /* Remote controller is basic NEC using address byte 0x08. + Anysee device RC query returns only two bytes, status and code, + address byte is dropped. Also it does not return any value for + NEC RCs having address byte other than 0x08. Due to that, we + cannot use that device as standard NEC receiver. + It could be possible make hack which reads whole code directly + from device memory... */ + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode)); + if (ret) + return ret; + + if (ircode[0]) { + deb_rc("%s: key pressed %02x\n", __func__, ircode[1]); + rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0); + } + + return 0; +} + +static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + rc->allowed_protos = RC_TYPE_NEC; + rc->query = anysee_rc_query; + rc->interval = 250; /* windows driver uses 500ms */ + + return 0; +} + +static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + struct anysee_state *state = d_to_priv(d); + + state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(300); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(30); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, + int open) +{ + struct dvb_usb_device *d = ci->data; + struct anysee_state *state = d_to_priv(d); + int ret; + u8 tmp; + + ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); + if (ret) + return ret; + + if (tmp == 0) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT; + if (time_after(jiffies, state->ci_cam_ready)) + ret |= DVB_CA_EN50221_POLL_CAM_READY; + } + + return ret; +} + +static int anysee_ci_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + int ret; + + state->ci.owner = THIS_MODULE; + state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; + state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; + state->ci.read_cam_control = anysee_ci_read_cam_control; + state->ci.write_cam_control = anysee_ci_write_cam_control; + state->ci.slot_reset = anysee_ci_slot_reset; + state->ci.slot_shutdown = anysee_ci_slot_shutdown; + state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; + state->ci.poll_slot_status = anysee_ci_poll_slot_status; + state->ci.data = d; + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07); + if (ret) + return ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07); + if (ret) + return ret; + + ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); + if (ret) + return ret; + + return 0; +} + +static void anysee_ci_release(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + + /* detach CI */ + if (state->has_ci) + dvb_ca_en50221_release(&state->ci); + + return; +} + +static int anysee_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + int ret; + + /* There is one interface with two alternate settings. + Alternate setting 0 is for bulk transfer. + Alternate setting 1 is for isochronous transfer. + We use bulk transfer (alternate setting 0). */ + ret = usb_set_interface(d->udev, 0, 0); + if (ret) + return ret; + + /* LED light */ + ret = anysee_led_ctrl(d, 0x01, 0x03); + if (ret) + return ret; + + /* enable IR */ + ret = anysee_ir_ctrl(d, 1); + if (ret) + return ret; + + /* attach CI */ + if (state->has_ci) { + ret = anysee_ci_init(d); + if (ret) { + state->has_ci = false; + return ret; + } + } + + return 0; +} + +static void anysee_exit(struct dvb_usb_device *d) +{ + return anysee_ci_release(d); +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties anysee_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct anysee_state), + + .generic_bulk_ctrl_endpoint = 0x01, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &anysee_i2c_algo, + .read_config = anysee_read_config, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, + .init = anysee_init, + .get_rc_config = anysee_get_rc_config, + .frontend_ctrl = anysee_frontend_ctrl, + .streaming_ctrl = anysee_streaming_ctrl, + .exit = anysee_exit, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512), + } + } +}; + +static const struct usb_device_id anysee_id_table[] = { + { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE, + &anysee_props, "Anysee", RC_MAP_ANYSEE) }, + { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE, + &anysee_props, "Anysee", RC_MAP_ANYSEE) }, + { } +}; +MODULE_DEVICE_TABLE(usb, anysee_id_table); + +static struct usb_driver anysee_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = anysee_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(anysee_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h new file mode 100644 index 00000000000..dc40dcf7c32 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/anysee.h @@ -0,0 +1,356 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * 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. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#ifndef _DVB_USB_ANYSEE_H_ +#define _DVB_USB_ANYSEE_H_ + +#define DVB_USB_LOG_PREFIX "anysee" +#include "dvb_usb.h" +#include "dvb_ca_en50221.h" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b, l, func) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif + +#define debug_dump(b, l, func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + +#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) + +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +enum cmd { + CMD_I2C_READ = 0x33, + CMD_I2C_WRITE = 0x31, + CMD_REG_READ = 0xb0, + CMD_REG_WRITE = 0xb1, + CMD_STREAMING_CTRL = 0x12, + CMD_LED_AND_IR_CTRL = 0x16, + CMD_GET_IR_CODE = 0x41, + CMD_GET_HW_INFO = 0x19, + CMD_SMARTCARD = 0x34, + CMD_CI = 0x37, +}; + +struct anysee_state { + u8 hw; /* PCB ID */ + u8 seq; + u8 fe_id:1; /* frondend ID */ + u8 has_ci:1; + struct dvb_ca_en50221 ci; + unsigned long ci_cam_ready; /* jiffies */ +}; + +#define ANYSEE_HW_507T 2 /* E30 */ +#define ANYSEE_HW_507CD 6 /* E30 Plus */ +#define ANYSEE_HW_507DC 10 /* E30 C Plus */ +#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ +#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ +#define ANYSEE_HW_508TC 18 /* E7 TC */ +#define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_508T2C 20 /* E7 T2C */ +#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ +#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ + +#define REG_IOA 0x80 /* Port A (bit addressable) */ +#define REG_IOB 0x90 /* Port B (bit addressable) */ +#define REG_IOC 0xa0 /* Port C (bit addressable) */ +#define REG_IOD 0xb0 /* Port D (bit addressable) */ +#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */ +#define REG_OEA 0xb2 /* Port A Output Enable */ +#define REG_OEB 0xb3 /* Port B Output Enable */ +#define REG_OEC 0xb4 /* Port C Output Enable */ +#define REG_OED 0xb5 /* Port D Output Enable */ +#define REG_OEE 0xb6 /* Port E Output Enable */ + +#endif + +/*************************************************************************** + * USB API description (reverse engineered) + *************************************************************************** + +Transaction flow: +================= +BULK[00001] >>> REQUEST PACKET 64 bytes +BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) +BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) + +General reply packet(s) are always used if not own reply defined. + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) +============================================================================ +| 00 | reply data (if any) from previous transaction +| | Just same reply packet as returned during previous transaction. +| | Needed only if reply is missed in previous transaction. +| | Just skip normally. +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) +============================================================================ +| 00 | reply data (if any) +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C WRITE REQUEST PACKET +============================================================================ +| 00 | 0x31 I2C write command +---------------------------------------------------------------------------- +| 01 | i2c address +---------------------------------------------------------------------------- +| 02 | data length +| | 0x02 (for typical I2C reg / val pair) +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04- | data +---------------------------------------------------------------------------- +| -59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C READ REQUEST PACKET +============================================================================ +| 00 | 0x33 I2C read command +---------------------------------------------------------------------------- +| 01 | i2c address + 1 +---------------------------------------------------------------------------- +| 02 | register +---------------------------------------------------------------------------- +| 03 | 0x00 +---------------------------------------------------------------------------- +| 04 | 0x00 +---------------------------------------------------------------------------- +| 05 | data length +---------------------------------------------------------------------------- +| 06-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET +============================================================================ +| 00 | 0xb1 register write command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04 | value +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET +============================================================================ +| 00 | 0xb0 register read command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | LED CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x01 (LED) +---------------------------------------------------------------------------- +| 03 | 0x00 blink +| | 0x01 lights continuously +---------------------------------------------------------------------------- +| 04 | blink interval +| | 0x00 fastest (looks like LED lights continuously) +| | 0xff slowest +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | IR CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x02 (IR) +---------------------------------------------------------------------------- +| 03 | 0x00 IR disabled +| | 0x01 IR enabled +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | STREAMING CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x12 streaming control command +---------------------------------------------------------------------------- +| 01 | 0x00 streaming disabled +| | 0x01 streaming enabled +---------------------------------------------------------------------------- +| 02 | 0x00 +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x41 remote control command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REPLY PACKET +============================================================================ +| 00 | 0x00 code not received +| | 0x01 code received +---------------------------------------------------------------------------- +| 01 | remote control code +---------------------------------------------------------------------------- +| 02-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REQUEST PACKET +============================================================================ +| 00 | 0x19 get hardware info command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REPLY PACKET +============================================================================ +| 00 | hardware id +---------------------------------------------------------------------------- +| 01-02 | firmware version +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | SMART CARD READER PACKET +============================================================================ +| 00 | 0x34 smart card reader command +---------------------------------------------------------------------------- +| xx | +---------------------------------------------------------------------------- +| xx-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +*/ diff --git a/drivers/media/usb/dvb-usb-v2/au6610.c b/drivers/media/usb/dvb-usb-v2/au6610.c new file mode 100644 index 00000000000..05f2a862814 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/au6610.c @@ -0,0 +1,206 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari + * + * 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 "au6610.h" +#include "zl10353.h" +#include "qt1010.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + int ret; + u16 index; + u8 *usb_buf; + + /* + * allocate enough for all known requests, + * read returns 5 and write 6 bytes + */ + usb_buf = kmalloc(6, GFP_KERNEL); + if (!usb_buf) + return -ENOMEM; + + switch (wlen) { + case 1: + index = wbuf[0] << 8; + break; + case 2: + index = wbuf[0] << 8; + index += wbuf[1]; + break; + default: + pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen); + ret = -EINVAL; + goto error; + } + + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, + USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, + usb_buf, 6, AU6610_USB_TIMEOUT); + if (ret < 0) + goto error; + + switch (operation) { + case AU6610_REQ_I2C_READ: + case AU6610_REQ_USB_READ: + /* requested value is always 5th byte in buffer */ + rbuf[0] = usb_buf[4]; + } +error: + kfree(usb_buf); + return ret; +} + +static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 request; + u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ + + if (wo) { + request = AU6610_REQ_I2C_WRITE; + } else { /* rw */ + request = AU6610_REQ_I2C_READ; + } + + return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); +} + + +/* I2C */ +static int au6610_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 (au6610_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 (au6610_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 au6610_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm au6610_i2c_algo = { + .master_xfer = au6610_i2c_xfer, + .functionality = au6610_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config au6610_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -ENODEV; + + return 0; +} + +static struct qt1010_config au6610_qt1010_config = { + .i2c_address = 0x62 +}; + +static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &au6610_qt1010_config) == NULL ? -ENODEV : 0; +} + +static int au6610_init(struct dvb_usb_device *d) +{ + /* TODO: this functionality belongs likely to the streaming control */ + /* bInterfaceNumber 0, bAlternateSetting 5 */ + return usb_set_interface(d->udev, 0, 5); +} + +static struct dvb_usb_device_properties au6610_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + + .i2c_algo = &au6610_i2c_algo, + .frontend_attach = au6610_zl10353_frontend_attach, + .tuner_attach = au6610_qt1010_tuner_attach, + .init = au6610_init, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1), + }, + }, +}; + +static const struct usb_device_id au6610_id_table[] = { + { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110, + &au6610_props, "Sigmatek DVB-110", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, au6610_id_table); + +static struct usb_driver au6610_driver = { + .name = KBUILD_MODNAME, + .id_table = au6610_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(au6610_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/au6610.h b/drivers/media/usb/dvb-usb-v2/au6610.h new file mode 100644 index 00000000000..ea337bfc00b --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/au6610.h @@ -0,0 +1,32 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari + * + * 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 AU6610_H +#define AU6610_H +#include "dvb_usb.h" + +#define AU6610_REQ_I2C_WRITE 0x14 +#define AU6610_REQ_I2C_READ 0x13 +#define AU6610_REQ_USB_WRITE 0x16 +#define AU6610_REQ_USB_READ 0x15 + +#define AU6610_USB_TIMEOUT 1000 + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c new file mode 100644 index 00000000000..54f1221d930 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -0,0 +1,919 @@ +/* + * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones + * + * Copyright (c) Henry Wang + * + * This driver was made publicly available by Terratec, at: + * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz + * The original driver's license is GPL, as declared with MODULE_LICENSE() + * + * Copyright (c) 2010-2012 Mauro Carvalho Chehab + * Driver modified by in order to work with upstream drxk driver, and + * tons of bugs got fixed, and converted to use dvb-usb-v2. + * + * 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 under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "drxk.h" +#include "mt2063.h" +#include "dvb_ca_en50221.h" +#include "dvb_usb.h" +#include "cypress_firmware.h" + +#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw" + +static int az6007_xfer_debug; +module_param_named(xfer_debug, az6007_xfer_debug, int, 0644); +MODULE_PARM_DESC(xfer_debug, "Enable xfer debug"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/ + +#define FX2_OED 0xb5 +#define AZ6007_READ_DATA 0xb7 +#define AZ6007_I2C_RD 0xb9 +#define AZ6007_POWER 0xbc +#define AZ6007_I2C_WR 0xbd +#define FX2_SCON1 0xc0 +#define AZ6007_TS_THROUGH 0xc7 +#define AZ6007_READ_IR 0xb4 + +struct az6007_device_state { + struct mutex mutex; + struct mutex ca_mutex; + struct dvb_ca_en50221 ca; + unsigned warm:1; + int (*gate_ctrl) (struct dvb_frontend *, int); + unsigned char data[4096]; +}; + +static struct drxk_config terratec_h7_drxk = { + .adr = 0x29, + .parallel_ts = true, + .dynamic_clk = true, + .single_master = true, + .enable_merr_cfg = true, + .no_i2c_bridge = false, + .chunk_size = 64, + .mpeg_out_clk_strength = 0x02, + .qam_demod_parameter_count = 2, + .microcode_name = "dvb-usb-terratec-h7-drxk.fw", +}; + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct az6007_device_state *st = fe_to_priv(fe); + struct dvb_usb_adapter *adap = fe->sec_priv; + int status = 0; + + pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable"); + + if (!adap || !st) + return -EINVAL; + + if (enable) + status = st->gate_ctrl(fe, 1); + else + status = st->gate_ctrl(fe, 0); + + return status; +} + +static struct mt2063_config az6007_mt2063_config = { + .tuner_address = 0x60, + .refclock = 36125000, +}; + +static int __az6007_read(struct usb_device *udev, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, b, blen, 5000); + if (ret < 0) { + pr_warn("usb read operation failed. (%d)\n", ret); + return -EIO; + } + + if (az6007_xfer_debug) { + printk(KERN_DEBUG "az6007: IN req: %02x, value: %04x, index: %04x\n", + req, value, index); + print_hex_dump_bytes("az6007: payload: ", + DUMP_PREFIX_NONE, b, blen); + } + + return ret; +} + +static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + struct az6007_device_state *st = d->priv; + int ret; + + if (mutex_lock_interruptible(&st->mutex) < 0) + return -EAGAIN; + + ret = __az6007_read(d->udev, req, value, index, b, blen); + + mutex_unlock(&st->mutex); + + return ret; +} + +static int __az6007_write(struct usb_device *udev, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + if (az6007_xfer_debug) { + printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n", + req, value, index); + print_hex_dump_bytes("az6007: payload: ", + DUMP_PREFIX_NONE, b, blen); + } + + if (blen > 64) { + pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", + blen); + return -EOPNOTSUPP; + } + + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, b, blen, 5000); + if (ret != blen) { + pr_err("usb write operation failed. (%d)\n", ret); + return -EIO; + } + + return 0; +} + +static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + struct az6007_device_state *st = d->priv; + int ret; + + if (mutex_lock_interruptible(&st->mutex) < 0) + return -EAGAIN; + + ret = __az6007_write(d->udev, req, value, index, b, blen); + + mutex_unlock(&st->mutex); + + return ret; +} + +static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_device *d = fe_to_d(fe); + + pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable"); + + return az6007_write(d, 0xbc, onoff, 0, NULL, 0); +} + +/* remote control stuff (does not work with my box) */ +static int az6007_rc_query(struct dvb_usb_device *d) +{ + struct az6007_device_state *st = d_to_priv(d); + unsigned code = 0; + + az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); + + if (st->data[1] == 0x44) + return 0; + + if ((st->data[1] ^ st->data[2]) == 0xff) + code = st->data[1]; + else + code = st->data[1] << 8 | st->data[2]; + + if ((st->data[3] ^ st->data[4]) == 0xff) + code = code << 8 | st->data[3]; + else + code = code << 16 | st->data[3] << 8 | st->data[4]; + + rc_keydown(d->rc_dev, code, st->data[5]); + + return 0; +} + +static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, + int address) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + if (slot != 0) + return -EINVAL; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + mutex_lock(&state->ca_mutex); + + req = 0xC1; + value = address; + index = 0; + blen = 1; + + ret = az6007_read(d, req, value, index, b, blen); + if (ret < 0) { + pr_warn("usb in operation failed. (%d)\n", ret); + ret = -EINVAL; + } else { + ret = b[0]; + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + +static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, + int address, + u8 value) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + + int ret; + u8 req; + u16 value1; + u16 index; + int blen; + + pr_debug("%s(), slot %d\n", __func__, slot); + if (slot != 0) + return -EINVAL; + + mutex_lock(&state->ca_mutex); + req = 0xC2; + value1 = address; + index = value; + blen = 0; + + ret = az6007_write(d, req, value1, index, NULL, blen); + if (ret != 0) + pr_warn("usb out operation failed. (%d)\n", ret); + + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + if (slot != 0) + return -EINVAL; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + mutex_lock(&state->ca_mutex); + + req = 0xC3; + value = address; + index = 0; + blen = 2; + + ret = az6007_read(d, req, value, index, b, blen); + if (ret < 0) { + pr_warn("usb in operation failed. (%d)\n", ret); + ret = -EINVAL; + } else { + if (b[0] == 0) + pr_warn("Read CI IO error\n"); + + ret = b[1]; + pr_debug("read cam data = %x from 0x%x\n", b[1], value); + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + +static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address, + u8 value) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + + int ret; + u8 req; + u16 value1; + u16 index; + int blen; + + if (slot != 0) + return -EINVAL; + + mutex_lock(&state->ca_mutex); + req = 0xC4; + value1 = address; + index = value; + blen = 0; + + ret = az6007_write(d, req, value1, index, NULL, blen); + if (ret != 0) { + pr_warn("usb out operation failed. (%d)\n", ret); + goto failed; + } + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + req = 0xC8; + value = 0; + index = 0; + blen = 1; + + ret = az6007_read(d, req, value, index, b, blen); + if (ret < 0) { + pr_warn("usb in operation failed. (%d)\n", ret); + ret = -EIO; + } else{ + ret = b[0]; + } + kfree(b); + return ret; +} + +static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + + int ret, i; + u8 req; + u16 value; + u16 index; + int blen; + + mutex_lock(&state->ca_mutex); + + req = 0xC6; + value = 1; + index = 0; + blen = 0; + + ret = az6007_write(d, req, value, index, NULL, blen); + if (ret != 0) { + pr_warn("usb out operation failed. (%d)\n", ret); + goto failed; + } + + msleep(500); + req = 0xC6; + value = 0; + index = 0; + blen = 0; + + ret = az6007_write(d, req, value, index, NULL, blen); + if (ret != 0) { + pr_warn("usb out operation failed. (%d)\n", ret); + goto failed; + } + + for (i = 0; i < 15; i++) { + msleep(100); + + if (CI_CamReady(ca, slot)) { + pr_debug("CAM Ready\n"); + break; + } + } + msleep(5000); + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return 0; +} + +static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + pr_debug("%s()\n", __func__); + mutex_lock(&state->ca_mutex); + req = 0xC7; + value = 1; + index = 0; + blen = 0; + + ret = az6007_write(d, req, value, index, NULL, blen); + if (ret != 0) { + pr_warn("usb out operation failed. (%d)\n", ret); + goto failed; + } + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6007_device_state *state = d_to_priv(d); + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + mutex_lock(&state->ca_mutex); + + req = 0xC5; + value = 0; + index = 0; + blen = 1; + + ret = az6007_read(d, req, value, index, b, blen); + if (ret < 0) { + pr_warn("usb in operation failed. (%d)\n", ret); + ret = -EIO; + } else + ret = 0; + + if (!ret && b[0] == 1) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + + +static void az6007_ci_uninit(struct dvb_usb_device *d) +{ + struct az6007_device_state *state; + + pr_debug("%s()\n", __func__); + + if (NULL == d) + return; + + state = d_to_priv(d); + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + + +static int az6007_ci_init(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct az6007_device_state *state = adap_to_priv(adap); + int ret; + + pr_debug("%s()\n", __func__); + + mutex_init(&state->ca_mutex); + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; + state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; + state->ca.read_cam_control = az6007_ci_read_cam_control; + state->ca.write_cam_control = az6007_ci_write_cam_control; + state->ca.slot_reset = az6007_ci_slot_reset; + state->ca.slot_shutdown = az6007_ci_slot_shutdown; + state->ca.slot_ts_enable = az6007_ci_slot_ts_enable; + state->ca.poll_slot_status = az6007_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&adap->dvb_adap, + &state->ca, + 0, /* flags */ + 1);/* n_slots */ + if (ret != 0) { + pr_err("Cannot initialize CI: Error %d.\n", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + pr_debug("CI initialized.\n"); + + return 0; +} + +static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6]) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct az6007_device_state *st = adap_to_priv(adap); + int ret; + + ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); + memcpy(mac, st->data, 6); + + if (ret > 0) + pr_debug("%s: mac is %pM\n", __func__, mac); + + return ret; +} + +static int az6007_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct az6007_device_state *st = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + + pr_debug("attaching demod drxk\n"); + + adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk, + &d->i2c_adap); + if (!adap->fe[0]) + return -EINVAL; + + adap->fe[0]->sec_priv = adap; + st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl; + adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; + + az6007_ci_init(adap); + + return 0; +} + +static int az6007_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + + pr_debug("attaching tuner mt2063\n"); + + /* Attach mt2063 to DVB-C frontend */ + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1); + if (!dvb_attach(mt2063_attach, adap->fe[0], + &az6007_mt2063_config, + &d->i2c_adap)) + return -EINVAL; + + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0); + + return 0; +} + +static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + struct az6007_device_state *state = d_to_priv(d); + int ret; + + pr_debug("%s()\n", __func__); + + if (!state->warm) { + mutex_init(&state->mutex); + + ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0); + if (ret < 0) + return ret; + msleep(60); + ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); + if (ret < 0) + return ret; + msleep(100); + ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0); + if (ret < 0) + return ret; + msleep(20); + ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); + if (ret < 0) + return ret; + + msleep(400); + ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0); + if (ret < 0) + return ret; + msleep(150); + ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0); + if (ret < 0) + return ret; + msleep(430); + ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); + if (ret < 0) + return ret; + + state->warm = true; + + return 0; + } + + if (!onoff) + return 0; + + az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); + az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0); + + return 0; +} + +/* I2C */ +static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct az6007_device_state *st = d_to_priv(d); + int i, j, len; + int ret = 0; + u16 index; + u16 value; + int length; + u8 req, addr; + + if (mutex_lock_interruptible(&st->mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + addr = msgs[i].addr << 1; + if (((i + 1) < num) + && (msgs[i].len == 1) + && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD) + && (msgs[i + 1].flags & I2C_M_RD) + && (msgs[i].addr == msgs[i + 1].addr)) { + /* + * A write + read xfer for the same address, where + * the first xfer has just 1 byte length. + * Need to join both into one operation + */ + if (az6007_xfer_debug) + printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n", + addr, msgs[i].len, msgs[i + 1].len); + req = AZ6007_I2C_RD; + index = msgs[i].buf[0]; + value = addr | (1 << 8); + length = 6 + msgs[i + 1].len; + len = msgs[i + 1].len; + ret = __az6007_read(d->udev, req, value, index, + st->data, length); + if (ret >= len) { + for (j = 0; j < len; j++) + msgs[i + 1].buf[j] = st->data[j + 5]; + } else + ret = -EIO; + i++; + } else if (!(msgs[i].flags & I2C_M_RD)) { + /* write bytes */ + if (az6007_xfer_debug) + printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n", + addr, msgs[i].len); + req = AZ6007_I2C_WR; + index = msgs[i].buf[0]; + value = addr | (1 << 8); + length = msgs[i].len - 1; + len = msgs[i].len - 1; + for (j = 0; j < len; j++) + st->data[j] = msgs[i].buf[j + 1]; + ret = __az6007_write(d->udev, req, value, index, + st->data, length); + } else { + /* read bytes */ + if (az6007_xfer_debug) + printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n", + addr, msgs[i].len); + req = AZ6007_I2C_RD; + index = msgs[i].buf[0]; + value = addr; + length = msgs[i].len + 6; + len = msgs[i].len; + ret = __az6007_read(d->udev, req, value, index, + st->data, length); + for (j = 0; j < len; j++) + msgs[i].buf[j] = st->data[j + 5]; + } + if (ret < 0) + goto err; + } +err: + mutex_unlock(&st->mutex); + + if (ret < 0) { + pr_info("%s ERROR: %i\n", __func__, ret); + return ret; + } + return num; +} + +static u32 az6007_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm az6007_i2c_algo = { + .master_xfer = az6007_i2c_xfer, + .functionality = az6007_i2c_func, +}; + +static int az6007_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 *mac; + + pr_debug("Identifying az6007 state\n"); + + mac = kmalloc(6, GFP_ATOMIC); + if (!mac) + return -ENOMEM; + + /* Try to read the mac address */ + ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6); + if (ret == 6) + ret = WARM; + else + ret = COLD; + + kfree(mac); + + if (ret == COLD) { + __az6007_write(d->udev, 0x09, 1, 0, NULL, 0); + __az6007_write(d->udev, 0x00, 0, 0, NULL, 0); + __az6007_write(d->udev, 0x00, 0, 0, NULL, 0); + } + + pr_debug("Device is on %s state\n", + ret == WARM ? "warm" : "cold"); + return ret; +} + +static void az6007_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + az6007_ci_uninit(d); + dvb_usbv2_disconnect(intf); +} + +static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + pr_debug("Getting az6007 Remote Control properties\n"); + + rc->allowed_protos = RC_TYPE_NEC; + rc->query = az6007_rc_query; + rc->interval = 400; + + return 0; +} + +static int az6007_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + pr_debug("Loading az6007 firmware\n"); + + return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2); +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties az6007_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .firmware = AZ6007_FIRMWARE, + + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct az6007_device_state), + .i2c_algo = &az6007_i2c_algo, + .tuner_attach = az6007_tuner_attach, + .frontend_attach = az6007_frontend_attach, + .streaming_ctrl = az6007_streaming_ctrl, + .get_rc_config = az6007_get_rc_config, + .read_mac_address = az6007_read_mac_addr, + .download_firmware = az6007_download_firmware, + .identify_state = az6007_identify_state, + .power_ctrl = az6007_power_ctrl, + .num_adapters = 1, + .adapter = { + { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), } + } +}; + +static struct usb_device_id az6007_usb_table[] = { + {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, + &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, + {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7, + &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, + {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2, + &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, + {0}, +}; + +MODULE_DEVICE_TABLE(usb, az6007_usb_table); + +static int az6007_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + az6007_ci_uninit(d); + return dvb_usbv2_suspend(intf, msg); +} + +static int az6007_resume(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct dvb_usb_adapter *adap = &d->adapter[0]; + + az6007_ci_init(adap); + return dvb_usbv2_resume(intf); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver az6007_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = az6007_usb_table, + .probe = dvb_usbv2_probe, + .disconnect = az6007_usb_disconnect, + .no_dynamic_id = 1, + .soft_unbind = 1, + /* + * FIXME: need to implement reset_resume, likely with + * dvb-usb-v2 core support + */ + .suspend = az6007_suspend, + .resume = az6007_resume, +}; + +module_usb_driver(az6007_usb_driver); + +MODULE_AUTHOR("Henry Wang "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); +MODULE_VERSION("2.0"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(AZ6007_FIRMWARE); diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.c b/drivers/media/usb/dvb-usb-v2/ce6230.c new file mode 100644 index 00000000000..84ff4a96ca4 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/ce6230.c @@ -0,0 +1,287 @@ +/* + * Intel CE6230 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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 "ce6230.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) +{ + int ret; + unsigned int pipe; + u8 request; + u8 requesttype; + u16 value; + u16 index; + u8 *buf; + + request = req->cmd; + value = req->value; + index = req->index; + + switch (req->cmd) { + case I2C_READ: + case DEMOD_READ: + case REG_READ: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + break; + case I2C_WRITE: + case DEMOD_WRITE: + case REG_WRITE: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + break; + default: + pr_debug("%s: unknown command=%02x\n", __func__, req->cmd); + ret = -EINVAL; + goto error; + } + + buf = kmalloc(req->data_len, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error; + } + + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { + /* write */ + memcpy(buf, req->data, req->data_len); + pipe = usb_sndctrlpipe(d->udev, 0); + } else { + /* read */ + pipe = usb_rcvctrlpipe(d->udev, 0); + } + + msleep(1); /* avoid I2C errors */ + + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, + buf, req->data_len, CE6230_USB_TIMEOUT); + + ce6230_debug_dump(request, requesttype, value, index, buf, + req->data_len); + + if (ret < 0) + pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME, + ret); + else + ret = 0; + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->data_len); + + kfree(buf); +error: + return ret; +} + +/* I2C */ +static struct zl10353_config ce6230_zl10353_config; + +static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i = 0; + struct usb_req req; + + if (num > 2) + return -EOPNOTSUPP; + + memset(&req, 0, sizeof(req)); + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == + ce6230_zl10353_config.demod_address) { + req.cmd = DEMOD_READ; + req.value = msg[i].addr >> 1; + req.index = msg[i].buf[0]; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = ce6230_ctrl_msg(d, &req); + } else { + pr_err("%s: I2C read not implemented\n", + KBUILD_MODNAME); + ret = -EOPNOTSUPP; + } + i += 2; + } else { + if (msg[i].addr == + ce6230_zl10353_config.demod_address) { + req.cmd = DEMOD_WRITE; + req.value = msg[i].addr >> 1; + req.index = msg[i].buf[0]; + req.data_len = msg[i].len-1; + req.data = &msg[i].buf[1]; + ret = ce6230_ctrl_msg(d, &req); + } else { + req.cmd = I2C_WRITE; + req.value = 0x2000 + (msg[i].addr >> 1); + req.index = 0x0000; + req.data_len = msg[i].len; + req.data = &msg[i].buf[0]; + ret = ce6230_ctrl_msg(d, &req); + } + i += 1; + } + if (ret) + break; + } + + mutex_unlock(&d->i2c_mutex); + return ret ? ret : i; +} + +static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ce6230_i2c_algorithm = { + .master_xfer = ce6230_i2c_master_xfer, + .functionality = ce6230_i2c_functionality, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config ce6230_zl10353_config = { + .demod_address = 0x1e, + .adc_clock = 450000, + .if2 = 45700, + .no_tuner = 1, + .parallel_ts = 1, + .clock_ctl_1 = 0x34, + .pll_0 = 0x0e, +}; + +static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) +{ + pr_debug("%s:\n", __func__); + + adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -ENODEV; + + return 0; +} + +static struct mxl5005s_config ce6230_mxl5003s_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + int ret; + + pr_debug("%s:\n", __func__); + + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; + return ret; +} + +static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + + pr_debug("%s: onoff=%d\n", __func__, onoff); + + /* InterfaceNumber 1 / AlternateSetting 0 idle + InterfaceNumber 1 / AlternateSetting 1 streaming */ + ret = usb_set_interface(d->udev, 1, onoff); + if (ret) + pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME, + ret); + + return ret; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ce6230_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .bInterfaceNumber = 1, + + .i2c_algo = &ce6230_i2c_algorithm, + .power_ctrl = ce6230_power_ctrl, + .frontend_attach = ce6230_zl10353_frontend_attach, + .tuner_attach = ce6230_mxl5003s_tuner_attach, + + .num_adapters = 1, + .adapter = { + { + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = (16 * 512), + } + } + }, + } + }, +}; + +static const struct usb_device_id ce6230_id_table[] = { + { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, + &ce6230_props, "Intel CE9500 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, + &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ce6230_id_table); + +static struct usb_driver ce6230_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = ce6230_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(ce6230_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Intel CE6230 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.h b/drivers/media/usb/dvb-usb-v2/ce6230.h new file mode 100644 index 00000000000..42d754494a3 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/ce6230.h @@ -0,0 +1,61 @@ +/* + * Intel CE6230 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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 CE6230_H +#define CE6230_H + +#include "dvb_usb.h" +#include "zl10353.h" +#include "mxl5005s.h" + +#define ce6230_debug_dump(r, t, v, i, b, l) { \ + char *direction; \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + direction = ">>>"; \ + else \ + direction = "<<<"; \ + pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \ + __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ + l & 0xff, l >> 8, direction, l); \ +} + +#define CE6230_USB_TIMEOUT 1000 + +struct usb_req { + u8 cmd; /* [1] */ + u16 value; /* [2|3] */ + u16 index; /* [4|5] */ + u16 data_len; /* [6|7] */ + u8 *data; +}; + +enum ce6230_cmd { + CONFIG_READ = 0xd0, /* rd 0 (unclear) */ + UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */ + I2C_READ = 0xd9, /* rd 9 (unclear) */ + I2C_WRITE = 0xca, /* wr a */ + DEMOD_READ = 0xdb, /* rd b */ + DEMOD_WRITE = 0xcc, /* wr c */ + REG_READ = 0xde, /* rd e */ + REG_WRITE = 0xcf, /* wr f */ +}; + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c new file mode 100644 index 00000000000..9f7c970c642 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c @@ -0,0 +1,125 @@ +/* cypress_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#include "dvb_usb.h" +#include "cypress_firmware.h" + +struct usb_cypress_controller { + u8 id; + const char *name; /* name of the usb controller */ + u16 cs_reg; /* needs to be restarted, + * when the firmware has been downloaded */ +}; + +static const struct usb_cypress_controller cypress[] = { + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, + u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +int usbv2_cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type) +{ + struct hexline hx; + u8 reset; + int ret, pos = 0; + + /* stop the CPU */ + reset = 1; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1); + if (ret != 1) + pr_err("%s: could not stop the USB controller CPU", + KBUILD_MODNAME); + + while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { + pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n", + __func__, hx.addr, hx.len, hx.chk); + + ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); + if (ret != hx.len) { + pr_err("%s: error while transferring firmware " \ + "(transferred size=%d, block size=%d)", + KBUILD_MODNAME, ret, hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + pr_err("%s: firmware download failed at %d with %d", + KBUILD_MODNAME, pos, ret); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ + reset = 0; + if (ret || usb_cypress_writemem( + udev, cypress[type].cs_reg, &reset, 1) != 1) { + pr_err("%s: could not restart the USB controller CPU", + KBUILD_MODNAME); + ret = -EINVAL; + } + } else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(usbv2_cypress_load_firmware); + +int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + + if (*pos >= fw->size) + return 0; + + memset(hx, 0, sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data + * field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); + /* + hx->len -= 2; + data_offs += 2; + */ + } + memcpy(hx->data, &b[data_offs], hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usbv2_get_hexline); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Cypress firmware download"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h new file mode 100644 index 00000000000..80085fd4132 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h @@ -0,0 +1,31 @@ +/* cypress_firmware.h is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#ifndef CYPRESS_FIRMWARE_H +#define CYPRESS_FIRMWARE_H + +#define CYPRESS_AN2135 0 +#define CYPRESS_AN2235 1 +#define CYPRESS_FX2 2 + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int usbv2_cypress_load_firmware(struct usb_device *, + const struct firmware *, int); +extern int dvb_usbv2_get_hexline(const struct firmware *, + struct hexline *, int *); + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h new file mode 100644 index 00000000000..79b3b8b6750 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -0,0 +1,389 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef DVB_USB_H +#define DVB_USB_H + +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "dmxdev.h" +#include "dvb-usb-ids.h" + +/* + * device file: /dev/dvb/adapter[0-1]/frontend[0-2] + * + * |-- device + * | |-- adapter0 + * | | |-- frontend0 + * | | |-- frontend1 + * | | `-- frontend2 + * | `-- adapter1 + * | |-- frontend0 + * | |-- frontend1 + * | `-- frontend2 + * + * + * Commonly used variable names: + * d = pointer to device (struct dvb_usb_device *) + * adap = pointer to adapter (struct dvb_usb_adapter *) + * fe = pointer to frontend (struct dvb_frontend *) + * + * Use macros defined in that file to resolve needed pointers. + */ + +/* helper macros for every DVB USB driver use */ +#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \ + adapter[adap->id])) +#define adap_to_priv(adap) (adap_to_d(adap)->priv) +#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv)) +#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe))) +#define fe_to_priv(fe) (fe_to_d(fe)->priv) +#define d_to_priv(d) (d->priv) + +#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \ + .type = USB_BULK, \ + .count = count_, \ + .endpoint = endpoint_, \ + .u = { \ + .bulk = { \ + .buffersize = size_, \ + } \ + } \ +} + +#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \ + .type = USB_ISOC, \ + .count = count_, \ + .endpoint = endpoint_, \ + .u = { \ + .isoc = { \ + .framesperurb = frames_, \ + .framesize = size_,\ + .interval = interval_, \ + } \ + } \ +} + +#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \ + .props = (props_), \ + .name = (name_), \ + .rc_map = (rc), \ + }) + +struct dvb_usb_device; +struct dvb_usb_adapter; + +/** + * structure for carrying all needed data from the device driver to the general + * dvb usb routines + * @name: device name + * @rc_map: name of rc codes table + * @props: structure containing all device properties + */ +struct dvb_usb_driver_info { + const char *name; + const char *rc_map; + const struct dvb_usb_device_properties *props; +}; + +/** + * structure for remote controller configuration + * @map_name: name of rc codes table + * @allowed_protos: protocol(s) supported by the driver + * @change_protocol: callback to change protocol + * @query: called to query an event from the device + * @interval: time in ms between two queries + * @driver_type: used to point if a device supports raw mode + * @bulk_mode: device supports bulk mode for rc (disable polling mode) + */ +struct dvb_usb_rc { + const char *map_name; + u64 allowed_protos; + int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + int (*query) (struct dvb_usb_device *d); + unsigned int interval; + const enum rc_driver_type driver_type; + bool bulk_mode; +}; + +/** + * usb streaming configration for adapter + * @type: urb type + * @count: count of used urbs + * @endpoint: stream usb endpoint number + */ +struct usb_data_stream_properties { +#define USB_BULK 1 +#define USB_ISOC 2 + u8 type; + u8 count; + u8 endpoint; + + union { + struct { + unsigned int buffersize; /* per URB */ + } bulk; + struct { + int framesperurb; + int framesize; + int interval; + } isoc; + } u; +}; + +/** + * properties of dvb usb device adapter + * @caps: adapter capabilities + * @pid_filter_count: pid count of adapter pid-filter + * @pid_filter_ctrl: called to enable/disable pid-filter + * @pid_filter: called to set/unset pid for filtering + * @stream: adapter usb stream configuration + */ +#define MAX_NO_OF_FE_PER_ADAP 3 +struct dvb_usb_adapter_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 + u8 caps; + + u8 pid_filter_count; + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + + struct usb_data_stream_properties stream; +}; + +/** + * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @driver_name: name of the owning driver module + * @owner: owner of the dvb_adapter + * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro + * @bInterfaceNumber: usb interface number driver binds + * @size_of_priv: bytes allocated for the driver private data + * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent + * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for + * receive + * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message + * @identify_state: called to determine the firmware state (cold or warm) and + * return possible firmware file name to be loaded + * @firmware: name of the firmware file to be loaded + * @download_firmware: called to download the firmware + * @i2c_algo: i2c_algorithm if the device has i2c-adapter + * @num_adapters: dvb usb device adapter count + * @get_adapter_count: called to resolve adapter count + * @adapter: array of all adapter properties of device + * @power_ctrl: called to enable/disable power of the device + * @read_config: called to resolve device configuration + * @read_mac_address: called to resolve adapter mac-address + * @frontend_attach: called to attach the possible frontends + * @tuner_attach: called to attach the possible tuners + * @frontend_ctrl: called to power on/off active frontend + * @streaming_ctrl: called to start/stop the usb streaming of adapter + * @init: called after adapters are created in order to finalize device + * configuration + * @exit: called when driver is unloaded + * @get_rc_config: called to resolve used remote controller configuration + * @get_stream_config: called to resolve input and output stream configuration + * of the adapter just before streaming is started. input stream is transport + * stream from the demodulator and output stream is usb stream to host. + */ +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 +struct dvb_usb_device_properties { + const char *driver_name; + struct module *owner; + short *adapter_nr; + + u8 bInterfaceNumber; + unsigned int size_of_priv; + u8 generic_bulk_ctrl_endpoint; + u8 generic_bulk_ctrl_endpoint_response; + unsigned int generic_bulk_ctrl_delay; + +#define WARM 0 +#define COLD 1 + int (*identify_state) (struct dvb_usb_device *, const char **); + const char *firmware; +#define RECONNECTS_USB 1 + int (*download_firmware) (struct dvb_usb_device *, + const struct firmware *); + + struct i2c_algorithm *i2c_algo; + + unsigned int num_adapters; + int (*get_adapter_count) (struct dvb_usb_device *); + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + int (*power_ctrl) (struct dvb_usb_device *, int); + int (*read_config) (struct dvb_usb_device *d); + int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + int (*frontend_ctrl) (struct dvb_frontend *, int); + int (*streaming_ctrl) (struct dvb_frontend *, int); + int (*init) (struct dvb_usb_device *); + void (*exit) (struct dvb_usb_device *); + int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); +#define DVB_USB_FE_TS_TYPE_188 0 +#define DVB_USB_FE_TS_TYPE_204 1 +#define DVB_USB_FE_TS_TYPE_RAW 2 + int (*get_stream_config) (struct dvb_frontend *, u8 *, + struct usb_data_stream_properties *); +}; + +/** + * generic object of an usb stream + * @buf_num: number of buffer allocated + * @buf_size: size of each buffer in buf_list + * @buf_list: array containing all allocate buffers for streaming + * @dma_addr: list of dma_addr_t for each buffer in buf_list + * + * @urbs_initialized: number of URBs initialized + * @urbs_submitted: number of URBs submitted + */ +#define MAX_NO_URBS_FOR_DATA_STREAM 10 +struct usb_data_stream { + struct usb_device *udev; + struct usb_data_stream_properties props; + +#define USB_STATE_INIT 0x00 +#define USB_STATE_URB_BUF 0x01 + u8 state; + + void (*complete) (struct usb_data_stream *, u8 *, size_t); + + struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; + dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; + + int urbs_initialized; + int urbs_submitted; + + void *user_priv; +}; + +/** + * dvb adapter object on dvb usb device + * @props: pointer to adapter properties + * @stream: adapter the usb data stream + * @id: index of this adapter (starting with 0) + * @ts_type: transport stream, input stream, type + * @pid_filtering: is hardware pid_filtering used or not + * @feed_count: current feed count + * @max_feed_count: maimum feed count device can handle + * @dvb_adap: adapter dvb_adapter + * @dmxdev: adapter dmxdev + * @demux: adapter software demuxer + * @dvb_net: adapter dvb_net interfaces + * @sync_mutex: mutex used to sync control and streaming of the adapter + * @fe: adapter frontends + * @fe_init: rerouted frontend-init function + * @fe_sleep: rerouted frontend-sleep function + */ +struct dvb_usb_adapter { + const struct dvb_usb_adapter_properties *props; + struct usb_data_stream stream; + u8 id; + u8 ts_type; + bool pid_filtering; + u8 feed_count; + u8 max_feed_count; + s8 active_fe; + + /* dvb */ + struct dvb_adapter dvb_adap; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvb_net; + struct mutex sync_mutex; + + struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; + int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); + int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); +}; + +/** + * dvb usb device object + * @props: device properties + * @name: device name + * @rc_map: name of rc codes table + * @udev: pointer to the device's struct usb_device + * @intf: pointer to the device's usb interface + * @rc: remote controller configuration + * @probe_work: work to defer .probe() + * @powered: indicated whether the device is power or not + * @usb_mutex: mutex for usb control messages + * @i2c_mutex: mutex for i2c-transfers + * @i2c_adap: device's i2c-adapter + * @rc_dev: rc device for the remote control + * @rc_query_work: work for polling remote + * @priv: private data of the actual driver (allocate by dvb usb, size defined + * in size_of_priv of dvb_usb_properties). + */ +struct dvb_usb_device { + const struct dvb_usb_device_properties *props; + const char *name; + const char *rc_map; + + struct usb_device *udev; + struct usb_interface *intf; + struct dvb_usb_rc rc; + struct work_struct probe_work; + pid_t work_pid; + int powered; + + /* locking */ + struct mutex usb_mutex; + + /* i2c */ + struct mutex i2c_mutex; + struct i2c_adapter i2c_adap; + + struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + /* remote control */ + struct rc_dev *rc_dev; + char rc_phys[64]; + struct delayed_work rc_query_work; + + void *priv; +}; + +extern int dvb_usbv2_probe(struct usb_interface *, + const struct usb_device_id *); +extern void dvb_usbv2_disconnect(struct usb_interface *); +extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t); +extern int dvb_usbv2_resume(struct usb_interface *); + +/* the generic read/write method for device control */ +extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16); +extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h new file mode 100644 index 00000000000..45f07090d43 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h @@ -0,0 +1,35 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef DVB_USB_COMMON_H +#define DVB_USB_COMMON_H + +#include "dvb_usb.h" + +/* commonly used methods */ +extern int usb_urb_initv2(struct usb_data_stream *stream, + const struct usb_data_stream_properties *props); +extern int usb_urb_exitv2(struct usb_data_stream *stream); +extern int usb_urb_submitv2(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); +extern int usb_urb_killv2(struct usb_data_stream *stream); + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c new file mode 100644 index 00000000000..a72f9c7de68 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -0,0 +1,997 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "dvb_usb_common.h" + +int dvb_usbv2_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, + "disable remote control polling (default: 0)"); +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, + int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \ + "PID filter, if any (default: 0)"); + +static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) +{ + int ret; + const struct firmware *fw; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (!d->props->download_firmware) { + ret = -EINVAL; + goto err; + } + + ret = request_firmware(&fw, name, &d->udev->dev); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: Did not find the firmware file "\ + "'%s'. Please see linux/Documentation/dvb/ " \ + "for more details on firmware-problems. " \ + "Status %d\n", KBUILD_MODNAME, name, ret); + goto err; + } + + dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n", + KBUILD_MODNAME, name); + + ret = d->props->download_firmware(d, fw); + release_firmware(fw); + if (ret < 0) + goto err; + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) +{ + int ret; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (!d->props->i2c_algo) + return 0; + + strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props->i2c_algo; + d->i2c_adap.dev.parent = &d->udev->dev; + i2c_set_adapdata(&d->i2c_adap, d); + + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) { + d->i2c_adap.algo = NULL; + dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n", + KBUILD_MODNAME, ret); + goto err; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) +{ + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (d->i2c_adap.algo) + i2c_del_adapter(&d->i2c_adap); + + return 0; +} + +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = container_of(work, + struct dvb_usb_device, rc_query_work.work); + int ret; + + /* + * When the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init. + */ + if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) + return; + + ret = d->rc.query(d); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n", + KBUILD_MODNAME, ret); + return; /* stop polling */ + } + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); +} + +static int dvb_usbv2_remote_init(struct dvb_usb_device *d) +{ + int ret; + struct rc_dev *dev; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) + return 0; + + d->rc.map_name = d->rc_map; + ret = d->props->get_rc_config(d, &d->rc); + if (ret < 0) + goto err; + + /* disable rc when there is no keymap defined */ + if (!d->rc.map_name) + return 0; + + dev = rc_allocate_device(); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->dev.parent = &d->udev->dev; + dev->input_name = d->name; + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + dev->input_phys = d->rc_phys; + usb_to_input_id(d->udev, &dev->input_id); + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props->driver_name; + dev->map_name = d->rc.map_name; + dev->driver_type = d->rc.driver_type; + dev->allowed_protos = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; + dev->priv = d; + + ret = rc_register_device(dev); + if (ret < 0) { + rc_free_device(dev); + goto err; + } + + d->rc_dev = dev; + + /* start polling if needed */ + if (d->rc.query && !d->rc.bulk_mode) { + /* initialize a work queue for handling polling */ + INIT_DELAYED_WORK(&d->rc_query_work, + dvb_usb_read_remote_control); + dev_info(&d->udev->dev, "%s: schedule remote query interval " \ + "to %d msecs\n", KBUILD_MODNAME, + d->rc.interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) +{ + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (d->rc_dev) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); + d->rc_dev = NULL; + } + + return 0; +} + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_204(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_raw(&adap->demux, buf, len); +} + +int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + adap->stream.udev = adap_to_d(adap)->udev; + adap->stream.user_priv = adap; + adap->stream.complete = dvb_usb_data_complete; + + return usb_urb_initv2(&adap->stream, &adap->props->stream); +} + +int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + return usb_urb_exitv2(&adap->stream); +} + +static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, + int count) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \ + "setting pid [%s]: %04x (%04d) at index %d '%s'\n", + __func__, adap->id, adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + (count == 1) ? "on" : "off"); + + if (adap->active_fe == -1) + return -EINVAL; + + adap->feed_count += count; + + /* stop feeding if it is last pid */ + if (adap->feed_count == 0) { + dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); + usb_urb_killv2(&adap->stream); + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl( + adap->fe[adap->active_fe], 0); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); + goto err_mutex_unlock; + } + } + mutex_unlock(&adap->sync_mutex); + } + + /* activate the pid on the device pid filter */ + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props->pid_filter) + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, (count == 1) ? 1 : 0); + if (ret < 0) + dev_err(&d->udev->dev, "%s: pid_filter() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); + + /* start feeding if it is first pid */ + if (adap->feed_count == 1 && count == 1) { + struct usb_data_stream_properties stream_props; + mutex_lock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); + + /* resolve input and output streaming paramters */ + if (d->props->get_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); + ret = d->props->get_stream_config( + adap->fe[adap->active_fe], + &adap->ts_type, &stream_props); + if (ret < 0) + goto err_mutex_unlock; + } else { + stream_props = adap->props->stream; + } + + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + + usb_urb_submitv2(&adap->stream, &stream_props); + + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props->caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, + adap->pid_filtering); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: " \ + "pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl( + adap->fe[adap->active_fe], 1); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); + goto err_mutex_unlock; + } + } + } + + return 0; +err_mutex_unlock: + mutex_unlock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, -1); +} + +int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); + + ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, + &d->udev->dev, d->props->adapter_nr); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n", + __func__, ret); + goto err_dvb_register_adapter; + } + + adap->dvb_adap.priv = adap; + + if (d->props->read_mac_address) { + ret = d->props->read_mac_address(adap, + adap->dvb_adap.proposed_mac); + if (ret < 0) + goto err_dvb_dmx_init; + + dev_info(&d->udev->dev, "%s: MAC address: %pM\n", + KBUILD_MODNAME, adap->dvb_adap.proposed_mac); + } + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.filternum = 0; + adap->demux.filternum = adap->max_feed_count; + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_dvb_dmx_init; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_dvb_dmxdev_init; + } + + ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_dvb_net_init; + } + + mutex_init(&adap->sync_mutex); + + return 0; +err_dvb_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dvb_dmxdev_init: + dvb_dmx_release(&adap->demux); +err_dvb_dmx_init: + dvb_unregister_adapter(&adap->dvb_adap); +err_dvb_register_adapter: + adap->dvb_adap.priv = NULL; + return ret; +} + +int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + if (adap->dvb_adap.priv) { + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + } + + return 0; +} + +int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { + /* when switching from 1 to 0 or from 0 to 1 */ + dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff); + if (d->props->power_ctrl) { + ret = d->props->power_ctrl(d, onoff); + if (ret < 0) + goto err; + } + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_init(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, + fe->id); + + ret = dvb_usbv2_device_power_ctrl(d, 1); + if (ret < 0) + goto err; + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 1); + if (ret < 0) + goto err; + } + + if (adap->fe_init[fe->id]) { + ret = adap->fe_init[fe->id](fe); + if (ret < 0) + goto err; + } + + adap->active_fe = fe->id; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, + fe->id); + + if (adap->fe_sleep[fe->id]) { + ret = adap->fe_sleep[fe->id](fe); + if (ret < 0) + goto err; + } + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 0); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_device_power_ctrl(d, 0); + if (ret < 0) + goto err; + + adap->active_fe = -1; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i, count_registered = 0; + struct dvb_usb_device *d = adap_to_d(adap); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); + + memset(adap->fe, 0, sizeof(adap->fe)); + adap->active_fe = -1; + + if (d->props->frontend_attach) { + ret = d->props->frontend_attach(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: frontend_attach() " \ + "failed=%d\n", __func__, ret); + goto err_dvb_frontend_detach; + } + } else { + dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n", + __func__); + ret = 0; + goto err; + } + + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { + adap->fe[i]->id = i; + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_init; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: frontend%d registration " \ + "failed\n", KBUILD_MODNAME, i); + goto err_dvb_unregister_frontend; + } + + count_registered++; + } + + if (d->props->tuner_attach) { + ret = d->props->tuner_attach(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n", + __func__, ret); + goto err_dvb_unregister_frontend; + } + } + + return 0; + +err_dvb_unregister_frontend: + for (i = count_registered - 1; i >= 0; i--) + dvb_unregister_frontend(adap->fe[i]); + +err_dvb_frontend_detach: + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) + dvb_frontend_detach(adap->fe[i]); + } + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i; + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } + } + + return 0; +} + +static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) +{ + struct dvb_usb_adapter *adap; + int ret, i, adapter_count; + + /* resolve adapter count */ + adapter_count = d->props->num_adapters; + if (d->props->get_adapter_count) { + ret = d->props->get_adapter_count(d); + if (ret < 0) + goto err; + + adapter_count = ret; + } + + for (i = 0; i < adapter_count; i++) { + adap = &d->adapter[i]; + adap->id = i; + adap->props = &d->props->adapter[i]; + + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && + !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + dev_err(&d->udev->dev, "%s: this USB2.0 device " \ + "cannot be run on a USB1.1 port (it " \ + "lacks a hardware PID filter)\n", + KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } else if ((d->udev->speed == USB_SPEED_FULL && + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + dev_info(&d->udev->dev, "%s: will use the device's " \ + "hardware PID filter " \ + "(table count: %d)\n", KBUILD_MODNAME, + adap->props->pid_filter_count); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props->pid_filter_count; + } else { + dev_info(&d->udev->dev, "%s: will pass the complete " \ + "MPEG2 transport stream to the " \ + "software demuxer\n", KBUILD_MODNAME); + adap->pid_filtering = 0; + adap->max_feed_count = 255; + } + + if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + dev_info(&d->udev->dev, "%s: PID filter enabled by " \ + "module option\n", KBUILD_MODNAME); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props->pid_filter_count; + } + + ret = dvb_usbv2_adapter_stream_init(adap); + if (ret) + goto err; + + ret = dvb_usbv2_adapter_dvb_init(adap); + if (ret) + goto err; + + ret = dvb_usbv2_adapter_frontend_init(adap); + if (ret) + goto err; + + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe[1]) + adap->dvb_adap.mfe_shared = 1; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) +{ + int i; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + if (d->adapter[i].props) { + dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); + dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); + dvb_usbv2_adapter_stream_exit(&d->adapter[i]); + } + } + + return 0; +} + +/* general initialization functions */ +static int dvb_usbv2_exit(struct dvb_usb_device *d) +{ + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dvb_usbv2_remote_exit(d); + dvb_usbv2_adapter_exit(d); + dvb_usbv2_i2c_exit(d); + kfree(d->priv); + kfree(d); + + return 0; +} + +static int dvb_usbv2_init(struct dvb_usb_device *d) +{ + int ret; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dvb_usbv2_device_power_ctrl(d, 1); + + if (d->props->read_config) { + ret = d->props->read_config(d); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_i2c_init(d); + if (ret < 0) + goto err; + + ret = dvb_usbv2_adapter_init(d); + if (ret < 0) + goto err; + + if (d->props->init) { + ret = d->props->init(d); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_remote_init(d); + if (ret < 0) + goto err; + + dvb_usbv2_device_power_ctrl(d, 0); + + return 0; +err: + dvb_usbv2_device_power_ctrl(d, 0); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +/* + * udev, which is used for the firmware downloading, requires we cannot + * block during module_init(). module_init() calls USB probe() which + * is this routine. Due to that we delay actual operation using workqueue + * and return always success here. + */ +static void dvb_usbv2_init_work(struct work_struct *work) +{ + int ret; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, probe_work); + + d->work_pid = current->pid; + dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid); + + if (d->props->size_of_priv) { + d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); + if (!d->priv) { + dev_err(&d->udev->dev, "%s: kzalloc() failed\n", + KBUILD_MODNAME); + ret = -ENOMEM; + goto err_usb_driver_release_interface; + } + } + + if (d->props->identify_state) { + const char *name = NULL; + ret = d->props->identify_state(d, &name); + if (ret == 0) { + ; + } else if (ret == COLD) { + dev_info(&d->udev->dev, "%s: found a '%s' in cold " \ + "state\n", KBUILD_MODNAME, d->name); + + if (!name) + name = d->props->firmware; + + ret = dvb_usbv2_download_firmware(d, name); + if (ret == 0) { + /* device is warm, continue initialization */ + ; + } else if (ret == RECONNECTS_USB) { + /* + * USB core will call disconnect() and then + * probe() as device reconnects itself from the + * USB bus. disconnect() will release all driver + * resources and probe() is called for 'new' + * device. As 'new' device is warm we should + * never go here again. + */ + return; + } else { + /* + * Unexpected error. We must unregister driver + * manually from the device, because device is + * already register by returning from probe() + * with success. usb_driver_release_interface() + * finally calls disconnect() in order to free + * resources. + */ + goto err_usb_driver_release_interface; + } + } else { + goto err_usb_driver_release_interface; + } + } + + dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n", + KBUILD_MODNAME, d->name); + + ret = dvb_usbv2_init(d); + if (ret < 0) + goto err_usb_driver_release_interface; + + dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \ + "connected\n", KBUILD_MODNAME, d->name); + + return; +err_usb_driver_release_interface: + dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n", + KBUILD_MODNAME, d->name, ret); + usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), + d->intf); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return; +} + +int dvb_usbv2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct dvb_usb_device *d; + struct usb_device *udev = interface_to_usbdev(intf); + struct dvb_usb_driver_info *driver_info = + (struct dvb_usb_driver_info *) id->driver_info; + + dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + if (!id->driver_info) { + dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (!d) { + dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + ret = -ENOMEM; + goto err; + } + + d->name = driver_info->name; + d->rc_map = driver_info->rc_map; + d->udev = udev; + d->intf = intf; + d->props = driver_info->props; + + if (d->intf->cur_altsetting->desc.bInterfaceNumber != + d->props->bInterfaceNumber) { + ret = -ENODEV; + goto err_kfree; + } + + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + INIT_WORK(&d->probe_work, dvb_usbv2_init_work); + usb_set_intfdata(intf, d); + ret = schedule_work(&d->probe_work); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: schedule_work() failed\n", + KBUILD_MODNAME); + goto err_kfree; + } + + return 0; +err_kfree: + kfree(d); +err: + dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_probe); + +void dvb_usbv2_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + const char *name = d->name; + struct device dev = d->udev->dev; + dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__, + current->pid, d->work_pid); + + /* ensure initialization work is finished until release resources */ + if (d->work_pid != current->pid) + cancel_work_sync(&d->probe_work); + + if (d->props->exit) + d->props->exit(d); + + dvb_usbv2_exit(d); + + dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n", + KBUILD_MODNAME, name); +} +EXPORT_SYMBOL(dvb_usbv2_disconnect); + +int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* stop remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + cancel_delayed_work_sync(&d->rc_query_work); + + /* stop streaming */ + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) + usb_urb_killv2(&d->adapter[i].stream); + } + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_suspend); + +int dvb_usbv2_resume(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* start streaming */ + for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) + usb_urb_submitv2(&d->adapter[i].stream, NULL); + } + + /* start remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_resume); + +MODULE_VERSION("2.0"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("DVB USB common"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c new file mode 100644 index 00000000000..0431beed0ef --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -0,0 +1,77 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "dvb_usb_common.h" + +int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen) +{ + int ret, actual_length; + + if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || + !d->props->generic_bulk_ctrl_endpoint_response) { + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&d->usb_mutex); + if (ret < 0) + return ret; + + dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf); + + ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, + d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, + &actual_length, 2000); + if (ret < 0) + dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", + KBUILD_MODNAME, ret); + else + ret = actual_length != wlen ? -EIO : 0; + + /* an answer is expected, and no error before */ + if (!ret && rbuf && rlen) { + if (d->props->generic_bulk_ctrl_delay) + usleep_range(d->props->generic_bulk_ctrl_delay, + d->props->generic_bulk_ctrl_delay + + 20000); + + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props->generic_bulk_ctrl_endpoint_response), + rbuf, rlen, &actual_length, 2000); + if (ret) + dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \ + "failed=%d\n", KBUILD_MODNAME, ret); + + dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__, + actual_length, rbuf); + } + + mutex_unlock(&d->usb_mutex); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_generic_rw); + +int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) +{ + return dvb_usbv2_generic_rw(d, buf, len, NULL, 0); +} +EXPORT_SYMBOL(dvb_usbv2_generic_write); diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c new file mode 100644 index 00000000000..ab77622c383 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/ec168.c @@ -0,0 +1,376 @@ +/* + * E3C EC168 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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 "ec168.h" +#include "ec100.h" +#include "mxl5005s.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) +{ + int ret; + unsigned int pipe; + u8 request, requesttype; + u8 *buf; + + switch (req->cmd) { + case DOWNLOAD_FIRMWARE: + case GPIO: + case WRITE_I2C: + case STREAMING_CTRL: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = req->cmd; + break; + case READ_I2C: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = req->cmd; + break; + case GET_CONFIG: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = CONFIG; + break; + case SET_CONFIG: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = CONFIG; + break; + case WRITE_DEMOD: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = DEMOD_RW; + break; + case READ_DEMOD: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = DEMOD_RW; + break; + default: + pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd); + ret = -EINVAL; + goto error; + } + + buf = kmalloc(req->size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error; + } + + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { + /* write */ + memcpy(buf, req->data, req->size); + pipe = usb_sndctrlpipe(d->udev, 0); + } else { + /* read */ + pipe = usb_rcvctrlpipe(d->udev, 0); + } + + msleep(1); /* avoid I2C errors */ + + ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value, + req->index, buf, req->size, EC168_USB_TIMEOUT); + + ec168_debug_dump(request, requesttype, req->value, req->index, buf, + req->size); + + if (ret < 0) + goto err_dealloc; + else + ret = 0; + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->size); + + kfree(buf); + return ret; + +err_dealloc: + kfree(buf); +error: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +/* I2C */ +static struct ec100_config ec168_ec100_config; + +static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct ec168_req req; + int i = 0; + int ret; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == ec168_ec100_config.demod_address) { + req.cmd = READ_DEMOD; + req.value = 0; + req.index = 0xff00 + msg[i].buf[0]; /* reg */ + req.size = msg[i+1].len; /* bytes to read */ + req.data = &msg[i+1].buf[0]; + ret = ec168_ctrl_msg(d, &req); + i += 2; + } else { + pr_err("%s: I2C read not implemented\n", + KBUILD_MODNAME); + ret = -EOPNOTSUPP; + i += 2; + } + } else { + if (msg[i].addr == ec168_ec100_config.demod_address) { + req.cmd = WRITE_DEMOD; + req.value = msg[i].buf[1]; /* val */ + req.index = 0xff00 + msg[i].buf[0]; /* reg */ + req.size = 0; + req.data = NULL; + ret = ec168_ctrl_msg(d, &req); + i += 1; + } else { + req.cmd = WRITE_I2C; + req.value = msg[i].buf[0]; /* val */ + req.index = 0x0100 + msg[i].addr; /* I2C addr */ + req.size = msg[i].len-1; + req.data = &msg[i].buf[1]; + ret = ec168_ctrl_msg(d, &req); + i += 1; + } + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 ec168_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ec168_i2c_algo = { + .master_xfer = ec168_i2c_xfer, + .functionality = ec168_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int ec168_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 reply; + struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; + pr_debug("%s:\n", __func__); + + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + pr_debug("%s: reply=%02x\n", __func__, reply); + + if (reply == 0x01) + ret = WARM; + else + ret = COLD; + + return ret; +error: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int ec168_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret, len, remaining; + struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; + pr_debug("%s:\n", __func__); + + #define LEN_MAX 2048 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + + req.size = len; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.index = fw->size - remaining; + + ret = ec168_ctrl_msg(d, &req); + if (ret) { + pr_err("%s: firmware download failed=%d\n", + KBUILD_MODNAME, ret); + goto error; + } + } + + req.size = 0; + + /* set "warm"? */ + req.cmd = SET_CONFIG; + req.value = 0; + req.index = 0x0001; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + /* really needed - no idea what does */ + req.cmd = GPIO; + req.value = 0; + req.index = 0x0206; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + /* activate tuner I2C? */ + req.cmd = WRITE_I2C; + req.value = 0; + req.index = 0x00c6; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + return ret; +error: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static struct ec100_config ec168_ec100_config = { + .demod_address = 0xff, /* not real address, demod is integrated */ +}; + +static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) +{ + pr_debug("%s:\n", __func__); + adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -ENODEV; + + return 0; +} + +static struct mxl5005s_config ec168_mxl5003s_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + pr_debug("%s:\n", __func__); + return dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; +} + +static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; + pr_debug("%s: onoff=%d\n", __func__, onoff); + if (onoff) + req.index = 0x0102; + return ec168_ctrl_msg(fe_to_d(fe), &req); +} + +/* DVB USB Driver stuff */ +/* bInterfaceNumber 0 is HID + * bInterfaceNumber 1 is DVB-T */ +static struct dvb_usb_device_properties ec168_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .bInterfaceNumber = 1, + + .identify_state = ec168_identify_state, + .firmware = "dvb-usb-ec168.fw", + .download_firmware = ec168_download_firmware, + + .i2c_algo = &ec168_i2c_algo, + .frontend_attach = ec168_ec100_frontend_attach, + .tuner_attach = ec168_mxl5003s_tuner_attach, + .streaming_ctrl = ec168_streaming_ctrl, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512), + } + }, +}; + +static const struct dvb_usb_driver_info ec168_driver_info = { + .name = "E3C EC168 reference design", + .props = &ec168_props, +}; + +static const struct usb_device_id ec168_id[] = { + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + {} +}; +MODULE_DEVICE_TABLE(usb, ec168_id); + +static struct usb_driver ec168_driver = { + .name = KBUILD_MODNAME, + .id_table = ec168_id, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(ec168_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("E3C EC168 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/ec168.h b/drivers/media/usb/dvb-usb-v2/ec168.h new file mode 100644 index 00000000000..9181236f6eb --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/ec168.h @@ -0,0 +1,63 @@ +/* + * E3C EC168 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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 EC168_H +#define EC168_H + +#include "dvb_usb.h" + +#define ec168_debug_dump(r, t, v, i, b, l) { \ + char *direction; \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + direction = ">>>"; \ + else \ + direction = "<<<"; \ + pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \ + __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ + l & 0xff, l >> 8, direction); \ +} + +#define EC168_USB_TIMEOUT 1000 + +struct ec168_req { + u8 cmd; /* [1] */ + u16 value; /* [2|3] */ + u16 index; /* [4|5] */ + u16 size; /* [6|7] */ + u8 *data; +}; + +enum ec168_cmd { + DOWNLOAD_FIRMWARE = 0x00, + CONFIG = 0x01, + DEMOD_RW = 0x03, + GPIO = 0x04, + STREAMING_CTRL = 0x10, + READ_I2C = 0x20, + WRITE_I2C = 0x21, + HID_DOWNLOAD = 0x30, + GET_CONFIG, + SET_CONFIG, + READ_DEMOD, + WRITE_DEMOD, +}; + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c new file mode 100644 index 00000000000..cf29f43e359 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -0,0 +1,175 @@ +/* DVB USB compliant linux driver for GL861 USB2.0 devices. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gl861.h" + +#include "zl10353.h" +#include "qt1010.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +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; + + if (wo) { + req = GL861_REQ_I2C_WRITE; + type = GL861_WRITE; + } else { /* rw */ + req = GL861_REQ_I2C_READ; + type = GL861_READ; + } + + switch (wlen) { + case 1: + index = wbuf[0]; + break; + case 2: + index = wbuf[0]; + value = value + wbuf[1]; + break; + default: + pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen); + return -EINVAL; + } + + msleep(1); /* avoid I2C errors */ + + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), 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 struct i2c_algorithm gl861_i2c_algo = { + .master_xfer = gl861_i2c_xfer, + .functionality = gl861_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config gl861_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int gl861_frontend_attach(struct dvb_usb_adapter *adap) +{ + + adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -EIO; + + return 0; +} + +static struct qt1010_config gl861_qt1010_config = { + .i2c_address = 0x62 +}; + +static int gl861_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe[0], &adap_to_d(adap)->i2c_adap, + &gl861_qt1010_config) == NULL ? -ENODEV : 0; +} + +static int gl861_init(struct dvb_usb_device *d) +{ + /* + * There is 2 interfaces. Interface 0 is for TV and interface 1 is + * for HID remote controller. Interface 0 has 2 alternate settings. + * For some reason we need to set interface explicitly, defaulted + * as alternate setting 1? + */ + return usb_set_interface(d->udev, 0, 0); +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties gl861_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + + .i2c_algo = &gl861_i2c_algo, + .frontend_attach = gl861_frontend_attach, + .tuner_attach = gl861_tuner_attach, + .init = gl861_init, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x81, 7, 512), + } + } +}; + +static const struct usb_device_id gl861_id_table[] = { + { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, + &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, + &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, gl861_id_table); + +static struct usb_driver gl861_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = gl861_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(gl861_usb_driver); + +MODULE_AUTHOR("Carl Lundqvist "); +MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/gl861.h b/drivers/media/usb/dvb-usb-v2/gl861.h new file mode 100644 index 00000000000..b0b80d87bb7 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/gl861.h @@ -0,0 +1,12 @@ +#ifndef _DVB_USB_GL861_H_ +#define _DVB_USB_GL861_H_ + +#include "dvb_usb.h" + +#define GL861_WRITE 0x40 +#define GL861_READ 0xc0 + +#define GL861_REQ_I2C_WRITE 0x01 +#define GL861_REQ_I2C_READ 0x02 + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c new file mode 100644 index 00000000000..695f9106bc5 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/it913x.c @@ -0,0 +1,799 @@ +/* + * DVB USB compliant linux driver for ITE IT9135 and IT9137 + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9135 (C) ITE Tech Inc. + * IT9137 (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * see Documentation/dvb/README.dvb-usb for more information + * see Documentation/dvb/it9137.txt for firmware information + * + */ +#define DVB_USB_LOG_PREFIX "it913x" + +#include +#include +#include + +#include "dvb_usb.h" +#include "it913x-fe.h" + +/* debug */ +static int dvb_usb_it913x_debug; +#define it_debug(var, level, args...) \ + do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \ +} while (0) +#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args) +#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args) + +module_param_named(debug, dvb_usb_it913x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +static int dvb_usb_it913x_firmware; +module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644); +MODULE_PARM_DESC(firmware, "set firmware 0=auto"\ + "1=IT9137 2=IT9135 V1 3=IT9135 V2"); +#define FW_IT9137 "dvb-usb-it9137-01.fw" +#define FW_IT9135_V1 "dvb-usb-it9135-01.fw" +#define FW_IT9135_V2 "dvb-usb-it9135-02.fw" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct it913x_state { + struct ite_config it913x_config; + u8 pid_filter_onoff; + bool proprietary_ir; + int cmd_counter; +}; + +static u16 check_sum(u8 *p, u8 len) +{ + u16 sum = 0; + u8 i = 1; + while (i < len) + sum += (i++ & 1) ? (*p++) << 8 : *p++; + return ~sum; +} + +static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro, + u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) +{ + struct it913x_state *st = d->priv; + int ret = 0, i, buf_size = 1; + u8 *buff; + u8 rlen; + u16 chk_sum; + + buff = kzalloc(256, GFP_KERNEL); + if (!buff) { + info("USB Buffer Failed"); + return -ENOMEM; + } + + buff[buf_size++] = pro; + buff[buf_size++] = cmd; + buff[buf_size++] = st->cmd_counter; + + switch (mode) { + case READ_LONG: + case WRITE_LONG: + buff[buf_size++] = len; + buff[buf_size++] = 2; + buff[buf_size++] = (reg >> 24); + buff[buf_size++] = (reg >> 16) & 0xff; + buff[buf_size++] = (reg >> 8) & 0xff; + buff[buf_size++] = reg & 0xff; + break; + case READ_SHORT: + buff[buf_size++] = addr; + break; + case WRITE_SHORT: + buff[buf_size++] = len; + buff[buf_size++] = addr; + buff[buf_size++] = (reg >> 8) & 0xff; + buff[buf_size++] = reg & 0xff; + break; + case READ_DATA: + case WRITE_DATA: + break; + case WRITE_CMD: + mode = 7; + break; + default: + kfree(buff); + return -EINVAL; + } + + if (mode & 1) { + for (i = 0; i < len ; i++) + buff[buf_size++] = data[i]; + } + chk_sum = check_sum(&buff[1], buf_size); + + buff[buf_size++] = chk_sum >> 8; + buff[0] = buf_size; + buff[buf_size++] = (chk_sum & 0xff); + + ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ? + 5 : len + 5); + if (ret < 0) + goto error; + + rlen = (mode & 0x1) ? 0x1 : len; + + if (mode & 1) + ret = buff[2]; + else + memcpy(data, &buff[3], rlen); + + st->cmd_counter++; + +error: kfree(buff); + + return ret; +} + +static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data) +{ + int ret; + u8 b[1]; + b[0] = data; + ret = it913x_io(d, WRITE_LONG, pro, + CMD_DEMOD_WRITE, reg, 0, b, sizeof(b)); + + return ret; +} + +static int it913x_read_reg(struct dvb_usb_device *d, u32 reg) +{ + int ret; + u8 data[1]; + + ret = it913x_io(d, READ_LONG, DEV_0, + CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data)); + + return (ret < 0) ? ret : data[0]; +} + +static int it913x_query(struct dvb_usb_device *d, u8 pro) +{ + struct it913x_state *st = d->priv; + int ret, i; + u8 data[4]; + u8 ver; + + for (i = 0; i < 5; i++) { + ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ, + 0x1222, 0, &data[0], 3); + ver = data[0]; + if (ver > 0 && ver < 3) + break; + msleep(100); + } + + if (ver < 1 || ver > 2) { + info("Failed to identify chip version applying 1"); + st->it913x_config.chip_ver = 0x1; + st->it913x_config.chip_type = 0x9135; + return 0; + } + + st->it913x_config.chip_ver = ver; + st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; + + info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver, + st->it913x_config.chip_type); + + ret = it913x_io(d, READ_SHORT, pro, + CMD_QUERYINFO, 0, 0x1, &data[0], 4); + + st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) | + (data[2] << 8) | data[3]; + + return ret; +} + +static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct it913x_state *st = adap_to_priv(adap); + int ret; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + + mutex_lock(&d->i2c_mutex); + + deb_info(1, "PID_C (%02x)", onoff); + + ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff); + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static int it913x_pid_filter(struct dvb_usb_adapter *adap, + int index, u16 pid, int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct it913x_state *st = adap_to_priv(adap); + int ret; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + + mutex_lock(&d->i2c_mutex); + + deb_info(1, "PID_F (%02x)", onoff); + + ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff)); + + ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8)); + + ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff); + + ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f)); + + if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) { + ret |= it913x_wr_reg(d , pro, PID_EN, !onoff); + st->pid_filter_onoff = !onoff; + } else + st->pid_filter_onoff = + adap->pid_filtering; + + mutex_unlock(&d->i2c_mutex); + return 0; +} + + +static int it913x_return_status(struct dvb_usb_device *d) +{ + struct it913x_state *st = d->priv; + int ret = it913x_query(d, DEV_0); + if (st->it913x_config.firmware > 0) + info("Firmware Version %d", st->it913x_config.firmware); + + return ret; +} + +static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + static u8 data[256]; + int ret; + u32 reg; + u8 pro; + + mutex_lock(&d->i2c_mutex); + + deb_info(2, "num of messages %d address %02x", num, msg[0].addr); + + pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0; + pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0; + memcpy(data, msg[0].buf, msg[0].len); + reg = (data[0] << 24) + (data[1] << 16) + + (data[2] << 8) + data[3]; + if (num == 2) { + ret = it913x_io(d, READ_LONG, pro, + CMD_DEMOD_READ, reg, 0, data, msg[1].len); + memcpy(msg[1].buf, data, msg[1].len); + } else + ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE, + reg, 0, &data[4], msg[0].len - 4); + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 it913x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm it913x_i2c_algo = { + .master_xfer = it913x_i2c_xfer, + .functionality = it913x_i2c_func, +}; + +/* Callbacks for DVB USB */ +#define IT913X_POLL 250 +static int it913x_rc_query(struct dvb_usb_device *d) +{ + u8 ibuf[4]; + int ret; + u32 key; + /* Avoid conflict with frontends*/ + mutex_lock(&d->i2c_mutex); + + ret = it913x_io(d, READ_LONG, PRO_LINK, CMD_IR_GET, + 0, 0, &ibuf[0], sizeof(ibuf)); + + if ((ibuf[2] + ibuf[3]) == 0xff) { + key = ibuf[2]; + key += ibuf[0] << 16; + key += ibuf[1] << 8; + deb_info(1, "NEC Extended Key =%08x", key); + if (d->rc_dev != NULL) + rc_keydown(d->rc_dev, key, 0); + } + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +/* Firmware sets raw */ +static const char fw_it9135_v1[] = FW_IT9135_V1; +static const char fw_it9135_v2[] = FW_IT9135_V2; +static const char fw_it9137[] = FW_IT9137; + +static void ite_get_firmware_name(struct dvb_usb_device *d, + const char **name) +{ + struct it913x_state *st = d->priv; + int sw; + /* auto switch */ + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2) + sw = IT9137_FW; + else if (st->it913x_config.chip_ver == 1) + sw = IT9135_V1_FW; + else + sw = IT9135_V2_FW; + + /* force switch */ + if (dvb_usb_it913x_firmware != IT9135_AUTO) + sw = dvb_usb_it913x_firmware; + + switch (sw) { + case IT9135_V1_FW: + st->it913x_config.firmware_ver = 1; + st->it913x_config.adc_x2 = 1; + st->it913x_config.read_slevel = false; + *name = fw_it9135_v1; + break; + case IT9135_V2_FW: + st->it913x_config.firmware_ver = 1; + st->it913x_config.adc_x2 = 1; + st->it913x_config.read_slevel = false; + *name = fw_it9135_v2; + switch (st->it913x_config.tuner_id_0) { + case IT9135_61: + case IT9135_62: + break; + default: + info("Unknown tuner ID applying default 0x60"); + case IT9135_60: + st->it913x_config.tuner_id_0 = IT9135_60; + } + break; + case IT9137_FW: + default: + st->it913x_config.firmware_ver = 0; + st->it913x_config.adc_x2 = 0; + st->it913x_config.read_slevel = true; + *name = fw_it9137; + } + + return; +} + +#define TS_MPEG_PKT_SIZE 188 +#define EP_LOW 21 +#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) +#define EP_HIGH 348 +#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) + +static int it913x_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, + struct usb_data_stream_properties *stream) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + if (adap->pid_filtering) + stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID; + else + stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX; + + return 0; +} + +static int it913x_select_config(struct dvb_usb_device *d) +{ + struct it913x_state *st = d->priv; + int ret, reg; + + ret = it913x_return_status(d); + if (ret < 0) + return ret; + + if (st->it913x_config.chip_ver == 0x02 + && st->it913x_config.chip_type == 0x9135) + reg = it913x_read_reg(d, 0x461d); + else + reg = it913x_read_reg(d, 0x461b); + + if (reg < 0) + return reg; + + if (reg == 0) { + st->it913x_config.dual_mode = 0; + st->it913x_config.tuner_id_0 = IT9135_38; + st->proprietary_ir = true; + } else { + /* TS mode */ + reg = it913x_read_reg(d, 0x49c5); + if (reg < 0) + return reg; + st->it913x_config.dual_mode = reg; + + /* IR mode type */ + reg = it913x_read_reg(d, 0x49ac); + if (reg < 0) + return reg; + if (reg == 5) { + info("Remote propriety (raw) mode"); + st->proprietary_ir = true; + } else if (reg == 1) { + info("Remote HID mode NOT SUPPORTED"); + st->proprietary_ir = false; + } + + /* Tuner_id */ + reg = it913x_read_reg(d, 0x49d0); + if (reg < 0) + return reg; + st->it913x_config.tuner_id_0 = reg; + } + + info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode, + st->it913x_config.tuner_id_0); + + return ret; +} + +static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + struct it913x_state *st = fe_to_priv(fe); + int ret = 0; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + + deb_info(1, "STM (%02x)", onoff); + + if (!onoff) { + mutex_lock(&d->i2c_mutex); + + ret = it913x_wr_reg(d, pro, PID_RST, 0x1); + + mutex_unlock(&d->i2c_mutex); + st->pid_filter_onoff = + adap->pid_filtering; + + } + + return ret; +} + +static int it913x_identify_state(struct dvb_usb_device *d, const char **name) +{ + struct it913x_state *st = d->priv; + int ret; + u8 reg; + + /* Read and select config */ + ret = it913x_select_config(d); + if (ret < 0) + return ret; + + ite_get_firmware_name(d, name); + + if (st->it913x_config.firmware > 0) + return WARM; + + if (st->it913x_config.dual_mode) { + st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0); + ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1); + ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1); + ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1); + msleep(50); + ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0); + msleep(50); + reg = it913x_read_reg(d, GPIOH1_O); + if (reg == 0) { + ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1); + ret |= it913x_return_status(d); + if (ret != 0) + ret = it913x_wr_reg(d, DEV_0, + GPIOH1_O, 0x0); + } + } + + reg = it913x_read_reg(d, IO_MUX_POWER_CLK); + + if (st->it913x_config.dual_mode) { + ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); + if (st->it913x_config.firmware_ver == 1) + ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x1); + else + ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x1); + } else { + ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0); + if (st->it913x_config.firmware_ver == 1) + ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x0); + else + ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x0); + } + + ret |= it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100); + + return (ret < 0) ? ret : COLD; +} + +static int it913x_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + struct it913x_state *st = d->priv; + int ret = 0, i = 0, pos = 0; + u8 packet_size, min_pkt; + u8 *fw_data; + + ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100); + + info("FRM Starting Firmware Download"); + + /* Multi firmware loader */ + /* This uses scatter write firmware headers */ + /* The firmware must start with 03 XX 00 */ + /* and be the extact firmware length */ + + if (st->it913x_config.chip_ver == 2) + min_pkt = 0x11; + else + min_pkt = 0x19; + + while (i <= fw->size) { + if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0)) + || (i == fw->size)) { + packet_size = i - pos; + if ((packet_size > min_pkt) || (i == fw->size)) { + fw_data = (u8 *)(fw->data + pos); + pos += packet_size; + if (packet_size > 0) { + ret = it913x_io(d, WRITE_DATA, + DEV_0, CMD_SCATTER_WRITE, 0, + 0, fw_data, packet_size); + if (ret < 0) + break; + } + udelay(1000); + } + } + i++; + } + + if (ret < 0) + info("FRM Firmware Download Failed (%d)" , ret); + else + info("FRM Firmware Download Completed - Resetting Device"); + + msleep(30); + + ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); + if (ret < 0) + info("FRM Device not responding to reboot"); + + ret = it913x_return_status(d); + if (st->it913x_config.firmware == 0) { + info("FRM Failed to reboot device"); + return -ENODEV; + } + + msleep(30); + + ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_400); + + msleep(30); + + /* Tuner function */ + if (st->it913x_config.dual_mode) + ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0); + else + ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68); + + if ((st->it913x_config.chip_ver == 1) && + (st->it913x_config.chip_type == 0x9135)) { + ret |= it913x_wr_reg(d, DEV_0, PADODPU, 0x0); + ret |= it913x_wr_reg(d, DEV_0, AGC_O_D, 0x0); + if (st->it913x_config.dual_mode) { + ret |= it913x_wr_reg(d, DEV_1, PADODPU, 0x0); + ret |= it913x_wr_reg(d, DEV_1, AGC_O_D, 0x0); + } + } + + return (ret < 0) ? -ENODEV : 0; +} + +static int it913x_name(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + const char *desc = d->name; + char *fe_name[] = {"_1", "_2", "_3", "_4"}; + char *name = adap->fe[0]->ops.info.name; + + strlcpy(name, desc, 128); + strlcat(name, fe_name[adap->id], 128); + + return 0; +} + +static int it913x_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct it913x_state *st = d->priv; + int ret = 0; + u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); + u16 ep_size = adap->stream.buf_size / 4; + u8 pkt_size = 0x80; + + if (d->udev->speed != USB_SPEED_HIGH) + pkt_size = 0x10; + + st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK); + + adap->fe[0] = dvb_attach(it913x_fe_attach, + &d->i2c_adap, adap_addr, &st->it913x_config); + + if (adap->id == 0 && adap->fe[0]) { + it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1); + it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1); + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f); + it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b); + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f); + it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB, + ep_size & 0xff); + it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); + ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size); + } else if (adap->id == 1 && adap->fe[0]) { + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f); + it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB, + ep_size & 0xff); + it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); + it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size); + it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1); + it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1); + it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1); + it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1); + it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0); + it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0); + it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0); + it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1); + it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0); + ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0); + } else + return -ENODEV; + + ret |= it913x_name(adap); + + return ret; +} + +/* DVB USB Driver */ +static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + struct it913x_state *st = d->priv; + + if (st->proprietary_ir == false) { + rc->map_name = NULL; + return 0; + } + + rc->allowed_protos = RC_TYPE_NEC; + rc->query = it913x_rc_query; + rc->interval = 250; + + return 0; +} + +static int it913x_get_adapter_count(struct dvb_usb_device *d) +{ + struct it913x_state *st = d->priv; + if (st->it913x_config.dual_mode) + return 2; + return 1; +} + +static struct dvb_usb_device_properties it913x_properties = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .bInterfaceNumber = 0, + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct it913x_state), + + .identify_state = it913x_identify_state, + .i2c_algo = &it913x_i2c_algo, + + .download_firmware = it913x_download_firmware, + + .frontend_attach = it913x_frontend_attach, + .get_rc_config = it913x_get_rc_config, + .get_stream_config = it913x_get_stream_config, + .get_adapter_count = it913x_get_adapter_count, + .streaming_ctrl = it913x_streaming_ctrl, + + + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = it913x_pid_filter, + .pid_filter_ctrl = it913x_pid_filter_ctrl, + .stream = + DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX), + }, + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = it913x_pid_filter, + .pid_filter_ctrl = it913x_pid_filter_ctrl, + .stream = + DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX), + } + } +}; + +static const struct usb_device_id it913x_id_table[] = { + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09, + &it913x_properties, "Kworld UB499-2T T09(IT9137)", + RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135, + &it913x_properties, "ITE 9135 Generic", + RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137, + &it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)", + RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005, + &it913x_properties, "ITE 9135(9005) Generic", + RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006, + &it913x_properties, "ITE 9135(9006) Generic", + RC_MAP_IT913X_V1) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, it913x_id_table); + +static struct usb_driver it913x_driver = { + .name = KBUILD_MODNAME, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .id_table = it913x_id_table, +}; + +module_usb_driver(it913x_driver); + +MODULE_AUTHOR("Malcolm Priestley "); +MODULE_DESCRIPTION("it913x USB 2 Driver"); +MODULE_VERSION("1.32"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(FW_IT9135_V1); +MODULE_FIRMWARE(FW_IT9135_V2); +MODULE_FIRMWARE(FW_IT9137); + diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c new file mode 100644 index 00000000000..c41d9d9ec7b --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -0,0 +1,1369 @@ +/* DVB USB compliant linux driver for + * + * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 + * LME2510C + LG TDQY-P001F + * LME2510C + BS2F7HZ0194 + * LME2510 + LG TDQY-P001F + * LME2510 + BS2F7HZ0194 + * + * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) + * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) + * + * MV001F (LME2510+LGTDQY-P001F) + * LG TDQY - P001F =(TDA8263 + TDA10086H) + * + * MVB0001F (LME2510C+LGTDQT-P001F) + * + * MV0194 (LME2510+SHARP:BS2F7HZ0194) + * SHARP:BS2F7HZ0194 = (STV0299+IX2410) + * + * MVB0194 (LME2510C+SHARP0194) + * + * LME2510C + M88RS2000 + * + * For firmware see Documentation/dvb/lmedm04.txt + * + * I2C addresses: + * 0xd0 - STV0288 - Demodulator + * 0xc0 - Sharp IX2505V - Tuner + * -- + * 0x1c - TDA10086 - Demodulator + * 0xc0 - TDA8263 - Tuner + * -- + * 0xd0 - STV0299 - Demodulator + * 0xc0 - IX2410 - Tuner + * + * + * VID = 3344 PID LME2510=1122 LME2510C=1120 + * + * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com) + * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * see Documentation/dvb/README.dvb-usb for more information + * + * Known Issues : + * LME2510: Non Intel USB chipsets fail to maintain High Speed on + * Boot or Hot Plug. + * + * QQbox suffers from noise on LNB voltage. + * + * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system + * with other tuners. After a cold reset streaming will not start. + * + * M88RS2000 suffers from loss of lock. + */ +#define DVB_USB_LOG_PREFIX "LME2510(C)" +#include +#include +#include + +#include "dvb_usb.h" +#include "lmedm04.h" +#include "tda826x.h" +#include "tda10086.h" +#include "stv0288.h" +#include "ix2505v.h" +#include "stv0299.h" +#include "dvb-pll.h" +#include "z0194a.h" +#include "m88rs2000.h" + + +#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; +#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; +#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; +#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; +#define LME2510_LG "dvb-usb-lme2510-lg.fw"; +#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; + +/* debug */ +static int dvb_usb_lme2510_debug; +#define lme_debug(var, level, args...) do { \ + if ((var >= level)) \ + pr_debug(DVB_USB_LOG_PREFIX": " args); \ +} while (0) +#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args) +#define debug_data_snipet(level, name, p) \ + deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ + *p, *(p+1), *(p+2), *(p+3), *(p+4), \ + *(p+5), *(p+6), *(p+7)); +#define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args) + +module_param_named(debug, dvb_usb_lme2510_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +static int dvb_usb_lme2510_firmware; +module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644); +MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); + +static int pid_filter; +module_param_named(pid, pid_filter, int, 0644); +MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); + + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define TUNER_DEFAULT 0x0 +#define TUNER_LG 0x1 +#define TUNER_S7395 0x2 +#define TUNER_S0194 0x3 +#define TUNER_RS2000 0x4 + +struct lme2510_state { + u8 id; + u8 tuner_config; + u8 signal_lock; + u8 signal_level; + u8 signal_sn; + u8 time_key; + u8 last_key; + u8 key_timeout; + u8 i2c_talk_onoff; + u8 i2c_gate; + u8 i2c_tuner_gate_w; + u8 i2c_tuner_gate_r; + u8 i2c_tuner_addr; + u8 stream_on; + u8 pid_size; + u8 pid_off; + void *buffer; + struct urb *lme_urb; + void *usb_buffer; + int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); + u8 dvb_usb_lme2510_firmware; +}; + +static int lme2510_bulk_write(struct usb_device *dev, + u8 *snd, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len , &actual_l, 100); + return ret; +} + +static int lme2510_bulk_read(struct usb_device *dev, + u8 *rev, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len , &actual_l, 200); + return ret; +} + +static int lme2510_usb_talk(struct dvb_usb_device *d, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct lme2510_state *st = d->priv; + u8 *buff; + int ret = 0; + + if (st->usb_buffer == NULL) { + st->usb_buffer = kmalloc(64, GFP_KERNEL); + if (st->usb_buffer == NULL) { + info("MEM Error no memory"); + return -ENOMEM; + } + } + buff = st->usb_buffer; + + ret = mutex_lock_interruptible(&d->usb_mutex); + + if (ret < 0) + return -EAGAIN; + + /* the read/write capped at 64 */ + memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); + + ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); + + ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? + rlen : 64 , 0x01); + + if (rlen > 0) + memcpy(rbuf, buff, rlen); + + mutex_unlock(&d->usb_mutex); + + return (ret < 0) ? -ENODEV : 0; +} + +static int lme2510_stream_restart(struct dvb_usb_device *d) +{ + struct lme2510_state *st = d->priv; + u8 all_pids[] = LME_ALL_PIDS; + u8 stream_on[] = LME_ST_ON_W; + int ret; + u8 rbuff[1]; + if (st->pid_off) + ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), + rbuff, sizeof(rbuff)); + /*Restart Stream Command*/ + ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), + rbuff, sizeof(rbuff)); + return ret; +} + +static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) +{ + struct lme2510_state *st = d->priv; + static u8 pid_buff[] = LME_ZERO_PID; + static u8 rbuf[1]; + u8 pid_no = index * 2; + u8 pid_len = pid_no + 2; + int ret = 0; + deb_info(1, "PID Setting Pid %04x", pid_out); + + if (st->pid_size == 0) + ret |= lme2510_stream_restart(d); + + pid_buff[2] = pid_no; + pid_buff[3] = (u8)pid_out & 0xff; + pid_buff[4] = pid_no + 1; + pid_buff[5] = (u8)(pid_out >> 8); + + if (pid_len > st->pid_size) + st->pid_size = pid_len; + pid_buff[7] = 0x80 + st->pid_size; + + ret |= lme2510_usb_talk(d, pid_buff , + sizeof(pid_buff) , rbuf, sizeof(rbuf)); + + if (st->stream_on) + ret |= lme2510_stream_restart(d); + + return ret; +} + +static void lme2510_int_response(struct urb *lme_urb) +{ + struct dvb_usb_adapter *adap = lme_urb->context; + struct lme2510_state *st = adap_to_priv(adap); + static u8 *ibuf, *rbuf; + int i = 0, offset; + u32 key; + + switch (lme_urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: + info("Error %x", lme_urb->status); + break; + } + + rbuf = (u8 *) lme_urb->transfer_buffer; + + offset = ((lme_urb->actual_length/8) > 4) + ? 4 : (lme_urb->actual_length/8) ; + + for (i = 0; i < offset; ++i) { + ibuf = (u8 *)&rbuf[i*8]; + deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x", + offset, i, ibuf[0], ibuf[1]); + + switch (ibuf[0]) { + case 0xaa: + debug_data_snipet(1, "INT Remote data snipet", ibuf); + if ((ibuf[4] + ibuf[5]) == 0xff) { + key = ibuf[5]; + key += (ibuf[3] > 0) + ? (ibuf[3] ^ 0xff) << 8 : 0; + key += (ibuf[2] ^ 0xff) << 16; + deb_info(1, "INT Key =%08x", key); + if (adap_to_d(adap)->rc_dev != NULL) + rc_keydown(adap_to_d(adap)->rc_dev, + key, 0); + } + break; + case 0xbb: + switch (st->tuner_config) { + case TUNER_LG: + if (ibuf[2] > 0) + st->signal_lock = ibuf[2]; + st->signal_level = ibuf[4]; + st->signal_sn = ibuf[3]; + st->time_key = ibuf[7]; + break; + case TUNER_S7395: + case TUNER_S0194: + /* Tweak for earlier firmware*/ + if (ibuf[1] == 0x03) { + if (ibuf[2] > 1) + st->signal_lock = ibuf[2]; + st->signal_level = ibuf[3]; + st->signal_sn = ibuf[4]; + } else { + st->signal_level = ibuf[4]; + st->signal_sn = ibuf[5]; + st->signal_lock = + (st->signal_lock & 0xf7) + + ((ibuf[2] & 0x01) << 0x03); + } + break; + case TUNER_RS2000: + if (ibuf[1] == 0x3 && ibuf[6] == 0xff) + st->signal_lock = 0xff; + else + st->signal_lock = 0x00; + st->signal_level = ibuf[5]; + st->signal_sn = ibuf[4]; + st->time_key = ibuf[7]; + default: + break; + } + debug_data_snipet(5, "INT Remote data snipet in", ibuf); + break; + case 0xcc: + debug_data_snipet(1, "INT Control data snipet", ibuf); + break; + default: + debug_data_snipet(1, "INT Unknown data snipet", ibuf); + break; + } + } + usb_submit_urb(lme_urb, GFP_ATOMIC); +} + +static int lme2510_int_read(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *lme_int = adap_to_priv(adap); + + lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (lme_int->lme_urb == NULL) + return -ENOMEM; + + lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC, + &lme_int->lme_urb->transfer_dma); + + if (lme_int->buffer == NULL) + return -ENOMEM; + + usb_fill_int_urb(lme_int->lme_urb, + d->udev, + usb_rcvintpipe(d->udev, 0xa), + lme_int->buffer, + 128, + lme2510_int_response, + adap, + 8); + + lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); + info("INT Interrupt Service Started"); + + return 0; +} + +static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + static u8 clear_pid_reg[] = LME_ALL_PIDS; + static u8 rbuf[1]; + int ret = 0; + + deb_info(1, "PID Clearing Filter"); + + mutex_lock(&d->i2c_mutex); + + if (!onoff) { + ret |= lme2510_usb_talk(d, clear_pid_reg, + sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); + st->pid_off = true; + } else + st->pid_off = false; + + st->pid_size = 0; + + mutex_unlock(&d->i2c_mutex); + + return 0; +} + +static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + int ret = 0; + + deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, + pid, index, onoff); + + if (onoff) { + mutex_lock(&d->i2c_mutex); + ret |= lme2510_enable_pid(d, index, pid); + mutex_unlock(&d->i2c_mutex); + } + + + return ret; +} + + +static int lme2510_return_status(struct dvb_usb_device *d) +{ + int ret = 0; + u8 *data; + + data = kzalloc(10, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); + info("Firmware Status: %x (%x)", ret , data[2]); + + ret = (ret < 0) ? -ENODEV : data[2]; + kfree(data); + return ret; +} + +static int lme2510_msg(struct dvb_usb_device *d, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int ret = 0; + struct lme2510_state *st = d->priv; + + if (st->i2c_talk_onoff == 1) { + + ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + + switch (st->tuner_config) { + case TUNER_LG: + if (wbuf[2] == 0x1c) { + if (wbuf[3] == 0x0e) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x10)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + msleep(80); + } + } + break; + case TUNER_S7395: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x24) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + } + break; + case TUNER_S0194: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x1b) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + } + break; + case TUNER_RS2000: + default: + break; + } + } else { + /* TODO rewrite this section */ + switch (st->tuner_config) { + case TUNER_LG: + switch (wbuf[3]) { + case 0x0e: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x43: + rbuf[0] = 0x55; + rbuf[1] = st->signal_level; + break; + case 0x1c: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_S7395: + switch (wbuf[3]) { + case 0x10: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x2d: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x2e: + case 0x26: + case 0x27: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_S0194: + switch (wbuf[3]) { + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x1b: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x19: + case 0x25: + case 0x1e: + case 0x1d: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_RS2000: + switch (wbuf[3]) { + case 0x8c: + rbuf[0] = 0x55; + rbuf[1] = 0xff; + if (st->last_key == st->time_key) { + st->key_timeout++; + if (st->key_timeout > 5) + rbuf[1] = 0; + } else + st->key_timeout = 0; + st->last_key = st->time_key; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + default: + break; + } + + deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", + wbuf[3], rbuf[1]); + + } + + return ret; +} + + +static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct lme2510_state *st = d->priv; + static u8 obuf[64], ibuf[64]; + int i, read, read_o; + u16 len; + u8 gate = st->i2c_gate; + + mutex_lock(&d->i2c_mutex); + + if (gate == 0) + gate = 5; + + for (i = 0; i < num; i++) { + read_o = 1 & (msg[i].flags & I2C_M_RD); + read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + read |= read_o; + gate = (msg[i].addr == st->i2c_tuner_addr) + ? (read) ? st->i2c_tuner_gate_r + : st->i2c_tuner_gate_w + : st->i2c_gate; + obuf[0] = gate | (read << 7); + + if (gate == 5) + obuf[1] = (read) ? 2 : msg[i].len + 1; + else + obuf[1] = msg[i].len + read + 1; + + obuf[2] = msg[i].addr; + if (read) { + if (read_o) + len = 3; + else { + memcpy(&obuf[3], msg[i].buf, msg[i].len); + obuf[msg[i].len+3] = msg[i+1].len; + len = msg[i].len+4; + } + } else { + memcpy(&obuf[3], msg[i].buf, msg[i].len); + len = msg[i].len+3; + } + + if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { + deb_info(1, "i2c transfer failed."); + mutex_unlock(&d->i2c_mutex); + return -EAGAIN; + } + + if (read) { + if (read_o) + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + else { + memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + i++; + } + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 lme2510_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm lme2510_i2c_algo = { + .master_xfer = lme2510_i2c_xfer, + .functionality = lme2510_i2c_func, +}; + +static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + static u8 clear_reg_3[] = LME_ALL_PIDS; + static u8 rbuf[1]; + int ret = 0, rlen = sizeof(rbuf); + + deb_info(1, "STM (%02x)", onoff); + + /* Streaming is started by FE_HAS_LOCK */ + if (onoff == 1) + st->stream_on = 1; + else { + deb_info(1, "STM Steam Off"); + /* mutex is here only to avoid collision with I2C */ + mutex_lock(&d->i2c_mutex); + + ret = lme2510_usb_talk(d, clear_reg_3, + sizeof(clear_reg_3), rbuf, rlen); + st->stream_on = 0; + st->i2c_talk_onoff = 1; + + mutex_unlock(&d->i2c_mutex); + } + + return (ret < 0) ? -ENODEV : 0; +} + +static u8 check_sum(u8 *p, u8 len) +{ + u8 sum = 0; + while (len--) + sum += *p++; + return sum; +} + +static int lme2510_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret = 0; + u8 *data; + u16 j, wlen, len_in, start, end; + u8 packet_size, dlen, i; + u8 *fw_data; + + packet_size = 0x31; + len_in = 1; + + data = kzalloc(128, GFP_KERNEL); + if (!data) { + info("FRM Could not start Firmware Download"\ + "(Buffer allocation failed)"); + return -ENOMEM; + } + + info("FRM Starting Firmware Download"); + + for (i = 1; i < 3; i++) { + start = (i == 1) ? 0 : 512; + end = (i == 1) ? 512 : fw->size; + for (j = start; j < end; j += (packet_size+1)) { + fw_data = (u8 *)(fw->data + j); + if ((end - j) > packet_size) { + data[0] = i; + dlen = packet_size; + } else { + data[0] = i | 0x80; + dlen = (u8)(end - j)-1; + } + data[1] = dlen; + memcpy(&data[2], fw_data, dlen+1); + wlen = (u8) dlen + 4; + data[wlen-1] = check_sum(fw_data, dlen+1); + deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3], + data[dlen+2], data[dlen+3]); + lme2510_usb_talk(d, data, wlen, data, len_in); + ret |= (data[0] == 0x88) ? 0 : -1; + } + } + + data[0] = 0x8a; + len_in = 1; + msleep(2000); + lme2510_usb_talk(d, data, len_in, data, len_in); + msleep(400); + + if (ret < 0) + info("FRM Firmware Download Failed (%04x)" , ret); + else + info("FRM Firmware Download Completed - Resetting Device"); + + kfree(data); + return RECONNECTS_USB; +} + +static void lme_coldreset(struct dvb_usb_device *d) +{ + u8 data[1] = {0}; + data[0] = 0x0a; + info("FRM Firmware Cold Reset"); + + lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data)); + + return; +} + +static const char fw_c_s7395[] = LME2510_C_S7395; +static const char fw_c_lg[] = LME2510_C_LG; +static const char fw_c_s0194[] = LME2510_C_S0194; +static const char fw_c_rs2000[] = LME2510_C_RS2000; +static const char fw_lg[] = LME2510_LG; +static const char fw_s0194[] = LME2510_S0194; + +const char *lme_firmware_switch(struct dvb_usb_device *d, int cold) +{ + struct lme2510_state *st = d->priv; + struct usb_device *udev = d->udev; + const struct firmware *fw = NULL; + const char *fw_lme; + int ret = 0; + + cold = (cold > 0) ? (cold & 1) : 0; + + switch (le16_to_cpu(udev->descriptor.idProduct)) { + case 0x1122: + switch (st->dvb_usb_lme2510_firmware) { + default: + st->dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0; + break; + } + st->dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; + break; + } + break; + case 0x1120: + switch (st->dvb_usb_lme2510_firmware) { + default: + st->dvb_usb_lme2510_firmware = TUNER_S7395; + case TUNER_S7395: + fw_lme = fw_c_s7395; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0; + break; + } + st->dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_c_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + st->dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_c_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; + cold = 0; + break; + } + break; + case 0x22f0: + fw_lme = fw_c_rs2000; + st->dvb_usb_lme2510_firmware = TUNER_RS2000; + break; + default: + fw_lme = fw_c_s7395; + } + + release_firmware(fw); + + if (cold) { + dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware; + info("FRM Changing to %s firmware", fw_lme); + lme_coldreset(d); + return NULL; + } + + return fw_lme; +} + +static int lme2510_kill_urb(struct usb_data_stream *stream) +{ + int i; + + for (i = 0; i < stream->urbs_submitted; i++) { + deb_info(3, "killing URB no. %d.", i); + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + + return 0; +} + +static struct tda10086_config tda10086_config = { + .demod_address = 0x1c, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct stv0288_config lme_config = { + .demod_address = 0xd0, + .min_delay_ms = 15, + .inittab = s7395_inittab, +}; + +static struct ix2505v_config lme_tuner = { + .tuner_address = 0xc0, + .min_delay_ms = 100, + .tuner_gain = 0x0, + .tuner_chargepump = 0x3, +}; + +static struct stv0299_config sharp_z0194_config = { + .demod_address = 0xd0, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, + int caller) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = d->priv; + + mutex_lock(&d->i2c_mutex); + if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { + st->i2c_talk_onoff = 0; + lme2510_stream_restart(d); + } + mutex_unlock(&d->i2c_mutex); + + return 0; +} + +static struct m88rs2000_config m88rs2000_config = { + .demod_addr = 0xd0, + .tuner_addr = 0xc0, + .set_ts_params = dm04_rs2000_set_ts_param, +}; + +static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct lme2510_state *st = fe_to_priv(fe); + static u8 voltage_low[] = LME_VOLTAGE_L; + static u8 voltage_high[] = LME_VOLTAGE_H; + static u8 rbuf[1]; + int ret = 0, len = 3, rlen = 1; + + mutex_lock(&d->i2c_mutex); + + switch (voltage) { + case SEC_VOLTAGE_18: + ret |= lme2510_usb_talk(d, + voltage_high, len, rbuf, rlen); + break; + + case SEC_VOLTAGE_OFF: + case SEC_VOLTAGE_13: + default: + ret |= lme2510_usb_talk(d, + voltage_low, len, rbuf, rlen); + break; + } + + mutex_unlock(&d->i2c_mutex); + + if (st->tuner_config == TUNER_RS2000) + if (st->fe_set_voltage) + st->fe_set_voltage(fe, voltage); + + + return (ret < 0) ? -ENODEV : 0; +} + +static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct lme2510_state *st = fe_to_priv(fe); + + *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); + + return 0; +} + +static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lme2510_state *st = fe_to_priv(fe); + + *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); + + return 0; +} + +static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + + return 0; +} + +static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + + return 0; +} + +static int lme_name(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + const char *desc = d->name; + char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", + " SHARP:BS2F7HZ0194", " RS2000"}; + char *name = adap->fe[0]->ops.info.name; + + strlcpy(name, desc, 128); + strlcat(name, fe_name[st->tuner_config], 128); + + return 0; +} + +static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = d->priv; + int ret = 0; + + st->i2c_talk_onoff = 1; + switch (le16_to_cpu(d->udev->descriptor.idProduct)) { + case 0x1122: + case 0x1120: + st->i2c_gate = 4; + adap->fe[0] = dvb_attach(tda10086_attach, + &tda10086_config, &d->i2c_adap); + if (adap->fe[0]) { + info("TUN Found Frontend TDA10086"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 4; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_LG; + if (st->dvb_usb_lme2510_firmware != TUNER_LG) { + st->dvb_usb_lme2510_firmware = TUNER_LG; + ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; + } + break; + } + + st->i2c_gate = 4; + adap->fe[0] = dvb_attach(stv0299_attach, + &sharp_z0194_config, &d->i2c_adap); + if (adap->fe[0]) { + info("FE Found Stv0299"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S0194; + if (st->dvb_usb_lme2510_firmware != TUNER_S0194) { + st->dvb_usb_lme2510_firmware = TUNER_S0194; + ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; + } + break; + } + + st->i2c_gate = 5; + adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, + &d->i2c_adap); + + if (adap->fe[0]) { + info("FE Found Stv0288"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S7395; + if (st->dvb_usb_lme2510_firmware != TUNER_S7395) { + st->dvb_usb_lme2510_firmware = TUNER_S7395; + ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV; + } + break; + } + case 0x22f0: + st->i2c_gate = 5; + adap->fe[0] = dvb_attach(m88rs2000_attach, + &m88rs2000_config, &d->i2c_adap); + + if (adap->fe[0]) { + info("FE Found M88RS2000"); + st->i2c_tuner_gate_w = 5; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_RS2000; + st->fe_set_voltage = + adap->fe[0]->ops.set_voltage; + + adap->fe[0]->ops.read_signal_strength = + dm04_rs2000_read_signal_strength; + adap->fe[0]->ops.read_snr = + dm04_rs2000_read_snr; + adap->fe[0]->ops.read_ber = + dm04_read_ber; + adap->fe[0]->ops.read_ucblocks = + dm04_read_ucblocks; + } + break; + } + + if (adap->fe[0] == NULL) { + info("DM04/QQBOX Not Powered up or not Supported"); + return -ENODEV; + } + + if (ret) { + if (adap->fe[0]) { + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; + } + d->rc_map = NULL; + return -ENODEV; + } + + adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; + ret = lme_name(adap); + return ret; +} + +static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct lme2510_state *st = adap_to_priv(adap); + char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; + int ret = 0; + + switch (st->tuner_config) { + case TUNER_LG: + if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, + &d->i2c_adap, 1)) + ret = st->tuner_config; + break; + case TUNER_S7395: + if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, + &d->i2c_adap)) + ret = st->tuner_config; + break; + case TUNER_S0194: + if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, + &d->i2c_adap, DVB_PLL_OPERA1)) + ret = st->tuner_config; + break; + case TUNER_RS2000: + ret = st->tuner_config; + break; + default: + break; + } + + if (ret) + info("TUN Found %s tuner", tun_msg[ret]); + else { + info("TUN No tuner found --- resetting device"); + lme_coldreset(d); + return -ENODEV; + } + + /* Start the Interrupt*/ + ret = lme2510_int_read(adap); + if (ret < 0) { + info("INT Unable to start Interrupt Service"); + return -ENODEV; + } + + return ret; +} + +static int lme2510_powerup(struct dvb_usb_device *d, int onoff) +{ + struct lme2510_state *st = d->priv; + static u8 lnb_on[] = LNB_ON; + static u8 lnb_off[] = LNB_OFF; + static u8 rbuf[1]; + int ret = 0, len = 3, rlen = 1; + + mutex_lock(&d->i2c_mutex); + + if (onoff) + ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); + else + ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); + + st->i2c_talk_onoff = 1; + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static int lme2510_get_adapter_count(struct dvb_usb_device *d) +{ + return 1; +} + +static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) +{ + struct lme2510_state *st = d->priv; + + usb_reset_configuration(d->udev); + + usb_set_interface(d->udev, + d->intf->cur_altsetting->desc.bInterfaceNumber, 1); + + st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; + + if (lme2510_return_status(d) == 0x44) { + *name = lme_firmware_switch(d, 0); + return COLD; + } + + return 0; +} + +static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, + struct usb_data_stream_properties *stream) +{ + struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct dvb_usb_device *d = adap_to_d(adap); + + if (adap == NULL) + return 0; + /* Turn PID filter on the fly by module option */ + if (pid_filter == 2) { + adap->pid_filtering = 1; + adap->max_feed_count = 15; + } + + if (!(le16_to_cpu(d->udev->descriptor.idProduct) + == 0x1122)) + stream->endpoint = 0x8; + + return 0; +} + +static int lme2510_get_rc_config(struct dvb_usb_device *d, + struct dvb_usb_rc *rc) +{ + rc->allowed_protos = RC_TYPE_NEC; + return 0; +} + +static void *lme2510_exit_int(struct dvb_usb_device *d) +{ + struct lme2510_state *st = d->priv; + struct dvb_usb_adapter *adap = &d->adapter[0]; + void *buffer = NULL; + + if (adap != NULL) { + lme2510_kill_urb(&adap->stream); + } + + if (st->usb_buffer != NULL) { + st->i2c_talk_onoff = 1; + st->signal_lock = 0; + st->signal_level = 0; + st->signal_sn = 0; + buffer = st->usb_buffer; + } + + if (st->lme_urb != NULL) { + usb_kill_urb(st->lme_urb); + usb_free_coherent(d->udev, 128, st->buffer, + st->lme_urb->transfer_dma); + info("Interrupt Service Stopped"); + } + + return buffer; +} + +static void lme2510_exit(struct dvb_usb_device *d) +{ + void *usb_buffer; + + if (d != NULL) { + usb_buffer = lme2510_exit_int(d); + if (usb_buffer != NULL) + kfree(usb_buffer); + } +} + +static struct dvb_usb_device_properties lme2510_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .bInterfaceNumber = 0, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct lme2510_state), + + .download_firmware = lme2510_download_firmware, + + .power_ctrl = lme2510_powerup, + .identify_state = lme2510_identify_state, + .i2c_algo = &lme2510_i2c_algo, + + .frontend_attach = dm04_lme2510_frontend_attach, + .tuner_attach = dm04_lme2510_tuner, + .get_stream_config = lme2510_get_stream_config, + .get_adapter_count = lme2510_get_adapter_count, + .streaming_ctrl = lme2510_streaming_ctrl, + + .get_rc_config = lme2510_get_rc_config, + + .exit = lme2510_exit, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 15, + .pid_filter = lme2510_pid_filter, + .pid_filter_ctrl = lme2510_pid_filter_ctrl, + .stream = + DVB_USB_STREAM_BULK(0x86, 10, 4096), + }, + { + } + }, +}; + +static const struct usb_device_id lme2510_id_table[] = { + { DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props, + "DM04_LME2510_DVB-S", RC_MAP_LME2510) }, + { DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props, + "DM04_LME2510C_DVB-S", RC_MAP_LME2510) }, + { DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props, + "DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, lme2510_id_table); + +static struct usb_driver lme2510_driver = { + .name = KBUILD_MODNAME, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .id_table = lme2510_id_table, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(lme2510_driver); + +MODULE_AUTHOR("Malcolm Priestley "); +MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); +MODULE_VERSION("2.06"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(LME2510_C_S7395); +MODULE_FIRMWARE(LME2510_C_LG); +MODULE_FIRMWARE(LME2510_C_S0194); +MODULE_FIRMWARE(LME2510_C_RS2000); +MODULE_FIRMWARE(LME2510_LG); +MODULE_FIRMWARE(LME2510_S0194); + diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.h b/drivers/media/usb/dvb-usb-v2/lmedm04.h new file mode 100644 index 00000000000..e9c207205c2 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.h @@ -0,0 +1,175 @@ +/* DVB USB compliant linux driver for + * + * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 + * LME2510C + LG TDQY-P001F + * LME2510 + LG TDQY-P001F + * + * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) + * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) + * + * MVB001F (LME2510+LGTDQT-P001F) + * LG TDQY - P001F =(TDA8263 + TDA10086H) + * + * MVB0001F (LME2510C+LGTDQT-P001F) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_LME2510_H_ +#define _DVB_USB_LME2510_H_ + +/* Streamer & PID + * + * Note: These commands do not actually stop the streaming + * but form some kind of packet filtering/stream count + * or tuning related functions. + * 06 XX + * offset 1 = 00 Enable Streaming + * + * + * PID + * 03 XX XX ----> reg number ---> setting....20 XX + * offset 1 = length + * offset 2 = start of data + * end byte -1 = 20 + * end byte = clear pid always a0, other wise 9c, 9a ?? + * +*/ +#define LME_ST_ON_W {0x06, 0x00} +#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} +#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} +#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} + +/* LNB Voltage + * 07 XX XX + * offset 1 = 01 + * offset 2 = 00=Voltage low 01=Voltage high + * + * LNB Power + * 03 01 XX + * offset 2 = 00=ON 01=OFF + */ + +#define LME_VOLTAGE_L {0x07, 0x01, 0x00} +#define LME_VOLTAGE_H {0x07, 0x01, 0x01} +#define LNB_ON {0x3a, 0x01, 0x00} +#define LNB_OFF {0x3a, 0x01, 0x01} + +/* Initial stv0288 settings for 7395 Frontend */ +static u8 s7395_inittab[] = { + 0x01, 0x15, + 0x02, 0x20, + 0x03, 0xa0, + 0x04, 0xa0, + 0x05, 0x12, + 0x06, 0x00, + 0x09, 0x00, + 0x0a, 0x04, + 0x0b, 0x00, + 0x0c, 0x00, + 0x0d, 0x00, + 0x0e, 0xc1, + 0x0f, 0x54, + 0x11, 0x7a, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0xc5, + 0x16, 0xb8, + 0x17, 0x9c, + 0x18, 0x00, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0xff, + 0x23, 0x01, + 0x28, 0x46, + 0x29, 0x66, + 0x2a, 0x90, + 0x2b, 0xfa, + 0x2c, 0xd9, + 0x30, 0x0, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbd, + 0x3a, 0x0, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x20, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x36, + 0x52, 0x21, + 0x53, 0x94, + 0x54, 0xb2, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x00, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0xff, + 0x5f, 0x8d, + 0x70, 0x0, + 0x71, 0x0, + 0x72, 0x0, + 0x74, 0x0, + 0x75, 0x0, + 0x76, 0x0, + 0x81, 0x0, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x0, + 0x85, 0x0, + 0x88, 0x0, + 0x89, 0x0, + 0x8a, 0x0, + 0x8b, 0x0, + 0x8c, 0x0, + 0x90, 0x0, + 0x91, 0x0, + 0x92, 0x0, + 0x93, 0x0, + 0x94, 0x1c, + 0x97, 0x0, + 0xa0, 0x48, + 0xa1, 0x0, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x0, + 0xf0, 0x0, + 0xf1, 0x0, + 0xf2, 0xc0, + 0xff, 0xff, +}; +#endif diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c new file mode 100644 index 00000000000..d83df4bb72d --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -0,0 +1,612 @@ +/* + * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator + * + * Copyright (C) 2010 Michael Krufky + * + * 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 "mxl111sf-demod.h" +#include "mxl111sf-reg.h" + +/* debug */ +static int mxl111sf_demod_debug; +module_param_named(debug, mxl111sf_demod_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define mxl_dbg(fmt, arg...) \ + if (mxl111sf_demod_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* ------------------------------------------------------------------------ */ + +struct mxl111sf_demod_state { + struct mxl111sf_state *mxl_state; + + struct mxl111sf_demod_config *cfg; + + struct dvb_frontend fe; +}; + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, + u8 addr, u8 *data) +{ + return (state->cfg->read_reg) ? + state->cfg->read_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, + u8 addr, u8 data) +{ + return (state->cfg->write_reg) ? + state->cfg->write_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static +int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + return (state->cfg->program_regs) ? + state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : + -EINVAL; +} + +/* ------------------------------------------------------------------------ */ +/* TPS */ + +static +int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, + fe_code_rate_t *code_rate) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); + /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ + if (mxl_fail(ret)) + goto fail; + + switch (val & V6_CODE_RATE_TPS_MASK) { + case 0: + *code_rate = FEC_1_2; + break; + case 1: + *code_rate = FEC_2_3; + break; + case 2: + *code_rate = FEC_3_4; + break; + case 3: + *code_rate = FEC_5_6; + break; + case 4: + *code_rate = FEC_7_8; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, + fe_modulation_t *modulation) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); + /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { + case 0: + *modulation = QPSK; + break; + case 1: + *modulation = QAM_16; + break; + case 2: + *modulation = QAM_64; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, + fe_transmit_mode_t *fft_mode) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); + /* FFT Mode, 00:2K, 01:8K, 10:4K */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { + case 0: + *fft_mode = TRANSMISSION_MODE_2K; + break; + case 1: + *fft_mode = TRANSMISSION_MODE_8K; + break; + case 2: + *fft_mode = TRANSMISSION_MODE_4K; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, + fe_guard_interval_t *guard) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); + /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_GI_MASK) >> 4) { + case 0: + *guard = GUARD_INTERVAL_1_32; + break; + case 1: + *guard = GUARD_INTERVAL_1_16; + break; + case 2: + *guard = GUARD_INTERVAL_1_8; + break; + case 3: + *guard = GUARD_INTERVAL_1_4; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, + fe_hierarchy_t *hierarchy) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); + /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { + case 0: + *hierarchy = HIERARCHY_NONE; + break; + case 1: + *hierarchy = HIERARCHY_1; + break; + case 2: + *hierarchy = HIERARCHY_2; + break; + case 3: + *hierarchy = HIERARCHY_4; + break; + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ +/* LOCKS */ + +static +int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, + int *sync_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); + if (mxl_fail(ret)) + goto fail; + *sync_lock = (val & SYNC_LOCK_MASK) >> 4; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, + int *rs_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); + if (mxl_fail(ret)) + goto fail; + *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, + int *tps_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); + if (mxl_fail(ret)) + goto fail; + *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, + int *fec_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); + if (mxl_fail(ret)) + goto fail; + *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; +fail: + return ret; +} + +#if 0 +static +int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, + int *cp_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); + if (mxl_fail(ret)) + goto fail; + *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; +fail: + return ret; +} +#endif + +static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) +{ + return mxl111sf_demod_write_reg(state, 0x0e, 0xff); +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + int ret = 0; + + struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { + {0x00, 0xff, 0x01}, /* change page to 1 */ + {0x40, 0xff, 0x05}, + {0x40, 0xff, 0x01}, + {0x41, 0xff, 0xca}, + {0x41, 0xff, 0xc0}, + {0x00, 0xff, 0x00}, /* change page to 0 */ + {0, 0, 0} + }; + + mxl_dbg("()"); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (mxl_fail(ret)) + goto fail; + msleep(50); + } + ret = mxl111sf_demod_program_regs(state, phy_pll_patch); + mxl_fail(ret); + msleep(50); + ret = mxl1x1sf_demod_reset_irq_status(state); + mxl_fail(ret); + msleep(100); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +/* resets TS Packet error count */ +/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ +static +int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) +{ + struct mxl111sf_reg_ctrl_info reset_per_count[] = { + {0x20, 0x01, 0x01}, + {0x20, 0x01, 0x00}, + {0, 0, 0} + }; + return mxl111sf_demod_program_regs(state, reset_per_count); +} +#endif + +/* returns TS Packet error count */ +/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ +static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + u32 fec_per_count, fec_per_scale; + u8 val; + int ret; + + *ucblocks = 0; + + /* FEC_PER_COUNT Register */ + ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); + if (mxl_fail(ret)) + goto fail; + + fec_per_count = val; + + /* FEC_PER_SCALE Register */ + ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); + if (mxl_fail(ret)) + goto fail; + + val &= V6_FEC_PER_SCALE_MASK; + val *= 4; + + fec_per_scale = 1 << val; + + fec_per_count *= fec_per_scale; + + *ucblocks = fec_per_count; +fail: + return ret; +} + +#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS +/* FIXME: leaving this enabled breaks the build on some architectures, + * and we shouldn't have any floating point math in the kernel, anyway. + * + * These macros need to be re-written, but it's harmless to simply + * return zero for now. */ +#define CALCULATE_BER(avg_errors, count) \ + ((u32)(avg_errors * 4)/(count*64*188*8)) +#define CALCULATE_SNR(data) \ + ((u32)((10 * (u32)data / 64) - 2.5)) +#else +#define CALCULATE_BER(avg_errors, count) 0 +#define CALCULATE_SNR(data) 0 +#endif + +static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + u8 val1, val2, val3; + int ret; + + *ber = 0; + + ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); + if (mxl_fail(ret)) + goto fail; + + *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); +fail: + return ret; +} + +static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, + u16 *snr) +{ + u8 val1, val2; + int ret; + + *snr = 0; + + ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + + *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); +fail: + return ret; +} + +static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + + int ret = mxl111sf_demod_calc_snr(state, snr); + if (mxl_fail(ret)) + goto fail; + + *snr /= 10; /* 0.1 dB */ +fail: + return ret; +} + +static int mxl111sf_demod_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + int ret, locked, cr_lock, sync_lock, fec_lock; + + *status = 0; + + ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); + if (mxl_fail(ret)) + goto fail; + + if (locked) + *status |= FE_HAS_SIGNAL; + if (cr_lock) + *status |= FE_HAS_CARRIER; + if (sync_lock) + *status |= FE_HAS_SYNC; + if (fec_lock) /* false positives? */ + *status |= FE_HAS_VITERBI; + + if ((locked) && (cr_lock) && (sync_lock)) + *status |= FE_HAS_LOCK; +fail: + return ret; +} + +static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + fe_modulation_t modulation; + u16 snr; + + mxl111sf_demod_calc_snr(state, &snr); + mxl1x1sf_demod_get_tps_modulation(state, &modulation); + + switch (modulation) { + case QPSK: + *signal_strength = (snr >= 1300) ? + min(65535, snr * 44) : snr * 38; + break; + case QAM_16: + *signal_strength = (snr >= 1500) ? + min(65535, snr * 38) : snr * 33; + break; + case QAM_64: + *signal_strength = (snr >= 2000) ? + min(65535, snr * 29) : snr * 25; + break; + default: + *signal_strength = 0; + return -EINVAL; + } + + return 0; +} + +static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct mxl111sf_demod_state *state = fe->demodulator_priv; + + mxl_dbg("()"); +#if 0 + p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; +#endif + if (fe->ops.tuner_ops.get_bandwidth) + fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz); + if (fe->ops.tuner_ops.get_frequency) + fe->ops.tuner_ops.get_frequency(fe, &p->frequency); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP); + mxl1x1sf_demod_get_tps_modulation(state, &p->modulation); + mxl1x1sf_demod_get_tps_guard_fft_mode(state, + &p->transmission_mode); + mxl1x1sf_demod_get_tps_guard_interval(state, + &p->guard_interval); + mxl1x1sf_demod_get_tps_hierarchy(state, + &p->hierarchy); + + return 0; +} + +static +int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void mxl111sf_demod_release(struct dvb_frontend *fe) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + mxl_dbg("()"); + kfree(state); + fe->demodulator_priv = NULL; +} + +static struct dvb_frontend_ops mxl111sf_demod_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "MaxLinear MxL111SF DVB-T demodulator", + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + }, + .release = mxl111sf_demod_release, +#if 0 + .init = mxl111sf_init, + .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, +#endif + .set_frontend = mxl111sf_demod_set_frontend, + .get_frontend = mxl111sf_demod_get_frontend, + .get_tune_settings = mxl111sf_demod_get_tune_settings, + .read_status = mxl111sf_demod_read_status, + .read_signal_strength = mxl111sf_demod_read_signal_strength, + .read_ber = mxl111sf_demod_read_ber, + .read_snr = mxl111sf_demod_read_snr, + .read_ucblocks = mxl111sf_demod_read_ucblocks, +}; + +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg) +{ + struct mxl111sf_demod_state *state = NULL; + + mxl_dbg("()"); + + state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->mxl_state = mxl_state; + state->cfg = cfg; + + memcpy(&state->fe.ops, &mxl111sf_demod_ops, + sizeof(struct dvb_frontend_ops)); + + state->fe.demodulator_priv = state; + return &state->fe; +} +EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); + +MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h new file mode 100644 index 00000000000..432706ae527 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h @@ -0,0 +1,55 @@ +/* + * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator + * + * Copyright (C) 2010 Michael Krufky + * + * 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 __MXL111SF_DEMOD_H__ +#define __MXL111SF_DEMOD_H__ + +#include "dvb_frontend.h" +#include "mxl111sf.h" + +struct mxl111sf_demod_config { + int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); + int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); + int (*program_regs)(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); +}; + +#if defined(CONFIG_DVB_USB_MXL111SF) || \ + (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +extern +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg); +#else +static inline +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_USB_MXL111SF */ + +#endif /* __MXL111SF_DEMOD_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c new file mode 100644 index 00000000000..e4121cb8f5e --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c @@ -0,0 +1,763 @@ +/* + * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 "mxl111sf-gpio.h" +#include "mxl111sf-i2c.h" +#include "mxl111sf.h" + +/* ------------------------------------------------------------------------- */ + +#define MXL_GPIO_MUX_REG_0 0x84 +#define MXL_GPIO_MUX_REG_1 0x89 +#define MXL_GPIO_MUX_REG_2 0x82 + +#define MXL_GPIO_DIR_INPUT 0 +#define MXL_GPIO_DIR_OUTPUT 1 + + +static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val) +{ + int ret; + u8 tmp; + + mxl_debug_adv("(%d, %d)", pin, val); + + if ((pin > 0) && (pin < 8)) { + ret = mxl111sf_read_reg(state, 0x19, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (pin - 1)); + tmp |= (val << (pin - 1)); + ret = mxl111sf_write_reg(state, 0x19, tmp); + if (mxl_fail(ret)) + goto fail; + } else if (pin <= 10) { + if (pin == 0) + pin += 7; + ret = mxl111sf_read_reg(state, 0x30, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (pin - 3)); + tmp |= (val << (pin - 3)); + ret = mxl111sf_write_reg(state, 0x30, tmp); + if (mxl_fail(ret)) + goto fail; + } else + ret = -EINVAL; +fail: + return ret; +} + +static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val) +{ + int ret; + u8 tmp; + + mxl_debug("(0x%02x)", pin); + + *val = 0; + + switch (pin) { + case 0: + case 1: + case 2: + case 3: + ret = mxl111sf_read_reg(state, 0x23, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> (pin + 4)) & 0x01; + break; + case 4: + case 5: + case 6: + case 7: + ret = mxl111sf_read_reg(state, 0x2f, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> pin) & 0x01; + break; + case 8: + case 9: + case 10: + ret = mxl111sf_read_reg(state, 0x22, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> (pin - 3)) & 0x01; + break; + default: + return -EINVAL; /* invalid pin */ + } +fail: + return ret; +} + +struct mxl_gpio_cfg { + u8 pin; + u8 dir; + u8 val; +}; + +static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state, + struct mxl_gpio_cfg *gpio_cfg) +{ + int ret; + u8 tmp; + + mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir); + + switch (gpio_cfg->pin) { + case 0: + case 1: + case 2: + case 3: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (gpio_cfg->pin + 4)); + tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4)); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp); + if (mxl_fail(ret)) + goto fail; + break; + case 4: + case 5: + case 6: + case 7: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << gpio_cfg->pin); + tmp |= (gpio_cfg->dir << gpio_cfg->pin); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp); + if (mxl_fail(ret)) + goto fail; + break; + case 8: + case 9: + case 10: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (gpio_cfg->pin - 3)); + tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3)); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp); + if (mxl_fail(ret)) + goto fail; + break; + default: + return -EINVAL; /* invalid pin */ + } + + ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ? + mxl111sf_set_gpo_state(state, + gpio_cfg->pin, gpio_cfg->val) : + mxl111sf_get_gpi_state(state, + gpio_cfg->pin, &gpio_cfg->val); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state, + int gpio, int direction, int val) +{ + struct mxl_gpio_cfg gpio_config = { + .pin = gpio, + .dir = direction, + .val = val, + }; + + mxl_debug("(%d, %d, %d)", gpio, direction, val); + + return mxl111sf_config_gpio_pins(state, &gpio_config); +} + +/* ------------------------------------------------------------------------- */ + +#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */ +#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */ +#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */ +#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */ +#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */ +#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */ +#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */ +#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */ +#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */ +#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */ +#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */ +#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */ +#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */ +#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */ +#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */ +#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */ +#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */ +#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */ +#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */ + +int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, + enum mxl111sf_mux_config pin_mux_config) +{ + u8 r12, r15, r17, r18, r3D, r82, r84, r89; + int ret; + + mxl_debug("(%d)", pin_mux_config); + + ret = mxl111sf_read_reg(state, 0x17, &r17); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x18, &r18); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x12, &r12); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x15, &r15); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x82, &r82); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x84, &r84); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x89, &r89); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x3D, &r3D); + if (mxl_fail(ret)) + goto fail; + + switch (pin_mux_config) { + case PIN_MUX_TS_OUT_PARALLEL: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 1 */ + r18 |= PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 1 */ + r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 1 */ + r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 1 */ + r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 1 */ + r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0xF */ + r84 |= 0xF0; + /* mdat_en_ctrl[7:4] = 0xF */ + r89 |= 0xF0; + break; + case PIN_MUX_TS_OUT_SERIAL: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 1 */ + r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 1 */ + r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 1 */ + r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 1 */ + r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0xF */ + r84 |= 0xF0; + /* mdat_en_ctrl[7:4] = 0xF */ + r89 |= 0xF0; + break; + case PIN_MUX_GPIO_MODE: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SERIAL_IN_MODE_0: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SERIAL_IN_MODE_1: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 1 */ + r3D |= PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SPI_IN_MODE_1: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 1 */ + r3D |= PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 1 */ + r3D |= PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SPI_IN_MODE_0: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 1 */ + r3D |= PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_PARALLEL_IN: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 1 */ + r18 |= PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_BT656_I2S_MODE: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 1 */ + r12 |= PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_DEFAULT: + default: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + } + + ret = mxl111sf_write_reg(state, 0x17, r17); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x18, r18); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x12, r12); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x15, r15); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x82, r82); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x84, r84); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x89, r89); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x3D, r3D); + if (mxl_fail(ret)) + goto fail; +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val); +} + +static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state) +{ + u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */ + int i, ret; + + mxl_debug("()"); + + for (i = 3; i < 8; i++) { + ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01); + if (mxl_fail(ret)) + break; + } + + return ret; +} + +#define PCA9534_I2C_ADDR (0x40 >> 1) +static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + u8 w[2] = { 1, 0 }; + u8 r = 0; + struct i2c_msg msg[] = { + { .addr = PCA9534_I2C_ADDR, + .flags = 0, .buf = w, .len = 1 }, + { .addr = PCA9534_I2C_ADDR, + .flags = I2C_M_RD, .buf = &r, .len = 1 }, + }; + + mxl_debug("(%d, %d)", gpio, val); + + /* read current GPIO levels from flip-flop */ + i2c_transfer(&state->d->i2c_adap, msg, 2); + + /* prepare write buffer with current GPIO levels */ + msg[0].len = 2; +#if 0 + w[0] = 1; +#endif + w[1] = r; + + /* clear the desired GPIO */ + w[1] &= ~(1 << gpio); + + /* set the desired GPIO value */ + w[1] |= ((val ? 1 : 0) << gpio); + + /* write new GPIO levels to flip-flop */ + i2c_transfer(&state->d->i2c_adap, &msg[0], 1); + + return 0; +} + +static int pca9534_init_port_expander(struct mxl111sf_state *state) +{ + u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */ + + struct i2c_msg msg = { + .addr = PCA9534_I2C_ADDR, + .flags = 0, .buf = w, .len = 2 + }; + + mxl_debug("()"); + + i2c_transfer(&state->d->i2c_adap, &msg, 1); + + /* configure all pins as outputs */ + w[0] = 3; + w[1] = 0; + + i2c_transfer(&state->d->i2c_adap, &msg, 1); + + return 0; +} + +int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + mxl_debug("(%d, %d)", gpio, val); + + switch (state->gpio_port_expander) { + default: + mxl_printk(KERN_ERR, + "gpio_port_expander undefined, assuming PCA9534"); + /* fall-thru */ + case mxl111sf_PCA9534: + return pca9534_set_gpio(state, gpio, val); + case mxl111sf_gpio_hw: + return mxl111sf_hw_set_gpio(state, gpio, val); + } +} + +static int mxl111sf_probe_port_expander(struct mxl111sf_state *state) +{ + int ret; + u8 w = 1; + u8 r = 0; + struct i2c_msg msg[] = { + { .flags = 0, .buf = &w, .len = 1 }, + { .flags = I2C_M_RD, .buf = &r, .len = 1 }, + }; + + mxl_debug("()"); + + msg[0].addr = 0x70 >> 1; + msg[1].addr = 0x70 >> 1; + + /* read current GPIO levels from flip-flop */ + ret = i2c_transfer(&state->d->i2c_adap, msg, 2); + if (ret == 2) { + state->port_expander_addr = msg[0].addr; + state->gpio_port_expander = mxl111sf_PCA9534; + mxl_debug("found port expander at 0x%02x", + state->port_expander_addr); + return 0; + } + + msg[0].addr = 0x40 >> 1; + msg[1].addr = 0x40 >> 1; + + ret = i2c_transfer(&state->d->i2c_adap, msg, 2); + if (ret == 2) { + state->port_expander_addr = msg[0].addr; + state->gpio_port_expander = mxl111sf_PCA9534; + mxl_debug("found port expander at 0x%02x", + state->port_expander_addr); + return 0; + } + state->port_expander_addr = 0xff; + state->gpio_port_expander = mxl111sf_gpio_hw; + mxl_debug("using hardware gpio"); + return 0; +} + +int mxl111sf_init_port_expander(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + if (0x00 == state->port_expander_addr) + mxl111sf_probe_port_expander(state); + + switch (state->gpio_port_expander) { + default: + mxl_printk(KERN_ERR, + "gpio_port_expander undefined, assuming PCA9534"); + /* fall-thru */ + case mxl111sf_PCA9534: + return pca9534_init_port_expander(state); + case mxl111sf_gpio_hw: + return mxl111sf_hw_gpio_initialize(state); + } +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) +{ +/* GPO: + * 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0 + * 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0 + * 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0 + * 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0 + * 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0 + */ + mxl_debug("(%d)", mode); + + switch (mode) { + case MXL111SF_GPIO_MOD_MH: + mxl111sf_set_gpio(state, 4, 0); + mxl111sf_set_gpio(state, 5, 0); + msleep(50); + mxl111sf_set_gpio(state, 7, 1); + msleep(50); + mxl111sf_set_gpio(state, 6, 1); + msleep(50); + + mxl111sf_set_gpio(state, 3, 0); + break; + case MXL111SF_GPIO_MOD_ATSC: + mxl111sf_set_gpio(state, 6, 0); + mxl111sf_set_gpio(state, 7, 0); + msleep(50); + mxl111sf_set_gpio(state, 5, 1); + msleep(50); + mxl111sf_set_gpio(state, 4, 1); + msleep(50); + mxl111sf_set_gpio(state, 3, 1); + break; + default: /* DVBT / STANDBY */ + mxl111sf_init_port_expander(state); + break; + } + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h new file mode 100644 index 00000000000..0220f54299a --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h @@ -0,0 +1,56 @@ +/* + * mxl111sf-gpio.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 _DVB_USB_MXL111SF_GPIO_H_ +#define _DVB_USB_MXL111SF_GPIO_H_ + +#include "mxl111sf.h" + +int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val); +int mxl111sf_init_port_expander(struct mxl111sf_state *state); + +#define MXL111SF_GPIO_MOD_DVBT 0 +#define MXL111SF_GPIO_MOD_MH 1 +#define MXL111SF_GPIO_MOD_ATSC 2 +int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode); + +enum mxl111sf_mux_config { + PIN_MUX_DEFAULT = 0, + PIN_MUX_TS_OUT_PARALLEL, + PIN_MUX_TS_OUT_SERIAL, + PIN_MUX_GPIO_MODE, + PIN_MUX_TS_SERIAL_IN_MODE_0, + PIN_MUX_TS_SERIAL_IN_MODE_1, + PIN_MUX_TS_SPI_IN_MODE_0, + PIN_MUX_TS_SPI_IN_MODE_1, + PIN_MUX_TS_PARALLEL_IN, + PIN_MUX_BT656_I2S_MODE, +}; + +int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, + enum mxl111sf_mux_config pin_mux_config); + +#endif /* _DVB_USB_MXL111SF_GPIO_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c new file mode 100644 index 00000000000..34434557ef6 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c @@ -0,0 +1,850 @@ +/* + * mxl111sf-i2c.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 "mxl111sf-i2c.h" +#include "mxl111sf.h" + +/* SW-I2C ----------------------------------------------------------------- */ + +#define SW_I2C_ADDR 0x1a +#define SW_I2C_EN 0x02 +#define SW_SCL_OUT 0x04 +#define SW_SDA_OUT 0x08 +#define SW_SDA_IN 0x04 + +#define SW_I2C_BUSY_ADDR 0x2f +#define SW_I2C_BUSY 0x02 + +static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state, + u8 byte) +{ + int i, ret; + u8 data = 0; + + mxl_i2c("(0x%02x)", byte); + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + for (i = 0; i < 8; i++) { + + data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data); + if (mxl_fail(ret)) + goto fail; + } + + /* last bit was 0 so we need to release SDA */ + if (!(byte & 1)) { + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + } + + /* CLK high for ACK readback */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + /* drop the CLK after getting ACK, SDA will go high right away */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + if (data & SW_SDA_IN) + ret = -EIO; +fail: + return ret; +} + +static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state, + u8 *pbyte) +{ + int i, ret; + u8 byte = 0; + u8 data = 0; + + mxl_i2c("()"); + + *pbyte = 0; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + for (i = 0; i < 8; i++) { + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | + SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + if (data & SW_SDA_IN) + byte |= (0x80 >> i); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + } + *pbyte = byte; +fail: + return ret; +} + +static int mxl111sf_i2c_start(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); /* start */ + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_stop(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); /* stop */ + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_SCL_OUT | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_ack(struct mxl111sf_state *state) +{ + int ret; + u8 b = 0; + + mxl_i2c("()"); + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); + if (mxl_fail(ret)) + goto fail; + + /* pull SDA low */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_nack(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + /* SDA high to signal last byte read from slave */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state, + struct i2c_msg *msg) +{ + int i, ret; + + mxl_i2c("()"); + + if (msg->flags & I2C_M_RD) { + + ret = mxl111sf_i2c_start(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_i2c_bitbang_sendbyte(state, + (msg->addr << 1) | 0x01); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + for (i = 0; i < msg->len; i++) { + ret = mxl111sf_i2c_bitbang_recvbyte(state, + &msg->buf[i]); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + if (i < msg->len - 1) + mxl111sf_i2c_ack(state); + } + + mxl111sf_i2c_nack(state); + + ret = mxl111sf_i2c_stop(state); + if (mxl_fail(ret)) + goto fail; + + } else { + + ret = mxl111sf_i2c_start(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_i2c_bitbang_sendbyte(state, + (msg->addr << 1) & 0xfe); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + for (i = 0; i < msg->len; i++) { + ret = mxl111sf_i2c_bitbang_sendbyte(state, + msg->buf[i]); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + } + + /* FIXME: we only want to do this on the last transaction */ + mxl111sf_i2c_stop(state); + } +fail: + return ret; +} + +/* HW-I2C ----------------------------------------------------------------- */ + +#define USB_WRITE_I2C_CMD 0x99 +#define USB_READ_I2C_CMD 0xdd +#define USB_END_I2C_CMD 0xfe + +#define USB_WRITE_I2C_CMD_LEN 26 +#define USB_READ_I2C_CMD_LEN 24 + +#define I2C_MUX_REG 0x30 +#define I2C_CONTROL_REG 0x00 +#define I2C_SLAVE_ADDR_REG 0x08 +#define I2C_DATA_REG 0x0c +#define I2C_INT_STATUS_REG 0x10 + +static int mxl111sf_i2c_send_data(struct mxl111sf_state *state, + u8 index, u8 *wdata) +{ + int ret = mxl111sf_ctrl_msg(state->d, wdata[0], + &wdata[1], 25, NULL, 0); + mxl_fail(ret); + + return ret; +} + +static int mxl111sf_i2c_get_data(struct mxl111sf_state *state, + u8 index, u8 *wdata, u8 *rdata) +{ + int ret = mxl111sf_ctrl_msg(state->d, wdata[0], + &wdata[1], 25, rdata, 24); + mxl_fail(ret); + + return ret; +} + +static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state) +{ + u8 status = 0; + u8 buf[26]; + + mxl_i2c_adv("()"); + + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + buf[2] = I2C_INT_STATUS_REG; + buf[3] = 0x00; + buf[4] = 0x00; + + buf[5] = USB_END_I2C_CMD; + + mxl111sf_i2c_get_data(state, 0, buf, buf); + + if (buf[1] & 0x04) + status = 1; + + return status; +} + +static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state) +{ + u8 status = 0; + u8 buf[26]; + + mxl_i2c("()"); + + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + buf[2] = I2C_MUX_REG; + buf[3] = 0x00; + buf[4] = 0x00; + + buf[5] = I2C_INT_STATUS_REG; + buf[6] = 0x00; + buf[7] = 0x00; + buf[8] = USB_END_I2C_CMD; + + mxl111sf_i2c_get_data(state, 0, buf, buf); + + if (0x08 == (buf[1] & 0x08)) + status = 1; + + if ((buf[5] & 0x02) == 0x02) + mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */ + + return status; +} + +static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, + u8 count, u8 *rbuf) +{ + u8 i2c_w_data[26]; + u8 i2c_r_data[24]; + u8 i = 0; + u8 fifo_status = 0; + int status = 0; + + mxl_i2c("read %d bytes", count); + + while ((fifo_status == 0) && (i++ < 5)) + fifo_status = mxl111sf_i2c_check_fifo(state); + + i2c_w_data[0] = 0xDD; + i2c_w_data[1] = 0x00; + + for (i = 2; i < 26; i++) + i2c_w_data[i] = 0xFE; + + for (i = 0; i < count; i++) { + i2c_w_data[2+(i*3)] = 0x0C; + i2c_w_data[3+(i*3)] = 0x00; + i2c_w_data[4+(i*3)] = 0x00; + } + + mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); + + /* Check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("error!"); + } else { + for (i = 0; i < count; i++) { + rbuf[i] = i2c_r_data[(i*3)+1]; + mxl_i2c("%02x\t %02x", + i2c_r_data[(i*3)+1], + i2c_r_data[(i*3)+2]); + } + + status = 1; + } + + return status; +} + +#define HWI2C400 1 +static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, + struct i2c_msg *msg) +{ + int i, k, ret = 0; + u16 index = 0; + u8 buf[26]; + u8 i2c_r_data[24]; + u16 block_len; + u16 left_over_len; + u8 rd_status[8]; + u8 ret_status; + u8 readbuff[26]; + + mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d", + msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0, + (!(msg->flags & I2C_M_RD)) ? msg->len : 0); + + for (index = 0; index < 26; index++) + buf[index] = USB_END_I2C_CMD; + + /* command to indicate data payload is destined for I2C interface */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* enable I2C interface */ + buf[2] = I2C_MUX_REG; + buf[3] = 0x80; + buf[4] = 0x00; + + /* enable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x81; + buf[7] = 0x00; + + /* set Timeout register on I2C interface */ + buf[8] = 0x14; + buf[9] = 0xff; + buf[10] = 0x00; +#if 0 + /* enable Interrupts on I2C interface */ + buf[8] = 0x24; + buf[9] = 0xF7; + buf[10] = 0x00; +#endif + buf[11] = 0x24; + buf[12] = 0xF7; + buf[13] = 0x00; + + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* write data on I2C bus */ + if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) { + mxl_i2c("%d\t%02x", msg->len, msg->buf[0]); + + /* control register on I2C interface to initialize I2C bus */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x5E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + /* I2C Slave device Address */ + buf[5] = I2C_SLAVE_ADDR_REG; + buf[6] = (msg->addr); + buf[7] = 0x00; + buf[8] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for slave device status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* I2C interface can do I2C operations in block of 8 bytes of + I2C data. calculation to figure out number of blocks of i2c + data required to program */ + block_len = (msg->len / 8); + left_over_len = (msg->len % 8); + index = 0; + + mxl_i2c("block_len %d, left_over_len %d", + block_len, left_over_len); + + for (index = 0; index < block_len; index++) { + for (i = 0; i < 8; i++) { + /* write data on I2C interface */ + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = msg->buf[(index*8)+i]; + buf[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + } + + if (left_over_len) { + for (k = 0; k < 26; k++) + buf[k] = USB_END_I2C_CMD; + + buf[0] = 0x99; + buf[1] = 0x00; + + for (i = 0; i < left_over_len; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = msg->buf[(index*8)+i]; + mxl_i2c("index = %d %d data %d", + index, i, msg->buf[(index*8)+i]); + buf[4+(i*3)] = 0x00; + } + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + } + + /* issue I2C STOP after write */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + } + + /* read data from I2C bus */ + if ((msg->flags & I2C_M_RD) && (msg->len > 0)) { + mxl_i2c("read buf len %d", msg->len); + + /* command to indicate data payload is + destined for I2C interface */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xDF; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + /* I2C xfer length */ + buf[5] = 0x14; + buf[6] = (msg->len & 0xFF); + buf[7] = 0; + + /* I2C slave device Address */ + buf[8] = I2C_SLAVE_ADDR_REG; + buf[9] = msg->addr; + buf[10] = 0x00; + buf[11] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* I2C interface can do I2C operations in block of 8 bytes of + I2C data. calculation to figure out number of blocks of + i2c data required to program */ + block_len = ((msg->len) / 8); + left_over_len = ((msg->len) % 8); + index = 0; + + mxl_i2c("block_len %d, left_over_len %d", + block_len, left_over_len); + + /* command to read data from I2C interface */ + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + for (index = 0; index < block_len; index++) { + /* setup I2C read request packet on I2C interface */ + for (i = 0; i < 8; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = 0x00; + buf[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* copy data from i2c data payload to read buffer */ + for (i = 0; i < 8; i++) { + rd_status[i] = i2c_r_data[(i*3)+2]; + + if (rd_status[i] == 0x04) { + if (i < 7) { + mxl_i2c("i2c fifo empty!" + " @ %d", i); + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + /* read again */ + ret_status = + mxl111sf_i2c_readagain( + state, 8-(i+1), + readbuff); + if (ret_status == 1) { + for (k = 0; + k < 8-(i+1); + k++) { + + msg->buf[(index*8)+(k+i+1)] = + readbuff[k]; + mxl_i2c("read data: %02x\t %02x", + msg->buf[(index*8)+(k+i)], + (index*8)+(k+i)); + mxl_i2c("read data: %02x\t %02x", + msg->buf[(index*8)+(k+i+1)], + readbuff[k]); + + } + goto stop_copy; + } else { + mxl_i2c("readagain " + "ERROR!"); + } + } else { + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + } + } else { + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + } + } +stop_copy: + ; + + } + + if (left_over_len) { + for (k = 0; k < 26; k++) + buf[k] = USB_END_I2C_CMD; + + buf[0] = 0xDD; + buf[1] = 0x00; + + for (i = 0; i < left_over_len; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = 0x00; + buf[4+(i*3)] = 0x00; + } + ret = mxl111sf_i2c_get_data(state, 0, buf, + i2c_r_data); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + for (i = 0; i < left_over_len; i++) { + msg->buf[(block_len*8)+i] = + i2c_r_data[(i*3)+1]; + mxl_i2c("read data: %02x\t %02x", + i2c_r_data[(i*3)+1], + i2c_r_data[(i*3)+2]); + } + } + + /* indicate I2C interface to issue NACK + after next I2C read op */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* control register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x17; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + buf[5] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* control register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + } +exit: + /* STOP and disable I2C MUX */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* de-initilize I2C BUS */ + buf[5] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + /* Control Register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xDF; + buf[4] = 0x03; + + /* disable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x00; + buf[7] = 0x00; + + /* de-initilize I2C BUS */ + buf[8] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + /* disable I2C interface */ + buf[2] = I2C_MUX_REG; + buf[3] = 0x81; + buf[4] = 0x00; + + /* disable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x00; + buf[7] = 0x00; + + /* disable I2C interface */ + buf[8] = I2C_MUX_REG; + buf[9] = 0x00; + buf[10] = 0x00; + + buf[11] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct mxl111sf_state *state = d->priv; + int hwi2c = (state->chip_rev > MXL111SF_V6); + int i, ret; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + ret = (hwi2c) ? + mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) : + mxl111sf_i2c_sw_xfer_msg(state, &msg[i]); + if (mxl_fail(ret)) { + mxl_debug_adv("failed with error %d on i2c " + "transaction %d of %d, %sing %d bytes " + "to/from 0x%02x", ret, i+1, num, + (msg[i].flags & I2C_M_RD) ? + "read" : "writ", + msg[i].len, msg[i].addr); + + break; + } + } + + mutex_unlock(&d->i2c_mutex); + + return i == num ? num : -EREMOTEIO; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h new file mode 100644 index 00000000000..a57a45ffb9e --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h @@ -0,0 +1,35 @@ +/* + * mxl111sf-i2c.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 _DVB_USB_MXL111SF_I2C_H_ +#define _DVB_USB_MXL111SF_I2C_H_ + +#include + +int mxl111sf_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num); + +#endif /* _DVB_USB_MXL111SF_I2C_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c new file mode 100644 index 00000000000..b741b3a7a32 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c @@ -0,0 +1,343 @@ +/* + * mxl111sf-phy.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 "mxl111sf-phy.h" +#include "mxl111sf-reg.h" + +int mxl111sf_init_tuner_demod(struct mxl111sf_state *state) +{ + struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = { + {0x07, 0xff, 0x0c}, + {0x58, 0xff, 0x9d}, + {0x09, 0xff, 0x00}, + {0x06, 0xff, 0x06}, + {0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */ + {0x8d, 0x01, 0x01}, /* NEGATE_Q */ + {0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */ + {0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */ + {0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */ + {0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */ + {0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */ + {0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */ + {0x88, 0xff, 0xf0}, /* INF_THD = 240 */ + {0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */ + {0x00, 0xff, 0x01}, /* Change to page 1 */ + {0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */ + {0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */ + {0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */ + {0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */ + {0x00, 0xff, 0x00}, /* Change to page 0 */ + {0, 0, 0} + }; + + mxl_debug("()"); + + return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default); +} + +int mxl1x1sf_soft_reset(struct mxl111sf_state *state) +{ + int ret; + mxl_debug("()"); + + ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */ + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */ + mxl_fail(ret); +fail: + return ret; +} + +int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode) +{ + int ret; + + mxl_debug("(%s)", MXL_SOC_MODE == mode ? + "MXL_SOC_MODE" : "MXL_TUNER_MODE"); + + /* set device mode */ + ret = mxl111sf_write_reg(state, 0x03, + MXL_SOC_MODE == mode ? 0x01 : 0x00); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg_mask(state, + 0x7d, 0x40, MXL_SOC_MODE == mode ? + 0x00 : /* enable impulse noise filter, + INF_BYP = 0 */ + 0x40); /* disable impulse noise filter, + INF_BYP = 1 */ + if (mxl_fail(ret)) + goto fail; + + state->device_mode = mode; +fail: + return ret; +} + +/* power up tuner */ +int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff) +{ + mxl_debug("(%d)", onoff); + + return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00); +} + +int mxl111sf_disable_656_port(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00); +} + +int mxl111sf_enable_usb_output(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00); +} + +/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */ +int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, + unsigned int parallel_serial, + unsigned int msb_lsb_1st, + unsigned int clock_phase, + unsigned int mpeg_valid_pol, + unsigned int mpeg_sync_pol) +{ + int ret; + u8 mode, tmp; + + mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st, + clock_phase, mpeg_valid_pol, mpeg_sync_pol); + + /* Enable PIN MUX */ + ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX); + mxl_fail(ret); + + /* Configure MPEG Clock phase */ + mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode); + + if (clock_phase == TSIF_NORMAL) + mode &= ~V6_INVERTED_CLK_PHASE; + else + mode |= V6_INVERTED_CLK_PHASE; + + ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode); + mxl_fail(ret); + + /* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity + * Get current configuration */ + ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode); + mxl_fail(ret); + + /* Data Input mode */ + if (parallel_serial == TSIF_INPUT_PARALLEL) { + /* Disable serial mode */ + mode &= ~V6_MPEG_IN_DATA_SERIAL; + + /* Enable Parallel mode */ + mode |= V6_MPEG_IN_DATA_PARALLEL; + } else { + /* Disable Parallel mode */ + mode &= ~V6_MPEG_IN_DATA_PARALLEL; + + /* Enable Serial Mode */ + mode |= V6_MPEG_IN_DATA_SERIAL; + + /* If serial interface is chosen, configure + MSB or LSB order in transmission */ + ret = mxl111sf_read_reg(state, + V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, + &tmp); + mxl_fail(ret); + + if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED) + tmp |= V6_MPEG_SER_MSB_FIRST; + else + tmp &= ~V6_MPEG_SER_MSB_FIRST; + + ret = mxl111sf_write_reg(state, + V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, + tmp); + mxl_fail(ret); + } + + /* MPEG Sync polarity */ + if (mpeg_sync_pol == TSIF_NORMAL) + mode &= ~V6_INVERTED_MPEG_SYNC; + else + mode |= V6_INVERTED_MPEG_SYNC; + + /* MPEG Valid polarity */ + if (mpeg_valid_pol == 0) + mode &= ~V6_INVERTED_MPEG_VALID; + else + mode |= V6_INVERTED_MPEG_VALID; + + ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode); + mxl_fail(ret); + + return ret; +} + +int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size) +{ + static struct mxl111sf_reg_ctrl_info init_i2s[] = { + {0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */ + {0x15, 0x60, 0x60}, /* Enable I2S */ + {0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB, + Inverted 656 Clock, I2S_SOFT_RESET, + 0 : Normal operation, 1 : Reset State */ +#if 0 + {0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */ +#endif + {0x00, 0xff, 0x02}, /* Change to Control Page */ + {0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */ + {0x00, 0xff, 0x00}, + {0, 0, 0} + }; + int ret; + + mxl_debug("(0x%02x)", sample_size); + + ret = mxl111sf_ctrl_program_regs(state, init_i2s); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_disable_i2s_port(struct mxl111sf_state *state) +{ + static struct mxl111sf_reg_ctrl_info disable_i2s[] = { + {0x15, 0x40, 0x00}, + {0, 0, 0} + }; + + mxl_debug("()"); + + return mxl111sf_ctrl_program_regs(state, disable_i2s); +} + +int mxl111sf_config_i2s(struct mxl111sf_state *state, + u8 msb_start_pos, u8 data_width) +{ + int ret; + u8 tmp; + + mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width); + + ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp); + if (mxl_fail(ret)) + goto fail; + + tmp &= 0xe0; + tmp |= msb_start_pos; + ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp); + if (mxl_fail(ret)) + goto fail; + + tmp &= 0xe0; + tmp |= data_width; + ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff) +{ + u8 val; + int ret; + + mxl_debug("(%d)", onoff); + + ret = mxl111sf_write_reg(state, 0x00, 0x02); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val); + if (mxl_fail(ret)) + goto fail; + + if (onoff) + val |= 0x04; + else + val &= ~0x04; + + ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, 0x00, 0x00); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_idac_config(struct mxl111sf_state *state, + u8 control_mode, u8 current_setting, + u8 current_value, u8 hysteresis_value) +{ + int ret; + u8 val; + /* current value will be set for both automatic & manual IDAC control */ + val = current_value; + + if (control_mode == IDAC_MANUAL_CONTROL) { + /* enable manual control of IDAC */ + val |= IDAC_MANUAL_CONTROL_BIT_MASK; + + if (current_setting == IDAC_CURRENT_SINKING_ENABLE) + /* enable current sinking in manual mode */ + val |= IDAC_CURRENT_SINKING_BIT_MASK; + else + /* disable current sinking in manual mode */ + val &= ~IDAC_CURRENT_SINKING_BIT_MASK; + } else { + /* disable manual control of IDAC */ + val &= ~IDAC_MANUAL_CONTROL_BIT_MASK; + + /* set hysteresis value reg: 0x0B<5:0> */ + ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG, + (hysteresis_value & 0x3F)); + mxl_fail(ret); + } + + ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val); + mxl_fail(ret); + + return ret; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h new file mode 100644 index 00000000000..f0756071d34 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h @@ -0,0 +1,53 @@ +/* + * mxl111sf-phy.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 _DVB_USB_MXL111SF_PHY_H_ +#define _DVB_USB_MXL111SF_PHY_H_ + +#include "mxl111sf.h" + +int mxl1x1sf_soft_reset(struct mxl111sf_state *state); +int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode); +int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff); +int mxl111sf_disable_656_port(struct mxl111sf_state *state); +int mxl111sf_init_tuner_demod(struct mxl111sf_state *state); +int mxl111sf_enable_usb_output(struct mxl111sf_state *state); +int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, + unsigned int parallel_serial, + unsigned int msb_lsb_1st, + unsigned int clock_phase, + unsigned int mpeg_valid_pol, + unsigned int mpeg_sync_pol); +int mxl111sf_config_i2s(struct mxl111sf_state *state, + u8 msb_start_pos, u8 data_width); +int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size); +int mxl111sf_disable_i2s_port(struct mxl111sf_state *state); +int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff); +int mxl111sf_idac_config(struct mxl111sf_state *state, + u8 control_mode, u8 current_setting, + u8 current_value, u8 hysteresis_value); + +#endif /* _DVB_USB_MXL111SF_PHY_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h new file mode 100644 index 00000000000..17831b0fb9d --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h @@ -0,0 +1,179 @@ +/* + * mxl111sf-reg.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 _DVB_USB_MXL111SF_REG_H_ +#define _DVB_USB_MXL111SF_REG_H_ + +#define CHIP_ID_REG 0xFC +#define TOP_CHIP_REV_ID_REG 0xFA + +#define V6_SNR_RB_LSB_REG 0x27 +#define V6_SNR_RB_MSB_REG 0x28 + +#define V6_N_ACCUMULATE_REG 0x11 +#define V6_RS_AVG_ERRORS_LSB_REG 0x2C +#define V6_RS_AVG_ERRORS_MSB_REG 0x2D + +#define V6_IRQ_STATUS_REG 0x24 +#define IRQ_MASK_FEC_LOCK 0x10 + +#define V6_SYNC_LOCK_REG 0x28 +#define SYNC_LOCK_MASK 0x10 + +#define V6_RS_LOCK_DET_REG 0x28 +#define RS_LOCK_DET_MASK 0x08 + +#define V6_INITACQ_NODETECT_REG 0x20 +#define V6_FORCE_NFFT_CPSIZE_REG 0x20 + +#define V6_CODE_RATE_TPS_REG 0x29 +#define V6_CODE_RATE_TPS_MASK 0x07 + + +#define V6_CP_LOCK_DET_REG 0x28 +#define V6_CP_LOCK_DET_MASK 0x04 + +#define V6_TPS_HIERACHY_REG 0x29 +#define V6_TPS_HIERARCHY_INFO_MASK 0x40 + +#define V6_MODORDER_TPS_REG 0x2A +#define V6_PARAM_CONSTELLATION_MASK 0x30 + +#define V6_MODE_TPS_REG 0x2A +#define V6_PARAM_FFT_MODE_MASK 0x0C + + +#define V6_CP_TPS_REG 0x29 +#define V6_PARAM_GI_MASK 0x30 + +#define V6_TPS_LOCK_REG 0x2A +#define V6_PARAM_TPS_LOCK_MASK 0x40 + +#define V6_FEC_PER_COUNT_REG 0x2E +#define V6_FEC_PER_SCALE_REG 0x2B +#define V6_FEC_PER_SCALE_MASK 0x03 +#define V6_FEC_PER_CLR_REG 0x20 +#define V6_FEC_PER_CLR_MASK 0x01 + +#define V6_PIN_MUX_MODE_REG 0x1B +#define V6_ENABLE_PIN_MUX 0x1E + +#define V6_I2S_NUM_SAMPLES_REG 0x16 + +#define V6_MPEG_IN_CLK_INV_REG 0x17 +#define V6_MPEG_IN_CTRL_REG 0x18 + +#define V6_INVERTED_CLK_PHASE 0x20 +#define V6_MPEG_IN_DATA_PARALLEL 0x01 +#define V6_MPEG_IN_DATA_SERIAL 0x02 + +#define V6_INVERTED_MPEG_SYNC 0x04 +#define V6_INVERTED_MPEG_VALID 0x08 + +#define TSIF_INPUT_PARALLEL 0 +#define TSIF_INPUT_SERIAL 1 +#define TSIF_NORMAL 0 + +#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19 +#define V6_MPEG_SER_MSB_FIRST 0x80 +#define MPEG_SER_MSB_FIRST_ENABLED 0x01 + +#define V6_656_I2S_BUFF_STATUS_REG 0x2F +#define V6_656_OVERFLOW_MASK_BIT 0x08 +#define V6_I2S_OVERFLOW_MASK_BIT 0x01 + +#define V6_I2S_STREAM_START_BIT_REG 0x14 +#define V6_I2S_STREAM_END_BIT_REG 0x15 +#define I2S_RIGHT_JUSTIFIED 0 +#define I2S_LEFT_JUSTIFIED 1 +#define I2S_DATA_FORMAT 2 + +#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09 +#define V6_ENABLE_LOOP_THRU 0x01 + +#define TOTAL_NUM_IF_OUTPUT_FREQ 16 + +#define TUNER_NORMAL_IF_SPECTRUM 0x0 +#define TUNER_INVERT_IF_SPECTRUM 0x10 + +#define V6_TUNER_IF_SEL_REG 0x06 +#define V6_TUNER_IF_FCW_REG 0x3C +#define V6_TUNER_IF_FCW_BYP_REG 0x3D +#define V6_RF_LOCK_STATUS_REG 0x23 + +#define NUM_DIG_TV_CHANNEL 1000 + +#define V6_DIG_CLK_FREQ_SEL_REG 0x07 +#define V6_REF_SYNTH_INT_REG 0x5C +#define V6_REF_SYNTH_REMAIN_REG 0x58 +#define V6_DIG_RFREFSELECT_REG 0x32 +#define V6_XTAL_CLK_OUT_GAIN_REG 0x31 +#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09 +#define V6_DIG_XTAL_ENABLE_REG 0x06 +#define V6_DIG_XTAL_BIAS_REG 0x66 +#define V6_XTAL_CAP_REG 0x08 + +#define V6_GPO_CTRL_REG 0x18 +#define MXL_GPO_0 0x00 +#define MXL_GPO_1 0x01 +#define V6_GPO_0_MASK 0x10 +#define V6_GPO_1_MASK 0x20 + +#define V6_111SF_GPO_CTRL_REG 0x19 +#define MXL_111SF_GPO_1 0x00 +#define MXL_111SF_GPO_2 0x01 +#define MXL_111SF_GPO_3 0x02 +#define MXL_111SF_GPO_4 0x03 +#define MXL_111SF_GPO_5 0x04 +#define MXL_111SF_GPO_6 0x05 +#define MXL_111SF_GPO_7 0x06 + +#define MXL_111SF_GPO_0_MASK 0x01 +#define MXL_111SF_GPO_1_MASK 0x02 +#define MXL_111SF_GPO_2_MASK 0x04 +#define MXL_111SF_GPO_3_MASK 0x08 +#define MXL_111SF_GPO_4_MASK 0x10 +#define MXL_111SF_GPO_5_MASK 0x20 +#define MXL_111SF_GPO_6_MASK 0x40 + +#define V6_ATSC_CONFIG_REG 0x0A + +#define MXL_MODE_REG 0x03 +#define START_TUNE_REG 0x1C + +#define V6_IDAC_HYSTERESIS_REG 0x0B +#define V6_IDAC_SETTINGS_REG 0x0C +#define IDAC_MANUAL_CONTROL 1 +#define IDAC_CURRENT_SINKING_ENABLE 1 +#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80 +#define IDAC_CURRENT_SINKING_BIT_MASK 0x40 + +#define V8_SPI_MODE_REG 0xE9 + +#define V6_DIG_RF_PWR_LSB_REG 0x46 +#define V6_DIG_RF_PWR_MSB_REG 0x47 + +#endif /* _DVB_USB_MXL111SF_REG_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c new file mode 100644 index 00000000000..ef4c65fcbb7 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c @@ -0,0 +1,527 @@ +/* + * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner + * + * Copyright (C) 2010 Michael Krufky + * + * 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 "mxl111sf-tuner.h" +#include "mxl111sf-phy.h" +#include "mxl111sf-reg.h" + +/* debug */ +static int mxl111sf_tuner_debug; +module_param_named(debug, mxl111sf_tuner_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define mxl_dbg(fmt, arg...) \ + if (mxl111sf_tuner_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define err pr_err + +/* ------------------------------------------------------------------------ */ + +struct mxl111sf_tuner_state { + struct mxl111sf_state *mxl_state; + + struct mxl111sf_tuner_config *cfg; + + enum mxl_if_freq if_freq; + + u32 frequency; + u32 bandwidth; +}; + +static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state, + u8 addr, u8 *data) +{ + return (state->cfg->read_reg) ? + state->cfg->read_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state, + u8 addr, u8 data) +{ + return (state->cfg->write_reg) ? + state->cfg->write_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + return (state->cfg->program_regs) ? + state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : + -EINVAL; +} + +static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state, + int onoff) +{ + return (state->cfg->top_master_ctrl) ? + state->cfg->top_master_ctrl(state->mxl_state, onoff) : + -EINVAL; +} + +/* ------------------------------------------------------------------------ */ + +static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = { + {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3, + DIG_MODEINDEX, _A, _CSF, */ + {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */ + {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */ + {0, 0, 0} +}; + +/* ------------------------------------------------------------------------ */ + +static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq, + u8 bw) +{ + u8 filt_bw; + + /* set channel bandwidth */ + switch (bw) { + case 0: /* ATSC */ + filt_bw = 25; + break; + case 1: /* QAM */ + filt_bw = 69; + break; + case 6: + filt_bw = 21; + break; + case 7: + filt_bw = 42; + break; + case 8: + filt_bw = 63; + break; + default: + err("%s: invalid bandwidth setting!", __func__); + return NULL; + } + + /* calculate RF channel */ + freq /= 1000000; + + freq *= 64; +#if 0 + /* do round */ + freq += 0.5; +#endif + /* set bandwidth */ + mxl_phy_tune_rf[0].data = filt_bw; + + /* set RF */ + mxl_phy_tune_rf[1].data = (freq & 0xff); + mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff; + + /* start tune */ + return mxl_phy_tune_rf; +} + +static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) +{ + int ret; + u8 ctrl; +#if 0 + u16 iffcw; + u32 if_freq; +#endif + mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)", + state->cfg->invert_spectrum, state->cfg->if_freq); + + /* set IF polarity */ + ctrl = state->cfg->invert_spectrum; + + ctrl |= state->cfg->if_freq; + + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + +#if 0 + if_freq /= 1000000; + + /* do round */ + if_freq += 0.5; + + if (MXL_IF_LO == state->cfg->if_freq) { + ctrl = 0x08; + iffcw = (u16)(if_freq / (108 * 4096)); + } else if (MXL_IF_HI == state->cfg->if_freq) { + ctrl = 0x08; + iffcw = (u16)(if_freq / (216 * 4096)); + } else { + ctrl = 0; + iffcw = 0; + } + + ctrl |= (iffcw >> 8); +#endif + ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl); + if (mxl_fail(ret)) + goto fail; + + ctrl &= 0xf0; + ctrl |= 0x90; + + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + +#if 0 + ctrl = iffcw & 0x00ff; +#endif + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + + state->if_freq = state->cfg->if_freq; +fail: + return ret; +} + +static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + static struct mxl111sf_reg_ctrl_info *reg_ctrl_array; + int ret; + u8 mxl_mode; + + mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw); + + /* stop tune */ + ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0); + if (mxl_fail(ret)) + goto fail; + + /* check device mode */ + ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode); + if (mxl_fail(ret)) + goto fail; + + /* Fill out registers for channel tune */ + reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw); + if (!reg_ctrl_array) + return -EINVAL; + + ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array); + if (mxl_fail(ret)) + goto fail; + + if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) { + /* IF tuner mode only */ + mxl1x1sf_tuner_top_master_ctrl(state, 0); + mxl1x1sf_tuner_top_master_ctrl(state, 1); + mxl1x1sf_tuner_set_if_output_freq(state); + } + + ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1); + if (mxl_fail(ret)) + goto fail; + + if (state->cfg->ant_hunt) + state->cfg->ant_hunt(fe); +fail: + return ret; +} + +static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state, + int *rf_synth_lock, + int *ref_synth_lock) +{ + int ret; + u8 data; + + *rf_synth_lock = 0; + *ref_synth_lock = 0; + + ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data); + if (mxl_fail(ret)) + goto fail; + + *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0; + *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0; +fail: + return ret; +} + +#if 0 +static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, + int onoff) +{ + return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG, + onoff ? 1 : 0); +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + u8 bw; + + mxl_dbg("()"); + + switch (delsys) { + case SYS_ATSC: + case SYS_ATSCMH: + bw = 0; /* ATSC */ + break; + case SYS_DVBC_ANNEX_B: + bw = 1; /* US CABLE */ + break; + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 6000000: + bw = 6; + break; + case 7000000: + bw = 7; + break; + case 8000000: + bw = 8; + break; + default: + err("%s: bandwidth not set!", __func__); + return -EINVAL; + } + break; + default: + err("%s: modulation type not supported!", __func__); + return -EINVAL; + } + ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = c->frequency; + state->bandwidth = c->bandwidth_hz; +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +static int mxl111sf_tuner_init(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + + /* wake from standby handled by usb driver */ + + return ret; +} + +static int mxl111sf_tuner_sleep(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + + /* enter standby mode handled by usb driver */ + + return ret; +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int rf_locked, ref_locked, ret; + + *status = 0; + + ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_info("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + if ((rf_locked) || (ref_locked)) + *status |= TUNER_STATUS_LOCKED; +fail: + return ret; +} + +static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + u8 val1, val2; + int ret; + + *strength = 0; + + ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + + *strength = val1 | ((val2 & 0x07) << 8); +fail: + ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00); + mxl_fail(ret); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, + u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MXL_IF_4_0: /* 4.0 MHz */ + *frequency = 4000000; + break; + case MXL_IF_4_5: /* 4.5 MHz */ + *frequency = 4500000; + break; + case MXL_IF_4_57: /* 4.57 MHz */ + *frequency = 4570000; + break; + case MXL_IF_5_0: /* 5.0 MHz */ + *frequency = 5000000; + break; + case MXL_IF_5_38: /* 5.38 MHz */ + *frequency = 5380000; + break; + case MXL_IF_6_0: /* 6.0 MHz */ + *frequency = 6000000; + break; + case MXL_IF_6_28: /* 6.28 MHz */ + *frequency = 6280000; + break; + case MXL_IF_7_2: /* 7.2 MHz */ + *frequency = 7200000; + break; + case MXL_IF_35_25: /* 35.25 MHz */ + *frequency = 35250000; + break; + case MXL_IF_36: /* 36 MHz */ + *frequency = 36000000; + break; + case MXL_IF_36_15: /* 36.15 MHz */ + *frequency = 36150000; + break; + case MXL_IF_44: /* 44 MHz */ + *frequency = 44000000; + break; + } + return 0; +} + +static int mxl111sf_tuner_release(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + mxl_dbg("()"); + kfree(state); + fe->tuner_priv = NULL; + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { + .info = { + .name = "MaxLinear MxL111SF", +#if 0 + .frequency_min = , + .frequency_max = , + .frequency_step = , +#endif + }, +#if 0 + .init = mxl111sf_tuner_init, + .sleep = mxl111sf_tuner_sleep, +#endif + .set_params = mxl111sf_tuner_set_params, + .get_status = mxl111sf_tuner_get_status, + .get_rf_strength = mxl111sf_get_rf_strength, + .get_frequency = mxl111sf_tuner_get_frequency, + .get_bandwidth = mxl111sf_tuner_get_bandwidth, + .get_if_frequency = mxl111sf_tuner_get_if_frequency, + .release = mxl111sf_tuner_release, +}; + +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state, + struct mxl111sf_tuner_config *cfg) +{ + struct mxl111sf_tuner_state *state = NULL; + + mxl_dbg("()"); + + state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->mxl_state = mxl_state; + state->cfg = cfg; + + memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; +} +EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); + +MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h new file mode 100644 index 00000000000..ff333960b18 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h @@ -0,0 +1,89 @@ +/* + * mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner + * + * Copyright (C) 2010 Michael Krufky + * + * 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 __MXL111SF_TUNER_H__ +#define __MXL111SF_TUNER_H__ + +#include "dvb_frontend.h" + +#include "mxl111sf.h" + +enum mxl_if_freq { +#if 0 + MXL_IF_LO = 0x00, /* other IF < 9MHz */ +#endif + MXL_IF_4_0 = 0x01, /* 4.0 MHz */ + MXL_IF_4_5 = 0x02, /* 4.5 MHz */ + MXL_IF_4_57 = 0x03, /* 4.57 MHz */ + MXL_IF_5_0 = 0x04, /* 5.0 MHz */ + MXL_IF_5_38 = 0x05, /* 5.38 MHz */ + MXL_IF_6_0 = 0x06, /* 6.0 MHz */ + MXL_IF_6_28 = 0x07, /* 6.28 MHz */ + MXL_IF_7_2 = 0x08, /* 7.2 MHz */ + MXL_IF_35_25 = 0x09, /* 35.25 MHz */ + MXL_IF_36 = 0x0a, /* 36 MHz */ + MXL_IF_36_15 = 0x0b, /* 36.15 MHz */ + MXL_IF_44 = 0x0c, /* 44 MHz */ +#if 0 + MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */ +#endif +}; + +struct mxl111sf_tuner_config { + enum mxl_if_freq if_freq; + unsigned int invert_spectrum:1; + + int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); + int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); + int (*program_regs)(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); + int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff); + int (*ant_hunt)(struct dvb_frontend *fe); +}; + +/* ------------------------------------------------------------------------ */ + +#if defined(CONFIG_DVB_USB_MXL111SF) || \ + (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +extern +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state, + struct mxl111sf_tuner_config *cfg); +#else +static inline +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state + struct mxl111sf_tuner_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL111SF_TUNER_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c new file mode 100644 index 00000000000..efdcb15358f --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -0,0 +1,1431 @@ +/* + * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#include +#include + +#include "mxl111sf.h" +#include "mxl111sf-reg.h" +#include "mxl111sf-phy.h" +#include "mxl111sf-i2c.h" +#include "mxl111sf-gpio.h" + +#include "mxl111sf-demod.h" +#include "mxl111sf-tuner.h" + +#include "lgdt3305.h" +#include "lg2160.h" + +int dvb_usb_mxl111sf_debug; +module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level " + "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); + +int dvb_usb_mxl111sf_isoc; +module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); +MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); + +int dvb_usb_mxl111sf_spi; +module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644); +MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); + +#define ANT_PATH_AUTO 0 +#define ANT_PATH_EXTERNAL 1 +#define ANT_PATH_INTERNAL 2 + +int dvb_usb_mxl111sf_rfswitch = +#if 0 + ANT_PATH_AUTO; +#else + ANT_PATH_EXTERNAL; +#endif + +module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644); +MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info pr_debug +#define deb_reg pr_debug +#define deb_adv pr_debug +#define err pr_err +#define info pr_info + +int mxl111sf_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + int ret; + u8 sndbuf[1+wlen]; + + deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); + + memset(sndbuf, 0, 1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1], wbuf, wlen); + + ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) : + dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen); + mxl_fail(ret); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#define MXL_CMD_REG_READ 0xaa +#define MXL_CMD_REG_WRITE 0x55 + +int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) +{ + u8 buf[2]; + int ret; + + ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); + if (mxl_fail(ret)) { + mxl_debug("error reading reg: 0x%02x", addr); + goto fail; + } + + if (buf[0] == addr) + *data = buf[1]; + else { + err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x", + addr, buf[0], buf[1]); + ret = -EINVAL; + } + + deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data); +fail: + return ret; +} + +int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data) +{ + u8 buf[] = { addr, data }; + int ret; + + deb_reg("W: (0x%02x, 0x%02x)\n", addr, data); + + ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); + if (mxl_fail(ret)) + err("error writing reg: 0x%02x, val: 0x%02x", addr, data); + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_write_reg_mask(struct mxl111sf_state *state, + u8 addr, u8 mask, u8 data) +{ + int ret; + u8 val; + + if (mask != 0xff) { + ret = mxl111sf_read_reg(state, addr, &val); +#if 1 + /* dont know why this usually errors out on the first try */ + if (mxl_fail(ret)) + err("error writing addr: 0x%02x, mask: 0x%02x, " + "data: 0x%02x, retrying...", addr, mask, data); + + ret = mxl111sf_read_reg(state, addr, &val); +#endif + if (mxl_fail(ret)) + goto fail; + } + val &= ~mask; + val |= data; + + ret = mxl111sf_write_reg(state, addr, val); + mxl_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + int i, ret = 0; + + for (i = 0; ctrl_reg_info[i].addr | + ctrl_reg_info[i].mask | + ctrl_reg_info[i].data; i++) { + + ret = mxl111sf_write_reg_mask(state, + ctrl_reg_info[i].addr, + ctrl_reg_info[i].mask, + ctrl_reg_info[i].data); + if (mxl_fail(ret)) { + err("failed on reg #%d (0x%02x)", i, + ctrl_reg_info[i].addr); + break; + } + } + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state) +{ + int ret; + u8 id, ver; + char *mxl_chip, *mxl_rev; + + if ((state->chip_id) && (state->chip_ver)) + return 0; + + ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id); + if (mxl_fail(ret)) + goto fail; + state->chip_id = id; + + ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver); + if (mxl_fail(ret)) + goto fail; + state->chip_ver = ver; + + switch (id) { + case 0x61: + mxl_chip = "MxL101SF"; + break; + case 0x63: + mxl_chip = "MxL111SF"; + break; + default: + mxl_chip = "UNKNOWN MxL1X1"; + break; + } + switch (ver) { + case 0x36: + state->chip_rev = MXL111SF_V6; + mxl_rev = "v6"; + break; + case 0x08: + state->chip_rev = MXL111SF_V8_100; + mxl_rev = "v8_100"; + break; + case 0x18: + state->chip_rev = MXL111SF_V8_200; + mxl_rev = "v8_200"; + break; + default: + state->chip_rev = 0; + mxl_rev = "UNKNOWN REVISION"; + break; + } + info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver); +fail: + return ret; +} + +#define get_chip_info(state) \ +({ \ + int ___ret; \ + ___ret = mxl1x1sf_get_chip_info(state); \ + if (mxl_fail(___ret)) { \ + mxl_debug("failed to get chip info" \ + " on first probe attempt"); \ + ___ret = mxl1x1sf_get_chip_info(state); \ + if (mxl_fail(___ret)) \ + err("failed to get chip info during probe"); \ + else \ + mxl_debug("probe needed a retry " \ + "in order to succeed."); \ + } \ + ___ret; \ +}) + +/* ------------------------------------------------------------------------ */ +#if 0 +static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + /* power control depends on which adapter is being woken: + * save this for init, instead, via mxl111sf_adap_fe_init */ + return 0; +} +#endif + +static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; + int err; + + /* exit if we didnt initialize the driver yet */ + if (!state->chip_id) { + mxl_debug("driver not yet initialized, exit."); + goto fail; + } + + deb_info("%s()\n", __func__); + + mutex_lock(&state->fe_lock); + + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + err = mxl1x1sf_soft_reset(state); + mxl_fail(err); + err = mxl111sf_init_tuner_demod(state); + mxl_fail(err); + err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + + mxl_fail(err); + mxl111sf_enable_usb_output(state); + mxl_fail(err); + mxl1x1sf_top_master_ctrl(state, 1); + mxl_fail(err); + + if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && + (state->chip_rev > MXL111SF_V6)) { + mxl111sf_config_pin_mux_modes(state, + PIN_MUX_TS_SPI_IN_MODE_1); + mxl_fail(err); + } + err = mxl111sf_init_port_expander(state); + if (!mxl_fail(err)) { + state->gpio_mode = adap_state->gpio_mode; + err = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + mxl_fail(err); +#if 0 + err = fe->ops.init(fe); +#endif + msleep(100); /* add short delay after enabling + * the demod before touching it */ + } + + return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0; +fail: + return -ENODEV; +} + +static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; + int err; + + /* exit if we didnt initialize the driver yet */ + if (!state->chip_id) { + mxl_debug("driver not yet initialized, exit."); + goto fail; + } + + deb_info("%s()\n", __func__); + + err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0; + + mutex_unlock(&state->fe_lock); + + return err; +fail: + return -ENODEV; +} + + +static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + ret = mxl111sf_config_mpeg_in(state, 1, 1, + adap_state->ep6_clockphase, + 0, 0); + mxl_fail(ret); +#if 0 + } else { + ret = mxl111sf_disable_656_port(state); + mxl_fail(ret); +#endif + } + + return ret; +} + +static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + + ret = mxl111sf_init_i2s_port(state, 200); + mxl_fail(ret); + ret = mxl111sf_config_i2s(state, 0, 15); + mxl_fail(ret); + } else { + ret = mxl111sf_disable_i2s_port(state); + mxl_fail(ret); + } + if (state->chip_rev > MXL111SF_V6) + ret = mxl111sf_config_spi(state, onoff); + mxl_fail(ret); + + return ret; +} + +static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + } + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static struct lgdt3305_config hauppauge_lgdt3305_config = { + .i2c_addr = 0xb2 >> 1, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .qam_if_khz = 6000, + .vsb_if_khz = 6000, +}; + +static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lgdt3305_attach, + &hauppauge_lgdt3305_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2160_config = { + .lg_chip = LG2160, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, +}; + +static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lg2160_attach, + &hauppauge_lg2160_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2161_1019_config = { + .lg_chip = LG2161_1019, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 2, /* LG2161_OIF_SPI_MAS */ +}; + +static struct lg2160_config hauppauge_lg2161_1040_config = { + .lg_chip = LG2161_1040, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 4, /* LG2161_OIF_SPI_MAS */ +}; + +static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lg2160_attach, + (MXL111SF_V8_200 == state->chip_rev) ? + &hauppauge_lg2161_1040_config : + &hauppauge_lg2161_1019_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2161_1019_ep6_config = { + .lg_chip = LG2161_1019, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 1, /* LG2161_OIF_SERIAL_TS */ +}; + +static struct lg2160_config hauppauge_lg2161_1040_ep6_config = { + .lg_chip = LG2161_1040, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 7, /* LG2161_OIF_SERIAL_TS */ +}; + +static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 0; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lg2160_attach, + (MXL111SF_V8_200 == state->chip_rev) ? + &hauppauge_lg2161_1040_ep6_config : + &hauppauge_lg2161_1019_ep6_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct mxl111sf_demod_config mxl_demod_config = { + .read_reg = mxl111sf_read_reg, + .write_reg = mxl111sf_write_reg, + .program_regs = mxl111sf_ctrl_program_regs, +}; + +static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_SOC_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + /* dont care if this fails */ + mxl111sf_init_port_expander(state); + + adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state, + &mxl_demod_config); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, + int antpath) +{ + return mxl111sf_idac_config(state, 1, 1, + (antpath == ANT_PATH_INTERNAL) ? + 0x3f : 0x00, 0); +} + +#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \ + err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \ + __func__, __LINE__, \ + (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \ + pwr0, pwr1, pwr2, pwr3) + +#define ANT_HUNT_SLEEP 90 +#define ANT_EXT_TWEAK 0 + +static int mxl111sf_ant_hunt(struct dvb_frontend *fe) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + int antctrl = dvb_usb_mxl111sf_rfswitch; + + u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; + + /* FIXME: must force EXTERNAL for QAM - done elsewhere */ + mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ? + ANT_PATH_EXTERNAL : antctrl); + + if (antctrl == ANT_PATH_AUTO) { +#if 0 + msleep(ANT_HUNT_SLEEP); +#endif + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA); + + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0); + + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1); + + mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2); + + if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) { + /* return with EXTERNAL enabled */ + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA, + rxPwr0, rxPwr1, rxPwr2); + } else { + /* return with INTERNAL enabled */ + DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA, + rxPwr0, rxPwr1, rxPwr2); + } + } + return 0; +} + +static struct mxl111sf_tuner_config mxl_tuner_config = { + .if_freq = MXL_IF_6_0, /* applies to external IF output, only */ + .invert_spectrum = 0, + .read_reg = mxl111sf_read_reg, + .write_reg = mxl111sf_write_reg, + .program_regs = mxl111sf_ctrl_program_regs, + .top_master_ctrl = mxl1x1sf_top_master_ctrl, + .ant_hunt = mxl111sf_ant_hunt, +}; + +static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) +{ + struct mxl111sf_state *state = adap_to_priv(adap); + int i; + + deb_adv("%s()\n", __func__); + + for (i = 0; i < state->num_frontends; i++) { + if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state, + &mxl_tuner_config) == NULL) + return -EIO; + adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength; + } + + return 0; +} + +static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm mxl111sf_i2c_algo = { + .master_xfer = mxl111sf_i2c_xfer, + .functionality = mxl111sf_i2c_func, +#ifdef NEED_ALGO_CONTROL + .algo_control = dummy_algo_control, +#endif +}; + +static int mxl111sf_init(struct dvb_usb_device *d) +{ + struct mxl111sf_state *state = d_to_priv(d); + int ret; + static u8 eeprom[256]; + struct i2c_client c; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + err("failed to get chip info during probe"); + + mutex_init(&state->fe_lock); + + if (state->chip_rev > MXL111SF_V6) + mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); + + c.adapter = &d->i2c_adap; + c.addr = 0xa0 >> 1; + + ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); + if (mxl_fail(ret)) + return 0; + tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? + eeprom + 0xa0 : eeprom + 0x80); +#if 0 + switch (state->tv.model) { + case 117001: + case 126001: + case 138001: + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", + __func__, state->tv.model); + } +#endif + return 0; +} + +static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap) +{ + return mxl111sf_attach_demod(adap, 0); +} + +static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap) +{ + return mxl111sf_lgdt3305_frontend_attach(adap, 0); +} + +static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap) +{ + return mxl111sf_lg2160_frontend_attach(adap, 0); +} + +static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); + if (ret < 0) + return ret; + + ret = mxl111sf_attach_demod(adap, 1); + if (ret < 0) + return ret; + + ret = mxl111sf_lg2160_frontend_attach(adap, 2); + if (ret < 0) + return ret; + + return ret; +} + +static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); + if (ret < 0) + return ret; + + ret = mxl111sf_attach_demod(adap, 1); + if (ret < 0) + return ret; + + ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); + if (ret < 0) + return ret; + + return ret; +} + +static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_attach_demod(adap, 0); + if (ret < 0) + return ret; + + if (dvb_usb_mxl111sf_spi) + ret = mxl111sf_lg2161_frontend_attach(adap, 1); + else + ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1); + + return ret; +} + +static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint) +{ + deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint); + stream->type = USB_BULK; + stream->count = 5; + stream->endpoint = endpoint; + stream->u.bulk.buffersize = 8192; +} + +static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream, + u8 endpoint, int framesperurb, int framesize) +{ + deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint, + framesperurb * framesize); + stream->type = USB_ISOC; + stream->count = 5; + stream->endpoint = endpoint; + stream->u.isoc.framesperurb = framesperurb; + stream->u.isoc.framesize = framesize; + stream->u.isoc.interval = 1; +} + +/* DVB USB Driver stuff */ + +/* dvbt mxl111sf + * bulk EP4/BULK/5/8192 + * isoc EP4/ISOC/5/96/564 + */ +static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_dvbt = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_dvbt, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_dvbt, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* atsc lgdt3305 + * bulk EP6/BULK/5/8192 + * isoc EP6/ISOC/5/24/3072 + */ +static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_atsc = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_atsc, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_atsc, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* mh lg2160 + * bulk EP5/BULK/5/8192/RAW + * isoc EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_mh, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* atsc mh lgdt3305 mxl111sf lg2160 + * bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } else if (fe->id == 1) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 2) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + else if (fe->id == 1) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 2) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_atsc_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_atsc_mh, + .get_stream_config = mxl111sf_get_stream_config_atsc_mh, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* mercury lgdt3305 mxl111sf lg2161 + * tp bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP6/BULK/5/8192/RAW + * tp isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW + * spi bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * spi isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } else if (fe->id == 1) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + else if (fe->id == 1) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 2 && dvb_usb_mxl111sf_spi) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mercury = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mercury, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_mercury, + .get_stream_config = mxl111sf_get_stream_config_mercury, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* mercury mh mxl111sf lg2161 + * tp bulk EP4/BULK/5/8192 EP6/BULK/5/8192/RAW + * tp isoc EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW + * spi bulk EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * spi isoc EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 1 && dvb_usb_mxl111sf_spi) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mercury_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_mercury_mh, + .get_stream_config = mxl111sf_get_stream_config_mercury_mh, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +static const struct usb_device_id mxl111sf_id_table[] = { + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, mxl111sf_id_table); + +static struct usb_driver mxl111sf_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = mxl111sf_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(mxl111sf_usb_driver); + +MODULE_AUTHOR("Michael Krufky "); +MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h new file mode 100644 index 00000000000..9816de86e48 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#ifndef _DVB_USB_MXL111SF_H_ +#define _DVB_USB_MXL111SF_H_ + +#ifdef DVB_USB_LOG_PREFIX +#undef DVB_USB_LOG_PREFIX +#endif +#define DVB_USB_LOG_PREFIX "mxl111sf" +#include "dvb_usb.h" +#include + +#define MXL_EP1_REG_READ 1 +#define MXL_EP2_REG_WRITE 2 +#define MXL_EP3_INTERRUPT 3 +#define MXL_EP4_MPEG2 4 +#define MXL_EP5_I2S 5 +#define MXL_EP6_656 6 +#define MXL_EP6_MPEG2 6 + +#ifdef USING_ENUM_mxl111sf_current_mode +enum mxl111sf_current_mode { + mxl_mode_dvbt = MXL_EP4_MPEG2, + mxl_mode_mh = MXL_EP5_I2S, + mxl_mode_atsc = MXL_EP6_MPEG2, +}; +#endif + +enum mxl111sf_gpio_port_expander { + mxl111sf_gpio_hw, + mxl111sf_PCA9534, +}; + +struct mxl111sf_adap_state { + int alt_mode; + int gpio_mode; + int device_mode; + int ep6_clockphase; + int (*fe_init)(struct dvb_frontend *); + int (*fe_sleep)(struct dvb_frontend *); +}; + +struct mxl111sf_state { + struct dvb_usb_device *d; + + enum mxl111sf_gpio_port_expander gpio_port_expander; + u8 port_expander_addr; + + u8 chip_id; + u8 chip_ver; +#define MXL111SF_V6 1 +#define MXL111SF_V8_100 2 +#define MXL111SF_V8_200 3 + u8 chip_rev; + +#ifdef USING_ENUM_mxl111sf_current_mode + enum mxl111sf_current_mode current_mode; +#endif + +#define MXL_TUNER_MODE 0 +#define MXL_SOC_MODE 1 +#define MXL_DEV_MODE_MASK 0x01 +#if 1 + int device_mode; +#endif + /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), + EP5 BULK transfer (atsc-mh), + EP6 BULK transfer (atsc/qam), + use usb alt setting 2 for EP4 BULK transfer (dvb-t), + EP5 ISOC transfer (atsc-mh), + EP6 ISOC transfer (atsc/qam), + */ + int alt_mode; + int gpio_mode; + struct tveeprom tv; + + struct mutex fe_lock; + u8 num_frontends; + struct mxl111sf_adap_state adap_state[3]; +}; + +int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); +int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data); + +struct mxl111sf_reg_ctrl_info { + u8 addr; + u8 mask; + u8 data; +}; + +int mxl111sf_write_reg_mask(struct mxl111sf_state *state, + u8 addr, u8 mask, u8 data); +int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); + +/* needed for hardware i2c functions in mxl111sf-i2c.c: + * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */ +int mxl111sf_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen); + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +extern int dvb_usb_mxl111sf_debug; +#define mxl_debug(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define MXL_I2C_DBG 0x04 +#define MXL_ADV_DBG 0x10 +#define mxl_debug_adv(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define mxl_i2c(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define mxl_i2c_adv(fmt, arg...) \ + if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \ + (MXL_I2C_DBG | MXL_ADV_DBG)) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* The following allows the mxl_fail() macro defined below to work + * in externel modules, such as mxl111sf-tuner.ko, even though + * dvb_usb_mxl111sf_debug is not defined within those modules */ +#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) +#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG +#else +#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug +#endif + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +#endif /* _DVB_USB_MXL111SF_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c new file mode 100644 index 00000000000..a2d1e5b9d9d --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -0,0 +1,1259 @@ +/* + * Realtek RTL28xxU DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * Copyright (C) 2011 Antti Palosaari + * Copyright (C) 2012 Thomas Mair + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "rtl28xxu.h" + +#include "rtl2830.h" +#include "rtl2832.h" + +#include "qt1010.h" +#include "mt2060.h" +#include "mxl5005s.h" +#include "fc0012.h" +#include "fc0013.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) +{ + int ret; + unsigned int pipe; + u8 requesttype; + u8 *buf; + + buf = kmalloc(req->size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto err; + } + + if (req->index & CMD_WR_FLAG) { + /* write */ + memcpy(buf, req->data, req->size); + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + pipe = usb_sndctrlpipe(d->udev, 0); + } else { + /* read */ + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + pipe = usb_rcvctrlpipe(d->udev, 0); + } + + ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, + req->index, buf, req->size, 1000); + if (ret > 0) + ret = 0; + + deb_dump(0, requesttype, req->value, req->index, buf, req->size); + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->size); + + kfree(buf); + + if (ret) + goto err; + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) +{ + struct rtl28xxu_req req; + + if (reg < 0x3000) + req.index = CMD_USB_WR; + else if (reg < 0x4000) + req.index = CMD_SYS_WR; + else + req.index = CMD_IR_WR; + + req.value = reg; + req.size = len; + req.data = val; + + return rtl28xxu_ctrl_msg(d, &req); +} + +static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) +{ + struct rtl28xxu_req req; + + if (reg < 0x3000) + req.index = CMD_USB_RD; + else if (reg < 0x4000) + req.index = CMD_SYS_RD; + else + req.index = CMD_IR_RD; + + req.value = reg; + req.size = len; + req.data = val; + + return rtl28xxu_ctrl_msg(d, &req); +} + +static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) +{ + return rtl28xx_wr_regs(d, reg, &val, 1); +} + +static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +{ + return rtl2831_rd_regs(d, reg, val, 1); +} + +/* I2C */ +static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + int ret; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct rtl28xxu_priv *priv = d->priv; + struct rtl28xxu_req req; + + /* + * It is not known which are real I2C bus xfer limits, but testing + * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes. + * TODO: find out RTL2832U lens + */ + + /* + * I2C adapter logic looks rather complicated due to fact it handles + * three different access methods. Those methods are; + * 1) integrated demod access + * 2) old I2C access + * 3) new I2C access + * + * Used method is selected in order 1, 2, 3. Method 3 can handle all + * requests but there is two reasons why not use it always; + * 1) It is most expensive, usually two USB messages are needed + * 2) At least RTL2831U does not support it + * + * Method 3 is needed in case of I2C write+read (typical register read) + * where write is more than one byte. + */ + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + if (msg[0].len > 24 || msg[1].len > 24) { + /* TODO: check msg[0].len max */ + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } else if (msg[0].addr == 0x10) { + /* method 1 - integrated demod */ + req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); + req.index = CMD_DEMOD_RD | priv->page; + req.size = msg[1].len; + req.data = &msg[1].buf[0]; + ret = rtl28xxu_ctrl_msg(d, &req); + } else if (msg[0].len < 2) { + /* method 2 - old I2C */ + req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); + req.index = CMD_I2C_RD; + req.size = msg[1].len; + req.data = &msg[1].buf[0]; + ret = rtl28xxu_ctrl_msg(d, &req); + } else { + /* method 3 - new I2C */ + req.value = (msg[0].addr << 1); + req.index = CMD_I2C_DA_WR; + req.size = msg[0].len; + req.data = msg[0].buf; + ret = rtl28xxu_ctrl_msg(d, &req); + if (ret) + goto err_mutex_unlock; + + req.value = (msg[0].addr << 1); + req.index = CMD_I2C_DA_RD; + req.size = msg[1].len; + req.data = msg[1].buf; + ret = rtl28xxu_ctrl_msg(d, &req); + } + } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + if (msg[0].len > 22) { + /* TODO: check msg[0].len max */ + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } else if (msg[0].addr == 0x10) { + /* method 1 - integrated demod */ + if (msg[0].buf[0] == 0x00) { + /* save demod page for later demod access */ + priv->page = msg[0].buf[1]; + ret = 0; + } else { + req.value = (msg[0].buf[0] << 8) | + (msg[0].addr << 1); + req.index = CMD_DEMOD_WR | priv->page; + req.size = msg[0].len-1; + req.data = &msg[0].buf[1]; + ret = rtl28xxu_ctrl_msg(d, &req); + } + } else if (msg[0].len < 23) { + /* method 2 - old I2C */ + req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); + req.index = CMD_I2C_WR; + req.size = msg[0].len-1; + req.data = &msg[0].buf[1]; + ret = rtl28xxu_ctrl_msg(d, &req); + } else { + /* method 3 - new I2C */ + req.value = (msg[0].addr << 1); + req.index = CMD_I2C_DA_WR; + req.size = msg[0].len; + req.data = msg[0].buf; + ret = rtl28xxu_ctrl_msg(d, &req); + } + } else { + ret = -EINVAL; + } + +err_mutex_unlock: + mutex_unlock(&d->i2c_mutex); + + return ret ? ret : num; +} + +static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm rtl28xxu_i2c_algo = { + .master_xfer = rtl28xxu_i2c_xfer, + .functionality = rtl28xxu_i2c_func, +}; + +static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .ts_mode = 0, + .spec_inv = 1, + .if_dvbt = 36150000, + .vtop = 0x20, + .krf = 0x04, + .agc_targ_val = 0x2d, + +}; + +static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .ts_mode = 0, + .spec_inv = 1, + .if_dvbt = 36125000, + .vtop = 0x20, + .krf = 0x04, + .agc_targ_val = 0x2d, +}; + +static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .ts_mode = 0, + .spec_inv = 0, + .if_dvbt = 4570000, + .vtop = 0x3f, + .krf = 0x04, + .agc_targ_val = 0x3e, +}; + +static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + struct rtl28xxu_priv *priv = d_to_priv(d); + u8 buf[1]; + struct rtl2830_config *rtl2830_config; + /* open RTL2831U/RTL2830 I2C gate */ + struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" }; + /* for MT2060 tuner probe */ + struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf }; + /* for QT1010 tuner probe */ + struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf }; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* + * RTL2831U GPIOs + * ========================================================= + * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?) + * GPIO2 | LED | 0 off | 1 on | + * GPIO4 | tuner#1 | 0 on | 1 off | MT2060 + */ + + /* GPIO direction */ + ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a); + if (ret) + goto err; + + /* enable as output GPIO0, GPIO2, GPIO4 */ + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, 0x15); + if (ret) + goto err; + + /* + * Probe used tuner. We need to know used tuner before demod attach + * since there is some demod params needed to set according to tuner. + */ + + /* demod needs some time to wake up */ + msleep(20); + + /* open demod I2C gate */ + ret = rtl28xxu_ctrl_msg(d, &req_gate); + if (ret) + goto err; + + /* check QT1010 ID(?) register; reg=0f val=2c */ + ret = rtl28xxu_ctrl_msg(d, &req_qt1010); + if (ret == 0 && buf[0] == 0x2c) { + priv->tuner = TUNER_RTL2830_QT1010; + rtl2830_config = &rtl28xxu_rtl2830_qt1010_config; + dev_dbg(&d->udev->dev, "%s: QT1010\n", __func__); + goto found; + } else { + dev_dbg(&d->udev->dev, "%s: QT1010 probe failed=%d - %02x\n", + __func__, ret, buf[0]); + } + + /* open demod I2C gate */ + ret = rtl28xxu_ctrl_msg(d, &req_gate); + if (ret) + goto err; + + /* check MT2060 ID register; reg=00 val=63 */ + ret = rtl28xxu_ctrl_msg(d, &req_mt2060); + if (ret == 0 && buf[0] == 0x63) { + priv->tuner = TUNER_RTL2830_MT2060; + rtl2830_config = &rtl28xxu_rtl2830_mt2060_config; + dev_dbg(&d->udev->dev, "%s: MT2060\n", __func__); + goto found; + } else { + dev_dbg(&d->udev->dev, "%s: MT2060 probe failed=%d - %02x\n", + __func__, ret, buf[0]); + } + + /* assume MXL5005S */ + ret = 0; + priv->tuner = TUNER_RTL2830_MXL5005S; + rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config; + dev_dbg(&d->udev->dev, "%s: MXL5005S\n", __func__); + goto found; + +found: + /* attach demodulator */ + adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config, + &d->i2c_adap); + if (adap->fe[0] == NULL) { + ret = -ENODEV; + goto err; + } + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .if_dvbt = 0, + .tuner = TUNER_RTL2832_FC0012 +}; + +static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .if_dvbt = 0, + .tuner = TUNER_RTL2832_FC0013 +}; + +static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + int ret; + u8 val; + + dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg); + + switch (cmd) { + case FC_FE_CALLBACK_VHF_ENABLE: + /* set output values */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + if (ret) + goto err; + + if (arg) + val &= 0xbf; /* set GPIO6 low */ + else + val |= 0x40; /* set GPIO6 high */ + + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + if (ret) + goto err; + break; + default: + ret = -EINVAL; + goto err; + } + return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + + +static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + /* TODO implement*/ + return 0; +} + +static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) +{ + struct rtl28xxu_priv *priv = d->priv; + + switch (priv->tuner) { + case TUNER_RTL2832_FC0012: + return rtl2832u_fc0012_tuner_callback(d, cmd, arg); + + case TUNER_RTL2832_FC0013: + return rtl2832u_fc0013_tuner_callback(d, cmd, arg); + default: + break; + } + + return -ENODEV; +} + +static int rtl2832u_frontend_callback(void *adapter_priv, int component, + int cmd, int arg) +{ + struct i2c_adapter *adap = adapter_priv; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + switch (component) { + case DVB_FRONTEND_COMPONENT_TUNER: + return rtl2832u_tuner_callback(d, cmd, arg); + default: + break; + } + + return -EINVAL; +} + +static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + struct rtl28xxu_priv *priv = d_to_priv(d); + struct rtl2832_config *rtl2832_config; + u8 buf[2], val; + /* open RTL2832U/RTL2832 I2C gate */ + struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"}; + /* close RTL2832U/RTL2832 I2C gate */ + struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"}; + /* for FC0012 tuner probe */ + struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf}; + /* for FC0013 tuner probe */ + struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf}; + /* for MT2266 tuner probe */ + struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf}; + /* for FC2580 tuner probe */ + struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf}; + /* for MT2063 tuner probe */ + struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf}; + /* for MAX3543 tuner probe */ + struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf}; + /* for TUA9001 tuner probe */ + struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf}; + /* for MXL5007T tuner probe */ + struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; + /* for E4000 tuner probe */ + struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; + /* for TDA18272 tuner probe */ + struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + ret = rtl28xx_rd_reg(d, SYS_GPIO_DIR, &val); + if (ret) + goto err; + + val &= 0xbf; + + ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, val); + if (ret) + goto err; + + /* enable as output GPIO3 and GPIO6*/ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_EN, &val); + if (ret) + goto err; + + val |= 0x48; + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, val); + if (ret) + goto err; + + /* + * Probe used tuner. We need to know used tuner before demod attach + * since there is some demod params needed to set according to tuner. + */ + + /* open demod I2C gate */ + ret = rtl28xxu_ctrl_msg(d, &req_gate_open); + if (ret) + goto err; + + priv->tuner = TUNER_NONE; + + /* check FC0012 ID register; reg=00 val=a1 */ + ret = rtl28xxu_ctrl_msg(d, &req_fc0012); + if (ret == 0 && buf[0] == 0xa1) { + priv->tuner = TUNER_RTL2832_FC0012; + rtl2832_config = &rtl28xxu_rtl2832_fc0012_config; + dev_info(&d->udev->dev, "%s: FC0012 tuner found", + KBUILD_MODNAME); + goto found; + } + + /* check FC0013 ID register; reg=00 val=a3 */ + ret = rtl28xxu_ctrl_msg(d, &req_fc0013); + if (ret == 0 && buf[0] == 0xa3) { + priv->tuner = TUNER_RTL2832_FC0013; + rtl2832_config = &rtl28xxu_rtl2832_fc0013_config; + dev_info(&d->udev->dev, "%s: FC0013 tuner found", + KBUILD_MODNAME); + goto found; + } + + /* check MT2266 ID register; reg=00 val=85 */ + ret = rtl28xxu_ctrl_msg(d, &req_mt2266); + if (ret == 0 && buf[0] == 0x85) { + priv->tuner = TUNER_RTL2832_MT2266; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: MT2266 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check FC2580 ID register; reg=01 val=56 */ + ret = rtl28xxu_ctrl_msg(d, &req_fc2580); + if (ret == 0 && buf[0] == 0x56) { + priv->tuner = TUNER_RTL2832_FC2580; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: FC2580 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check MT2063 ID register; reg=00 val=9e || 9c */ + ret = rtl28xxu_ctrl_msg(d, &req_mt2063); + if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) { + priv->tuner = TUNER_RTL2832_MT2063; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: MT2063 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check MAX3543 ID register; reg=00 val=38 */ + ret = rtl28xxu_ctrl_msg(d, &req_max3543); + if (ret == 0 && buf[0] == 0x38) { + priv->tuner = TUNER_RTL2832_MAX3543; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: MAX3534 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check TUA9001 ID register; reg=7e val=2328 */ + ret = rtl28xxu_ctrl_msg(d, &req_tua9001); + if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) { + priv->tuner = TUNER_RTL2832_TUA9001; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: TUA9001 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check MXL5007R ID register; reg=d9 val=14 */ + ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t); + if (ret == 0 && buf[0] == 0x14) { + priv->tuner = TUNER_RTL2832_MXL5007T; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: MXL5007T tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check E4000 ID register; reg=02 val=40 */ + ret = rtl28xxu_ctrl_msg(d, &req_e4000); + if (ret == 0 && buf[0] == 0x40) { + priv->tuner = TUNER_RTL2832_E4000; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: E4000 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + + /* check TDA18272 ID register; reg=00 val=c760 */ + ret = rtl28xxu_ctrl_msg(d, &req_tda18272); + if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) { + priv->tuner = TUNER_RTL2832_TDA18272; + /* TODO implement tuner */ + dev_info(&d->udev->dev, "%s: TDA18272 tuner found", + KBUILD_MODNAME); + goto unsupported; + } + +unsupported: + /* close demod I2C gate */ + ret = rtl28xxu_ctrl_msg(d, &req_gate_close); + if (ret) + goto err; + + /* tuner not found */ + dev_dbg(&d->udev->dev, "%s: No compatible tuner found\n", __func__); + ret = -ENODEV; + return ret; + +found: + /* close demod I2C gate */ + ret = rtl28xxu_ctrl_msg(d, &req_gate_close); + if (ret) + goto err; + + /* attach demodulator */ + adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config, + &d->i2c_adap); + if (adap->fe[0] == NULL) { + ret = -ENODEV; + goto err; + } + + /* set fe callbacks */ + adap->fe[0]->callback = rtl2832u_frontend_callback; + + return ret; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static struct qt1010_config rtl28xxu_qt1010_config = { + .i2c_address = 0x62, /* 0xc4 */ +}; + +static struct mt2060_config rtl28xxu_mt2060_config = { + .i2c_address = 0x60, /* 0xc0 */ + .clock_out = 0, +}; + +static struct mxl5005s_config rtl28xxu_mxl5005s_config = { + .i2c_address = 0x63, /* 0xc6 */ + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C_H, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + struct rtl28xxu_priv *priv = d_to_priv(d); + struct i2c_adapter *rtl2830_tuner_i2c; + struct dvb_frontend *fe; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */ + rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]); + + switch (priv->tuner) { + case TUNER_RTL2830_QT1010: + fe = dvb_attach(qt1010_attach, adap->fe[0], + rtl2830_tuner_i2c, &rtl28xxu_qt1010_config); + break; + case TUNER_RTL2830_MT2060: + fe = dvb_attach(mt2060_attach, adap->fe[0], + rtl2830_tuner_i2c, &rtl28xxu_mt2060_config, + 1220); + break; + case TUNER_RTL2830_MXL5005S: + fe = dvb_attach(mxl5005s_attach, adap->fe[0], + rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config); + break; + default: + fe = NULL; + dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, + priv->tuner); + } + + if (fe == NULL) { + ret = -ENODEV; + goto err; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + struct rtl28xxu_priv *priv = d_to_priv(d); + struct dvb_frontend *fe; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + switch (priv->tuner) { + case TUNER_RTL2832_FC0012: + fe = dvb_attach(fc0012_attach, adap->fe[0], + &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); + + /* since fc0012 includs reading the signal strength delegate + * that to the tuner driver */ + adap->fe[0]->ops.read_signal_strength = + adap->fe[0]->ops.tuner_ops.get_rf_strength; + return 0; + break; + case TUNER_RTL2832_FC0013: + fe = dvb_attach(fc0013_attach, adap->fe[0], + &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); + + /* fc0013 also supports signal strength reading */ + adap->fe[0]->ops.read_signal_strength = + adap->fe[0]->ops.tuner_ops.get_rf_strength; + return 0; + default: + fe = NULL; + dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, + priv->tuner); + } + + if (fe == NULL) { + ret = -ENODEV; + goto err; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl28xxu_init(struct dvb_usb_device *d) +{ + int ret; + u8 val; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* init USB endpoints */ + ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val); + if (ret) + goto err; + + /* enable DMA and Full Packet Mode*/ + val |= 0x09; + ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val); + if (ret) + goto err; + + /* set EPA maximum packet size to 0x0200 */ + ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); + if (ret) + goto err; + + /* change EPA FIFO length */ + ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); + if (ret) + goto err; + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl28xxu_streaming_ctrl(struct dvb_frontend *fe , int onoff) +{ + int ret; + u8 buf[2]; + struct dvb_usb_device *d = fe_to_d(fe); + + dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + + if (onoff) { + buf[0] = 0x00; + buf[1] = 0x00; + } else { + buf[0] = 0x10; /* stall EPA */ + buf[1] = 0x02; /* reset EPA */ + } + + ret = rtl28xx_wr_regs(d, USB_EPA_CTL, buf, 2); + if (ret) + goto err; + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 gpio, sys0; + + dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + + /* demod adc */ + ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0); + if (ret) + goto err; + + /* tuner power, read GPIOs */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); + if (ret) + goto err; + + dev_dbg(&d->udev->dev, "%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, + sys0, gpio); + + if (onoff) { + gpio |= 0x01; /* GPIO0 = 1 */ + gpio &= (~0x10); /* GPIO4 = 0 */ + gpio |= 0x04; /* GPIO2 = 1, LED on */ + sys0 = sys0 & 0x0f; + sys0 |= 0xe0; + } else { + gpio &= (~0x01); /* GPIO0 = 0 */ + gpio |= 0x10; /* GPIO4 = 1 */ + gpio &= (~0x04); /* GPIO2 = 1, LED off */ + sys0 = sys0 & (~0xc0); + } + + dev_dbg(&d->udev->dev, "%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, + sys0, gpio); + + /* demod adc */ + ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0); + if (ret) + goto err; + + /* tuner power, write GPIOs */ + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); + if (ret) + goto err; + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 val; + + dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + + if (onoff) { + /* set output values */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + if (ret) + goto err; + + val |= 0x08; + val &= 0xef; + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + if (ret) + goto err; + + /* demod_ctl_1 */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val); + if (ret) + goto err; + + val &= 0xef; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val); + if (ret) + goto err; + + /* demod control */ + /* PLL enable */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + /* bit 7 to 1 */ + val |= 0x80; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + /* demod HW reset */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + /* bit 5 to 0 */ + val &= 0xdf; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + val |= 0x20; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + mdelay(5); + + /*enable ADC_Q and ADC_I */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + val |= 0x48; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + + } else { + /* demod_ctl_1 */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val); + if (ret) + goto err; + + val |= 0x0c; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val); + if (ret) + goto err; + + /* set output values */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + if (ret) + goto err; + + val |= 0x10; + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + if (ret) + goto err; + + /* demod control */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + val &= 0x37; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + } + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + + +static int rtl2831u_rc_query(struct dvb_usb_device *d) +{ + int ret, i; + struct rtl28xxu_priv *priv = d->priv; + u8 buf[5]; + u32 rc_code; + struct rtl28xxu_reg_val rc_nec_tab[] = { + { 0x3033, 0x80 }, + { 0x3020, 0x43 }, + { 0x3021, 0x16 }, + { 0x3022, 0x16 }, + { 0x3023, 0x5a }, + { 0x3024, 0x2d }, + { 0x3025, 0x16 }, + { 0x3026, 0x01 }, + { 0x3028, 0xb0 }, + { 0x3029, 0x04 }, + { 0x302c, 0x88 }, + { 0x302e, 0x13 }, + { 0x3030, 0xdf }, + { 0x3031, 0x05 }, + }; + + /* init remote controller */ + if (!priv->rc_active) { + for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { + ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, + rc_nec_tab[i].val); + if (ret) + goto err; + } + priv->rc_active = true; + } + + ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5); + if (ret) + goto err; + + if (buf[4] & 0x01) { + if (buf[2] == (u8) ~buf[3]) { + if (buf[0] == (u8) ~buf[1]) { + /* NEC standard (16 bit) */ + rc_code = buf[0] << 8 | buf[2]; + } else { + /* NEC extended (24 bit) */ + rc_code = buf[0] << 16 | + buf[1] << 8 | buf[2]; + } + } else { + /* NEC full (32 bit) */ + rc_code = buf[0] << 24 | buf[1] << 16 | + buf[2] << 8 | buf[3]; + } + + rc_keydown(d->rc_dev, rc_code, 0); + + ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); + if (ret) + goto err; + + /* repeated intentionally to avoid extra keypress */ + ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); + if (ret) + goto err; + } + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl2831u_get_rc_config(struct dvb_usb_device *d, + struct dvb_usb_rc *rc) +{ + rc->map_name = RC_MAP_EMPTY; + rc->allowed_protos = RC_TYPE_NEC; + rc->query = rtl2831u_rc_query; + rc->interval = 400; + + return 0; +} + +static int rtl2832u_rc_query(struct dvb_usb_device *d) +{ + int ret, i; + struct rtl28xxu_priv *priv = d->priv; + u8 buf[128]; + int len; + struct rtl28xxu_reg_val rc_nec_tab[] = { + { IR_RX_CTRL, 0x20 }, + { IR_RX_BUF_CTRL, 0x80 }, + { IR_RX_IF, 0xff }, + { IR_RX_IE, 0xff }, + { IR_MAX_DURATION0, 0xd0 }, + { IR_MAX_DURATION1, 0x07 }, + { IR_IDLE_LEN0, 0xc0 }, + { IR_IDLE_LEN1, 0x00 }, + { IR_GLITCH_LEN, 0x03 }, + { IR_RX_CLK, 0x09 }, + { IR_RX_CFG, 0x1c }, + { IR_MAX_H_TOL_LEN, 0x1e }, + { IR_MAX_L_TOL_LEN, 0x1e }, + { IR_RX_CTRL, 0x80 }, + }; + + /* init remote controller */ + if (!priv->rc_active) { + for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { + ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, + rc_nec_tab[i].val); + if (ret) + goto err; + } + priv->rc_active = true; + } + + ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]); + if (ret) + goto err; + + if (buf[0] != 0x83) + goto exit; + + ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]); + if (ret) + goto err; + + len = buf[0]; + ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len); + + /* TODO: pass raw IR to Kernel IR decoder */ + + ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03); + ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80); + ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80); + +exit: + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl2832u_get_rc_config(struct dvb_usb_device *d, + struct dvb_usb_rc *rc) +{ + rc->map_name = RC_MAP_EMPTY; + rc->allowed_protos = RC_TYPE_NEC; + rc->query = rtl2832u_rc_query; + rc->interval = 400; + + return 0; +} + +static const struct dvb_usb_device_properties rtl2831u_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct rtl28xxu_priv), + + .power_ctrl = rtl2831u_power_ctrl, + .i2c_algo = &rtl28xxu_i2c_algo, + .frontend_attach = rtl2831u_frontend_attach, + .tuner_attach = rtl2831u_tuner_attach, + .init = rtl28xxu_init, + .get_rc_config = rtl2831u_get_rc_config, + .streaming_ctrl = rtl28xxu_streaming_ctrl, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512), + }, + }, +}; + +static const struct dvb_usb_device_properties rtl2832u_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct rtl28xxu_priv), + + .power_ctrl = rtl2832u_power_ctrl, + .i2c_algo = &rtl28xxu_i2c_algo, + .frontend_attach = rtl2832u_frontend_attach, + .tuner_attach = rtl2832u_tuner_attach, + .init = rtl28xxu_init, + .get_rc_config = rtl2832u_get_rc_config, + .streaming_ctrl = rtl28xxu_streaming_ctrl, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512), + }, + }, +}; + +static const struct usb_device_id rtl28xxu_id_table[] = { + { DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U, + &rtl2831u_props, "Realtek RTL2831U reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT, + &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, + { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2, + &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, + + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1, + &rtl2832u_props, "Terratec Cinergy T Stick Black", NULL) }, + { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT, + &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK, + &rtl2832u_props, "NOXON DAB/DAB+ USB dongle", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); + +static struct usb_driver rtl28xxu_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl28xxu_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(rtl28xxu_usb_driver); + +MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_AUTHOR("Thomas Mair "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h new file mode 100644 index 00000000000..575edbf13a9 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -0,0 +1,254 @@ +/* + * Realtek RTL28xxU DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * Copyright (C) 2011 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef RTL28XXU_H +#define RTL28XXU_H + +#include "dvb_usb.h" + +#define deb_dump(r, t, v, i, b, l) { \ + char *direction; \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + direction = ">>>"; \ + else \ + direction = "<<<"; \ + dev_dbg(&d->udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \ + "%s [%d bytes]\n", __func__, t, r, v & 0xff, v >> 8, \ + i & 0xff, i >> 8, l & 0xff, l >> 8, direction, l); \ +} + +/* + * USB commands + * (usb_control_msg() index parameter) + */ + +#define DEMOD 0x0000 +#define USB 0x0100 +#define SYS 0x0200 +#define I2C 0x0300 +#define I2C_DA 0x0600 + +#define CMD_WR_FLAG 0x0010 +#define CMD_DEMOD_RD 0x0000 +#define CMD_DEMOD_WR 0x0010 +#define CMD_USB_RD 0x0100 +#define CMD_USB_WR 0x0110 +#define CMD_SYS_RD 0x0200 +#define CMD_IR_RD 0x0201 +#define CMD_IR_WR 0x0211 +#define CMD_SYS_WR 0x0210 +#define CMD_I2C_RD 0x0300 +#define CMD_I2C_WR 0x0310 +#define CMD_I2C_DA_RD 0x0600 +#define CMD_I2C_DA_WR 0x0610 + + +struct rtl28xxu_priv { + u8 chip_id; + u8 tuner; + u8 page; /* integrated demod active register page */ + bool rc_active; +}; + +enum rtl28xxu_chip_id { + CHIP_ID_NONE, + CHIP_ID_RTL2831U, + CHIP_ID_RTL2832U, +}; + +enum rtl28xxu_tuner { + TUNER_NONE, + + TUNER_RTL2830_QT1010, + TUNER_RTL2830_MT2060, + TUNER_RTL2830_MXL5005S, + + TUNER_RTL2832_MT2266, + TUNER_RTL2832_FC2580, + TUNER_RTL2832_MT2063, + TUNER_RTL2832_MAX3543, + TUNER_RTL2832_TUA9001, + TUNER_RTL2832_MXL5007T, + TUNER_RTL2832_FC0012, + TUNER_RTL2832_E4000, + TUNER_RTL2832_TDA18272, + TUNER_RTL2832_FC0013, +}; + +struct rtl28xxu_req { + u16 value; + u16 index; + u16 size; + u8 *data; +}; + +struct rtl28xxu_reg_val { + u16 reg; + u8 val; +}; + +/* + * memory map + * + * 0x0000 DEMOD : demodulator + * 0x2000 USB : SIE, USB endpoint, debug, DMA + * 0x3000 SYS : system + * 0xfc00 RC : remote controller (not RTL2831U) + */ + +/* + * USB registers + */ +/* SIE Control Registers */ +#define USB_SYSCTL 0x2000 /* USB system control */ +#define USB_SYSCTL_0 0x2000 /* USB system control */ +#define USB_SYSCTL_1 0x2001 /* USB system control */ +#define USB_SYSCTL_2 0x2002 /* USB system control */ +#define USB_SYSCTL_3 0x2003 /* USB system control */ +#define USB_IRQSTAT 0x2008 /* SIE interrupt status */ +#define USB_IRQEN 0x200C /* SIE interrupt enable */ +#define USB_CTRL 0x2010 /* USB control */ +#define USB_STAT 0x2014 /* USB status */ +#define USB_DEVADDR 0x2018 /* USB device address */ +#define USB_TEST 0x201C /* USB test mode */ +#define USB_FRAME_NUMBER 0x2020 /* frame number */ +#define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */ +#define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */ +#define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */ +/* Endpoint Registers */ +#define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */ +#define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */ +#define USB_EP0_CFG 0x2104 /* EP 0 configure */ +#define USB_EP0_CTL 0x2108 /* EP 0 control */ +#define USB_EP0_STAT 0x210C /* EP 0 status */ +#define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */ +#define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */ +#define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */ +#define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */ +#define USB_EPA_CFG 0x2144 /* EP A configure */ +#define USB_EPA_CFG_0 0x2144 /* EP A configure */ +#define USB_EPA_CFG_1 0x2145 /* EP A configure */ +#define USB_EPA_CFG_2 0x2146 /* EP A configure */ +#define USB_EPA_CFG_3 0x2147 /* EP A configure */ +#define USB_EPA_CTL 0x2148 /* EP A control */ +#define USB_EPA_CTL_0 0x2148 /* EP A control */ +#define USB_EPA_CTL_1 0x2149 /* EP A control */ +#define USB_EPA_CTL_2 0x214A /* EP A control */ +#define USB_EPA_CTL_3 0x214B /* EP A control */ +#define USB_EPA_STAT 0x214C /* EP A status */ +#define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */ +#define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */ +#define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */ +#define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */ +#define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */ +#define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */ +#define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */ +#define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */ +#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */ +#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */ +#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */ +#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */ +/* Debug Registers */ +#define USB_PHYTSTDIS 0x2F04 /* PHY test disable */ +#define USB_TOUT_VAL 0x2F08 /* USB time-out time */ +#define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */ +#define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */ +#define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */ +#define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */ +#define USB_UTMI_TST 0x2F80 /* UTMI test */ +#define USB_UTMI_STATUS 0x2F84 /* UTMI status */ +#define USB_TSTCTL 0x2F88 /* test control */ +#define USB_TSTCTL2 0x2F8C /* test control 2 */ +#define USB_PID_FORCE 0x2F90 /* force PID */ +#define USB_PKTERR_CNT 0x2F94 /* packet error counter */ +#define USB_RXERR_CNT 0x2F98 /* RX error counter */ +#define USB_MEM_BIST 0x2F9C /* MEM BIST test */ +#define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */ +#define USB_CNTTEST 0x2FA4 /* counter test */ +#define USB_PHYTST 0x2FC0 /* USB PHY test */ +#define USB_DBGIDX 0x2FF0 /* select individual block debug signal */ +#define USB_DBGMUX 0x2FF4 /* debug signal module mux */ + +/* + * SYS registers + */ +/* demod control registers */ +#define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */ +#define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */ +/* GPIO registers */ +#define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */ +#define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */ +#define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */ +#define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */ +#define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */ +#define SYS_SYSINTE 0x3005 /* system interrupt enable */ +#define SYS_SYSINTS 0x3006 /* system interrupt status */ +#define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */ +#define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */ +#define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */ +#define SYS_DEMOD_CTL1 0x300B + +/* IrDA registers */ +#define SYS_IRRC_PSR 0x3020 /* IR protocol selection */ +#define SYS_IRRC_PER 0x3024 /* IR protocol extension */ +#define SYS_IRRC_SF 0x3028 /* IR sampling frequency */ +#define SYS_IRRC_DPIR 0x302C /* IR data package interval */ +#define SYS_IRRC_CR 0x3030 /* IR control */ +#define SYS_IRRC_RP 0x3034 /* IR read port */ +#define SYS_IRRC_SR 0x3038 /* IR status */ +/* I2C master registers */ +#define SYS_I2CCR 0x3040 /* I2C clock */ +#define SYS_I2CMCR 0x3044 /* I2C master control */ +#define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */ +#define SYS_I2CMSR 0x304C /* I2C master status */ +#define SYS_I2CMFR 0x3050 /* I2C master FIFO */ + +/* + * IR registers + */ +#define IR_RX_BUF 0xFC00 +#define IR_RX_IE 0xFD00 +#define IR_RX_IF 0xFD01 +#define IR_RX_CTRL 0xFD02 +#define IR_RX_CFG 0xFD03 +#define IR_MAX_DURATION0 0xFD04 +#define IR_MAX_DURATION1 0xFD05 +#define IR_IDLE_LEN0 0xFD06 +#define IR_IDLE_LEN1 0xFD07 +#define IR_GLITCH_LEN 0xFD08 +#define IR_RX_BUF_CTRL 0xFD09 +#define IR_RX_BUF_DATA 0xFD0A +#define IR_RX_BC 0xFD0B +#define IR_RX_CLK 0xFD0C +#define IR_RX_C_COUNT_L 0xFD0D +#define IR_RX_C_COUNT_H 0xFD0E +#define IR_SUSPEND_CTRL 0xFD10 +#define IR_ERR_TOL_CTRL 0xFD11 +#define IR_UNIT_LEN 0xFD12 +#define IR_ERR_TOL_LEN 0xFD13 +#define IR_MAX_H_TOL_LEN 0xFD14 +#define IR_MAX_L_TOL_LEN 0xFD15 +#define IR_MASK_CTRL 0xFD16 +#define IR_MASK_DATA 0xFD17 +#define IR_RES_MASK_ADDR 0xFD18 +#define IR_RES_MASK_T_LEN 0xFD19 + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c new file mode 100644 index 00000000000..eaf673a3978 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c @@ -0,0 +1,357 @@ +/* usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * BULK and ISOC USB data transfers in a generic way. + * Can be used for DVB-only and also, that's the plan, for + * Hybrid USB devices (analog and DVB). + */ +#include "dvb_usb_common.h" + +/* URB stuff for streaming */ + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); + +static void usb_urb_complete(struct urb *urb) +{ + struct usb_data_stream *stream = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; + + dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \ + "length=%d/%d pack_num=%d errors=%d\n", __func__, + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status, urb->actual_length, + urb->transfer_buffer_length, + urb->number_of_packets, urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n", + __func__, urb->status); + break; + } + + b = (u8 *) urb->transfer_buffer; + switch (ptype) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status != 0) + dev_dbg(&stream->udev->dev, "%s: iso frame " \ + "descriptor has an error=%d\n", + __func__, + urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, + b + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \ + "completition handler\n", KBUILD_MODNAME); + return; + } + usb_submit_urb(urb, GFP_ATOMIC); +} + +int usb_urb_killv2(struct usb_data_stream *stream) +{ + int i; + for (i = 0; i < stream->urbs_submitted; i++) { + dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i); + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + return 0; +} + +int usb_urb_submitv2(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) +{ + int i, ret; + + if (props) { + ret = usb_urb_reconfig(stream, props); + if (ret < 0) + return ret; + } + + for (i = 0; i < stream->urbs_initialized; i++) { + dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); + ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); + if (ret) { + dev_err(&stream->udev->dev, "%s: could not submit " \ + "urb no. %d - get them all back\n", + KBUILD_MODNAME, i); + usb_urb_killv2(stream); + return ret; + } + stream->urbs_submitted++; + } + return 0; +} + +int usb_urb_free_urbs(struct usb_data_stream *stream) +{ + int i; + + usb_urb_killv2(stream); + + for (i = stream->urbs_initialized - 1; i >= 0; i--) { + if (stream->urb_list[i]) { + dev_dbg(&stream->udev->dev, "%s: free urb=%d\n", + __func__, i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + return 0; +} + +static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb(stream->urb_list[i], + stream->udev, + usb_rcvbulkpipe(stream->udev, + stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); + stream->urb_list[i] = usb_alloc_urb( + stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev, + stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = + stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_free_stream_buffers(struct usb_data_stream *stream) +{ + if (stream->state & USB_STATE_URB_BUF) { + while (stream->buf_num) { + stream->buf_num--; + dev_dbg(&stream->udev->dev, "%s: free buf=%d\n", + __func__, stream->buf_num); + usb_free_coherent(stream->udev, stream->buf_size, + stream->buf_list[stream->buf_num], + stream->dma_addr[stream->buf_num]); + } + } + + stream->state &= ~USB_STATE_URB_BUF; + + return 0; +} + +int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, + unsigned long size) +{ + stream->buf_num = 0; + stream->buf_size = size; + + dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \ + "streaming\n", __func__, num * size); + + for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { + stream->buf_list[stream->buf_num] = usb_alloc_coherent( + stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]); + if (!stream->buf_list[stream->buf_num]) { + dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", + __func__, stream->buf_num); + usb_free_stream_buffers(stream); + return -ENOMEM; + } + + dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", + __func__, stream->buf_num, + stream->buf_list[stream->buf_num], + (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num], 0, size); + stream->state |= USB_STATE_URB_BUF; + } + + return 0; +} + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) +{ + int buf_size; + + if (!props) + return 0; + + /* check allocated buffers are large enough for the request */ + if (props->type == USB_BULK) { + buf_size = stream->props.u.bulk.buffersize; + } else if (props->type == USB_ISOC) { + buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; + } else { + dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n", + KBUILD_MODNAME, props->type); + return -EINVAL; + } + + if (stream->buf_num < props->count || stream->buf_size < buf_size) { + dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \ + "allocated buffers are too small\n", + KBUILD_MODNAME); + return -EINVAL; + } + + /* check if all fields are same */ + if (stream->props.type == props->type && + stream->props.count == props->count && + stream->props.endpoint == props->endpoint) { + if (props->type == USB_BULK && + props->u.bulk.buffersize == + stream->props.u.bulk.buffersize) + return 0; + else if (props->type == USB_ISOC && + props->u.isoc.framesperurb == + stream->props.u.isoc.framesperurb && + props->u.isoc.framesize == + stream->props.u.isoc.framesize && + props->u.isoc.interval == + stream->props.u.isoc.interval) + return 0; + } + + dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__); + + usb_urb_free_urbs(stream); + memcpy(&stream->props, props, sizeof(*props)); + if (props->type == USB_BULK) + return usb_urb_alloc_bulk_urbs(stream); + else if (props->type == USB_ISOC) + return usb_urb_alloc_isoc_urbs(stream); + + return 0; +} + +int usb_urb_initv2(struct usb_data_stream *stream, + const struct usb_data_stream_properties *props) +{ + int ret; + + if (!stream || !props) + return -EINVAL; + + memcpy(&stream->props, props, sizeof(*props)); + + if (!stream->complete) { + dev_err(&stream->udev->dev, "%s: there is no data callback - " \ + "this doesn't make sense\n", KBUILD_MODNAME); + return -EINVAL; + } + + switch (stream->props.type) { + case USB_BULK: + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.bulk.buffersize); + if (ret < 0) + return ret; + + return usb_urb_alloc_bulk_urbs(stream); + case USB_ISOC: + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb); + if (ret < 0) + return ret; + + return usb_urb_alloc_isoc_urbs(stream); + default: + dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \ + "transfer\n", KBUILD_MODNAME); + return -EINVAL; + } +} + +int usb_urb_exitv2(struct usb_data_stream *stream) +{ + usb_urb_free_urbs(stream); + usb_free_stream_buffers(stream); + + return 0; +} diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig new file mode 100644 index 00000000000..00173ee15d4 --- /dev/null +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -0,0 +1,313 @@ +config DVB_USB + tristate "Support for various USB DVB devices" + depends on DVB_CORE && USB && I2C && RC_CORE + help + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. + + Almost every USB device needs a firmware, please look into + . + + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a USB DVB device. + +config DVB_USB_DEBUG + bool "Enable extended debug support for all DVB-USB devices" + depends on DVB_USB + help + Say Y if you want to enable debugging. See modinfo dvb-usb (and the + appropriate drivers) for debug levels. + +config DVB_USB_A800 + tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" + depends on DVB_USB + select DVB_DIB3000MC + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. + +config DVB_USB_DIBUSB_MB + tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_DIB3000MB + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by + DiBcom () equipped with a DiB3000M-B demodulator. + + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_DIBUSB_MB_FAULTY + bool "Support faulty USB IDs" + depends on DVB_USB_DIBUSB_MB + help + Support for faulty USB IDs due to an invalid EEPROM on some Artec devices. + +config DVB_USB_DIBUSB_MC + tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" + depends on DVB_USB + select DVB_DIB3000MC + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Support for USB2.0 DVB-T receivers based on reference designs made by + DiBcom () equipped with a DiB3000M-C/P demodulator. + + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_DIB0700 + tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" + depends on DVB_USB + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_DIB7000M if !DVB_FE_CUSTOMISE + select DVB_DIB8000 if !DVB_FE_CUSTOMISE + select DVB_DIB3000MC if !DVB_FE_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + help + Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The + USB bridge is also present in devices having the DiB7700 DVB-T-USB + silicon. This chip can be found in devices offered by Hauppauge, + Avermedia and other big and small companies. + + For an up-to-date list of devices supported by this driver, have a look + on the LinuxTV Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_UMT_010 + tristate "HanfTek UMT-010 DVB-T USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_DIB3000MC + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + help + Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. + +config DVB_USB_CXUSB + tristate "Conexant USB2.0 hybrid reference design support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_CX22702 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select DVB_ATBM8830 if !DVB_FE_CUSTOMISE + select DVB_LGS8GXX if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Conexant USB2.0 hybrid reference design. + Currently, only DVB and ATSC modes are supported, analog mode + shall be added in the future. Devices that require this module: + + Medion MD95700 hybrid USB2.0 device. + DViCO FusionHDTV (Bluebird) USB2.0 devices + +config DVB_USB_M920X + tristate "Uli m920x DVB-T USB2.0 support" + depends on DVB_USB + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. + Currently, only devices with a product id of + "DTV USB MINI" (in cold state) are supported. + Firmware required. + +config DVB_USB_DIGITV + tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_NXT6000 if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + help + Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. + +config DVB_USB_VP7045 + tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" + depends on DVB_USB + help + Say Y here to support the + + TwinhanDTV Alpha (stick) (VP-7045), + TwinhanDTV MagicBox II (VP-7046), + DigitalNow TinyUSB 2 DVB-t, + DigitalRise USB 2.0 Ter (Beetle) and + TYPHOON DVB-T USB DRIVE + + DVB-T USB2.0 receivers. + +config DVB_USB_VP702X + tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" + depends on DVB_USB + help + Say Y here to support the + + TwinhanDTV StarBox, + DigitalRise USB Starbox and + TYPHOON DVB-S USB 2.0 BOX + + DVB-S USB2.0 receivers. + +config DVB_USB_GP8PSK + tristate "GENPIX 8PSK->USB module support" + depends on DVB_USB + help + Say Y here to support the + GENPIX 8psk module + + DVB-S USB2.0 receivers. + +config DVB_USB_NOVA_T_USB2 + tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" + depends on DVB_USB + select DVB_DIB3000MC + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. + +config DVB_USB_TTUSB2 + tristate "Pinnacle 400e DVB-S USB2.0 support" + depends on DVB_USB + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + help + Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The + firmware protocol used by this module is similar to the one used by the + old ttusb-driver - that's why the module is called dvb-usb-ttusb2. + +config DVB_USB_DTT200U + tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" + depends on DVB_USB + help + Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. + + The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). + + The WT-220U and its clones are pen-sized. + +config DVB_USB_OPERA1 + tristate "Opera1 DVB-S USB2.0 receiver" + depends on DVB_USB + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE + help + Say Y here to support the Opera DVB-S USB2.0 receiver. + +config DVB_USB_AF9005 + tristate "Afatech AF9005 DVB-T USB1.1 support" + depends on DVB_USB && EXPERIMENTAL + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver + and the TerraTec Cinergy T USB XE (Rev.1) + +config DVB_USB_AF9005_REMOTE + tristate "Afatech AF9005 default remote control support" + depends on DVB_USB_AF9005 + help + Say Y here to support the default remote control decoding for the + Afatech AF9005 based receiver. + +config DVB_USB_PCTV452E + tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600" + depends on DVB_USB + select TTPCI_EEPROM + select DVB_LNBP22 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + help + Support for external USB adapter designed by Pinnacle, + shipped under the brand name 'PCTV HDTV Pro USB'. + Also supports TT Connect S2-3600/3650 cards. + Say Y if you own such a device and want to use it. + +config DVB_USB_DW2102 + tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_MT312 if !DVB_FE_CUSTOMISE + select DVB_ZL10039 if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + help + Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 + receivers. + +config DVB_USB_CINERGY_T2 + tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" + depends on DVB_USB + help + Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers + + Say Y if you own such a device and want to use it. + +config DVB_USB_DTV5100 + tristate "AME DTV-5100 USB2.0 DVB-T support" + depends on DVB_USB + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the AME DTV-5100 USB2.0 DVB-T 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. + +config DVB_USB_AZ6027 + tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" + depends on DVB_USB + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + help + Say Y here to support the AZ6027 device + +config DVB_USB_TECHNISAT_USB2 + tristate "Technisat DVB-S/S2 USB2.0 support" + depends on DVB_USB + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + help + Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile new file mode 100644 index 00000000000..a5630e30ead --- /dev/null +++ b/drivers/media/usb/dvb-usb/Makefile @@ -0,0 +1,82 @@ +dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o +obj-$(CONFIG_DVB_USB) += dvb-usb.o + +dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o +obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o + +dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o +obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o + +dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o +obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o + +dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o +obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o + +dvb-usb-dibusb-common-objs = dibusb-common.o + +dvb-usb-a800-objs = a800.o +obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o + +dvb-usb-dibusb-mb-objs = dibusb-mb.o +obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o + +dvb-usb-dibusb-mc-objs = dibusb-mc.o +obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o + +dvb-usb-nova-t-usb2-objs = nova-t-usb2.o +obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o + +dvb-usb-umt-010-objs = umt-010.o +obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o + +dvb-usb-m920x-objs = m920x.o +obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o + +dvb-usb-digitv-objs = digitv.o +obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o + +dvb-usb-cxusb-objs = cxusb.o +obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o + +dvb-usb-ttusb2-objs = ttusb2.o +obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o + +dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o +obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o + +dvb-usb-opera-objs = opera1.o +obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o + +dvb-usb-af9005-objs = af9005.o af9005-fe.o +obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o + +dvb-usb-af9005-remote-objs = af9005-remote.o +obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o + +dvb-usb-pctv452e-objs = pctv452e.o +obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o + +dvb-usb-dw2102-objs = dw2102.o +obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o + +dvb-usb-dtv5100-objs = dtv5100.o +obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o + +dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o +obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o + +dvb-usb-friio-objs = friio.o friio-fe.o +obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o + +dvb-usb-az6027-objs = az6027.o +obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o + +dvb-usb-technisat-usb2-objs = technisat-usb2.o +obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o + +ccflags-y += -I$(srctree)/drivers/media/dvb-core +ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/ +# due to tuner-xc3028 +ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c new file mode 100644 index 00000000000..8d7fef84afd --- /dev/null +++ b/drivers/media/usb/dvb-usb/a800.c @@ -0,0 +1,191 @@ +/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T + * USB2.0 (A800) DVB-T receiver. + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to + * - AVerMedia who kindly provided information and + * - Glen Harris who suffered from my mistakes during development. + * + * 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 "dibusb.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_rc(args...) dprintk(debug,0x01,args) + +static int a800_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + /* do nothing for the AVerMedia */ + return 0; +} + +/* assure to put cold to 0 for iManufacturer == 1 */ +static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + *cold = udev->descriptor.iManufacturer != 1; + return 0; +} + +static struct rc_map_table rc_map_a800_table[] = { + { 0x0201, KEY_MODE }, /* SOURCE */ + { 0x0200, KEY_POWER2 }, /* POWER */ + { 0x0205, KEY_1 }, /* 1 */ + { 0x0206, KEY_2 }, /* 2 */ + { 0x0207, KEY_3 }, /* 3 */ + { 0x0209, KEY_4 }, /* 4 */ + { 0x020a, KEY_5 }, /* 5 */ + { 0x020b, KEY_6 }, /* 6 */ + { 0x020d, KEY_7 }, /* 7 */ + { 0x020e, KEY_8 }, /* 8 */ + { 0x020f, KEY_9 }, /* 9 */ + { 0x0212, KEY_LEFT }, /* L / DISPLAY */ + { 0x0211, KEY_0 }, /* 0 */ + { 0x0213, KEY_RIGHT }, /* R / CH RTN */ + { 0x0217, KEY_CAMERA }, /* SNAP SHOT */ + { 0x0210, KEY_LAST }, /* 16-CH PREV */ + { 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */ + { 0x020c, KEY_ZOOM }, /* FULL SCREEN */ + { 0x021f, KEY_VOLUMEUP }, /* VOL UP */ + { 0x0214, KEY_MUTE }, /* MUTE */ + { 0x0208, KEY_AUDIO }, /* AUDIO */ + { 0x0219, KEY_RECORD }, /* RECORD */ + { 0x0218, KEY_PLAY }, /* PLAY */ + { 0x021b, KEY_STOP }, /* STOP */ + { 0x021a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ + { 0x021d, KEY_BACK }, /* << / RED */ + { 0x021c, KEY_FORWARD }, /* >> / YELLOW */ + { 0x0203, KEY_TEXT }, /* TELETEXT */ + { 0x0204, KEY_EPG }, /* EPG */ + { 0x0215, KEY_MENU }, /* MENU */ + + { 0x0303, KEY_CHANNELUP }, /* CH UP */ + { 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */ + { 0x0301, KEY_FIRST }, /* |<< / GREEN */ + { 0x0300, KEY_LAST }, /* >>| / BLUE */ + +}; + +static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + int ret; + u8 *key = kmalloc(5, GFP_KERNEL); + if (!key) + return -ENOMEM; + + if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), + 0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5, + 2000) != 5) { + ret = -ENODEV; + goto out; + } + + /* call the universal NEC remote processor, to find out the key's state and event */ + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + ret = 0; +out: + kfree(key); + return ret; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties a800_properties; + +static int a800_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &a800_properties, + THIS_MODULE, NULL, adapter_nr); +} + +/* do not change the order of the ID table */ +static struct usb_device_id a800_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, a800_table); + +static struct dvb_usb_device_properties a800_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-avertv-a800-02.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + }, + }, + + .power_ctrl = a800_power_ctrl, + .identify_state = a800_identify_state, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_a800_table, + .rc_map_size = ARRAY_SIZE(rc_map_a800_table), + .rc_query = a800_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + .num_device_descs = 1, + .devices = { + { "AVerMedia AverTV DVB-T USB 2.0 (A800)", + { &a800_table[0], NULL }, + { &a800_table[1], NULL }, + }, + } +}; + +static struct usb_driver a800_driver = { + .name = "dvb_usb_a800", + .probe = a800_probe, + .disconnect = dvb_usb_device_exit, + .id_table = a800_table, +}; + +module_usb_driver(a800_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c new file mode 100644 index 00000000000..740f3f496f1 --- /dev/null +++ b/drivers/media/usb/dvb-usb/af9005-fe.c @@ -0,0 +1,1487 @@ +/* Frontend part of the Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "af9005.h" +#include "af9005-script.h" +#include "mt2060.h" +#include "qt1010.h" +#include + +struct af9005_fe_state { + struct dvb_usb_device *d; + fe_status_t stat; + + /* retraining parameters */ + u32 original_fcw; + u16 original_rf_top; + u16 original_if_top; + u16 original_if_min; + u16 original_aci0_if_top; + u16 original_aci1_if_top; + u16 original_aci0_if_min; + u8 original_if_unplug_th; + u8 original_rf_unplug_th; + u8 original_dtop_if_unplug_th; + u8 original_dtop_rf_unplug_th; + + /* statistics */ + u32 pre_vit_error_count; + u32 pre_vit_bit_count; + u32 ber; + u32 post_vit_error_count; + u32 post_vit_bit_count; + u32 unc; + u16 abort_count; + + int opened; + int strong; + unsigned long next_status_check; + struct dvb_frontend frontend; +}; + +static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, + u16 reglo, u8 pos, u8 len, u16 value) +{ + int ret; + + if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) + return ret; + return af9005_write_register_bits(d, reghi, pos, len, + (u8) ((value & 0x300) >> 8)); +} + +static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi, + u16 reglo, u8 pos, u8 len, u16 * value) +{ + int ret; + u8 temp0, temp1; + + if ((ret = af9005_read_ofdm_register(d, reglo, &temp0))) + return ret; + if ((ret = af9005_read_ofdm_register(d, reghi, &temp1))) + return ret; + switch (pos) { + case 0: + *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0; + break; + case 2: + *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0; + break; + case 4: + *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0; + break; + case 6: + *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0; + break; + default: + err("invalid pos in read word agc"); + return -EINVAL; + } + return 0; + +} + +static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp; + + *available = false; + + ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, + fec_vtb_rsd_mon_en_pos, + fec_vtb_rsd_mon_en_len, &temp); + if (ret) + return ret; + if (temp & 1) { + ret = + af9005_read_register_bits(state->d, + xd_p_reg_ofsm_read_rbc_en, + reg_ofsm_read_rbc_en_pos, + reg_ofsm_read_rbc_en_len, &temp); + if (ret) + return ret; + if ((temp & 1) == 0) + *available = true; + + } + return 0; +} + +static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe, + u32 * post_err_count, + u32 * post_cw_count, + u16 * abort_count) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u32 err_count; + u32 cw_count; + u8 temp, temp0, temp1, temp2; + u16 loc_abort_count; + + *post_err_count = 0; + *post_cw_count = 0; + + /* check if error bit count is ready */ + ret = + af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy, + fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len, + &temp); + if (ret) + return ret; + if (!temp) { + deb_info("rsd counter not ready\n"); + return 100; + } + /* get abort count */ + ret = + af9005_read_ofdm_register(state->d, + xd_r_fec_rsd_abort_packet_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, + xd_r_fec_rsd_abort_packet_cnt_15_8, + &temp1); + if (ret) + return ret; + loc_abort_count = ((u16) temp1 << 8) + temp0; + + /* get error count */ + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8, + &temp1); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16, + &temp2); + if (ret) + return ret; + err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; + *post_err_count = err_count - (u32) loc_abort_count *8 * 8; + + /* get RSD packet number */ + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, + &temp1); + if (ret) + return ret; + cw_count = ((u32) temp1 << 8) + temp0; + if (cw_count == 0) { + err("wrong RSD packet count"); + return -EIO; + } + deb_info("POST abort count %d err count %d rsd packets %d\n", + loc_abort_count, err_count, cw_count); + *post_cw_count = cw_count - (u32) loc_abort_count; + *abort_count = loc_abort_count; + return 0; + +} + +static int af9005_get_post_vit_ber(struct dvb_frontend *fe, + u32 * post_err_count, u32 * post_cw_count, + u16 * abort_count) +{ + u32 loc_cw_count = 0, loc_err_count; + u16 loc_abort_count = 0; + int ret; + + ret = + af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count, + &loc_abort_count); + if (ret) + return ret; + *post_err_count = loc_err_count; + *post_cw_count = loc_cw_count * 204 * 8; + *abort_count = loc_abort_count; + + return 0; +} + +static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, + u32 * pre_err_count, + u32 * pre_bit_count) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp, temp0, temp1, temp2; + u32 super_frame_count, x, bits; + int ret; + + ret = + af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy, + fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len, + &temp); + if (ret) + return ret; + if (!temp) { + deb_info("viterbi counter not ready\n"); + return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */ + } + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8, + &temp1); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16, + &temp2); + if (ret) + return ret; + *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; + + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, + &temp1); + if (ret) + return ret; + super_frame_count = ((u32) temp1 << 8) + temp0; + if (super_frame_count == 0) { + deb_info("super frame count 0\n"); + return 102; + } + + /* read fft mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, + reg_tpsd_txmod_pos, reg_tpsd_txmod_len, + &temp); + if (ret) + return ret; + if (temp == 0) { + /* 2K */ + x = 1512; + } else if (temp == 1) { + /* 8k */ + x = 6048; + } else { + err("Invalid fft mode"); + return -EINVAL; + } + + /* read modulation mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, + reg_tpsd_const_pos, reg_tpsd_const_len, + &temp); + if (ret) + return ret; + switch (temp) { + case 0: /* QPSK */ + bits = 2; + break; + case 1: /* QAM_16 */ + bits = 4; + break; + case 2: /* QAM_64 */ + bits = 6; + break; + default: + err("invalid modulation mode"); + return -EINVAL; + } + *pre_bit_count = super_frame_count * 68 * 4 * x * bits; + deb_info("PRE err count %d frame count %d bit count %d\n", + *pre_err_count, super_frame_count, *pre_bit_count); + return 0; +} + +static int af9005_reset_pre_viterbi(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + + /* set super frame count to 1 */ + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, + 1 & 0xff); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, + 1 >> 8); + if (ret) + return ret; + /* reset pre viterbi error count */ + ret = + af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst, + fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len, + 1); + + return ret; +} + +static int af9005_reset_post_viterbi(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + + /* set packet unit */ + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, + 10000 & 0xff); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, + 10000 >> 8); + if (ret) + return ret; + /* reset post viterbi error count */ + ret = + af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst, + fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len, + 1); + + return ret; +} + +static int af9005_get_statistic(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret, fecavailable; + u64 numerator, denominator; + + deb_info("GET STATISTIC\n"); + ret = af9005_is_fecmon_available(fe, &fecavailable); + if (ret) + return ret; + if (!fecavailable) { + deb_info("fecmon not available\n"); + return 0; + } + + ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count, + &state->pre_vit_bit_count); + if (ret == 0) { + af9005_reset_pre_viterbi(fe); + if (state->pre_vit_bit_count > 0) { + /* according to v 0.0.4 of the dvb api ber should be a multiple + of 10E-9 so we have to multiply the error count by + 10E9=1000000000 */ + numerator = + (u64) state->pre_vit_error_count * (u64) 1000000000; + denominator = (u64) state->pre_vit_bit_count; + state->ber = do_div(numerator, denominator); + } else { + state->ber = 0xffffffff; + } + } + + ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count, + &state->post_vit_bit_count, + &state->abort_count); + if (ret == 0) { + ret = af9005_reset_post_viterbi(fe); + state->unc += state->abort_count; + if (ret) + return ret; + } + return 0; +} + +static int af9005_fe_refresh_state(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (time_after(jiffies, state->next_status_check)) { + deb_info("REFRESH STATE\n"); + + /* statistics */ + if (af9005_get_statistic(fe)) + err("get_statistic_failed"); + state->next_status_check = jiffies + 250 * HZ / 1000; + } + return 0; +} + +static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp; + int ret; + + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + + *stat = 0; + ret = af9005_read_register_bits(state->d, xd_p_agc_lock, + agc_lock_pos, agc_lock_len, &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_SIGNAL; + + ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock, + fd_tpsd_lock_pos, fd_tpsd_lock_len, + &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_CARRIER; + + ret = af9005_read_register_bits(state->d, + xd_r_mp2if_sync_byte_locked, + mp2if_sync_byte_locked_pos, + mp2if_sync_byte_locked_pos, &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; + if (state->opened) + af9005_led_control(state->d, *stat & FE_HAS_LOCK); + + ret = + af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected, + reg_strong_sginal_detected_pos, + reg_strong_sginal_detected_len, &temp); + if (ret) + return ret; + if (temp != state->strong) { + deb_info("adjust for strong signal %d\n", temp); + state->strong = temp; + } + return 0; +} + +static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + af9005_fe_refresh_state(fe); + *ber = state->ber; + return 0; +} + +static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + af9005_fe_refresh_state(fe); + *unc = state->unc; + return 0; +} + +static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, + u16 * strength) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 if_gain, rf_gain; + + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + ret = + af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain, + &rf_gain); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain, + &if_gain); + if (ret) + return ret; + /* this value has no real meaning, but i don't have the tables that relate + the rf and if gain with the dbm, so I just scale the value */ + *strength = (512 - rf_gain - if_gain) << 7; + return 0; +} + +static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + /* the snr can be derived from the ber and the modulation + but I don't think this kind of complex calculations belong + in the driver. I may be wrong.... */ + return -ENOSYS; +} + +static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw) +{ + u8 temp0, temp1, temp2, temp3, buf[4]; + int ret; + u32 NS_coeff1_2048Nu; + u32 NS_coeff1_8191Nu; + u32 NS_coeff1_8192Nu; + u32 NS_coeff1_8193Nu; + u32 NS_coeff2_2k; + u32 NS_coeff2_8k; + + switch (bw) { + case 6000000: + NS_coeff1_2048Nu = 0x2ADB6DC; + NS_coeff1_8191Nu = 0xAB7313; + NS_coeff1_8192Nu = 0xAB6DB7; + NS_coeff1_8193Nu = 0xAB685C; + NS_coeff2_2k = 0x156DB6E; + NS_coeff2_8k = 0x55B6DC; + break; + + case 7000000: + NS_coeff1_2048Nu = 0x3200001; + NS_coeff1_8191Nu = 0xC80640; + NS_coeff1_8192Nu = 0xC80000; + NS_coeff1_8193Nu = 0xC7F9C0; + NS_coeff2_2k = 0x1900000; + NS_coeff2_8k = 0x640000; + break; + + case 8000000: + NS_coeff1_2048Nu = 0x3924926; + NS_coeff1_8191Nu = 0xE4996E; + NS_coeff1_8192Nu = 0xE49249; + NS_coeff1_8193Nu = 0xE48B25; + NS_coeff2_2k = 0x1C92493; + NS_coeff2_8k = 0x724925; + break; + default: + err("Invalid bandwidth %d.", bw); + return -EINVAL; + } + + /* + * write NS_coeff1_2048Nu + */ + + temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF); + temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16); + temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + /* cfoe_NS_2k_coeff1_25_24 */ + ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_23_16 */ + ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_15_8 */ + ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_7_0 */ + ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff2_2k + */ + + temp0 = (u8) ((NS_coeff2_2k & 0x0000003F)); + temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6); + temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14); + temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8191Nu + */ + + temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF)); + temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8192Nu + */ + + temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF); + temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8193Nu + */ + + temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF)); + temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff2_8k + */ + + temp0 = (u8) ((NS_coeff2_8k & 0x0000003F)); + temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6); + temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14); + temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]); + return ret; + +} + +static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw) +{ + u8 temp; + switch (bw) { + case 6000000: + temp = 0; + break; + case 7000000: + temp = 1; + break; + case 8000000: + temp = 2; + break; + default: + err("Invalid bandwidth %d.", bw); + return -EINVAL; + } + return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos, + reg_bw_len, temp); +} + +static int af9005_fe_power(struct dvb_frontend *fe, int on) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp = on; + int ret; + deb_info("power %s tuner\n", on ? "on" : "off"); + ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); + return ret; +} + +static struct mt2060_config af9005_mt2060_config = { + 0xC0 +}; + +static struct qt1010_config af9005_qt1010_config = { + 0xC4 +}; + +static int af9005_fe_init(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; + int ret, i, scriptlen; + u8 temp, temp0 = 0, temp1 = 0, temp2 = 0; + u8 buf[2]; + u16 if1; + + deb_info("in af9005_fe_init\n"); + + /* reset */ + deb_info("reset\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en, + 4, 1, 0x01))) + return ret; + if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0))) + return ret; + /* clear ofdm reset */ + deb_info("clear ofdm reset\n"); + for (i = 0; i < 150; i++) { + if ((ret = + af9005_read_ofdm_register(state->d, + xd_I2C_reg_ofdm_rst, &temp))) + return ret; + if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos)) + break; + msleep(10); + } + if (i == 150) + return -ETIMEDOUT; + + /*FIXME in the dump + write B200 A9 + write xd_g_reg_ofsm_clk 7 + read eepr c6 (2) + read eepr c7 (2) + misc ctrl 3 -> 1 + read eepr ca (6) + write xd_g_reg_ofsm_clk 0 + write B200 a1 + */ + ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07); + if (ret) + return ret; + temp = 0x01; + ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1); + if (ret) + return ret; + + temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos; + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, + reg_ofdm_rst_pos, reg_ofdm_rst_len, 1))) + return ret; + ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, + reg_ofdm_rst_pos, reg_ofdm_rst_len, 0); + + if (ret) + return ret; + /* don't know what register aefc is, but this is what the windows driver does */ + ret = af9005_write_ofdm_register(state->d, 0xaefc, 0); + if (ret) + return ret; + + /* set stand alone chip */ + deb_info("set stand alone chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone, + reg_dca_stand_alone_pos, + reg_dca_stand_alone_len, 1))) + return ret; + + /* set dca upper & lower chip */ + deb_info("set dca upper & lower chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip, + reg_dca_upper_chip_pos, + reg_dca_upper_chip_len, 0))) + return ret; + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip, + reg_dca_lower_chip_pos, + reg_dca_lower_chip_len, 0))) + return ret; + + /* set 2wire master clock to 0x14 (for 60KHz) */ + deb_info("set 2wire master clock to 0x14 (for 60KHz)\n"); + if ((ret = + af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14))) + return ret; + + /* clear dca enable chip */ + deb_info("clear dca enable chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_en, + reg_dca_en_pos, reg_dca_en_len, 0))) + return ret; + /* FIXME these are register bits, but I don't know which ones */ + ret = af9005_write_ofdm_register(state->d, 0xa16c, 1); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0); + if (ret) + return ret; + + /* init other parameters: program cfoe and select bandwidth */ + deb_info("program cfoe\n"); + ret = af9005_fe_program_cfoe(state->d, 6000000); + if (ret) + return ret; + /* set read-update bit for modulation */ + deb_info("set read-update bit for modulation\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, + reg_feq_read_update_pos, + reg_feq_read_update_len, 1))) + return ret; + + /* sample code has a set MPEG TS code here + but sniffing reveals that it doesn't do it */ + + /* set read-update bit to 1 for DCA modulation */ + deb_info("set read-update bit 1 for DCA modulation\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, + reg_dca_read_update_pos, + reg_dca_read_update_len, 1))) + return ret; + + /* enable fec monitor */ + deb_info("enable fec monitor\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, + fec_vtb_rsd_mon_en_pos, + fec_vtb_rsd_mon_en_len, 1))) + return ret; + + /* FIXME should be register bits, I don't know which ones */ + ret = af9005_write_ofdm_register(state->d, 0xa601, 0); + + /* set api_retrain_never_freeze */ + deb_info("set api_retrain_never_freeze\n"); + if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01))) + return ret; + + /* load init script */ + deb_info("load init script\n"); + scriptlen = sizeof(script) / sizeof(RegDesc); + for (i = 0; i < scriptlen; i++) { + if ((ret = + af9005_write_register_bits(state->d, script[i].reg, + script[i].pos, + script[i].len, script[i].val))) + return ret; + /* save 3 bytes of original fcw */ + if (script[i].reg == 0xae18) + temp2 = script[i].val; + if (script[i].reg == 0xae19) + temp1 = script[i].val; + if (script[i].reg == 0xae1a) + temp0 = script[i].val; + + /* save original unplug threshold */ + if (script[i].reg == xd_p_reg_unplug_th) + state->original_if_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_rf_gain_th) + state->original_rf_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th) + state->original_dtop_if_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th) + state->original_dtop_rf_unplug_th = script[i].val; + + } + state->original_fcw = + ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0; + + + /* save original TOPs */ + deb_info("save original TOPs\n"); + + /* RF TOP */ + ret = + af9005_read_word_agc(state->d, + xd_p_reg_aagc_rf_top_numerator_9_8, + xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, + &state->original_rf_top); + if (ret) + return ret; + + /* IF TOP */ + ret = + af9005_read_word_agc(state->d, + xd_p_reg_aagc_if_top_numerator_9_8, + xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, + &state->original_if_top); + if (ret) + return ret; + + /* ACI 0 IF TOP */ + ret = + af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, + &state->original_aci0_if_top); + if (ret) + return ret; + + /* ACI 1 IF TOP */ + ret = + af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, + &state->original_aci1_if_top); + if (ret) + return ret; + + /* attach tuner and init */ + if (fe->ops.tuner_ops.release == NULL) { + /* read tuner and board id from eeprom */ + ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2); + if (ret) { + err("Impossible to read EEPROM\n"); + return ret; + } + deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]); + switch (buf[0]) { + case 2: /* MT2060 */ + /* read if1 from eeprom */ + ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2); + if (ret) { + err("Impossible to read EEPROM\n"); + return ret; + } + if1 = (u16) (buf[0] << 8) + buf[1]; + if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap, + &af9005_mt2060_config, if1) == NULL) { + deb_info("MT2060 attach failed\n"); + return -ENODEV; + } + break; + case 3: /* QT1010 */ + case 9: /* QT1010B */ + if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap, + &af9005_qt1010_config) ==NULL) { + deb_info("QT1010 attach failed\n"); + return -ENODEV; + } + break; + default: + err("Unsupported tuner type %d", buf[0]); + return -ENODEV; + } + ret = fe->ops.tuner_ops.init(fe); + if (ret) + return ret; + } + + deb_info("profit!\n"); + return 0; +} + +static int af9005_fe_sleep(struct dvb_frontend *fe) +{ + return af9005_fe_power(fe, 0); +} + +static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + + if (acquire) { + state->opened++; + } else { + + state->opened--; + if (!state->opened) + af9005_led_control(state->d, 0); + } + return 0; +} + +static int af9005_fe_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp, temp0, temp1, temp2; + + deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, + fep->bandwidth_hz); + if (fe->ops.tuner_ops.release == NULL) { + err("Tuner not attached"); + return -ENODEV; + } + + deb_info("turn off led\n"); + /* not in the log */ + ret = af9005_led_control(state->d, 0); + if (ret) + return ret; + /* not sure about the bits */ + ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0); + if (ret) + return ret; + + /* set FCW to default value */ + deb_info("set FCW to default value\n"); + temp0 = (u8) (state->original_fcw & 0x000000ff); + temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8); + temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16); + ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xae19, temp1); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xae18, temp2); + if (ret) + return ret; + + /* restore original TOPs */ + deb_info("restore original TOPs\n"); + ret = + af9005_write_word_agc(state->d, + xd_p_reg_aagc_rf_top_numerator_9_8, + xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, + state->original_rf_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, + xd_p_reg_aagc_if_top_numerator_9_8, + xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, + state->original_if_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, + state->original_aci0_if_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, + state->original_aci1_if_top); + if (ret) + return ret; + + /* select bandwidth */ + deb_info("select bandwidth"); + ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz); + if (ret) + return ret; + ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz); + if (ret) + return ret; + + /* clear easy mode flag */ + deb_info("clear easy mode flag\n"); + ret = af9005_write_ofdm_register(state->d, 0xaefd, 0); + if (ret) + return ret; + + /* set unplug threshold to original value */ + deb_info("set unplug threshold to original value\n"); + ret = + af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th, + state->original_if_unplug_th); + if (ret) + return ret; + /* set tuner */ + deb_info("set tuner\n"); + ret = fe->ops.tuner_ops.set_params(fe); + if (ret) + return ret; + + /* trigger ofsm */ + deb_info("trigger ofsm\n"); + temp = 0; + ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1); + if (ret) + return ret; + + /* clear retrain and freeze flag */ + deb_info("clear retrain and freeze flag\n"); + ret = + af9005_write_register_bits(state->d, + xd_p_reg_api_retrain_request, + reg_api_retrain_request_pos, 2, 0); + if (ret) + return ret; + + /* reset pre viterbi and post viterbi registers and statistics */ + af9005_reset_pre_viterbi(fe); + af9005_reset_post_viterbi(fe); + state->pre_vit_error_count = 0; + state->pre_vit_bit_count = 0; + state->ber = 0; + state->post_vit_error_count = 0; + /* state->unc = 0; commented out since it should be ever increasing */ + state->abort_count = 0; + + state->next_status_check = jiffies; + state->strong = -1; + + return 0; +} + +static int af9005_fe_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp; + + /* mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, + reg_tpsd_const_pos, reg_tpsd_const_len, + &temp); + if (ret) + return ret; + deb_info("===== fe_get_frontend_legacy = =============\n"); + deb_info("CONSTELLATION "); + switch (temp) { + case 0: + fep->modulation = QPSK; + deb_info("QPSK\n"); + break; + case 1: + fep->modulation = QAM_16; + deb_info("QAM_16\n"); + break; + case 2: + fep->modulation = QAM_64; + deb_info("QAM_64\n"); + break; + } + + /* tps hierarchy and alpha value */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier, + reg_tpsd_hier_pos, reg_tpsd_hier_len, + &temp); + if (ret) + return ret; + deb_info("HIERARCHY "); + switch (temp) { + case 0: + fep->hierarchy = HIERARCHY_NONE; + deb_info("NONE\n"); + break; + case 1: + fep->hierarchy = HIERARCHY_1; + deb_info("1\n"); + break; + case 2: + fep->hierarchy = HIERARCHY_2; + deb_info("2\n"); + break; + case 3: + fep->hierarchy = HIERARCHY_4; + deb_info("4\n"); + break; + } + + /* high/low priority */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_dec_pri, + reg_dec_pri_pos, reg_dec_pri_len, &temp); + if (ret) + return ret; + /* if temp is set = high priority */ + deb_info("PRIORITY %s\n", temp ? "high" : "low"); + + /* high coderate */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr, + reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len, + &temp); + if (ret) + return ret; + deb_info("CODERATE HP "); + switch (temp) { + case 0: + fep->code_rate_HP = FEC_1_2; + deb_info("FEC_1_2\n"); + break; + case 1: + fep->code_rate_HP = FEC_2_3; + deb_info("FEC_2_3\n"); + break; + case 2: + fep->code_rate_HP = FEC_3_4; + deb_info("FEC_3_4\n"); + break; + case 3: + fep->code_rate_HP = FEC_5_6; + deb_info("FEC_5_6\n"); + break; + case 4: + fep->code_rate_HP = FEC_7_8; + deb_info("FEC_7_8\n"); + break; + } + + /* low coderate */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr, + reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len, + &temp); + if (ret) + return ret; + deb_info("CODERATE LP "); + switch (temp) { + case 0: + fep->code_rate_LP = FEC_1_2; + deb_info("FEC_1_2\n"); + break; + case 1: + fep->code_rate_LP = FEC_2_3; + deb_info("FEC_2_3\n"); + break; + case 2: + fep->code_rate_LP = FEC_3_4; + deb_info("FEC_3_4\n"); + break; + case 3: + fep->code_rate_LP = FEC_5_6; + deb_info("FEC_5_6\n"); + break; + case 4: + fep->code_rate_LP = FEC_7_8; + deb_info("FEC_7_8\n"); + break; + } + + /* guard interval */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi, + reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp); + if (ret) + return ret; + deb_info("GUARD INTERVAL "); + switch (temp) { + case 0: + fep->guard_interval = GUARD_INTERVAL_1_32; + deb_info("1_32\n"); + break; + case 1: + fep->guard_interval = GUARD_INTERVAL_1_16; + deb_info("1_16\n"); + break; + case 2: + fep->guard_interval = GUARD_INTERVAL_1_8; + deb_info("1_8\n"); + break; + case 3: + fep->guard_interval = GUARD_INTERVAL_1_4; + deb_info("1_4\n"); + break; + } + + /* fft */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, + reg_tpsd_txmod_pos, reg_tpsd_txmod_len, + &temp); + if (ret) + return ret; + deb_info("TRANSMISSION MODE "); + switch (temp) { + case 0: + fep->transmission_mode = TRANSMISSION_MODE_2K; + deb_info("2K\n"); + break; + case 1: + fep->transmission_mode = TRANSMISSION_MODE_8K; + deb_info("8K\n"); + break; + } + + /* bandwidth */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos, + reg_bw_len, &temp); + deb_info("BANDWIDTH "); + switch (temp) { + case 0: + fep->bandwidth_hz = 6000000; + deb_info("6\n"); + break; + case 1: + fep->bandwidth_hz = 7000000; + deb_info("7\n"); + break; + case 2: + fep->bandwidth_hz = 8000000; + deb_info("8\n"); + break; + } + return 0; +} + +static void af9005_fe_release(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = + (struct af9005_fe_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops af9005_fe_ops; + +struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) +{ + struct af9005_fe_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL); + if (state == NULL) + goto error; + + deb_info("attaching frontend af9005\n"); + + state->d = d; + state->opened = 0; + + memcpy(&state->frontend.ops, &af9005_fe_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; + error: + return NULL; +} + +static struct dvb_frontend_ops af9005_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "AF9005 USB DVB-T", + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = af9005_fe_release, + + .init = af9005_fe_init, + .sleep = af9005_fe_sleep, + .ts_bus_ctrl = af9005_ts_bus_ctrl, + + .set_frontend = af9005_fe_set_frontend, + .get_frontend = af9005_fe_get_frontend, + + .read_status = af9005_fe_read_status, + .read_ber = af9005_fe_read_ber, + .read_signal_strength = af9005_fe_read_signal_strength, + .read_snr = af9005_fe_read_snr, + .read_ucblocks = af9005_fe_read_unc_blocks, +}; diff --git a/drivers/media/usb/dvb-usb/af9005-remote.c b/drivers/media/usb/dvb-usb/af9005-remote.c new file mode 100644 index 00000000000..7e3961d0db6 --- /dev/null +++ b/drivers/media/usb/dvb-usb/af9005-remote.c @@ -0,0 +1,157 @@ +/* DVB USB compliant Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Standard remote decode function + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "af9005.h" +/* debug */ +static int dvb_usb_af9005_remote_debug; +module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); +MODULE_PARM_DESC(debug, + "enable (1) or disable (0) debug messages." + DVB_USB_DEBUG_STATUS); + +#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args) + +struct rc_map_table rc_map_af9005_table[] = { + + {0x01b7, KEY_POWER}, + {0x01a7, KEY_VOLUMEUP}, + {0x0187, KEY_CHANNELUP}, + {0x017f, KEY_MUTE}, + {0x01bf, KEY_VOLUMEDOWN}, + {0x013f, KEY_CHANNELDOWN}, + {0x01df, KEY_1}, + {0x015f, KEY_2}, + {0x019f, KEY_3}, + {0x011f, KEY_4}, + {0x01ef, KEY_5}, + {0x016f, KEY_6}, + {0x01af, KEY_7}, + {0x0127, KEY_8}, + {0x0107, KEY_9}, + {0x01cf, KEY_ZOOM}, + {0x014f, KEY_0}, + {0x018f, KEY_GOTO}, /* marked jump on the remote */ + + {0x00bd, KEY_POWER}, + {0x007d, KEY_VOLUMEUP}, + {0x00fd, KEY_CHANNELUP}, + {0x009d, KEY_MUTE}, + {0x005d, KEY_VOLUMEDOWN}, + {0x00dd, KEY_CHANNELDOWN}, + {0x00ad, KEY_1}, + {0x006d, KEY_2}, + {0x00ed, KEY_3}, + {0x008d, KEY_4}, + {0x004d, KEY_5}, + {0x00cd, KEY_6}, + {0x00b5, KEY_7}, + {0x0075, KEY_8}, + {0x00f5, KEY_9}, + {0x0095, KEY_ZOOM}, + {0x0055, KEY_0}, + {0x00d5, KEY_GOTO}, /* marked jump on the remote */ +}; + +int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table); + +static int repeatable_keys[] = { + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + KEY_CHANNELUP, + KEY_CHANNELDOWN +}; + +int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event, + int *state) +{ + u16 mark, space; + u32 result; + u8 cust, dat, invdat; + int i; + + if (len >= 6) { + mark = (u16) (data[0] << 8) + data[1]; + space = (u16) (data[2] << 8) + data[3]; + if (space * 3 < mark) { + for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { + if (d->last_event == repeatable_keys[i]) { + *state = REMOTE_KEY_REPEAT; + *event = d->last_event; + deb_decode("repeat key, event %x\n", + *event); + return 0; + } + } + deb_decode("repeated key ignored (non repeatable)\n"); + return 0; + } else if (len >= 33 * 4) { /*32 bits + start code */ + result = 0; + for (i = 4; i < 4 + 32 * 4; i += 4) { + result <<= 1; + mark = (u16) (data[i] << 8) + data[i + 1]; + mark >>= 1; + space = (u16) (data[i + 2] << 8) + data[i + 3]; + space >>= 1; + if (mark * 2 > space) + result += 1; + } + deb_decode("key pressed, raw value %x\n", result); + if ((result & 0xff000000) != 0xfe000000) { + deb_decode + ("doesn't start with 0xfe, ignored\n"); + return 0; + } + cust = (result >> 16) & 0xff; + dat = (result >> 8) & 0xff; + invdat = (~result) & 0xff; + if (dat != invdat) { + deb_decode("code != inverted code\n"); + return 0; + } + for (i = 0; i < rc_map_af9005_table_size; i++) { + if (rc5_custom(&rc_map_af9005_table[i]) == cust + && rc5_data(&rc_map_af9005_table[i]) == dat) { + *event = rc_map_af9005_table[i].keycode; + *state = REMOTE_KEY_PRESSED; + deb_decode + ("key pressed, event %x\n", *event); + return 0; + } + } + deb_decode("not found in table\n"); + } + } + return 0; +} + +EXPORT_SYMBOL(rc_map_af9005_table); +EXPORT_SYMBOL(rc_map_af9005_table_size); +EXPORT_SYMBOL(af9005_rc_decode); + +MODULE_AUTHOR("Luca Olivetti "); +MODULE_DESCRIPTION + ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/af9005-script.h b/drivers/media/usb/dvb-usb/af9005-script.h new file mode 100644 index 00000000000..4d69045426d --- /dev/null +++ b/drivers/media/usb/dvb-usb/af9005-script.h @@ -0,0 +1,203 @@ +/* +File automatically generated by createinit.py using data +extracted from AF05BDA.sys (windows driver): + +dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110 +python createinit.py > af9005-script.h + +*/ + +typedef struct { + u16 reg; + u8 pos; + u8 len; + u8 val; +} RegDesc; + +static RegDesc script[] = { + {0xa180, 0x0, 0x8, 0xa}, + {0xa181, 0x0, 0x8, 0xd7}, + {0xa182, 0x0, 0x8, 0xa3}, + {0xa0a0, 0x0, 0x8, 0x0}, + {0xa0a1, 0x0, 0x5, 0x0}, + {0xa0a1, 0x5, 0x1, 0x1}, + {0xa0c0, 0x0, 0x4, 0x1}, + {0xa20e, 0x4, 0x4, 0xa}, + {0xa20f, 0x0, 0x8, 0x40}, + {0xa210, 0x0, 0x8, 0x8}, + {0xa32a, 0x0, 0x4, 0xa}, + {0xa32c, 0x0, 0x8, 0x20}, + {0xa32b, 0x0, 0x8, 0x15}, + {0xa1a0, 0x1, 0x1, 0x1}, + {0xa000, 0x0, 0x1, 0x1}, + {0xa000, 0x1, 0x1, 0x0}, + {0xa001, 0x1, 0x1, 0x1}, + {0xa001, 0x0, 0x1, 0x0}, + {0xa001, 0x5, 0x1, 0x0}, + {0xa00e, 0x0, 0x5, 0x10}, + {0xa00f, 0x0, 0x3, 0x4}, + {0xa00f, 0x3, 0x3, 0x5}, + {0xa010, 0x0, 0x3, 0x4}, + {0xa010, 0x3, 0x3, 0x5}, + {0xa016, 0x4, 0x4, 0x3}, + {0xa01f, 0x0, 0x6, 0xa}, + {0xa020, 0x0, 0x6, 0xa}, + {0xa2bc, 0x0, 0x1, 0x1}, + {0xa2bc, 0x5, 0x1, 0x1}, + {0xa015, 0x0, 0x8, 0x50}, + {0xa016, 0x0, 0x1, 0x0}, + {0xa02a, 0x0, 0x8, 0x50}, + {0xa029, 0x0, 0x8, 0x4b}, + {0xa614, 0x0, 0x8, 0x46}, + {0xa002, 0x0, 0x5, 0x19}, + {0xa003, 0x0, 0x5, 0x1a}, + {0xa004, 0x0, 0x5, 0x19}, + {0xa005, 0x0, 0x5, 0x1a}, + {0xa008, 0x0, 0x8, 0x69}, + {0xa009, 0x0, 0x2, 0x2}, + {0xae1b, 0x0, 0x8, 0x69}, + {0xae1c, 0x0, 0x8, 0x2}, + {0xae1d, 0x0, 0x8, 0x2a}, + {0xa022, 0x0, 0x8, 0xaa}, + {0xa006, 0x0, 0x8, 0xc8}, + {0xa007, 0x0, 0x2, 0x0}, + {0xa00c, 0x0, 0x8, 0xba}, + {0xa00d, 0x0, 0x2, 0x2}, + {0xa608, 0x0, 0x8, 0xba}, + {0xa60e, 0x0, 0x2, 0x2}, + {0xa609, 0x0, 0x8, 0x80}, + {0xa60e, 0x2, 0x2, 0x3}, + {0xa00a, 0x0, 0x8, 0xb6}, + {0xa00b, 0x0, 0x2, 0x0}, + {0xa011, 0x0, 0x8, 0xb9}, + {0xa012, 0x0, 0x2, 0x0}, + {0xa013, 0x0, 0x8, 0xbd}, + {0xa014, 0x0, 0x2, 0x2}, + {0xa366, 0x0, 0x1, 0x1}, + {0xa2bc, 0x3, 0x1, 0x0}, + {0xa2bd, 0x0, 0x8, 0xa}, + {0xa2be, 0x0, 0x8, 0x14}, + {0xa2bf, 0x0, 0x8, 0x8}, + {0xa60a, 0x0, 0x8, 0xbd}, + {0xa60e, 0x4, 0x2, 0x2}, + {0xa60b, 0x0, 0x8, 0x86}, + {0xa60e, 0x6, 0x2, 0x3}, + {0xa001, 0x2, 0x2, 0x1}, + {0xa1c7, 0x0, 0x8, 0xf5}, + {0xa03d, 0x0, 0x8, 0xb1}, + {0xa616, 0x0, 0x8, 0xff}, + {0xa617, 0x0, 0x8, 0xad}, + {0xa618, 0x0, 0x8, 0xad}, + {0xa61e, 0x3, 0x1, 0x1}, + {0xae1a, 0x0, 0x8, 0x0}, + {0xae19, 0x0, 0x8, 0xc8}, + {0xae18, 0x0, 0x8, 0x61}, + {0xa140, 0x0, 0x8, 0x0}, + {0xa141, 0x0, 0x8, 0xc8}, + {0xa142, 0x0, 0x7, 0x61}, + {0xa023, 0x0, 0x8, 0xff}, + {0xa021, 0x0, 0x8, 0xad}, + {0xa026, 0x0, 0x1, 0x0}, + {0xa024, 0x0, 0x8, 0xff}, + {0xa025, 0x0, 0x8, 0xff}, + {0xa1c8, 0x0, 0x8, 0xf}, + {0xa2bc, 0x1, 0x1, 0x0}, + {0xa60c, 0x0, 0x4, 0x5}, + {0xa60c, 0x4, 0x4, 0x6}, + {0xa60d, 0x0, 0x8, 0xa}, + {0xa371, 0x0, 0x1, 0x1}, + {0xa366, 0x1, 0x3, 0x7}, + {0xa338, 0x0, 0x8, 0x10}, + {0xa339, 0x0, 0x6, 0x7}, + {0xa33a, 0x0, 0x6, 0x1f}, + {0xa33b, 0x0, 0x8, 0xf6}, + {0xa33c, 0x3, 0x5, 0x4}, + {0xa33d, 0x4, 0x4, 0x0}, + {0xa33d, 0x1, 0x1, 0x1}, + {0xa33d, 0x2, 0x1, 0x1}, + {0xa33d, 0x3, 0x1, 0x1}, + {0xa16d, 0x0, 0x4, 0xf}, + {0xa161, 0x0, 0x5, 0x5}, + {0xa162, 0x0, 0x4, 0x5}, + {0xa165, 0x0, 0x8, 0xff}, + {0xa166, 0x0, 0x8, 0x9c}, + {0xa2c3, 0x0, 0x4, 0x5}, + {0xa61a, 0x0, 0x6, 0xf}, + {0xb200, 0x0, 0x8, 0xa1}, + {0xb201, 0x0, 0x8, 0x7}, + {0xa093, 0x0, 0x1, 0x0}, + {0xa093, 0x1, 0x5, 0xf}, + {0xa094, 0x0, 0x8, 0xff}, + {0xa095, 0x0, 0x8, 0xf}, + {0xa080, 0x2, 0x5, 0x3}, + {0xa081, 0x0, 0x4, 0x0}, + {0xa081, 0x4, 0x4, 0x9}, + {0xa082, 0x0, 0x5, 0x1f}, + {0xa08d, 0x0, 0x8, 0x1}, + {0xa083, 0x0, 0x8, 0x32}, + {0xa084, 0x0, 0x1, 0x0}, + {0xa08e, 0x0, 0x8, 0x3}, + {0xa085, 0x0, 0x8, 0x32}, + {0xa086, 0x0, 0x3, 0x0}, + {0xa087, 0x0, 0x8, 0x6e}, + {0xa088, 0x0, 0x5, 0x15}, + {0xa089, 0x0, 0x8, 0x0}, + {0xa08a, 0x0, 0x5, 0x19}, + {0xa08b, 0x0, 0x8, 0x92}, + {0xa08c, 0x0, 0x5, 0x1c}, + {0xa120, 0x0, 0x8, 0x0}, + {0xa121, 0x0, 0x5, 0x10}, + {0xa122, 0x0, 0x8, 0x0}, + {0xa123, 0x0, 0x7, 0x40}, + {0xa123, 0x7, 0x1, 0x0}, + {0xa124, 0x0, 0x8, 0x13}, + {0xa125, 0x0, 0x7, 0x10}, + {0xa1c0, 0x0, 0x8, 0x0}, + {0xa1c1, 0x0, 0x5, 0x4}, + {0xa1c2, 0x0, 0x8, 0x0}, + {0xa1c3, 0x0, 0x5, 0x10}, + {0xa1c3, 0x5, 0x3, 0x0}, + {0xa1c4, 0x0, 0x6, 0x0}, + {0xa1c5, 0x0, 0x7, 0x10}, + {0xa100, 0x0, 0x8, 0x0}, + {0xa101, 0x0, 0x5, 0x10}, + {0xa102, 0x0, 0x8, 0x0}, + {0xa103, 0x0, 0x7, 0x40}, + {0xa103, 0x7, 0x1, 0x0}, + {0xa104, 0x0, 0x8, 0x18}, + {0xa105, 0x0, 0x7, 0xa}, + {0xa106, 0x0, 0x8, 0x20}, + {0xa107, 0x0, 0x8, 0x40}, + {0xa108, 0x0, 0x4, 0x0}, + {0xa38c, 0x0, 0x8, 0xfc}, + {0xa38d, 0x0, 0x8, 0x0}, + {0xa38e, 0x0, 0x8, 0x7e}, + {0xa38f, 0x0, 0x8, 0x0}, + {0xa390, 0x0, 0x8, 0x2f}, + {0xa60f, 0x5, 0x1, 0x1}, + {0xa170, 0x0, 0x8, 0xdc}, + {0xa171, 0x0, 0x2, 0x0}, + {0xa2ae, 0x0, 0x1, 0x1}, + {0xa2ae, 0x1, 0x1, 0x1}, + {0xa392, 0x0, 0x1, 0x1}, + {0xa391, 0x2, 0x1, 0x0}, + {0xabc1, 0x0, 0x8, 0xff}, + {0xabc2, 0x0, 0x8, 0x0}, + {0xabc8, 0x0, 0x8, 0x8}, + {0xabca, 0x0, 0x8, 0x10}, + {0xabcb, 0x0, 0x1, 0x0}, + {0xabc3, 0x5, 0x3, 0x7}, + {0xabc0, 0x6, 0x1, 0x0}, + {0xabc0, 0x4, 0x2, 0x0}, + {0xa344, 0x4, 0x4, 0x1}, + {0xabc0, 0x7, 0x1, 0x1}, + {0xabc0, 0x2, 0x1, 0x1}, + {0xa345, 0x0, 0x8, 0x66}, + {0xa346, 0x0, 0x8, 0x66}, + {0xa347, 0x0, 0x4, 0x0}, + {0xa343, 0x0, 0x4, 0xa}, + {0xa347, 0x4, 0x4, 0x2}, + {0xa348, 0x0, 0x4, 0xc}, + {0xa348, 0x4, 0x4, 0x7}, + {0xa349, 0x0, 0x6, 0x2}, +}; diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c new file mode 100644 index 00000000000..af176b6ce73 --- /dev/null +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -0,0 +1,1117 @@ +/* DVB USB compliant Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "af9005.h" + +/* debug */ +int dvb_usb_af9005_debug; +module_param_named(debug, dvb_usb_af9005_debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." + DVB_USB_DEBUG_STATUS); +/* enable obnoxious led */ +bool dvb_usb_af9005_led = 1; +module_param_named(led, dvb_usb_af9005_led, bool, 0644); +MODULE_PARM_DESC(led, "enable led (default: 1)."); + +/* eeprom dump */ +static int dvb_usb_af9005_dump_eeprom; +module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); +MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* remote control decoder */ +static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, + u32 *event, int *state); +static void *rc_keys; +static int *rc_keys_size; + +u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + +struct af9005_device_state { + u8 sequence; + int led_state; +}; + +static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, + int readwrite, int type, u8 * values, int len) +{ + struct af9005_device_state *st = d->priv; + u8 obuf[16] = { 0 }; + u8 ibuf[17] = { 0 }; + u8 command; + int i; + int ret; + + if (len < 1) { + err("generic read/write, less than 1 byte. Makes no sense."); + return -EINVAL; + } + if (len > 8) { + err("generic read/write, more than 8 bytes. Not supported."); + return -EINVAL; + } + + obuf[0] = 14; /* rest of buffer length low */ + obuf[1] = 0; /* rest of buffer length high */ + + obuf[2] = AF9005_REGISTER_RW; /* register operation */ + obuf[3] = 12; /* rest of buffer length */ + + obuf[4] = st->sequence++; /* sequence number */ + + obuf[5] = (u8) (reg >> 8); /* register address */ + obuf[6] = (u8) (reg & 0xff); + + if (type == AF9005_OFDM_REG) { + command = AF9005_CMD_OFDM_REG; + } else { + command = AF9005_CMD_TUNER; + } + + if (len > 1) + command |= + AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3; + command |= readwrite; + if (readwrite == AF9005_CMD_WRITE) + for (i = 0; i < len; i++) + obuf[8 + i] = values[i]; + else if (type == AF9005_TUNER_REG) + /* read command for tuner, the first byte contains the i2c address */ + obuf[8] = values[0]; + obuf[7] = command; + + ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0); + if (ret) + return ret; + + /* sanity check */ + if (ibuf[2] != AF9005_REGISTER_RW_ACK) { + err("generic read/write, wrong reply code."); + return -EIO; + } + if (ibuf[3] != 0x0d) { + err("generic read/write, wrong length in reply."); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("generic read/write, wrong sequence in reply."); + return -EIO; + } + /* + Windows driver doesn't check these fields, in fact sometimes + the register in the reply is different that what has been sent + + if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) { + err("generic read/write, wrong register in reply."); + return -EIO; + } + if (ibuf[7] != command) { + err("generic read/write wrong command in reply."); + return -EIO; + } + */ + if (ibuf[16] != 0x01) { + err("generic read/write wrong status code in reply."); + return -EIO; + } + if (readwrite == AF9005_CMD_READ) + for (i = 0; i < len; i++) + values[i] = ibuf[8 + i]; + + return 0; + +} + +int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value) +{ + int ret; + deb_reg("read register %x ", reg); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_OFDM_REG, + value, 1); + if (ret) + deb_reg("failed\n"); + else + deb_reg("value %x\n", *value); + return ret; +} + +int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + int ret; + deb_reg("read %d registers %x ", len, reg); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_OFDM_REG, + values, len); + if (ret) + deb_reg("failed\n"); + else + debug_dump(values, len, deb_reg); + return ret; +} + +int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value) +{ + int ret; + u8 temp = value; + deb_reg("write register %x value %x ", reg, value); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, AF9005_OFDM_REG, + &temp, 1); + if (ret) + deb_reg("failed\n"); + else + deb_reg("ok\n"); + return ret; +} + +int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + int ret; + deb_reg("write %d registers %x values ", len, reg); + debug_dump(values, len, deb_reg); + + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, AF9005_OFDM_REG, + values, len); + if (ret) + deb_reg("failed\n"); + else + deb_reg("ok\n"); + return ret; +} + +int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, + u8 len, u8 * value) +{ + u8 temp; + int ret; + deb_reg("read bits %x %x %x", reg, pos, len); + ret = af9005_read_ofdm_register(d, reg, &temp); + if (ret) { + deb_reg(" failed\n"); + return ret; + } + *value = (temp >> pos) & regmask[len - 1]; + deb_reg(" value %x\n", *value); + return 0; + +} + +int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, + u8 len, u8 value) +{ + u8 temp, mask; + int ret; + deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value); + if (pos == 0 && len == 8) + return af9005_write_ofdm_register(d, reg, value); + ret = af9005_read_ofdm_register(d, reg, &temp); + if (ret) + return ret; + mask = regmask[len - 1] << pos; + temp = (temp & ~mask) | ((value << pos) & mask); + return af9005_write_ofdm_register(d, reg, temp); + +} + +static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d, + u16 reg, u8 * values, int len) +{ + return af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_TUNER_REG, + values, len); +} + +static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d, + u16 reg, u8 * values, int len) +{ + return af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, + AF9005_TUNER_REG, values, len); +} + +int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + /* don't let the name of this function mislead you: it's just used + as an interface from the firmware to the i2c bus. The actual + i2c addresses are contained in the data */ + int ret, i, done = 0, fail = 0; + u8 temp; + ret = af9005_usb_write_tuner_registers(d, reg, values, len); + if (ret) + return ret; + if (reg != 0xffff) { + /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */ + for (i = 0; i < 200; i++) { + ret = + af9005_read_ofdm_register(d, + xd_I2C_i2c_m_status_wdat_done, + &temp); + if (ret) + return ret; + done = temp & (regmask[i2c_m_status_wdat_done_len - 1] + << i2c_m_status_wdat_done_pos); + if (done) + break; + fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1] + << i2c_m_status_wdat_fail_pos); + if (fail) + break; + msleep(50); + } + if (i == 200) + return -ETIMEDOUT; + if (fail) { + /* clear write fail bit */ + af9005_write_register_bits(d, + xd_I2C_i2c_m_status_wdat_fail, + i2c_m_status_wdat_fail_pos, + i2c_m_status_wdat_fail_len, + 1); + return -EIO; + } + /* clear write done bit */ + ret = + af9005_write_register_bits(d, + xd_I2C_i2c_m_status_wdat_fail, + i2c_m_status_wdat_done_pos, + i2c_m_status_wdat_done_len, 1); + if (ret) + return ret; + } + return 0; +} + +int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr, + u8 * values, int len) +{ + /* don't let the name of this function mislead you: it's just used + as an interface from the firmware to the i2c bus. The actual + i2c addresses are contained in the data */ + int ret, i; + u8 temp, buf[2]; + + buf[0] = addr; /* tuner i2c address */ + buf[1] = values[0]; /* tuner register */ + + values[0] = addr + 0x01; /* i2c read address */ + + if (reg == APO_REG_I2C_RW_SILICON_TUNER) { + /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */ + ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2); + if (ret) + return ret; + } + + /* send read command to ofsm */ + ret = af9005_usb_read_tuner_registers(d, reg, values, 1); + if (ret) + return ret; + + /* check if read done */ + for (i = 0; i < 200; i++) { + ret = af9005_read_ofdm_register(d, 0xa408, &temp); + if (ret) + return ret; + if (temp & 0x01) + break; + msleep(50); + } + if (i == 200) + return -ETIMEDOUT; + + /* clear read done bit (by writing 1) */ + ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1); + if (ret) + return ret; + + /* get read data (available from 0xa400) */ + for (i = 0; i < len; i++) { + ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp); + if (ret) + return ret; + values[i] = temp; + } + return 0; +} + +static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg, + u8 * data, int len) +{ + int ret, i; + u8 buf[3]; + deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr, + reg, len); + debug_dump(data, len, deb_i2c); + + for (i = 0; i < len; i++) { + buf[0] = i2caddr; + buf[1] = reg + (u8) i; + buf[2] = data[i]; + ret = + af9005_write_tuner_registers(d, + APO_REG_I2C_RW_SILICON_TUNER, + buf, 3); + if (ret) { + deb_i2c("i2c_write failed\n"); + return ret; + } + } + deb_i2c("i2c_write ok\n"); + return 0; +} + +static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg, + u8 * data, int len) +{ + int ret, i; + u8 temp; + deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len); + for (i = 0; i < len; i++) { + temp = reg + i; + ret = + af9005_read_tuner_registers(d, + APO_REG_I2C_RW_SILICON_TUNER, + i2caddr, &temp, 1); + if (ret) { + deb_i2c("i2c_read failed\n"); + return ret; + } + data[i] = temp; + } + deb_i2c("i2c data read: "); + debug_dump(data, len, deb_i2c); + return 0; +} + +static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + /* only implements what the mt2060 module does, don't know how + to make it really generic */ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; + u8 reg, addr; + u8 *value; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + if (num == 2) { + /* reads a single register */ + reg = *msg[0].buf; + addr = msg[0].addr; + value = msg[1].buf; + ret = af9005_i2c_read(d, addr, reg, value, 1); + if (ret == 0) + ret = 2; + } else { + /* write one or more registers */ + reg = msg[0].buf[0]; + addr = msg[0].addr; + value = &msg[0].buf[1]; + ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1); + if (ret == 0) + ret = 1; + } + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static u32 af9005_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9005_i2c_algo = { + .master_xfer = af9005_i2c_xfer, + .functionality = af9005_i2c_func, +}; + +int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf, + int wlen, u8 * rbuf, int rlen) +{ + struct af9005_device_state *st = d->priv; + + int ret, i, packet_len; + u8 buf[64]; + u8 ibuf[64]; + + if (wlen < 0) { + err("send command, wlen less than 0 bytes. Makes no sense."); + return -EINVAL; + } + if (wlen > 54) { + err("send command, wlen more than 54 bytes. Not supported."); + return -EINVAL; + } + if (rlen > 54) { + err("send command, rlen more than 54 bytes. Not supported."); + return -EINVAL; + } + packet_len = wlen + 5; + buf[0] = (u8) (packet_len & 0xff); + buf[1] = (u8) ((packet_len & 0xff00) >> 8); + + buf[2] = 0x26; /* packet type */ + buf[3] = wlen + 3; + buf[4] = st->sequence++; + buf[5] = command; + buf[6] = wlen; + for (i = 0; i < wlen; i++) + buf[7 + i] = wbuf[i]; + ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0); + if (ret) + return ret; + if (ibuf[2] != 0x27) { + err("send command, wrong reply code."); + return -EIO; + } + if (ibuf[4] != buf[4]) { + err("send command, wrong sequence in reply."); + return -EIO; + } + if (ibuf[5] != 0x01) { + err("send command, wrong status code in reply."); + return -EIO; + } + if (ibuf[6] != rlen) { + err("send command, invalid data length in reply."); + return -EIO; + } + for (i = 0; i < rlen; i++) + rbuf[i] = ibuf[i + 7]; + return 0; +} + +int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values, + int len) +{ + struct af9005_device_state *st = d->priv; + u8 obuf[16], ibuf[14]; + int ret, i; + + memset(obuf, 0, sizeof(obuf)); + memset(ibuf, 0, sizeof(ibuf)); + + obuf[0] = 14; /* length of rest of packet low */ + obuf[1] = 0; /* length of rest of packer high */ + + obuf[2] = 0x2a; /* read/write eeprom */ + + obuf[3] = 12; /* size */ + + obuf[4] = st->sequence++; + + obuf[5] = 0; /* read */ + + obuf[6] = len; + obuf[7] = address; + ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0); + if (ret) + return ret; + if (ibuf[2] != 0x2b) { + err("Read eeprom, invalid reply code"); + return -EIO; + } + if (ibuf[3] != 10) { + err("Read eeprom, invalid reply length"); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("Read eeprom, wrong sequence in reply "); + return -EIO; + } + if (ibuf[5] != 1) { + err("Read eeprom, wrong status in reply "); + return -EIO; + } + for (i = 0; i < len; i++) { + values[i] = ibuf[6 + i]; + } + return 0; +} + +static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) +{ + u8 buf[FW_BULKOUT_SIZE + 2]; + u16 checksum; + int act_len, i, ret; + memset(buf, 0, sizeof(buf)); + buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); + buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); + switch (type) { + case FW_CONFIG: + buf[2] = 0x11; + buf[3] = 0x04; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x03; + checksum = buf[4] + buf[5]; + buf[6] = (u8) ((checksum >> 8) & 0xff); + buf[7] = (u8) (checksum & 0xff); + break; + case FW_CONFIRM: + buf[2] = 0x11; + buf[3] = 0x04; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x01; + checksum = buf[4] + buf[5]; + buf[6] = (u8) ((checksum >> 8) & 0xff); + buf[7] = (u8) (checksum & 0xff); + break; + case FW_BOOT: + buf[2] = 0x10; + buf[3] = 0x08; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x97; + buf[6] = 0xaa; + buf[7] = 0x55; + buf[8] = 0xa5; + buf[9] = 0x5a; + checksum = 0; + for (i = 4; i <= 9; i++) + checksum += buf[i]; + buf[10] = (u8) ((checksum >> 8) & 0xff); + buf[11] = (u8) (checksum & 0xff); + break; + default: + err("boot packet invalid boot packet type"); + return -EINVAL; + } + deb_fw(">>> "); + debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); + + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x02), + buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); + if (ret) + err("boot packet bulk message failed: %d (%d/%d)", ret, + FW_BULKOUT_SIZE + 2, act_len); + else + ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; + if (ret) + return ret; + memset(buf, 0, 9); + ret = usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); + if (ret) { + err("boot packet recv bulk message failed: %d", ret); + return ret; + } + deb_fw("<<< "); + debug_dump(buf, act_len, deb_fw); + checksum = 0; + switch (type) { + case FW_CONFIG: + if (buf[2] != 0x11) { + err("boot bad config header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad config size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad config sequence."); + return -EIO; + } + if (buf[5] != 0x04) { + err("boot bad config subtype."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad config checksum."); + return -EIO; + } + *reply = buf[6]; + break; + case FW_CONFIRM: + if (buf[2] != 0x11) { + err("boot bad confirm header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad confirm size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad confirm sequence."); + return -EIO; + } + if (buf[5] != 0x02) { + err("boot bad confirm subtype."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad confirm checksum."); + return -EIO; + } + *reply = buf[6]; + break; + case FW_BOOT: + if (buf[2] != 0x10) { + err("boot bad boot header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad boot size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad boot sequence."); + return -EIO; + } + if (buf[5] != 0x01) { + err("boot bad boot pattern 01."); + return -EIO; + } + if (buf[6] != 0x10) { + err("boot bad boot pattern 10."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad boot checksum."); + return -EIO; + } + break; + + } + + return 0; +} + +static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) +{ + int i, packets, ret, act_len; + + u8 buf[FW_BULKOUT_SIZE + 2]; + u8 reply; + + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + if (reply != 0x01) { + err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); + return -EIO; + } + packets = fw->size / FW_BULKOUT_SIZE; + buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); + buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); + for (i = 0; i < packets; i++) { + memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, + FW_BULKOUT_SIZE); + deb_fw(">>> "); + debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x02), + buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); + if (ret) { + err("firmware download failed at packet %d with code %d", i, ret); + return ret; + } + } + ret = af9005_boot_packet(udev, FW_CONFIRM, &reply); + if (ret) + return ret; + if (reply != (u8) (packets & 0xff)) { + err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); + return -EIO; + } + ret = af9005_boot_packet(udev, FW_BOOT, &reply); + if (ret) + return ret; + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + if (reply != 0x02) { + err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); + return -EIO; + } + + return 0; + +} + +int af9005_led_control(struct dvb_usb_device *d, int onoff) +{ + struct af9005_device_state *st = d->priv; + int temp, ret; + + if (onoff && dvb_usb_af9005_led) + temp = 1; + else + temp = 0; + if (st->led_state != temp) { + ret = + af9005_write_register_bits(d, xd_p_reg_top_locken1, + reg_top_locken1_pos, + reg_top_locken1_len, temp); + if (ret) + return ret; + ret = + af9005_write_register_bits(d, xd_p_reg_top_lock1, + reg_top_lock1_pos, + reg_top_lock1_len, temp); + if (ret) + return ret; + st->led_state = temp; + } + return 0; +} + +static int af9005_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[8]; + int i; + + /* without these calls the first commands after downloading + the firmware fail. I put these calls here to simulate + what it is done in dvb-usb-init.c. + */ + struct usb_device *udev = adap->dev->udev; + usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); + if (dvb_usb_af9005_dump_eeprom) { + printk("EEPROM DUMP\n"); + for (i = 0; i < 255; i += 8) { + af9005_read_eeprom(adap->dev, i, buf, 8); + printk("ADDR %x ", i); + debug_dump(buf, 8, printk); + } + } + adap->fe_adap[0].fe = af9005_fe_attach(adap->dev); + return 0; +} + +static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) +{ + struct af9005_device_state *st = d->priv; + int ret, len; + + u8 obuf[5]; + u8 ibuf[256]; + + *state = REMOTE_NO_KEY_PRESSED; + if (rc_decode == NULL) { + /* it shouldn't never come here */ + return 0; + } + /* deb_info("rc_query\n"); */ + obuf[0] = 3; /* rest of packet length low */ + obuf[1] = 0; /* rest of packet lentgh high */ + obuf[2] = 0x40; /* read remote */ + obuf[3] = 1; /* rest of packet length */ + obuf[4] = st->sequence++; /* sequence number */ + ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0); + if (ret) { + err("rc query failed"); + return ret; + } + if (ibuf[2] != 0x41) { + err("rc query bad header."); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("rc query bad sequence."); + return -EIO; + } + len = ibuf[5]; + if (len > 246) { + err("rc query invalid length"); + return -EIO; + } + if (len > 0) { + deb_rc("rc data (%d) ", len); + debug_dump((ibuf + 6), len, deb_rc); + ret = rc_decode(d, &ibuf[6], len, event, state); + if (ret) { + err("rc_decode failed"); + return ret; + } else { + deb_rc("rc_decode state %x event %x\n", *state, *event); + if (*state == REMOTE_KEY_REPEAT) + *event = d->last_event; + } + } + return 0; +} + +static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + + return 0; +} + +static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("pid filter control onoff %d\n", onoff); + if (onoff) { + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); + if (ret) + return ret; + ret = + af9005_write_register_bits(adap->dev, + XD_MP2IF_DMX_CTRL, 1, 1, 1); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); + } else + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); + if (ret) + return ret; + deb_info("pid filter control ok\n"); + return 0; +} + +static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, + u16 pid, int onoff) +{ + u8 cmd = index & 0x1f; + int ret; + deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, + pid, onoff); + if (onoff) { + /* cannot use it as pid_filter_ctrl since it has to be done + before setting the first pid */ + if (adap->feedcount == 1) { + deb_info("first pid set, enable pid table\n"); + ret = af9005_pid_filter_control(adap, onoff); + if (ret) + return ret; + } + ret = + af9005_write_ofdm_register(adap->dev, + XD_MP2IF_PID_DATA_L, + (u8) (pid & 0xff)); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(adap->dev, + XD_MP2IF_PID_DATA_H, + (u8) (pid >> 8)); + if (ret) + return ret; + cmd |= 0x20 | 0x40; + } else { + if (adap->feedcount == 0) { + deb_info("last pid unset, disable pid table\n"); + ret = af9005_pid_filter_control(adap, onoff); + if (ret) + return ret; + } + } + ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); + if (ret) + return ret; + deb_info("set pid ok\n"); + return 0; +} + +static int af9005_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret; + u8 reply; + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + deb_info("result of FW_CONFIG in identify state %d\n", reply); + if (reply == 0x01) + *cold = 1; + else if (reply == 0x02) + *cold = 0; + else + return -EIO; + deb_info("Identify state cold = %d\n", *cold); + return 0; +} + +static struct dvb_usb_device_properties af9005_properties; + +static int af9005_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &af9005_properties, + THIS_MODULE, NULL, adapter_nr); +} + +enum af9005_usb_table_entry { + AFATECH_AF9005, + TERRATEC_AF9005, + ANSONIC_AF9005, +}; + +static struct usb_device_id af9005_usb_table[] = { + [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH, + USB_PID_AFATECH_AF9005)}, + [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC, + USB_PID_ANSONIC_DVBT_USB)}, + { } +}; + +MODULE_DEVICE_TABLE(usb, af9005_usb_table); + +static struct dvb_usb_device_properties af9005_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "af9005.fw", + .download_firmware = af9005_download_firmware, + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9005_device_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = + DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9005_pid_filter, + /* .pid_filter_ctrl = af9005_pid_filter_control, */ + .frontend_attach = af9005_frontend_attach, + /* .tuner_attach = af9005_tuner_attach, */ + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 4096, /* actual size seen is 3948 */ + } + } + }, + }}, + } + }, + .power_ctrl = af9005_power_ctrl, + .identify_state = af9005_identify_state, + + .i2c_algo = &af9005_i2c_algo, + + .rc.legacy = { + .rc_interval = 200, + .rc_map_table = NULL, + .rc_map_size = 0, + .rc_query = af9005_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 2, + .generic_bulk_ctrl_endpoint_response = 1, + + .num_device_descs = 3, + .devices = { + {.name = "Afatech DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL}, + .warm_ids = {NULL}, + }, + {.name = "TerraTec Cinergy T USB XE", + .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL}, + .warm_ids = {NULL}, + }, + {.name = "Ansonic DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL}, + .warm_ids = {NULL}, + }, + {NULL}, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9005_usb_driver = { + .name = "dvb_usb_af9005", + .probe = af9005_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = af9005_usb_table, +}; + +/* module stuff */ +static int __init af9005_usb_module_init(void) +{ + int result; + if ((result = usb_register(&af9005_usb_driver))) { + err("usb_register failed. (%d)", result); + return result; + } + rc_decode = symbol_request(af9005_rc_decode); + rc_keys = symbol_request(rc_map_af9005_table); + rc_keys_size = symbol_request(rc_map_af9005_table_size); + if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { + err("af9005_rc_decode function not found, disabling remote"); + af9005_properties.rc.legacy.rc_query = NULL; + } else { + af9005_properties.rc.legacy.rc_map_table = rc_keys; + af9005_properties.rc.legacy.rc_map_size = *rc_keys_size; + } + + return 0; +} + +static void __exit af9005_usb_module_exit(void) +{ + /* release rc decode symbols */ + if (rc_decode != NULL) + symbol_put(af9005_rc_decode); + if (rc_keys != NULL) + symbol_put(rc_map_af9005_table); + if (rc_keys_size != NULL) + symbol_put(rc_map_af9005_table_size); + /* deregister this driver from the USB subsystem */ + usb_deregister(&af9005_usb_driver); +} + +module_init(af9005_usb_module_init); +module_exit(af9005_usb_module_exit); + +MODULE_AUTHOR("Luca Olivetti "); +MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/af9005.h b/drivers/media/usb/dvb-usb/af9005.h new file mode 100644 index 00000000000..6a2bf3de845 --- /dev/null +++ b/drivers/media/usb/dvb-usb/af9005.h @@ -0,0 +1,3496 @@ +/* Common header-file of the Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_AF9005_H_ +#define _DVB_USB_AF9005_H_ + +#define DVB_USB_LOG_PREFIX "af9005" +#include "dvb-usb.h" + +extern int dvb_usb_af9005_debug; +#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args) +#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args) +#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) +#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) + +extern bool dvb_usb_af9005_led; + +/* firmware */ +#define FW_BULKOUT_SIZE 250 +enum { + FW_CONFIG, + FW_CONFIRM, + FW_BOOT +}; + +/* af9005 commands */ +#define AF9005_OFDM_REG 0 +#define AF9005_TUNER_REG 1 + +#define AF9005_REGISTER_RW 0x20 +#define AF9005_REGISTER_RW_ACK 0x21 + +#define AF9005_CMD_OFDM_REG 0x00 +#define AF9005_CMD_TUNER 0x80 +#define AF9005_CMD_BURST 0x02 +#define AF9005_CMD_AUTOINC 0x04 +#define AF9005_CMD_READ 0x00 +#define AF9005_CMD_WRITE 0x01 + +/* af9005 registers */ +#define APO_REG_RESET 0xAEFF + +#define APO_REG_I2C_RW_CAN_TUNER 0xF000 +#define APO_REG_I2C_RW_SILICON_TUNER 0xF001 +#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */ +#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */ + +/*********************************************************************** + * Apollo Registers from VLSI * + ***********************************************************************/ +#define xd_p_reg_aagc_inverted_agc 0xA000 +#define reg_aagc_inverted_agc_pos 0 +#define reg_aagc_inverted_agc_len 1 +#define reg_aagc_inverted_agc_lsb 0 +#define xd_p_reg_aagc_sign_only 0xA000 +#define reg_aagc_sign_only_pos 1 +#define reg_aagc_sign_only_len 1 +#define reg_aagc_sign_only_lsb 0 +#define xd_p_reg_aagc_slow_adc_en 0xA000 +#define reg_aagc_slow_adc_en_pos 2 +#define reg_aagc_slow_adc_en_len 1 +#define reg_aagc_slow_adc_en_lsb 0 +#define xd_p_reg_aagc_slow_adc_scale 0xA000 +#define reg_aagc_slow_adc_scale_pos 3 +#define reg_aagc_slow_adc_scale_len 5 +#define reg_aagc_slow_adc_scale_lsb 0 +#define xd_p_reg_aagc_check_slow_adc_lock 0xA001 +#define reg_aagc_check_slow_adc_lock_pos 0 +#define reg_aagc_check_slow_adc_lock_len 1 +#define reg_aagc_check_slow_adc_lock_lsb 0 +#define xd_p_reg_aagc_init_control 0xA001 +#define reg_aagc_init_control_pos 1 +#define reg_aagc_init_control_len 1 +#define reg_aagc_init_control_lsb 0 +#define xd_p_reg_aagc_total_gain_sel 0xA001 +#define reg_aagc_total_gain_sel_pos 2 +#define reg_aagc_total_gain_sel_len 2 +#define reg_aagc_total_gain_sel_lsb 0 +#define xd_p_reg_aagc_out_inv 0xA001 +#define reg_aagc_out_inv_pos 5 +#define reg_aagc_out_inv_len 1 +#define reg_aagc_out_inv_lsb 0 +#define xd_p_reg_aagc_int_en 0xA001 +#define reg_aagc_int_en_pos 6 +#define reg_aagc_int_en_len 1 +#define reg_aagc_int_en_lsb 0 +#define xd_p_reg_aagc_lock_change_flag 0xA001 +#define reg_aagc_lock_change_flag_pos 7 +#define reg_aagc_lock_change_flag_len 1 +#define reg_aagc_lock_change_flag_lsb 0 +#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002 +#define reg_aagc_rf_loop_bw_scale_acquire_pos 0 +#define reg_aagc_rf_loop_bw_scale_acquire_len 5 +#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0 +#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003 +#define reg_aagc_rf_loop_bw_scale_track_pos 0 +#define reg_aagc_rf_loop_bw_scale_track_len 5 +#define reg_aagc_rf_loop_bw_scale_track_lsb 0 +#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004 +#define reg_aagc_if_loop_bw_scale_acquire_pos 0 +#define reg_aagc_if_loop_bw_scale_acquire_len 5 +#define reg_aagc_if_loop_bw_scale_acquire_lsb 0 +#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005 +#define reg_aagc_if_loop_bw_scale_track_pos 0 +#define reg_aagc_if_loop_bw_scale_track_len 5 +#define reg_aagc_if_loop_bw_scale_track_lsb 0 +#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006 +#define reg_aagc_max_rf_agc_7_0_pos 0 +#define reg_aagc_max_rf_agc_7_0_len 8 +#define reg_aagc_max_rf_agc_7_0_lsb 0 +#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007 +#define reg_aagc_max_rf_agc_9_8_pos 0 +#define reg_aagc_max_rf_agc_9_8_len 2 +#define reg_aagc_max_rf_agc_9_8_lsb 8 +#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008 +#define reg_aagc_min_rf_agc_7_0_pos 0 +#define reg_aagc_min_rf_agc_7_0_len 8 +#define reg_aagc_min_rf_agc_7_0_lsb 0 +#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009 +#define reg_aagc_min_rf_agc_9_8_pos 0 +#define reg_aagc_min_rf_agc_9_8_len 2 +#define reg_aagc_min_rf_agc_9_8_lsb 8 +#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A +#define reg_aagc_max_if_agc_7_0_pos 0 +#define reg_aagc_max_if_agc_7_0_len 8 +#define reg_aagc_max_if_agc_7_0_lsb 0 +#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B +#define reg_aagc_max_if_agc_9_8_pos 0 +#define reg_aagc_max_if_agc_9_8_len 2 +#define reg_aagc_max_if_agc_9_8_lsb 8 +#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C +#define reg_aagc_min_if_agc_7_0_pos 0 +#define reg_aagc_min_if_agc_7_0_len 8 +#define reg_aagc_min_if_agc_7_0_lsb 0 +#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D +#define reg_aagc_min_if_agc_9_8_pos 0 +#define reg_aagc_min_if_agc_9_8_len 2 +#define reg_aagc_min_if_agc_9_8_lsb 8 +#define xd_p_reg_aagc_lock_sample_scale 0xA00E +#define reg_aagc_lock_sample_scale_pos 0 +#define reg_aagc_lock_sample_scale_len 5 +#define reg_aagc_lock_sample_scale_lsb 0 +#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F +#define reg_aagc_rf_agc_lock_scale_acquire_pos 0 +#define reg_aagc_rf_agc_lock_scale_acquire_len 3 +#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0 +#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F +#define reg_aagc_rf_agc_lock_scale_track_pos 3 +#define reg_aagc_rf_agc_lock_scale_track_len 3 +#define reg_aagc_rf_agc_lock_scale_track_lsb 0 +#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010 +#define reg_aagc_if_agc_lock_scale_acquire_pos 0 +#define reg_aagc_if_agc_lock_scale_acquire_len 3 +#define reg_aagc_if_agc_lock_scale_acquire_lsb 0 +#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010 +#define reg_aagc_if_agc_lock_scale_track_pos 3 +#define reg_aagc_if_agc_lock_scale_track_len 3 +#define reg_aagc_if_agc_lock_scale_track_lsb 0 +#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011 +#define reg_aagc_rf_top_numerator_7_0_pos 0 +#define reg_aagc_rf_top_numerator_7_0_len 8 +#define reg_aagc_rf_top_numerator_7_0_lsb 0 +#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012 +#define reg_aagc_rf_top_numerator_9_8_pos 0 +#define reg_aagc_rf_top_numerator_9_8_len 2 +#define reg_aagc_rf_top_numerator_9_8_lsb 8 +#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013 +#define reg_aagc_if_top_numerator_7_0_pos 0 +#define reg_aagc_if_top_numerator_7_0_len 8 +#define reg_aagc_if_top_numerator_7_0_lsb 0 +#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014 +#define reg_aagc_if_top_numerator_9_8_pos 0 +#define reg_aagc_if_top_numerator_9_8_len 2 +#define reg_aagc_if_top_numerator_9_8_lsb 8 +#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015 +#define reg_aagc_adc_out_desired_7_0_pos 0 +#define reg_aagc_adc_out_desired_7_0_len 8 +#define reg_aagc_adc_out_desired_7_0_lsb 0 +#define xd_p_reg_aagc_adc_out_desired_8 0xA016 +#define reg_aagc_adc_out_desired_8_pos 0 +#define reg_aagc_adc_out_desired_8_len 1 +#define reg_aagc_adc_out_desired_8_lsb 0 +#define xd_p_reg_aagc_fixed_gain 0xA016 +#define reg_aagc_fixed_gain_pos 3 +#define reg_aagc_fixed_gain_len 1 +#define reg_aagc_fixed_gain_lsb 0 +#define xd_p_reg_aagc_lock_count_th 0xA016 +#define reg_aagc_lock_count_th_pos 4 +#define reg_aagc_lock_count_th_len 4 +#define reg_aagc_lock_count_th_lsb 0 +#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017 +#define reg_aagc_fixed_rf_agc_control_7_0_pos 0 +#define reg_aagc_fixed_rf_agc_control_7_0_len 8 +#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0 +#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018 +#define reg_aagc_fixed_rf_agc_control_15_8_pos 0 +#define reg_aagc_fixed_rf_agc_control_15_8_len 8 +#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8 +#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019 +#define reg_aagc_fixed_rf_agc_control_23_16_pos 0 +#define reg_aagc_fixed_rf_agc_control_23_16_len 8 +#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16 +#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A +#define reg_aagc_fixed_rf_agc_control_30_24_pos 0 +#define reg_aagc_fixed_rf_agc_control_30_24_len 7 +#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24 +#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B +#define reg_aagc_fixed_if_agc_control_7_0_pos 0 +#define reg_aagc_fixed_if_agc_control_7_0_len 8 +#define reg_aagc_fixed_if_agc_control_7_0_lsb 0 +#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C +#define reg_aagc_fixed_if_agc_control_15_8_pos 0 +#define reg_aagc_fixed_if_agc_control_15_8_len 8 +#define reg_aagc_fixed_if_agc_control_15_8_lsb 8 +#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D +#define reg_aagc_fixed_if_agc_control_23_16_pos 0 +#define reg_aagc_fixed_if_agc_control_23_16_len 8 +#define reg_aagc_fixed_if_agc_control_23_16_lsb 16 +#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E +#define reg_aagc_fixed_if_agc_control_30_24_pos 0 +#define reg_aagc_fixed_if_agc_control_30_24_len 7 +#define reg_aagc_fixed_if_agc_control_30_24_lsb 24 +#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F +#define reg_aagc_rf_agc_unlock_numerator_pos 0 +#define reg_aagc_rf_agc_unlock_numerator_len 6 +#define reg_aagc_rf_agc_unlock_numerator_lsb 0 +#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020 +#define reg_aagc_if_agc_unlock_numerator_pos 0 +#define reg_aagc_if_agc_unlock_numerator_len 6 +#define reg_aagc_if_agc_unlock_numerator_lsb 0 +#define xd_p_reg_unplug_th 0xA021 +#define reg_unplug_th_pos 0 +#define reg_unplug_th_len 8 +#define reg_aagc_rf_x0_lsb 0 +#define xd_p_reg_weak_signal_rfagc_thr 0xA022 +#define reg_weak_signal_rfagc_thr_pos 0 +#define reg_weak_signal_rfagc_thr_len 8 +#define reg_weak_signal_rfagc_thr_lsb 0 +#define xd_p_reg_unplug_rf_gain_th 0xA023 +#define reg_unplug_rf_gain_th_pos 0 +#define reg_unplug_rf_gain_th_len 8 +#define reg_unplug_rf_gain_th_lsb 0 +#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024 +#define reg_unplug_dtop_rf_gain_th_pos 0 +#define reg_unplug_dtop_rf_gain_th_len 8 +#define reg_unplug_dtop_rf_gain_th_lsb 0 +#define xd_p_reg_unplug_dtop_if_gain_th 0xA025 +#define reg_unplug_dtop_if_gain_th_pos 0 +#define reg_unplug_dtop_if_gain_th_len 8 +#define reg_unplug_dtop_if_gain_th_lsb 0 +#define xd_p_reg_top_recover_at_unplug_en 0xA026 +#define reg_top_recover_at_unplug_en_pos 0 +#define reg_top_recover_at_unplug_en_len 1 +#define reg_top_recover_at_unplug_en_lsb 0 +#define xd_p_reg_aagc_rf_x6 0xA027 +#define reg_aagc_rf_x6_pos 0 +#define reg_aagc_rf_x6_len 8 +#define reg_aagc_rf_x6_lsb 0 +#define xd_p_reg_aagc_rf_x7 0xA028 +#define reg_aagc_rf_x7_pos 0 +#define reg_aagc_rf_x7_len 8 +#define reg_aagc_rf_x7_lsb 0 +#define xd_p_reg_aagc_rf_x8 0xA029 +#define reg_aagc_rf_x8_pos 0 +#define reg_aagc_rf_x8_len 8 +#define reg_aagc_rf_x8_lsb 0 +#define xd_p_reg_aagc_rf_x9 0xA02A +#define reg_aagc_rf_x9_pos 0 +#define reg_aagc_rf_x9_len 8 +#define reg_aagc_rf_x9_lsb 0 +#define xd_p_reg_aagc_rf_x10 0xA02B +#define reg_aagc_rf_x10_pos 0 +#define reg_aagc_rf_x10_len 8 +#define reg_aagc_rf_x10_lsb 0 +#define xd_p_reg_aagc_rf_x11 0xA02C +#define reg_aagc_rf_x11_pos 0 +#define reg_aagc_rf_x11_len 8 +#define reg_aagc_rf_x11_lsb 0 +#define xd_p_reg_aagc_rf_x12 0xA02D +#define reg_aagc_rf_x12_pos 0 +#define reg_aagc_rf_x12_len 8 +#define reg_aagc_rf_x12_lsb 0 +#define xd_p_reg_aagc_rf_x13 0xA02E +#define reg_aagc_rf_x13_pos 0 +#define reg_aagc_rf_x13_len 8 +#define reg_aagc_rf_x13_lsb 0 +#define xd_p_reg_aagc_if_x0 0xA02F +#define reg_aagc_if_x0_pos 0 +#define reg_aagc_if_x0_len 8 +#define reg_aagc_if_x0_lsb 0 +#define xd_p_reg_aagc_if_x1 0xA030 +#define reg_aagc_if_x1_pos 0 +#define reg_aagc_if_x1_len 8 +#define reg_aagc_if_x1_lsb 0 +#define xd_p_reg_aagc_if_x2 0xA031 +#define reg_aagc_if_x2_pos 0 +#define reg_aagc_if_x2_len 8 +#define reg_aagc_if_x2_lsb 0 +#define xd_p_reg_aagc_if_x3 0xA032 +#define reg_aagc_if_x3_pos 0 +#define reg_aagc_if_x3_len 8 +#define reg_aagc_if_x3_lsb 0 +#define xd_p_reg_aagc_if_x4 0xA033 +#define reg_aagc_if_x4_pos 0 +#define reg_aagc_if_x4_len 8 +#define reg_aagc_if_x4_lsb 0 +#define xd_p_reg_aagc_if_x5 0xA034 +#define reg_aagc_if_x5_pos 0 +#define reg_aagc_if_x5_len 8 +#define reg_aagc_if_x5_lsb 0 +#define xd_p_reg_aagc_if_x6 0xA035 +#define reg_aagc_if_x6_pos 0 +#define reg_aagc_if_x6_len 8 +#define reg_aagc_if_x6_lsb 0 +#define xd_p_reg_aagc_if_x7 0xA036 +#define reg_aagc_if_x7_pos 0 +#define reg_aagc_if_x7_len 8 +#define reg_aagc_if_x7_lsb 0 +#define xd_p_reg_aagc_if_x8 0xA037 +#define reg_aagc_if_x8_pos 0 +#define reg_aagc_if_x8_len 8 +#define reg_aagc_if_x8_lsb 0 +#define xd_p_reg_aagc_if_x9 0xA038 +#define reg_aagc_if_x9_pos 0 +#define reg_aagc_if_x9_len 8 +#define reg_aagc_if_x9_lsb 0 +#define xd_p_reg_aagc_if_x10 0xA039 +#define reg_aagc_if_x10_pos 0 +#define reg_aagc_if_x10_len 8 +#define reg_aagc_if_x10_lsb 0 +#define xd_p_reg_aagc_if_x11 0xA03A +#define reg_aagc_if_x11_pos 0 +#define reg_aagc_if_x11_len 8 +#define reg_aagc_if_x11_lsb 0 +#define xd_p_reg_aagc_if_x12 0xA03B +#define reg_aagc_if_x12_pos 0 +#define reg_aagc_if_x12_len 8 +#define reg_aagc_if_x12_lsb 0 +#define xd_p_reg_aagc_if_x13 0xA03C +#define reg_aagc_if_x13_pos 0 +#define reg_aagc_if_x13_len 8 +#define reg_aagc_if_x13_lsb 0 +#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D +#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0 +#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8 +#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0 +#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E +#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0 +#define reg_aagc_min_if_ctl_8bit_for_dca_len 8 +#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0 +#define xd_r_reg_aagc_total_gain_7_0 0xA070 +#define reg_aagc_total_gain_7_0_pos 0 +#define reg_aagc_total_gain_7_0_len 8 +#define reg_aagc_total_gain_7_0_lsb 0 +#define xd_r_reg_aagc_total_gain_15_8 0xA071 +#define reg_aagc_total_gain_15_8_pos 0 +#define reg_aagc_total_gain_15_8_len 8 +#define reg_aagc_total_gain_15_8_lsb 8 +#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074 +#define reg_aagc_in_sat_cnt_7_0_pos 0 +#define reg_aagc_in_sat_cnt_7_0_len 8 +#define reg_aagc_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075 +#define reg_aagc_in_sat_cnt_15_8_pos 0 +#define reg_aagc_in_sat_cnt_15_8_len 8 +#define reg_aagc_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076 +#define reg_aagc_in_sat_cnt_23_16_pos 0 +#define reg_aagc_in_sat_cnt_23_16_len 8 +#define reg_aagc_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077 +#define reg_aagc_in_sat_cnt_31_24_pos 0 +#define reg_aagc_in_sat_cnt_31_24_len 8 +#define reg_aagc_in_sat_cnt_31_24_lsb 24 +#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078 +#define reg_aagc_digital_rf_volt_7_0_pos 0 +#define reg_aagc_digital_rf_volt_7_0_len 8 +#define reg_aagc_digital_rf_volt_7_0_lsb 0 +#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079 +#define reg_aagc_digital_rf_volt_9_8_pos 0 +#define reg_aagc_digital_rf_volt_9_8_len 2 +#define reg_aagc_digital_rf_volt_9_8_lsb 8 +#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A +#define reg_aagc_digital_if_volt_7_0_pos 0 +#define reg_aagc_digital_if_volt_7_0_len 8 +#define reg_aagc_digital_if_volt_7_0_lsb 0 +#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B +#define reg_aagc_digital_if_volt_9_8_pos 0 +#define reg_aagc_digital_if_volt_9_8_len 2 +#define reg_aagc_digital_if_volt_9_8_lsb 8 +#define xd_r_reg_aagc_rf_gain 0xA07C +#define reg_aagc_rf_gain_pos 0 +#define reg_aagc_rf_gain_len 8 +#define reg_aagc_rf_gain_lsb 0 +#define xd_r_reg_aagc_if_gain 0xA07D +#define reg_aagc_if_gain_pos 0 +#define reg_aagc_if_gain_len 8 +#define reg_aagc_if_gain_lsb 0 +#define xd_p_tinr_imp_indicator 0xA080 +#define tinr_imp_indicator_pos 0 +#define tinr_imp_indicator_len 2 +#define tinr_imp_indicator_lsb 0 +#define xd_p_reg_tinr_fifo_size 0xA080 +#define reg_tinr_fifo_size_pos 2 +#define reg_tinr_fifo_size_len 5 +#define reg_tinr_fifo_size_lsb 0 +#define xd_p_reg_tinr_saturation_cnt_th 0xA081 +#define reg_tinr_saturation_cnt_th_pos 0 +#define reg_tinr_saturation_cnt_th_len 4 +#define reg_tinr_saturation_cnt_th_lsb 0 +#define xd_p_reg_tinr_saturation_th_3_0 0xA081 +#define reg_tinr_saturation_th_3_0_pos 4 +#define reg_tinr_saturation_th_3_0_len 4 +#define reg_tinr_saturation_th_3_0_lsb 0 +#define xd_p_reg_tinr_saturation_th_8_4 0xA082 +#define reg_tinr_saturation_th_8_4_pos 0 +#define reg_tinr_saturation_th_8_4_len 5 +#define reg_tinr_saturation_th_8_4_lsb 4 +#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083 +#define reg_tinr_imp_duration_th_2k_7_0_pos 0 +#define reg_tinr_imp_duration_th_2k_7_0_len 8 +#define reg_tinr_imp_duration_th_2k_7_0_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084 +#define reg_tinr_imp_duration_th_2k_8_pos 0 +#define reg_tinr_imp_duration_th_2k_8_len 1 +#define reg_tinr_imp_duration_th_2k_8_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085 +#define reg_tinr_imp_duration_th_8k_7_0_pos 0 +#define reg_tinr_imp_duration_th_8k_7_0_len 8 +#define reg_tinr_imp_duration_th_8k_7_0_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086 +#define reg_tinr_imp_duration_th_8k_10_8_pos 0 +#define reg_tinr_imp_duration_th_8k_10_8_len 3 +#define reg_tinr_imp_duration_th_8k_10_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087 +#define reg_tinr_freq_ratio_6m_7_0_pos 0 +#define reg_tinr_freq_ratio_6m_7_0_len 8 +#define reg_tinr_freq_ratio_6m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088 +#define reg_tinr_freq_ratio_6m_12_8_pos 0 +#define reg_tinr_freq_ratio_6m_12_8_len 5 +#define reg_tinr_freq_ratio_6m_12_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089 +#define reg_tinr_freq_ratio_7m_7_0_pos 0 +#define reg_tinr_freq_ratio_7m_7_0_len 8 +#define reg_tinr_freq_ratio_7m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A +#define reg_tinr_freq_ratio_7m_12_8_pos 0 +#define reg_tinr_freq_ratio_7m_12_8_len 5 +#define reg_tinr_freq_ratio_7m_12_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B +#define reg_tinr_freq_ratio_8m_7_0_pos 0 +#define reg_tinr_freq_ratio_8m_7_0_len 8 +#define reg_tinr_freq_ratio_8m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C +#define reg_tinr_freq_ratio_8m_12_8_pos 0 +#define reg_tinr_freq_ratio_8m_12_8_len 5 +#define reg_tinr_freq_ratio_8m_12_8_lsb 8 +#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D +#define reg_tinr_imp_duration_th_low_2k_pos 0 +#define reg_tinr_imp_duration_th_low_2k_len 8 +#define reg_tinr_imp_duration_th_low_2k_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E +#define reg_tinr_imp_duration_th_low_8k_pos 0 +#define reg_tinr_imp_duration_th_low_8k_len 8 +#define reg_tinr_imp_duration_th_low_8k_lsb 0 +#define xd_r_reg_tinr_counter_7_0 0xA090 +#define reg_tinr_counter_7_0_pos 0 +#define reg_tinr_counter_7_0_len 8 +#define reg_tinr_counter_7_0_lsb 0 +#define xd_r_reg_tinr_counter_15_8 0xA091 +#define reg_tinr_counter_15_8_pos 0 +#define reg_tinr_counter_15_8_len 8 +#define reg_tinr_counter_15_8_lsb 8 +#define xd_p_reg_tinr_adative_tinr_en 0xA093 +#define reg_tinr_adative_tinr_en_pos 0 +#define reg_tinr_adative_tinr_en_len 1 +#define reg_tinr_adative_tinr_en_lsb 0 +#define xd_p_reg_tinr_peak_fifo_size 0xA093 +#define reg_tinr_peak_fifo_size_pos 1 +#define reg_tinr_peak_fifo_size_len 5 +#define reg_tinr_peak_fifo_size_lsb 0 +#define xd_p_reg_tinr_counter_rst 0xA093 +#define reg_tinr_counter_rst_pos 6 +#define reg_tinr_counter_rst_len 1 +#define reg_tinr_counter_rst_lsb 0 +#define xd_p_reg_tinr_search_period_7_0 0xA094 +#define reg_tinr_search_period_7_0_pos 0 +#define reg_tinr_search_period_7_0_len 8 +#define reg_tinr_search_period_7_0_lsb 0 +#define xd_p_reg_tinr_search_period_15_8 0xA095 +#define reg_tinr_search_period_15_8_pos 0 +#define reg_tinr_search_period_15_8_len 8 +#define reg_tinr_search_period_15_8_lsb 8 +#define xd_p_reg_ccifs_fcw_7_0 0xA0A0 +#define reg_ccifs_fcw_7_0_pos 0 +#define reg_ccifs_fcw_7_0_len 8 +#define reg_ccifs_fcw_7_0_lsb 0 +#define xd_p_reg_ccifs_fcw_12_8 0xA0A1 +#define reg_ccifs_fcw_12_8_pos 0 +#define reg_ccifs_fcw_12_8_len 5 +#define reg_ccifs_fcw_12_8_lsb 8 +#define xd_p_reg_ccifs_spec_inv 0xA0A1 +#define reg_ccifs_spec_inv_pos 5 +#define reg_ccifs_spec_inv_len 1 +#define reg_ccifs_spec_inv_lsb 0 +#define xd_p_reg_gp_trigger 0xA0A2 +#define reg_gp_trigger_pos 0 +#define reg_gp_trigger_len 1 +#define reg_gp_trigger_lsb 0 +#define xd_p_reg_trigger_sel 0xA0A2 +#define reg_trigger_sel_pos 1 +#define reg_trigger_sel_len 2 +#define reg_trigger_sel_lsb 0 +#define xd_p_reg_debug_ofdm 0xA0A2 +#define reg_debug_ofdm_pos 3 +#define reg_debug_ofdm_len 2 +#define reg_debug_ofdm_lsb 0 +#define xd_p_reg_trigger_module_sel 0xA0A3 +#define reg_trigger_module_sel_pos 0 +#define reg_trigger_module_sel_len 6 +#define reg_trigger_module_sel_lsb 0 +#define xd_p_reg_trigger_set_sel 0xA0A4 +#define reg_trigger_set_sel_pos 0 +#define reg_trigger_set_sel_len 6 +#define reg_trigger_set_sel_lsb 0 +#define xd_p_reg_fw_int_mask_n 0xA0A4 +#define reg_fw_int_mask_n_pos 6 +#define reg_fw_int_mask_n_len 1 +#define reg_fw_int_mask_n_lsb 0 +#define xd_p_reg_debug_group 0xA0A5 +#define reg_debug_group_pos 0 +#define reg_debug_group_len 4 +#define reg_debug_group_lsb 0 +#define xd_p_reg_odbg_clk_sel 0xA0A5 +#define reg_odbg_clk_sel_pos 4 +#define reg_odbg_clk_sel_len 2 +#define reg_odbg_clk_sel_lsb 0 +#define xd_p_reg_ccif_sc 0xA0C0 +#define reg_ccif_sc_pos 0 +#define reg_ccif_sc_len 4 +#define reg_ccif_sc_lsb 0 +#define xd_r_reg_ccif_saturate 0xA0C1 +#define reg_ccif_saturate_pos 0 +#define reg_ccif_saturate_len 2 +#define reg_ccif_saturate_lsb 0 +#define xd_r_reg_antif_saturate 0xA0C1 +#define reg_antif_saturate_pos 2 +#define reg_antif_saturate_len 4 +#define reg_antif_saturate_lsb 0 +#define xd_r_reg_acif_saturate 0xA0C2 +#define reg_acif_saturate_pos 0 +#define reg_acif_saturate_len 8 +#define reg_acif_saturate_lsb 0 +#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8 +#define reg_tmr_timer0_threshold_7_0_pos 0 +#define reg_tmr_timer0_threshold_7_0_len 8 +#define reg_tmr_timer0_threshold_7_0_lsb 0 +#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9 +#define reg_tmr_timer0_threshold_15_8_pos 0 +#define reg_tmr_timer0_threshold_15_8_len 8 +#define reg_tmr_timer0_threshold_15_8_lsb 8 +#define xd_p_reg_tmr_timer0_enable 0xA0CA +#define reg_tmr_timer0_enable_pos 0 +#define reg_tmr_timer0_enable_len 1 +#define reg_tmr_timer0_enable_lsb 0 +#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA +#define reg_tmr_timer0_clk_sel_pos 1 +#define reg_tmr_timer0_clk_sel_len 1 +#define reg_tmr_timer0_clk_sel_lsb 0 +#define xd_p_reg_tmr_timer0_int 0xA0CA +#define reg_tmr_timer0_int_pos 2 +#define reg_tmr_timer0_int_len 1 +#define reg_tmr_timer0_int_lsb 0 +#define xd_p_reg_tmr_timer0_rst 0xA0CA +#define reg_tmr_timer0_rst_pos 3 +#define reg_tmr_timer0_rst_len 1 +#define reg_tmr_timer0_rst_lsb 0 +#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB +#define reg_tmr_timer0_count_7_0_pos 0 +#define reg_tmr_timer0_count_7_0_len 8 +#define reg_tmr_timer0_count_7_0_lsb 0 +#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC +#define reg_tmr_timer0_count_15_8_pos 0 +#define reg_tmr_timer0_count_15_8_len 8 +#define reg_tmr_timer0_count_15_8_lsb 8 +#define xd_p_reg_suspend 0xA0CD +#define reg_suspend_pos 0 +#define reg_suspend_len 1 +#define reg_suspend_lsb 0 +#define xd_p_reg_suspend_rdy 0xA0CD +#define reg_suspend_rdy_pos 1 +#define reg_suspend_rdy_len 1 +#define reg_suspend_rdy_lsb 0 +#define xd_p_reg_resume 0xA0CD +#define reg_resume_pos 2 +#define reg_resume_len 1 +#define reg_resume_lsb 0 +#define xd_p_reg_resume_rdy 0xA0CD +#define reg_resume_rdy_pos 3 +#define reg_resume_rdy_len 1 +#define reg_resume_rdy_lsb 0 +#define xd_p_reg_fmf 0xA0CE +#define reg_fmf_pos 0 +#define reg_fmf_len 8 +#define reg_fmf_lsb 0 +#define xd_p_ccid_accumulate_num_2k_7_0 0xA100 +#define ccid_accumulate_num_2k_7_0_pos 0 +#define ccid_accumulate_num_2k_7_0_len 8 +#define ccid_accumulate_num_2k_7_0_lsb 0 +#define xd_p_ccid_accumulate_num_2k_12_8 0xA101 +#define ccid_accumulate_num_2k_12_8_pos 0 +#define ccid_accumulate_num_2k_12_8_len 5 +#define ccid_accumulate_num_2k_12_8_lsb 8 +#define xd_p_ccid_accumulate_num_8k_7_0 0xA102 +#define ccid_accumulate_num_8k_7_0_pos 0 +#define ccid_accumulate_num_8k_7_0_len 8 +#define ccid_accumulate_num_8k_7_0_lsb 0 +#define xd_p_ccid_accumulate_num_8k_14_8 0xA103 +#define ccid_accumulate_num_8k_14_8_pos 0 +#define ccid_accumulate_num_8k_14_8_len 7 +#define ccid_accumulate_num_8k_14_8_lsb 8 +#define xd_p_ccid_desired_level_0 0xA103 +#define ccid_desired_level_0_pos 7 +#define ccid_desired_level_0_len 1 +#define ccid_desired_level_0_lsb 0 +#define xd_p_ccid_desired_level_8_1 0xA104 +#define ccid_desired_level_8_1_pos 0 +#define ccid_desired_level_8_1_len 8 +#define ccid_desired_level_8_1_lsb 1 +#define xd_p_ccid_apply_delay 0xA105 +#define ccid_apply_delay_pos 0 +#define ccid_apply_delay_len 7 +#define ccid_apply_delay_lsb 0 +#define xd_p_ccid_CCID_Threshold1 0xA106 +#define ccid_CCID_Threshold1_pos 0 +#define ccid_CCID_Threshold1_len 8 +#define ccid_CCID_Threshold1_lsb 0 +#define xd_p_ccid_CCID_Threshold2 0xA107 +#define ccid_CCID_Threshold2_pos 0 +#define ccid_CCID_Threshold2_len 8 +#define ccid_CCID_Threshold2_lsb 0 +#define xd_p_reg_ccid_gain_scale 0xA108 +#define reg_ccid_gain_scale_pos 0 +#define reg_ccid_gain_scale_len 4 +#define reg_ccid_gain_scale_lsb 0 +#define xd_p_reg_ccid2_passband_gain_set 0xA108 +#define reg_ccid2_passband_gain_set_pos 4 +#define reg_ccid2_passband_gain_set_len 4 +#define reg_ccid2_passband_gain_set_lsb 0 +#define xd_r_ccid_multiplier_7_0 0xA109 +#define ccid_multiplier_7_0_pos 0 +#define ccid_multiplier_7_0_len 8 +#define ccid_multiplier_7_0_lsb 0 +#define xd_r_ccid_multiplier_15_8 0xA10A +#define ccid_multiplier_15_8_pos 0 +#define ccid_multiplier_15_8_len 8 +#define ccid_multiplier_15_8_lsb 8 +#define xd_r_ccid_right_shift_bits 0xA10B +#define ccid_right_shift_bits_pos 0 +#define ccid_right_shift_bits_len 4 +#define ccid_right_shift_bits_lsb 0 +#define xd_r_reg_ccid_sx_7_0 0xA10C +#define reg_ccid_sx_7_0_pos 0 +#define reg_ccid_sx_7_0_len 8 +#define reg_ccid_sx_7_0_lsb 0 +#define xd_r_reg_ccid_sx_15_8 0xA10D +#define reg_ccid_sx_15_8_pos 0 +#define reg_ccid_sx_15_8_len 8 +#define reg_ccid_sx_15_8_lsb 8 +#define xd_r_reg_ccid_sx_21_16 0xA10E +#define reg_ccid_sx_21_16_pos 0 +#define reg_ccid_sx_21_16_len 6 +#define reg_ccid_sx_21_16_lsb 16 +#define xd_r_reg_ccid_sy_7_0 0xA110 +#define reg_ccid_sy_7_0_pos 0 +#define reg_ccid_sy_7_0_len 8 +#define reg_ccid_sy_7_0_lsb 0 +#define xd_r_reg_ccid_sy_15_8 0xA111 +#define reg_ccid_sy_15_8_pos 0 +#define reg_ccid_sy_15_8_len 8 +#define reg_ccid_sy_15_8_lsb 8 +#define xd_r_reg_ccid_sy_23_16 0xA112 +#define reg_ccid_sy_23_16_pos 0 +#define reg_ccid_sy_23_16_len 8 +#define reg_ccid_sy_23_16_lsb 16 +#define xd_r_reg_ccid2_sz_7_0 0xA114 +#define reg_ccid2_sz_7_0_pos 0 +#define reg_ccid2_sz_7_0_len 8 +#define reg_ccid2_sz_7_0_lsb 0 +#define xd_r_reg_ccid2_sz_15_8 0xA115 +#define reg_ccid2_sz_15_8_pos 0 +#define reg_ccid2_sz_15_8_len 8 +#define reg_ccid2_sz_15_8_lsb 8 +#define xd_r_reg_ccid2_sz_23_16 0xA116 +#define reg_ccid2_sz_23_16_pos 0 +#define reg_ccid2_sz_23_16_len 8 +#define reg_ccid2_sz_23_16_lsb 16 +#define xd_r_reg_ccid2_sz_25_24 0xA117 +#define reg_ccid2_sz_25_24_pos 0 +#define reg_ccid2_sz_25_24_len 2 +#define reg_ccid2_sz_25_24_lsb 24 +#define xd_r_reg_ccid2_sy_7_0 0xA118 +#define reg_ccid2_sy_7_0_pos 0 +#define reg_ccid2_sy_7_0_len 8 +#define reg_ccid2_sy_7_0_lsb 0 +#define xd_r_reg_ccid2_sy_15_8 0xA119 +#define reg_ccid2_sy_15_8_pos 0 +#define reg_ccid2_sy_15_8_len 8 +#define reg_ccid2_sy_15_8_lsb 8 +#define xd_r_reg_ccid2_sy_23_16 0xA11A +#define reg_ccid2_sy_23_16_pos 0 +#define reg_ccid2_sy_23_16_len 8 +#define reg_ccid2_sy_23_16_lsb 16 +#define xd_r_reg_ccid2_sy_25_24 0xA11B +#define reg_ccid2_sy_25_24_pos 0 +#define reg_ccid2_sy_25_24_len 2 +#define reg_ccid2_sy_25_24_lsb 24 +#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120 +#define dagc1_accumulate_num_2k_7_0_pos 0 +#define dagc1_accumulate_num_2k_7_0_len 8 +#define dagc1_accumulate_num_2k_7_0_lsb 0 +#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121 +#define dagc1_accumulate_num_2k_12_8_pos 0 +#define dagc1_accumulate_num_2k_12_8_len 5 +#define dagc1_accumulate_num_2k_12_8_lsb 8 +#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122 +#define dagc1_accumulate_num_8k_7_0_pos 0 +#define dagc1_accumulate_num_8k_7_0_len 8 +#define dagc1_accumulate_num_8k_7_0_lsb 0 +#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123 +#define dagc1_accumulate_num_8k_14_8_pos 0 +#define dagc1_accumulate_num_8k_14_8_len 7 +#define dagc1_accumulate_num_8k_14_8_lsb 8 +#define xd_p_dagc1_desired_level_0 0xA123 +#define dagc1_desired_level_0_pos 7 +#define dagc1_desired_level_0_len 1 +#define dagc1_desired_level_0_lsb 0 +#define xd_p_dagc1_desired_level_8_1 0xA124 +#define dagc1_desired_level_8_1_pos 0 +#define dagc1_desired_level_8_1_len 8 +#define dagc1_desired_level_8_1_lsb 1 +#define xd_p_dagc1_apply_delay 0xA125 +#define dagc1_apply_delay_pos 0 +#define dagc1_apply_delay_len 7 +#define dagc1_apply_delay_lsb 0 +#define xd_p_dagc1_bypass_scale_ctl 0xA126 +#define dagc1_bypass_scale_ctl_pos 0 +#define dagc1_bypass_scale_ctl_len 2 +#define dagc1_bypass_scale_ctl_lsb 0 +#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127 +#define reg_dagc1_in_sat_cnt_7_0_pos 0 +#define reg_dagc1_in_sat_cnt_7_0_len 8 +#define reg_dagc1_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128 +#define reg_dagc1_in_sat_cnt_15_8_pos 0 +#define reg_dagc1_in_sat_cnt_15_8_len 8 +#define reg_dagc1_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129 +#define reg_dagc1_in_sat_cnt_23_16_pos 0 +#define reg_dagc1_in_sat_cnt_23_16_len 8 +#define reg_dagc1_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A +#define reg_dagc1_in_sat_cnt_31_24_pos 0 +#define reg_dagc1_in_sat_cnt_31_24_len 8 +#define reg_dagc1_in_sat_cnt_31_24_lsb 24 +#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B +#define reg_dagc1_out_sat_cnt_7_0_pos 0 +#define reg_dagc1_out_sat_cnt_7_0_len 8 +#define reg_dagc1_out_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C +#define reg_dagc1_out_sat_cnt_15_8_pos 0 +#define reg_dagc1_out_sat_cnt_15_8_len 8 +#define reg_dagc1_out_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D +#define reg_dagc1_out_sat_cnt_23_16_pos 0 +#define reg_dagc1_out_sat_cnt_23_16_len 8 +#define reg_dagc1_out_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E +#define reg_dagc1_out_sat_cnt_31_24_pos 0 +#define reg_dagc1_out_sat_cnt_31_24_len 8 +#define reg_dagc1_out_sat_cnt_31_24_lsb 24 +#define xd_r_dagc1_multiplier_7_0 0xA136 +#define dagc1_multiplier_7_0_pos 0 +#define dagc1_multiplier_7_0_len 8 +#define dagc1_multiplier_7_0_lsb 0 +#define xd_r_dagc1_multiplier_15_8 0xA137 +#define dagc1_multiplier_15_8_pos 0 +#define dagc1_multiplier_15_8_len 8 +#define dagc1_multiplier_15_8_lsb 8 +#define xd_r_dagc1_right_shift_bits 0xA138 +#define dagc1_right_shift_bits_pos 0 +#define dagc1_right_shift_bits_len 4 +#define dagc1_right_shift_bits_lsb 0 +#define xd_p_reg_bfs_fcw_7_0 0xA140 +#define reg_bfs_fcw_7_0_pos 0 +#define reg_bfs_fcw_7_0_len 8 +#define reg_bfs_fcw_7_0_lsb 0 +#define xd_p_reg_bfs_fcw_15_8 0xA141 +#define reg_bfs_fcw_15_8_pos 0 +#define reg_bfs_fcw_15_8_len 8 +#define reg_bfs_fcw_15_8_lsb 8 +#define xd_p_reg_bfs_fcw_22_16 0xA142 +#define reg_bfs_fcw_22_16_pos 0 +#define reg_bfs_fcw_22_16_len 7 +#define reg_bfs_fcw_22_16_lsb 16 +#define xd_p_reg_antif_sf_7_0 0xA144 +#define reg_antif_sf_7_0_pos 0 +#define reg_antif_sf_7_0_len 8 +#define reg_antif_sf_7_0_lsb 0 +#define xd_p_reg_antif_sf_11_8 0xA145 +#define reg_antif_sf_11_8_pos 0 +#define reg_antif_sf_11_8_len 4 +#define reg_antif_sf_11_8_lsb 8 +#define xd_r_bfs_fcw_q_7_0 0xA150 +#define bfs_fcw_q_7_0_pos 0 +#define bfs_fcw_q_7_0_len 8 +#define bfs_fcw_q_7_0_lsb 0 +#define xd_r_bfs_fcw_q_15_8 0xA151 +#define bfs_fcw_q_15_8_pos 0 +#define bfs_fcw_q_15_8_len 8 +#define bfs_fcw_q_15_8_lsb 8 +#define xd_r_bfs_fcw_q_22_16 0xA152 +#define bfs_fcw_q_22_16_pos 0 +#define bfs_fcw_q_22_16_len 7 +#define bfs_fcw_q_22_16_lsb 16 +#define xd_p_reg_dca_enu 0xA160 +#define reg_dca_enu_pos 0 +#define reg_dca_enu_len 1 +#define reg_dca_enu_lsb 0 +#define xd_p_reg_dca_enl 0xA160 +#define reg_dca_enl_pos 1 +#define reg_dca_enl_len 1 +#define reg_dca_enl_lsb 0 +#define xd_p_reg_dca_lower_chip 0xA160 +#define reg_dca_lower_chip_pos 2 +#define reg_dca_lower_chip_len 1 +#define reg_dca_lower_chip_lsb 0 +#define xd_p_reg_dca_upper_chip 0xA160 +#define reg_dca_upper_chip_pos 3 +#define reg_dca_upper_chip_len 1 +#define reg_dca_upper_chip_lsb 0 +#define xd_p_reg_dca_platch 0xA160 +#define reg_dca_platch_pos 4 +#define reg_dca_platch_len 1 +#define reg_dca_platch_lsb 0 +#define xd_p_reg_dca_th 0xA161 +#define reg_dca_th_pos 0 +#define reg_dca_th_len 5 +#define reg_dca_th_lsb 0 +#define xd_p_reg_dca_scale 0xA162 +#define reg_dca_scale_pos 0 +#define reg_dca_scale_len 4 +#define reg_dca_scale_lsb 0 +#define xd_p_reg_dca_tone_7_0 0xA163 +#define reg_dca_tone_7_0_pos 0 +#define reg_dca_tone_7_0_len 8 +#define reg_dca_tone_7_0_lsb 0 +#define xd_p_reg_dca_tone_12_8 0xA164 +#define reg_dca_tone_12_8_pos 0 +#define reg_dca_tone_12_8_len 5 +#define reg_dca_tone_12_8_lsb 8 +#define xd_p_reg_dca_time_7_0 0xA165 +#define reg_dca_time_7_0_pos 0 +#define reg_dca_time_7_0_len 8 +#define reg_dca_time_7_0_lsb 0 +#define xd_p_reg_dca_time_15_8 0xA166 +#define reg_dca_time_15_8_pos 0 +#define reg_dca_time_15_8_len 8 +#define reg_dca_time_15_8_lsb 8 +#define xd_r_dcasm 0xA167 +#define dcasm_pos 0 +#define dcasm_len 3 +#define dcasm_lsb 0 +#define xd_p_reg_qnt_valuew_7_0 0xA168 +#define reg_qnt_valuew_7_0_pos 0 +#define reg_qnt_valuew_7_0_len 8 +#define reg_qnt_valuew_7_0_lsb 0 +#define xd_p_reg_qnt_valuew_10_8 0xA169 +#define reg_qnt_valuew_10_8_pos 0 +#define reg_qnt_valuew_10_8_len 3 +#define reg_qnt_valuew_10_8_lsb 8 +#define xd_p_dca_sbx_gain_diff_7_0 0xA16A +#define dca_sbx_gain_diff_7_0_pos 0 +#define dca_sbx_gain_diff_7_0_len 8 +#define dca_sbx_gain_diff_7_0_lsb 0 +#define xd_p_dca_sbx_gain_diff_9_8 0xA16B +#define dca_sbx_gain_diff_9_8_pos 0 +#define dca_sbx_gain_diff_9_8_len 2 +#define dca_sbx_gain_diff_9_8_lsb 8 +#define xd_p_reg_dca_stand_alone 0xA16C +#define reg_dca_stand_alone_pos 0 +#define reg_dca_stand_alone_len 1 +#define reg_dca_stand_alone_lsb 0 +#define xd_p_reg_dca_upper_out_en 0xA16C +#define reg_dca_upper_out_en_pos 1 +#define reg_dca_upper_out_en_len 1 +#define reg_dca_upper_out_en_lsb 0 +#define xd_p_reg_dca_rc_en 0xA16C +#define reg_dca_rc_en_pos 2 +#define reg_dca_rc_en_len 1 +#define reg_dca_rc_en_lsb 0 +#define xd_p_reg_dca_retrain_send 0xA16C +#define reg_dca_retrain_send_pos 3 +#define reg_dca_retrain_send_len 1 +#define reg_dca_retrain_send_lsb 0 +#define xd_p_reg_dca_retrain_rec 0xA16C +#define reg_dca_retrain_rec_pos 4 +#define reg_dca_retrain_rec_len 1 +#define reg_dca_retrain_rec_lsb 0 +#define xd_p_reg_dca_api_tpsrdy 0xA16C +#define reg_dca_api_tpsrdy_pos 5 +#define reg_dca_api_tpsrdy_len 1 +#define reg_dca_api_tpsrdy_lsb 0 +#define xd_p_reg_dca_symbol_gap 0xA16D +#define reg_dca_symbol_gap_pos 0 +#define reg_dca_symbol_gap_len 4 +#define reg_dca_symbol_gap_lsb 0 +#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E +#define reg_qnt_nfvaluew_7_0_pos 0 +#define reg_qnt_nfvaluew_7_0_len 8 +#define reg_qnt_nfvaluew_7_0_lsb 0 +#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F +#define reg_qnt_nfvaluew_10_8_pos 0 +#define reg_qnt_nfvaluew_10_8_len 3 +#define reg_qnt_nfvaluew_10_8_lsb 8 +#define xd_p_reg_qnt_flatness_thr_7_0 0xA170 +#define reg_qnt_flatness_thr_7_0_pos 0 +#define reg_qnt_flatness_thr_7_0_len 8 +#define reg_qnt_flatness_thr_7_0_lsb 0 +#define xd_p_reg_qnt_flatness_thr_9_8 0xA171 +#define reg_qnt_flatness_thr_9_8_pos 0 +#define reg_qnt_flatness_thr_9_8_len 2 +#define reg_qnt_flatness_thr_9_8_lsb 8 +#define xd_p_reg_dca_tone_idx_5_0 0xA171 +#define reg_dca_tone_idx_5_0_pos 2 +#define reg_dca_tone_idx_5_0_len 6 +#define reg_dca_tone_idx_5_0_lsb 0 +#define xd_p_reg_dca_tone_idx_12_6 0xA172 +#define reg_dca_tone_idx_12_6_pos 0 +#define reg_dca_tone_idx_12_6_len 7 +#define reg_dca_tone_idx_12_6_lsb 6 +#define xd_p_reg_dca_data_vld 0xA173 +#define reg_dca_data_vld_pos 0 +#define reg_dca_data_vld_len 1 +#define reg_dca_data_vld_lsb 0 +#define xd_p_reg_dca_read_update 0xA173 +#define reg_dca_read_update_pos 1 +#define reg_dca_read_update_len 1 +#define reg_dca_read_update_lsb 0 +#define xd_r_reg_dca_data_re_5_0 0xA173 +#define reg_dca_data_re_5_0_pos 2 +#define reg_dca_data_re_5_0_len 6 +#define reg_dca_data_re_5_0_lsb 0 +#define xd_r_reg_dca_data_re_10_6 0xA174 +#define reg_dca_data_re_10_6_pos 0 +#define reg_dca_data_re_10_6_len 5 +#define reg_dca_data_re_10_6_lsb 6 +#define xd_r_reg_dca_data_im_7_0 0xA175 +#define reg_dca_data_im_7_0_pos 0 +#define reg_dca_data_im_7_0_len 8 +#define reg_dca_data_im_7_0_lsb 0 +#define xd_r_reg_dca_data_im_10_8 0xA176 +#define reg_dca_data_im_10_8_pos 0 +#define reg_dca_data_im_10_8_len 3 +#define reg_dca_data_im_10_8_lsb 8 +#define xd_r_reg_dca_data_h2_7_0 0xA178 +#define reg_dca_data_h2_7_0_pos 0 +#define reg_dca_data_h2_7_0_len 8 +#define reg_dca_data_h2_7_0_lsb 0 +#define xd_r_reg_dca_data_h2_9_8 0xA179 +#define reg_dca_data_h2_9_8_pos 0 +#define reg_dca_data_h2_9_8_len 2 +#define reg_dca_data_h2_9_8_lsb 8 +#define xd_p_reg_f_adc_7_0 0xA180 +#define reg_f_adc_7_0_pos 0 +#define reg_f_adc_7_0_len 8 +#define reg_f_adc_7_0_lsb 0 +#define xd_p_reg_f_adc_15_8 0xA181 +#define reg_f_adc_15_8_pos 0 +#define reg_f_adc_15_8_len 8 +#define reg_f_adc_15_8_lsb 8 +#define xd_p_reg_f_adc_23_16 0xA182 +#define reg_f_adc_23_16_pos 0 +#define reg_f_adc_23_16_len 8 +#define reg_f_adc_23_16_lsb 16 +#define xd_r_intp_mu_7_0 0xA190 +#define intp_mu_7_0_pos 0 +#define intp_mu_7_0_len 8 +#define intp_mu_7_0_lsb 0 +#define xd_r_intp_mu_15_8 0xA191 +#define intp_mu_15_8_pos 0 +#define intp_mu_15_8_len 8 +#define intp_mu_15_8_lsb 8 +#define xd_r_intp_mu_19_16 0xA192 +#define intp_mu_19_16_pos 0 +#define intp_mu_19_16_len 4 +#define intp_mu_19_16_lsb 16 +#define xd_p_reg_agc_rst 0xA1A0 +#define reg_agc_rst_pos 0 +#define reg_agc_rst_len 1 +#define reg_agc_rst_lsb 0 +#define xd_p_rf_agc_en 0xA1A0 +#define rf_agc_en_pos 1 +#define rf_agc_en_len 1 +#define rf_agc_en_lsb 0 +#define xd_p_rf_agc_dis 0xA1A0 +#define rf_agc_dis_pos 2 +#define rf_agc_dis_len 1 +#define rf_agc_dis_lsb 0 +#define xd_p_if_agc_rst 0xA1A0 +#define if_agc_rst_pos 3 +#define if_agc_rst_len 1 +#define if_agc_rst_lsb 0 +#define xd_p_if_agc_en 0xA1A0 +#define if_agc_en_pos 4 +#define if_agc_en_len 1 +#define if_agc_en_lsb 0 +#define xd_p_if_agc_dis 0xA1A0 +#define if_agc_dis_pos 5 +#define if_agc_dis_len 1 +#define if_agc_dis_lsb 0 +#define xd_p_agc_lock 0xA1A0 +#define agc_lock_pos 6 +#define agc_lock_len 1 +#define agc_lock_lsb 0 +#define xd_p_reg_tinr_rst 0xA1A1 +#define reg_tinr_rst_pos 0 +#define reg_tinr_rst_len 1 +#define reg_tinr_rst_lsb 0 +#define xd_p_reg_tinr_en 0xA1A1 +#define reg_tinr_en_pos 1 +#define reg_tinr_en_len 1 +#define reg_tinr_en_lsb 0 +#define xd_p_reg_ccifs_en 0xA1A2 +#define reg_ccifs_en_pos 0 +#define reg_ccifs_en_len 1 +#define reg_ccifs_en_lsb 0 +#define xd_p_reg_ccifs_dis 0xA1A2 +#define reg_ccifs_dis_pos 1 +#define reg_ccifs_dis_len 1 +#define reg_ccifs_dis_lsb 0 +#define xd_p_reg_ccifs_rst 0xA1A2 +#define reg_ccifs_rst_pos 2 +#define reg_ccifs_rst_len 1 +#define reg_ccifs_rst_lsb 0 +#define xd_p_reg_ccifs_byp 0xA1A2 +#define reg_ccifs_byp_pos 3 +#define reg_ccifs_byp_len 1 +#define reg_ccifs_byp_lsb 0 +#define xd_p_reg_ccif_en 0xA1A3 +#define reg_ccif_en_pos 0 +#define reg_ccif_en_len 1 +#define reg_ccif_en_lsb 0 +#define xd_p_reg_ccif_dis 0xA1A3 +#define reg_ccif_dis_pos 1 +#define reg_ccif_dis_len 1 +#define reg_ccif_dis_lsb 0 +#define xd_p_reg_ccif_rst 0xA1A3 +#define reg_ccif_rst_pos 2 +#define reg_ccif_rst_len 1 +#define reg_ccif_rst_lsb 0 +#define xd_p_reg_ccif_byp 0xA1A3 +#define reg_ccif_byp_pos 3 +#define reg_ccif_byp_len 1 +#define reg_ccif_byp_lsb 0 +#define xd_p_dagc1_rst 0xA1A4 +#define dagc1_rst_pos 0 +#define dagc1_rst_len 1 +#define dagc1_rst_lsb 0 +#define xd_p_dagc1_en 0xA1A4 +#define dagc1_en_pos 1 +#define dagc1_en_len 1 +#define dagc1_en_lsb 0 +#define xd_p_dagc1_mode 0xA1A4 +#define dagc1_mode_pos 2 +#define dagc1_mode_len 2 +#define dagc1_mode_lsb 0 +#define xd_p_dagc1_done 0xA1A4 +#define dagc1_done_pos 4 +#define dagc1_done_len 1 +#define dagc1_done_lsb 0 +#define xd_p_ccid_rst 0xA1A5 +#define ccid_rst_pos 0 +#define ccid_rst_len 1 +#define ccid_rst_lsb 0 +#define xd_p_ccid_en 0xA1A5 +#define ccid_en_pos 1 +#define ccid_en_len 1 +#define ccid_en_lsb 0 +#define xd_p_ccid_mode 0xA1A5 +#define ccid_mode_pos 2 +#define ccid_mode_len 2 +#define ccid_mode_lsb 0 +#define xd_p_ccid_done 0xA1A5 +#define ccid_done_pos 4 +#define ccid_done_len 1 +#define ccid_done_lsb 0 +#define xd_r_ccid_deted 0xA1A5 +#define ccid_deted_pos 5 +#define ccid_deted_len 1 +#define ccid_deted_lsb 0 +#define xd_p_ccid2_en 0xA1A5 +#define ccid2_en_pos 6 +#define ccid2_en_len 1 +#define ccid2_en_lsb 0 +#define xd_p_ccid2_done 0xA1A5 +#define ccid2_done_pos 7 +#define ccid2_done_len 1 +#define ccid2_done_lsb 0 +#define xd_p_reg_bfs_en 0xA1A6 +#define reg_bfs_en_pos 0 +#define reg_bfs_en_len 1 +#define reg_bfs_en_lsb 0 +#define xd_p_reg_bfs_dis 0xA1A6 +#define reg_bfs_dis_pos 1 +#define reg_bfs_dis_len 1 +#define reg_bfs_dis_lsb 0 +#define xd_p_reg_bfs_rst 0xA1A6 +#define reg_bfs_rst_pos 2 +#define reg_bfs_rst_len 1 +#define reg_bfs_rst_lsb 0 +#define xd_p_reg_bfs_byp 0xA1A6 +#define reg_bfs_byp_pos 3 +#define reg_bfs_byp_len 1 +#define reg_bfs_byp_lsb 0 +#define xd_p_reg_antif_en 0xA1A7 +#define reg_antif_en_pos 0 +#define reg_antif_en_len 1 +#define reg_antif_en_lsb 0 +#define xd_p_reg_antif_dis 0xA1A7 +#define reg_antif_dis_pos 1 +#define reg_antif_dis_len 1 +#define reg_antif_dis_lsb 0 +#define xd_p_reg_antif_rst 0xA1A7 +#define reg_antif_rst_pos 2 +#define reg_antif_rst_len 1 +#define reg_antif_rst_lsb 0 +#define xd_p_reg_antif_byp 0xA1A7 +#define reg_antif_byp_pos 3 +#define reg_antif_byp_len 1 +#define reg_antif_byp_lsb 0 +#define xd_p_intp_en 0xA1A8 +#define intp_en_pos 0 +#define intp_en_len 1 +#define intp_en_lsb 0 +#define xd_p_intp_dis 0xA1A8 +#define intp_dis_pos 1 +#define intp_dis_len 1 +#define intp_dis_lsb 0 +#define xd_p_intp_rst 0xA1A8 +#define intp_rst_pos 2 +#define intp_rst_len 1 +#define intp_rst_lsb 0 +#define xd_p_intp_byp 0xA1A8 +#define intp_byp_pos 3 +#define intp_byp_len 1 +#define intp_byp_lsb 0 +#define xd_p_reg_acif_en 0xA1A9 +#define reg_acif_en_pos 0 +#define reg_acif_en_len 1 +#define reg_acif_en_lsb 0 +#define xd_p_reg_acif_dis 0xA1A9 +#define reg_acif_dis_pos 1 +#define reg_acif_dis_len 1 +#define reg_acif_dis_lsb 0 +#define xd_p_reg_acif_rst 0xA1A9 +#define reg_acif_rst_pos 2 +#define reg_acif_rst_len 1 +#define reg_acif_rst_lsb 0 +#define xd_p_reg_acif_byp 0xA1A9 +#define reg_acif_byp_pos 3 +#define reg_acif_byp_len 1 +#define reg_acif_byp_lsb 0 +#define xd_p_reg_acif_sync_mode 0xA1A9 +#define reg_acif_sync_mode_pos 4 +#define reg_acif_sync_mode_len 1 +#define reg_acif_sync_mode_lsb 0 +#define xd_p_dagc2_rst 0xA1AA +#define dagc2_rst_pos 0 +#define dagc2_rst_len 1 +#define dagc2_rst_lsb 0 +#define xd_p_dagc2_en 0xA1AA +#define dagc2_en_pos 1 +#define dagc2_en_len 1 +#define dagc2_en_lsb 0 +#define xd_p_dagc2_mode 0xA1AA +#define dagc2_mode_pos 2 +#define dagc2_mode_len 2 +#define dagc2_mode_lsb 0 +#define xd_p_dagc2_done 0xA1AA +#define dagc2_done_pos 4 +#define dagc2_done_len 1 +#define dagc2_done_lsb 0 +#define xd_p_reg_dca_en 0xA1AB +#define reg_dca_en_pos 0 +#define reg_dca_en_len 1 +#define reg_dca_en_lsb 0 +#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0 +#define dagc2_accumulate_num_2k_7_0_pos 0 +#define dagc2_accumulate_num_2k_7_0_len 8 +#define dagc2_accumulate_num_2k_7_0_lsb 0 +#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1 +#define dagc2_accumulate_num_2k_12_8_pos 0 +#define dagc2_accumulate_num_2k_12_8_len 5 +#define dagc2_accumulate_num_2k_12_8_lsb 8 +#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2 +#define dagc2_accumulate_num_8k_7_0_pos 0 +#define dagc2_accumulate_num_8k_7_0_len 8 +#define dagc2_accumulate_num_8k_7_0_lsb 0 +#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3 +#define dagc2_accumulate_num_8k_12_8_pos 0 +#define dagc2_accumulate_num_8k_12_8_len 5 +#define dagc2_accumulate_num_8k_12_8_lsb 8 +#define xd_p_dagc2_desired_level_2_0 0xA1C3 +#define dagc2_desired_level_2_0_pos 5 +#define dagc2_desired_level_2_0_len 3 +#define dagc2_desired_level_2_0_lsb 0 +#define xd_p_dagc2_desired_level_8_3 0xA1C4 +#define dagc2_desired_level_8_3_pos 0 +#define dagc2_desired_level_8_3_len 6 +#define dagc2_desired_level_8_3_lsb 3 +#define xd_p_dagc2_apply_delay 0xA1C5 +#define dagc2_apply_delay_pos 0 +#define dagc2_apply_delay_len 7 +#define dagc2_apply_delay_lsb 0 +#define xd_p_dagc2_bypass_scale_ctl 0xA1C6 +#define dagc2_bypass_scale_ctl_pos 0 +#define dagc2_bypass_scale_ctl_len 3 +#define dagc2_bypass_scale_ctl_lsb 0 +#define xd_p_dagc2_programmable_shift1 0xA1C7 +#define dagc2_programmable_shift1_pos 0 +#define dagc2_programmable_shift1_len 8 +#define dagc2_programmable_shift1_lsb 0 +#define xd_p_dagc2_programmable_shift2 0xA1C8 +#define dagc2_programmable_shift2_pos 0 +#define dagc2_programmable_shift2_len 8 +#define dagc2_programmable_shift2_lsb 0 +#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9 +#define reg_dagc2_in_sat_cnt_7_0_pos 0 +#define reg_dagc2_in_sat_cnt_7_0_len 8 +#define reg_dagc2_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA +#define reg_dagc2_in_sat_cnt_15_8_pos 0 +#define reg_dagc2_in_sat_cnt_15_8_len 8 +#define reg_dagc2_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB +#define reg_dagc2_in_sat_cnt_23_16_pos 0 +#define reg_dagc2_in_sat_cnt_23_16_len 8 +#define reg_dagc2_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC +#define reg_dagc2_in_sat_cnt_31_24_pos 0 +#define reg_dagc2_in_sat_cnt_31_24_len 8 +#define reg_dagc2_in_sat_cnt_31_24_lsb 24 +#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD +#define reg_dagc2_out_sat_cnt_7_0_pos 0 +#define reg_dagc2_out_sat_cnt_7_0_len 8 +#define reg_dagc2_out_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE +#define reg_dagc2_out_sat_cnt_15_8_pos 0 +#define reg_dagc2_out_sat_cnt_15_8_len 8 +#define reg_dagc2_out_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF +#define reg_dagc2_out_sat_cnt_23_16_pos 0 +#define reg_dagc2_out_sat_cnt_23_16_len 8 +#define reg_dagc2_out_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0 +#define reg_dagc2_out_sat_cnt_31_24_pos 0 +#define reg_dagc2_out_sat_cnt_31_24_len 8 +#define reg_dagc2_out_sat_cnt_31_24_lsb 24 +#define xd_r_dagc2_multiplier_7_0 0xA1D6 +#define dagc2_multiplier_7_0_pos 0 +#define dagc2_multiplier_7_0_len 8 +#define dagc2_multiplier_7_0_lsb 0 +#define xd_r_dagc2_multiplier_15_8 0xA1D7 +#define dagc2_multiplier_15_8_pos 0 +#define dagc2_multiplier_15_8_len 8 +#define dagc2_multiplier_15_8_lsb 8 +#define xd_r_dagc2_right_shift_bits 0xA1D8 +#define dagc2_right_shift_bits_pos 0 +#define dagc2_right_shift_bits_len 4 +#define dagc2_right_shift_bits_lsb 0 +#define xd_p_cfoe_NS_coeff1_7_0 0xA200 +#define cfoe_NS_coeff1_7_0_pos 0 +#define cfoe_NS_coeff1_7_0_len 8 +#define cfoe_NS_coeff1_7_0_lsb 0 +#define xd_p_cfoe_NS_coeff1_15_8 0xA201 +#define cfoe_NS_coeff1_15_8_pos 0 +#define cfoe_NS_coeff1_15_8_len 8 +#define cfoe_NS_coeff1_15_8_lsb 8 +#define xd_p_cfoe_NS_coeff1_23_16 0xA202 +#define cfoe_NS_coeff1_23_16_pos 0 +#define cfoe_NS_coeff1_23_16_len 8 +#define cfoe_NS_coeff1_23_16_lsb 16 +#define xd_p_cfoe_NS_coeff1_25_24 0xA203 +#define cfoe_NS_coeff1_25_24_pos 0 +#define cfoe_NS_coeff1_25_24_len 2 +#define cfoe_NS_coeff1_25_24_lsb 24 +#define xd_p_cfoe_NS_coeff2_5_0 0xA203 +#define cfoe_NS_coeff2_5_0_pos 2 +#define cfoe_NS_coeff2_5_0_len 6 +#define cfoe_NS_coeff2_5_0_lsb 0 +#define xd_p_cfoe_NS_coeff2_13_6 0xA204 +#define cfoe_NS_coeff2_13_6_pos 0 +#define cfoe_NS_coeff2_13_6_len 8 +#define cfoe_NS_coeff2_13_6_lsb 6 +#define xd_p_cfoe_NS_coeff2_21_14 0xA205 +#define cfoe_NS_coeff2_21_14_pos 0 +#define cfoe_NS_coeff2_21_14_len 8 +#define cfoe_NS_coeff2_21_14_lsb 14 +#define xd_p_cfoe_NS_coeff2_24_22 0xA206 +#define cfoe_NS_coeff2_24_22_pos 0 +#define cfoe_NS_coeff2_24_22_len 3 +#define cfoe_NS_coeff2_24_22_lsb 22 +#define xd_p_cfoe_lf_c1_4_0 0xA206 +#define cfoe_lf_c1_4_0_pos 3 +#define cfoe_lf_c1_4_0_len 5 +#define cfoe_lf_c1_4_0_lsb 0 +#define xd_p_cfoe_lf_c1_12_5 0xA207 +#define cfoe_lf_c1_12_5_pos 0 +#define cfoe_lf_c1_12_5_len 8 +#define cfoe_lf_c1_12_5_lsb 5 +#define xd_p_cfoe_lf_c1_20_13 0xA208 +#define cfoe_lf_c1_20_13_pos 0 +#define cfoe_lf_c1_20_13_len 8 +#define cfoe_lf_c1_20_13_lsb 13 +#define xd_p_cfoe_lf_c1_25_21 0xA209 +#define cfoe_lf_c1_25_21_pos 0 +#define cfoe_lf_c1_25_21_len 5 +#define cfoe_lf_c1_25_21_lsb 21 +#define xd_p_cfoe_lf_c2_2_0 0xA209 +#define cfoe_lf_c2_2_0_pos 5 +#define cfoe_lf_c2_2_0_len 3 +#define cfoe_lf_c2_2_0_lsb 0 +#define xd_p_cfoe_lf_c2_10_3 0xA20A +#define cfoe_lf_c2_10_3_pos 0 +#define cfoe_lf_c2_10_3_len 8 +#define cfoe_lf_c2_10_3_lsb 3 +#define xd_p_cfoe_lf_c2_18_11 0xA20B +#define cfoe_lf_c2_18_11_pos 0 +#define cfoe_lf_c2_18_11_len 8 +#define cfoe_lf_c2_18_11_lsb 11 +#define xd_p_cfoe_lf_c2_25_19 0xA20C +#define cfoe_lf_c2_25_19_pos 0 +#define cfoe_lf_c2_25_19_len 7 +#define cfoe_lf_c2_25_19_lsb 19 +#define xd_p_cfoe_ifod_7_0 0xA20D +#define cfoe_ifod_7_0_pos 0 +#define cfoe_ifod_7_0_len 8 +#define cfoe_ifod_7_0_lsb 0 +#define xd_p_cfoe_ifod_10_8 0xA20E +#define cfoe_ifod_10_8_pos 0 +#define cfoe_ifod_10_8_len 3 +#define cfoe_ifod_10_8_lsb 8 +#define xd_p_cfoe_Divg_ctr_th 0xA20E +#define cfoe_Divg_ctr_th_pos 4 +#define cfoe_Divg_ctr_th_len 4 +#define cfoe_Divg_ctr_th_lsb 0 +#define xd_p_cfoe_FOT_divg_th 0xA20F +#define cfoe_FOT_divg_th_pos 0 +#define cfoe_FOT_divg_th_len 8 +#define cfoe_FOT_divg_th_lsb 0 +#define xd_p_cfoe_FOT_cnvg_th 0xA210 +#define cfoe_FOT_cnvg_th_pos 0 +#define cfoe_FOT_cnvg_th_len 8 +#define cfoe_FOT_cnvg_th_lsb 0 +#define xd_p_reg_cfoe_offset_7_0 0xA211 +#define reg_cfoe_offset_7_0_pos 0 +#define reg_cfoe_offset_7_0_len 8 +#define reg_cfoe_offset_7_0_lsb 0 +#define xd_p_reg_cfoe_offset_9_8 0xA212 +#define reg_cfoe_offset_9_8_pos 0 +#define reg_cfoe_offset_9_8_len 2 +#define reg_cfoe_offset_9_8_lsb 8 +#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212 +#define reg_cfoe_ifoe_sign_corr_pos 2 +#define reg_cfoe_ifoe_sign_corr_len 1 +#define reg_cfoe_ifoe_sign_corr_lsb 0 +#define xd_r_cfoe_fot_LF_output_7_0 0xA218 +#define cfoe_fot_LF_output_7_0_pos 0 +#define cfoe_fot_LF_output_7_0_len 8 +#define cfoe_fot_LF_output_7_0_lsb 0 +#define xd_r_cfoe_fot_LF_output_15_8 0xA219 +#define cfoe_fot_LF_output_15_8_pos 0 +#define cfoe_fot_LF_output_15_8_len 8 +#define cfoe_fot_LF_output_15_8_lsb 8 +#define xd_r_cfoe_ifo_metric_7_0 0xA21A +#define cfoe_ifo_metric_7_0_pos 0 +#define cfoe_ifo_metric_7_0_len 8 +#define cfoe_ifo_metric_7_0_lsb 0 +#define xd_r_cfoe_ifo_metric_15_8 0xA21B +#define cfoe_ifo_metric_15_8_pos 0 +#define cfoe_ifo_metric_15_8_len 8 +#define cfoe_ifo_metric_15_8_lsb 8 +#define xd_r_cfoe_ifo_metric_23_16 0xA21C +#define cfoe_ifo_metric_23_16_pos 0 +#define cfoe_ifo_metric_23_16_len 8 +#define cfoe_ifo_metric_23_16_lsb 16 +#define xd_p_ste_Nu 0xA220 +#define ste_Nu_pos 0 +#define ste_Nu_len 2 +#define ste_Nu_lsb 0 +#define xd_p_ste_GI 0xA220 +#define ste_GI_pos 2 +#define ste_GI_len 3 +#define ste_GI_lsb 0 +#define xd_p_ste_symbol_num 0xA221 +#define ste_symbol_num_pos 0 +#define ste_symbol_num_len 2 +#define ste_symbol_num_lsb 0 +#define xd_p_ste_sample_num 0xA221 +#define ste_sample_num_pos 2 +#define ste_sample_num_len 2 +#define ste_sample_num_lsb 0 +#define xd_p_reg_ste_buf_en 0xA221 +#define reg_ste_buf_en_pos 7 +#define reg_ste_buf_en_len 1 +#define reg_ste_buf_en_lsb 0 +#define xd_p_ste_FFT_offset_7_0 0xA222 +#define ste_FFT_offset_7_0_pos 0 +#define ste_FFT_offset_7_0_len 8 +#define ste_FFT_offset_7_0_lsb 0 +#define xd_p_ste_FFT_offset_11_8 0xA223 +#define ste_FFT_offset_11_8_pos 0 +#define ste_FFT_offset_11_8_len 4 +#define ste_FFT_offset_11_8_lsb 8 +#define xd_p_reg_ste_tstmod 0xA223 +#define reg_ste_tstmod_pos 5 +#define reg_ste_tstmod_len 1 +#define reg_ste_tstmod_lsb 0 +#define xd_p_ste_adv_start_7_0 0xA224 +#define ste_adv_start_7_0_pos 0 +#define ste_adv_start_7_0_len 8 +#define ste_adv_start_7_0_lsb 0 +#define xd_p_ste_adv_start_10_8 0xA225 +#define ste_adv_start_10_8_pos 0 +#define ste_adv_start_10_8_len 3 +#define ste_adv_start_10_8_lsb 8 +#define xd_p_ste_adv_stop 0xA226 +#define ste_adv_stop_pos 0 +#define ste_adv_stop_len 8 +#define ste_adv_stop_lsb 0 +#define xd_r_ste_P_value_7_0 0xA228 +#define ste_P_value_7_0_pos 0 +#define ste_P_value_7_0_len 8 +#define ste_P_value_7_0_lsb 0 +#define xd_r_ste_P_value_10_8 0xA229 +#define ste_P_value_10_8_pos 0 +#define ste_P_value_10_8_len 3 +#define ste_P_value_10_8_lsb 8 +#define xd_r_ste_M_value_7_0 0xA22A +#define ste_M_value_7_0_pos 0 +#define ste_M_value_7_0_len 8 +#define ste_M_value_7_0_lsb 0 +#define xd_r_ste_M_value_10_8 0xA22B +#define ste_M_value_10_8_pos 0 +#define ste_M_value_10_8_len 3 +#define ste_M_value_10_8_lsb 8 +#define xd_r_ste_H1 0xA22C +#define ste_H1_pos 0 +#define ste_H1_len 7 +#define ste_H1_lsb 0 +#define xd_r_ste_H2 0xA22D +#define ste_H2_pos 0 +#define ste_H2_len 7 +#define ste_H2_lsb 0 +#define xd_r_ste_H3 0xA22E +#define ste_H3_pos 0 +#define ste_H3_len 7 +#define ste_H3_lsb 0 +#define xd_r_ste_H4 0xA22F +#define ste_H4_pos 0 +#define ste_H4_len 7 +#define ste_H4_lsb 0 +#define xd_r_ste_Corr_value_I_7_0 0xA230 +#define ste_Corr_value_I_7_0_pos 0 +#define ste_Corr_value_I_7_0_len 8 +#define ste_Corr_value_I_7_0_lsb 0 +#define xd_r_ste_Corr_value_I_15_8 0xA231 +#define ste_Corr_value_I_15_8_pos 0 +#define ste_Corr_value_I_15_8_len 8 +#define ste_Corr_value_I_15_8_lsb 8 +#define xd_r_ste_Corr_value_I_23_16 0xA232 +#define ste_Corr_value_I_23_16_pos 0 +#define ste_Corr_value_I_23_16_len 8 +#define ste_Corr_value_I_23_16_lsb 16 +#define xd_r_ste_Corr_value_I_27_24 0xA233 +#define ste_Corr_value_I_27_24_pos 0 +#define ste_Corr_value_I_27_24_len 4 +#define ste_Corr_value_I_27_24_lsb 24 +#define xd_r_ste_Corr_value_Q_7_0 0xA234 +#define ste_Corr_value_Q_7_0_pos 0 +#define ste_Corr_value_Q_7_0_len 8 +#define ste_Corr_value_Q_7_0_lsb 0 +#define xd_r_ste_Corr_value_Q_15_8 0xA235 +#define ste_Corr_value_Q_15_8_pos 0 +#define ste_Corr_value_Q_15_8_len 8 +#define ste_Corr_value_Q_15_8_lsb 8 +#define xd_r_ste_Corr_value_Q_23_16 0xA236 +#define ste_Corr_value_Q_23_16_pos 0 +#define ste_Corr_value_Q_23_16_len 8 +#define ste_Corr_value_Q_23_16_lsb 16 +#define xd_r_ste_Corr_value_Q_27_24 0xA237 +#define ste_Corr_value_Q_27_24_pos 0 +#define ste_Corr_value_Q_27_24_len 4 +#define ste_Corr_value_Q_27_24_lsb 24 +#define xd_r_ste_J_num_7_0 0xA238 +#define ste_J_num_7_0_pos 0 +#define ste_J_num_7_0_len 8 +#define ste_J_num_7_0_lsb 0 +#define xd_r_ste_J_num_15_8 0xA239 +#define ste_J_num_15_8_pos 0 +#define ste_J_num_15_8_len 8 +#define ste_J_num_15_8_lsb 8 +#define xd_r_ste_J_num_23_16 0xA23A +#define ste_J_num_23_16_pos 0 +#define ste_J_num_23_16_len 8 +#define ste_J_num_23_16_lsb 16 +#define xd_r_ste_J_num_31_24 0xA23B +#define ste_J_num_31_24_pos 0 +#define ste_J_num_31_24_len 8 +#define ste_J_num_31_24_lsb 24 +#define xd_r_ste_J_den_7_0 0xA23C +#define ste_J_den_7_0_pos 0 +#define ste_J_den_7_0_len 8 +#define ste_J_den_7_0_lsb 0 +#define xd_r_ste_J_den_15_8 0xA23D +#define ste_J_den_15_8_pos 0 +#define ste_J_den_15_8_len 8 +#define ste_J_den_15_8_lsb 8 +#define xd_r_ste_J_den_18_16 0xA23E +#define ste_J_den_18_16_pos 0 +#define ste_J_den_18_16_len 3 +#define ste_J_den_18_16_lsb 16 +#define xd_r_ste_Beacon_Indicator 0xA23E +#define ste_Beacon_Indicator_pos 4 +#define ste_Beacon_Indicator_len 1 +#define ste_Beacon_Indicator_lsb 0 +#define xd_r_tpsd_Frame_Num 0xA250 +#define tpsd_Frame_Num_pos 0 +#define tpsd_Frame_Num_len 2 +#define tpsd_Frame_Num_lsb 0 +#define xd_r_tpsd_Constel 0xA250 +#define tpsd_Constel_pos 2 +#define tpsd_Constel_len 2 +#define tpsd_Constel_lsb 0 +#define xd_r_tpsd_GI 0xA250 +#define tpsd_GI_pos 4 +#define tpsd_GI_len 2 +#define tpsd_GI_lsb 0 +#define xd_r_tpsd_Mode 0xA250 +#define tpsd_Mode_pos 6 +#define tpsd_Mode_len 2 +#define tpsd_Mode_lsb 0 +#define xd_r_tpsd_CR_HP 0xA251 +#define tpsd_CR_HP_pos 0 +#define tpsd_CR_HP_len 3 +#define tpsd_CR_HP_lsb 0 +#define xd_r_tpsd_CR_LP 0xA251 +#define tpsd_CR_LP_pos 3 +#define tpsd_CR_LP_len 3 +#define tpsd_CR_LP_lsb 0 +#define xd_r_tpsd_Hie 0xA252 +#define tpsd_Hie_pos 0 +#define tpsd_Hie_len 3 +#define tpsd_Hie_lsb 0 +#define xd_r_tpsd_Res_Bits 0xA252 +#define tpsd_Res_Bits_pos 3 +#define tpsd_Res_Bits_len 5 +#define tpsd_Res_Bits_lsb 0 +#define xd_r_tpsd_Res_Bits_0 0xA253 +#define tpsd_Res_Bits_0_pos 0 +#define tpsd_Res_Bits_0_len 1 +#define tpsd_Res_Bits_0_lsb 0 +#define xd_r_tpsd_LengthInd 0xA253 +#define tpsd_LengthInd_pos 1 +#define tpsd_LengthInd_len 6 +#define tpsd_LengthInd_lsb 0 +#define xd_r_tpsd_Cell_Id_7_0 0xA254 +#define tpsd_Cell_Id_7_0_pos 0 +#define tpsd_Cell_Id_7_0_len 8 +#define tpsd_Cell_Id_7_0_lsb 0 +#define xd_r_tpsd_Cell_Id_15_8 0xA255 +#define tpsd_Cell_Id_15_8_pos 0 +#define tpsd_Cell_Id_15_8_len 8 +#define tpsd_Cell_Id_15_8_lsb 0 +#define xd_p_reg_fft_mask_tone0_7_0 0xA260 +#define reg_fft_mask_tone0_7_0_pos 0 +#define reg_fft_mask_tone0_7_0_len 8 +#define reg_fft_mask_tone0_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone0_12_8 0xA261 +#define reg_fft_mask_tone0_12_8_pos 0 +#define reg_fft_mask_tone0_12_8_len 5 +#define reg_fft_mask_tone0_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone1_7_0 0xA262 +#define reg_fft_mask_tone1_7_0_pos 0 +#define reg_fft_mask_tone1_7_0_len 8 +#define reg_fft_mask_tone1_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone1_12_8 0xA263 +#define reg_fft_mask_tone1_12_8_pos 0 +#define reg_fft_mask_tone1_12_8_len 5 +#define reg_fft_mask_tone1_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone2_7_0 0xA264 +#define reg_fft_mask_tone2_7_0_pos 0 +#define reg_fft_mask_tone2_7_0_len 8 +#define reg_fft_mask_tone2_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone2_12_8 0xA265 +#define reg_fft_mask_tone2_12_8_pos 0 +#define reg_fft_mask_tone2_12_8_len 5 +#define reg_fft_mask_tone2_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone3_7_0 0xA266 +#define reg_fft_mask_tone3_7_0_pos 0 +#define reg_fft_mask_tone3_7_0_len 8 +#define reg_fft_mask_tone3_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone3_12_8 0xA267 +#define reg_fft_mask_tone3_12_8_pos 0 +#define reg_fft_mask_tone3_12_8_len 5 +#define reg_fft_mask_tone3_12_8_lsb 8 +#define xd_p_reg_fft_mask_from0_7_0 0xA268 +#define reg_fft_mask_from0_7_0_pos 0 +#define reg_fft_mask_from0_7_0_len 8 +#define reg_fft_mask_from0_7_0_lsb 0 +#define xd_p_reg_fft_mask_from0_12_8 0xA269 +#define reg_fft_mask_from0_12_8_pos 0 +#define reg_fft_mask_from0_12_8_len 5 +#define reg_fft_mask_from0_12_8_lsb 8 +#define xd_p_reg_fft_mask_to0_7_0 0xA26A +#define reg_fft_mask_to0_7_0_pos 0 +#define reg_fft_mask_to0_7_0_len 8 +#define reg_fft_mask_to0_7_0_lsb 0 +#define xd_p_reg_fft_mask_to0_12_8 0xA26B +#define reg_fft_mask_to0_12_8_pos 0 +#define reg_fft_mask_to0_12_8_len 5 +#define reg_fft_mask_to0_12_8_lsb 8 +#define xd_p_reg_fft_mask_from1_7_0 0xA26C +#define reg_fft_mask_from1_7_0_pos 0 +#define reg_fft_mask_from1_7_0_len 8 +#define reg_fft_mask_from1_7_0_lsb 0 +#define xd_p_reg_fft_mask_from1_12_8 0xA26D +#define reg_fft_mask_from1_12_8_pos 0 +#define reg_fft_mask_from1_12_8_len 5 +#define reg_fft_mask_from1_12_8_lsb 8 +#define xd_p_reg_fft_mask_to1_7_0 0xA26E +#define reg_fft_mask_to1_7_0_pos 0 +#define reg_fft_mask_to1_7_0_len 8 +#define reg_fft_mask_to1_7_0_lsb 0 +#define xd_p_reg_fft_mask_to1_12_8 0xA26F +#define reg_fft_mask_to1_12_8_pos 0 +#define reg_fft_mask_to1_12_8_len 5 +#define reg_fft_mask_to1_12_8_lsb 8 +#define xd_p_reg_cge_idx0_7_0 0xA280 +#define reg_cge_idx0_7_0_pos 0 +#define reg_cge_idx0_7_0_len 8 +#define reg_cge_idx0_7_0_lsb 0 +#define xd_p_reg_cge_idx0_12_8 0xA281 +#define reg_cge_idx0_12_8_pos 0 +#define reg_cge_idx0_12_8_len 5 +#define reg_cge_idx0_12_8_lsb 8 +#define xd_p_reg_cge_idx1_7_0 0xA282 +#define reg_cge_idx1_7_0_pos 0 +#define reg_cge_idx1_7_0_len 8 +#define reg_cge_idx1_7_0_lsb 0 +#define xd_p_reg_cge_idx1_12_8 0xA283 +#define reg_cge_idx1_12_8_pos 0 +#define reg_cge_idx1_12_8_len 5 +#define reg_cge_idx1_12_8_lsb 8 +#define xd_p_reg_cge_idx2_7_0 0xA284 +#define reg_cge_idx2_7_0_pos 0 +#define reg_cge_idx2_7_0_len 8 +#define reg_cge_idx2_7_0_lsb 0 +#define xd_p_reg_cge_idx2_12_8 0xA285 +#define reg_cge_idx2_12_8_pos 0 +#define reg_cge_idx2_12_8_len 5 +#define reg_cge_idx2_12_8_lsb 8 +#define xd_p_reg_cge_idx3_7_0 0xA286 +#define reg_cge_idx3_7_0_pos 0 +#define reg_cge_idx3_7_0_len 8 +#define reg_cge_idx3_7_0_lsb 0 +#define xd_p_reg_cge_idx3_12_8 0xA287 +#define reg_cge_idx3_12_8_pos 0 +#define reg_cge_idx3_12_8_len 5 +#define reg_cge_idx3_12_8_lsb 8 +#define xd_p_reg_cge_idx4_7_0 0xA288 +#define reg_cge_idx4_7_0_pos 0 +#define reg_cge_idx4_7_0_len 8 +#define reg_cge_idx4_7_0_lsb 0 +#define xd_p_reg_cge_idx4_12_8 0xA289 +#define reg_cge_idx4_12_8_pos 0 +#define reg_cge_idx4_12_8_len 5 +#define reg_cge_idx4_12_8_lsb 8 +#define xd_p_reg_cge_idx5_7_0 0xA28A +#define reg_cge_idx5_7_0_pos 0 +#define reg_cge_idx5_7_0_len 8 +#define reg_cge_idx5_7_0_lsb 0 +#define xd_p_reg_cge_idx5_12_8 0xA28B +#define reg_cge_idx5_12_8_pos 0 +#define reg_cge_idx5_12_8_len 5 +#define reg_cge_idx5_12_8_lsb 8 +#define xd_p_reg_cge_idx6_7_0 0xA28C +#define reg_cge_idx6_7_0_pos 0 +#define reg_cge_idx6_7_0_len 8 +#define reg_cge_idx6_7_0_lsb 0 +#define xd_p_reg_cge_idx6_12_8 0xA28D +#define reg_cge_idx6_12_8_pos 0 +#define reg_cge_idx6_12_8_len 5 +#define reg_cge_idx6_12_8_lsb 8 +#define xd_p_reg_cge_idx7_7_0 0xA28E +#define reg_cge_idx7_7_0_pos 0 +#define reg_cge_idx7_7_0_len 8 +#define reg_cge_idx7_7_0_lsb 0 +#define xd_p_reg_cge_idx7_12_8 0xA28F +#define reg_cge_idx7_12_8_pos 0 +#define reg_cge_idx7_12_8_len 5 +#define reg_cge_idx7_12_8_lsb 8 +#define xd_p_reg_cge_idx8_7_0 0xA290 +#define reg_cge_idx8_7_0_pos 0 +#define reg_cge_idx8_7_0_len 8 +#define reg_cge_idx8_7_0_lsb 0 +#define xd_p_reg_cge_idx8_12_8 0xA291 +#define reg_cge_idx8_12_8_pos 0 +#define reg_cge_idx8_12_8_len 5 +#define reg_cge_idx8_12_8_lsb 8 +#define xd_p_reg_cge_idx9_7_0 0xA292 +#define reg_cge_idx9_7_0_pos 0 +#define reg_cge_idx9_7_0_len 8 +#define reg_cge_idx9_7_0_lsb 0 +#define xd_p_reg_cge_idx9_12_8 0xA293 +#define reg_cge_idx9_12_8_pos 0 +#define reg_cge_idx9_12_8_len 5 +#define reg_cge_idx9_12_8_lsb 8 +#define xd_p_reg_cge_idx10_7_0 0xA294 +#define reg_cge_idx10_7_0_pos 0 +#define reg_cge_idx10_7_0_len 8 +#define reg_cge_idx10_7_0_lsb 0 +#define xd_p_reg_cge_idx10_12_8 0xA295 +#define reg_cge_idx10_12_8_pos 0 +#define reg_cge_idx10_12_8_len 5 +#define reg_cge_idx10_12_8_lsb 8 +#define xd_p_reg_cge_idx11_7_0 0xA296 +#define reg_cge_idx11_7_0_pos 0 +#define reg_cge_idx11_7_0_len 8 +#define reg_cge_idx11_7_0_lsb 0 +#define xd_p_reg_cge_idx11_12_8 0xA297 +#define reg_cge_idx11_12_8_pos 0 +#define reg_cge_idx11_12_8_len 5 +#define reg_cge_idx11_12_8_lsb 8 +#define xd_p_reg_cge_idx12_7_0 0xA298 +#define reg_cge_idx12_7_0_pos 0 +#define reg_cge_idx12_7_0_len 8 +#define reg_cge_idx12_7_0_lsb 0 +#define xd_p_reg_cge_idx12_12_8 0xA299 +#define reg_cge_idx12_12_8_pos 0 +#define reg_cge_idx12_12_8_len 5 +#define reg_cge_idx12_12_8_lsb 8 +#define xd_p_reg_cge_idx13_7_0 0xA29A +#define reg_cge_idx13_7_0_pos 0 +#define reg_cge_idx13_7_0_len 8 +#define reg_cge_idx13_7_0_lsb 0 +#define xd_p_reg_cge_idx13_12_8 0xA29B +#define reg_cge_idx13_12_8_pos 0 +#define reg_cge_idx13_12_8_len 5 +#define reg_cge_idx13_12_8_lsb 8 +#define xd_p_reg_cge_idx14_7_0 0xA29C +#define reg_cge_idx14_7_0_pos 0 +#define reg_cge_idx14_7_0_len 8 +#define reg_cge_idx14_7_0_lsb 0 +#define xd_p_reg_cge_idx14_12_8 0xA29D +#define reg_cge_idx14_12_8_pos 0 +#define reg_cge_idx14_12_8_len 5 +#define reg_cge_idx14_12_8_lsb 8 +#define xd_p_reg_cge_idx15_7_0 0xA29E +#define reg_cge_idx15_7_0_pos 0 +#define reg_cge_idx15_7_0_len 8 +#define reg_cge_idx15_7_0_lsb 0 +#define xd_p_reg_cge_idx15_12_8 0xA29F +#define reg_cge_idx15_12_8_pos 0 +#define reg_cge_idx15_12_8_len 5 +#define reg_cge_idx15_12_8_lsb 8 +#define xd_r_reg_fft_crc 0xA2A8 +#define reg_fft_crc_pos 0 +#define reg_fft_crc_len 8 +#define reg_fft_crc_lsb 0 +#define xd_p_fd_fft_shift_max 0xA2A9 +#define fd_fft_shift_max_pos 0 +#define fd_fft_shift_max_len 4 +#define fd_fft_shift_max_lsb 0 +#define xd_r_fd_fft_shift 0xA2A9 +#define fd_fft_shift_pos 4 +#define fd_fft_shift_len 4 +#define fd_fft_shift_lsb 0 +#define xd_r_fd_fft_frame_num 0xA2AA +#define fd_fft_frame_num_pos 0 +#define fd_fft_frame_num_len 2 +#define fd_fft_frame_num_lsb 0 +#define xd_r_fd_fft_symbol_count 0xA2AB +#define fd_fft_symbol_count_pos 0 +#define fd_fft_symbol_count_len 7 +#define fd_fft_symbol_count_lsb 0 +#define xd_r_reg_fft_idx_max_7_0 0xA2AC +#define reg_fft_idx_max_7_0_pos 0 +#define reg_fft_idx_max_7_0_len 8 +#define reg_fft_idx_max_7_0_lsb 0 +#define xd_r_reg_fft_idx_max_12_8 0xA2AD +#define reg_fft_idx_max_12_8_pos 0 +#define reg_fft_idx_max_12_8_len 5 +#define reg_fft_idx_max_12_8_lsb 8 +#define xd_p_reg_cge_program 0xA2AE +#define reg_cge_program_pos 0 +#define reg_cge_program_len 1 +#define reg_cge_program_lsb 0 +#define xd_p_reg_cge_fixed 0xA2AE +#define reg_cge_fixed_pos 1 +#define reg_cge_fixed_len 1 +#define reg_cge_fixed_lsb 0 +#define xd_p_reg_fft_rotate_en 0xA2AE +#define reg_fft_rotate_en_pos 2 +#define reg_fft_rotate_en_len 1 +#define reg_fft_rotate_en_lsb 0 +#define xd_p_reg_fft_rotate_base_4_0 0xA2AE +#define reg_fft_rotate_base_4_0_pos 3 +#define reg_fft_rotate_base_4_0_len 5 +#define reg_fft_rotate_base_4_0_lsb 0 +#define xd_p_reg_fft_rotate_base_12_5 0xA2AF +#define reg_fft_rotate_base_12_5_pos 0 +#define reg_fft_rotate_base_12_5_len 8 +#define reg_fft_rotate_base_12_5_lsb 5 +#define xd_p_reg_gp_trigger_fd 0xA2B8 +#define reg_gp_trigger_fd_pos 0 +#define reg_gp_trigger_fd_len 1 +#define reg_gp_trigger_fd_lsb 0 +#define xd_p_reg_trigger_sel_fd 0xA2B8 +#define reg_trigger_sel_fd_pos 1 +#define reg_trigger_sel_fd_len 2 +#define reg_trigger_sel_fd_lsb 0 +#define xd_p_reg_trigger_module_sel_fd 0xA2B9 +#define reg_trigger_module_sel_fd_pos 0 +#define reg_trigger_module_sel_fd_len 6 +#define reg_trigger_module_sel_fd_lsb 0 +#define xd_p_reg_trigger_set_sel_fd 0xA2BA +#define reg_trigger_set_sel_fd_pos 0 +#define reg_trigger_set_sel_fd_len 6 +#define reg_trigger_set_sel_fd_lsb 0 +#define xd_p_reg_fd_noname_7_0 0xA2BC +#define reg_fd_noname_7_0_pos 0 +#define reg_fd_noname_7_0_len 8 +#define reg_fd_noname_7_0_lsb 0 +#define xd_p_reg_fd_noname_15_8 0xA2BD +#define reg_fd_noname_15_8_pos 0 +#define reg_fd_noname_15_8_len 8 +#define reg_fd_noname_15_8_lsb 8 +#define xd_p_reg_fd_noname_23_16 0xA2BE +#define reg_fd_noname_23_16_pos 0 +#define reg_fd_noname_23_16_len 8 +#define reg_fd_noname_23_16_lsb 16 +#define xd_p_reg_fd_noname_31_24 0xA2BF +#define reg_fd_noname_31_24_pos 0 +#define reg_fd_noname_31_24_len 8 +#define reg_fd_noname_31_24_lsb 24 +#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0 +#define fd_fpcc_cp_corr_signn_pos 0 +#define fd_fpcc_cp_corr_signn_len 8 +#define fd_fpcc_cp_corr_signn_lsb 0 +#define xd_p_reg_feq_s1 0xA2C1 +#define reg_feq_s1_pos 0 +#define reg_feq_s1_len 5 +#define reg_feq_s1_lsb 0 +#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2 +#define fd_fpcc_cp_corr_tone_th_pos 0 +#define fd_fpcc_cp_corr_tone_th_len 6 +#define fd_fpcc_cp_corr_tone_th_lsb 0 +#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3 +#define fd_fpcc_cp_corr_symbol_log_th_pos 0 +#define fd_fpcc_cp_corr_symbol_log_th_len 4 +#define fd_fpcc_cp_corr_symbol_log_th_lsb 0 +#define xd_p_fd_fpcc_cp_corr_int 0xA2C4 +#define fd_fpcc_cp_corr_int_pos 0 +#define fd_fpcc_cp_corr_int_len 1 +#define fd_fpcc_cp_corr_int_lsb 0 +#define xd_p_reg_sfoe_ns_7_0 0xA320 +#define reg_sfoe_ns_7_0_pos 0 +#define reg_sfoe_ns_7_0_len 8 +#define reg_sfoe_ns_7_0_lsb 0 +#define xd_p_reg_sfoe_ns_14_8 0xA321 +#define reg_sfoe_ns_14_8_pos 0 +#define reg_sfoe_ns_14_8_len 7 +#define reg_sfoe_ns_14_8_lsb 8 +#define xd_p_reg_sfoe_c1_7_0 0xA322 +#define reg_sfoe_c1_7_0_pos 0 +#define reg_sfoe_c1_7_0_len 8 +#define reg_sfoe_c1_7_0_lsb 0 +#define xd_p_reg_sfoe_c1_15_8 0xA323 +#define reg_sfoe_c1_15_8_pos 0 +#define reg_sfoe_c1_15_8_len 8 +#define reg_sfoe_c1_15_8_lsb 8 +#define xd_p_reg_sfoe_c1_17_16 0xA324 +#define reg_sfoe_c1_17_16_pos 0 +#define reg_sfoe_c1_17_16_len 2 +#define reg_sfoe_c1_17_16_lsb 16 +#define xd_p_reg_sfoe_c2_7_0 0xA325 +#define reg_sfoe_c2_7_0_pos 0 +#define reg_sfoe_c2_7_0_len 8 +#define reg_sfoe_c2_7_0_lsb 0 +#define xd_p_reg_sfoe_c2_15_8 0xA326 +#define reg_sfoe_c2_15_8_pos 0 +#define reg_sfoe_c2_15_8_len 8 +#define reg_sfoe_c2_15_8_lsb 8 +#define xd_p_reg_sfoe_c2_17_16 0xA327 +#define reg_sfoe_c2_17_16_pos 0 +#define reg_sfoe_c2_17_16_len 2 +#define reg_sfoe_c2_17_16_lsb 16 +#define xd_r_reg_sfoe_out_9_2 0xA328 +#define reg_sfoe_out_9_2_pos 0 +#define reg_sfoe_out_9_2_len 8 +#define reg_sfoe_out_9_2_lsb 0 +#define xd_r_reg_sfoe_out_1_0 0xA329 +#define reg_sfoe_out_1_0_pos 0 +#define reg_sfoe_out_1_0_len 2 +#define reg_sfoe_out_1_0_lsb 0 +#define xd_p_reg_sfoe_lm_counter_th 0xA32A +#define reg_sfoe_lm_counter_th_pos 0 +#define reg_sfoe_lm_counter_th_len 4 +#define reg_sfoe_lm_counter_th_lsb 0 +#define xd_p_reg_sfoe_convg_th 0xA32B +#define reg_sfoe_convg_th_pos 0 +#define reg_sfoe_convg_th_len 8 +#define reg_sfoe_convg_th_lsb 0 +#define xd_p_reg_sfoe_divg_th 0xA32C +#define reg_sfoe_divg_th_pos 0 +#define reg_sfoe_divg_th_len 8 +#define reg_sfoe_divg_th_lsb 0 +#define xd_p_fd_tpsd_en 0xA330 +#define fd_tpsd_en_pos 0 +#define fd_tpsd_en_len 1 +#define fd_tpsd_en_lsb 0 +#define xd_p_fd_tpsd_dis 0xA330 +#define fd_tpsd_dis_pos 1 +#define fd_tpsd_dis_len 1 +#define fd_tpsd_dis_lsb 0 +#define xd_p_fd_tpsd_rst 0xA330 +#define fd_tpsd_rst_pos 2 +#define fd_tpsd_rst_len 1 +#define fd_tpsd_rst_lsb 0 +#define xd_p_fd_tpsd_lock 0xA330 +#define fd_tpsd_lock_pos 3 +#define fd_tpsd_lock_len 1 +#define fd_tpsd_lock_lsb 0 +#define xd_r_fd_tpsd_s19 0xA330 +#define fd_tpsd_s19_pos 4 +#define fd_tpsd_s19_len 1 +#define fd_tpsd_s19_lsb 0 +#define xd_r_fd_tpsd_s17 0xA330 +#define fd_tpsd_s17_pos 5 +#define fd_tpsd_s17_len 1 +#define fd_tpsd_s17_lsb 0 +#define xd_p_fd_sfr_ste_en 0xA331 +#define fd_sfr_ste_en_pos 0 +#define fd_sfr_ste_en_len 1 +#define fd_sfr_ste_en_lsb 0 +#define xd_p_fd_sfr_ste_dis 0xA331 +#define fd_sfr_ste_dis_pos 1 +#define fd_sfr_ste_dis_len 1 +#define fd_sfr_ste_dis_lsb 0 +#define xd_p_fd_sfr_ste_rst 0xA331 +#define fd_sfr_ste_rst_pos 2 +#define fd_sfr_ste_rst_len 1 +#define fd_sfr_ste_rst_lsb 0 +#define xd_p_fd_sfr_ste_mode 0xA331 +#define fd_sfr_ste_mode_pos 3 +#define fd_sfr_ste_mode_len 1 +#define fd_sfr_ste_mode_lsb 0 +#define xd_p_fd_sfr_ste_done 0xA331 +#define fd_sfr_ste_done_pos 4 +#define fd_sfr_ste_done_len 1 +#define fd_sfr_ste_done_lsb 0 +#define xd_p_reg_cfoe_ffoe_en 0xA332 +#define reg_cfoe_ffoe_en_pos 0 +#define reg_cfoe_ffoe_en_len 1 +#define reg_cfoe_ffoe_en_lsb 0 +#define xd_p_reg_cfoe_ffoe_dis 0xA332 +#define reg_cfoe_ffoe_dis_pos 1 +#define reg_cfoe_ffoe_dis_len 1 +#define reg_cfoe_ffoe_dis_lsb 0 +#define xd_p_reg_cfoe_ffoe_rst 0xA332 +#define reg_cfoe_ffoe_rst_pos 2 +#define reg_cfoe_ffoe_rst_len 1 +#define reg_cfoe_ffoe_rst_lsb 0 +#define xd_p_reg_cfoe_ifoe_en 0xA332 +#define reg_cfoe_ifoe_en_pos 3 +#define reg_cfoe_ifoe_en_len 1 +#define reg_cfoe_ifoe_en_lsb 0 +#define xd_p_reg_cfoe_ifoe_dis 0xA332 +#define reg_cfoe_ifoe_dis_pos 4 +#define reg_cfoe_ifoe_dis_len 1 +#define reg_cfoe_ifoe_dis_lsb 0 +#define xd_p_reg_cfoe_ifoe_rst 0xA332 +#define reg_cfoe_ifoe_rst_pos 5 +#define reg_cfoe_ifoe_rst_len 1 +#define reg_cfoe_ifoe_rst_lsb 0 +#define xd_p_reg_cfoe_fot_en 0xA332 +#define reg_cfoe_fot_en_pos 6 +#define reg_cfoe_fot_en_len 1 +#define reg_cfoe_fot_en_lsb 0 +#define xd_p_reg_cfoe_fot_lm_en 0xA332 +#define reg_cfoe_fot_lm_en_pos 7 +#define reg_cfoe_fot_lm_en_len 1 +#define reg_cfoe_fot_lm_en_lsb 0 +#define xd_p_reg_cfoe_fot_rst 0xA333 +#define reg_cfoe_fot_rst_pos 0 +#define reg_cfoe_fot_rst_len 1 +#define reg_cfoe_fot_rst_lsb 0 +#define xd_r_fd_cfoe_ffoe_done 0xA333 +#define fd_cfoe_ffoe_done_pos 1 +#define fd_cfoe_ffoe_done_len 1 +#define fd_cfoe_ffoe_done_lsb 0 +#define xd_p_fd_cfoe_metric_vld 0xA333 +#define fd_cfoe_metric_vld_pos 2 +#define fd_cfoe_metric_vld_len 1 +#define fd_cfoe_metric_vld_lsb 0 +#define xd_p_reg_cfoe_ifod_vld 0xA333 +#define reg_cfoe_ifod_vld_pos 3 +#define reg_cfoe_ifod_vld_len 1 +#define reg_cfoe_ifod_vld_lsb 0 +#define xd_r_fd_cfoe_ifoe_done 0xA333 +#define fd_cfoe_ifoe_done_pos 4 +#define fd_cfoe_ifoe_done_len 1 +#define fd_cfoe_ifoe_done_lsb 0 +#define xd_r_fd_cfoe_fot_valid 0xA333 +#define fd_cfoe_fot_valid_pos 5 +#define fd_cfoe_fot_valid_len 1 +#define fd_cfoe_fot_valid_lsb 0 +#define xd_p_reg_cfoe_divg_int 0xA333 +#define reg_cfoe_divg_int_pos 6 +#define reg_cfoe_divg_int_len 1 +#define reg_cfoe_divg_int_lsb 0 +#define xd_r_reg_cfoe_divg_flag 0xA333 +#define reg_cfoe_divg_flag_pos 7 +#define reg_cfoe_divg_flag_len 1 +#define reg_cfoe_divg_flag_lsb 0 +#define xd_p_reg_sfoe_en 0xA334 +#define reg_sfoe_en_pos 0 +#define reg_sfoe_en_len 1 +#define reg_sfoe_en_lsb 0 +#define xd_p_reg_sfoe_dis 0xA334 +#define reg_sfoe_dis_pos 1 +#define reg_sfoe_dis_len 1 +#define reg_sfoe_dis_lsb 0 +#define xd_p_reg_sfoe_rst 0xA334 +#define reg_sfoe_rst_pos 2 +#define reg_sfoe_rst_len 1 +#define reg_sfoe_rst_lsb 0 +#define xd_p_reg_sfoe_vld_int 0xA334 +#define reg_sfoe_vld_int_pos 3 +#define reg_sfoe_vld_int_len 1 +#define reg_sfoe_vld_int_lsb 0 +#define xd_p_reg_sfoe_lm_en 0xA334 +#define reg_sfoe_lm_en_pos 4 +#define reg_sfoe_lm_en_len 1 +#define reg_sfoe_lm_en_lsb 0 +#define xd_p_reg_sfoe_divg_int 0xA334 +#define reg_sfoe_divg_int_pos 5 +#define reg_sfoe_divg_int_len 1 +#define reg_sfoe_divg_int_lsb 0 +#define xd_r_reg_sfoe_divg_flag 0xA334 +#define reg_sfoe_divg_flag_pos 6 +#define reg_sfoe_divg_flag_len 1 +#define reg_sfoe_divg_flag_lsb 0 +#define xd_p_reg_fft_rst 0xA335 +#define reg_fft_rst_pos 0 +#define reg_fft_rst_len 1 +#define reg_fft_rst_lsb 0 +#define xd_p_reg_fft_fast_beacon 0xA335 +#define reg_fft_fast_beacon_pos 1 +#define reg_fft_fast_beacon_len 1 +#define reg_fft_fast_beacon_lsb 0 +#define xd_p_reg_fft_fast_valid 0xA335 +#define reg_fft_fast_valid_pos 2 +#define reg_fft_fast_valid_len 1 +#define reg_fft_fast_valid_lsb 0 +#define xd_p_reg_fft_mask_en 0xA335 +#define reg_fft_mask_en_pos 3 +#define reg_fft_mask_en_len 1 +#define reg_fft_mask_en_lsb 0 +#define xd_p_reg_fft_crc_en 0xA335 +#define reg_fft_crc_en_pos 4 +#define reg_fft_crc_en_len 1 +#define reg_fft_crc_en_lsb 0 +#define xd_p_reg_finr_en 0xA336 +#define reg_finr_en_pos 0 +#define reg_finr_en_len 1 +#define reg_finr_en_lsb 0 +#define xd_p_fd_fste_en 0xA337 +#define fd_fste_en_pos 1 +#define fd_fste_en_len 1 +#define fd_fste_en_lsb 0 +#define xd_p_fd_sqi_tps_level_shift 0xA338 +#define fd_sqi_tps_level_shift_pos 0 +#define fd_sqi_tps_level_shift_len 8 +#define fd_sqi_tps_level_shift_lsb 0 +#define xd_p_fd_pilot_ma_len 0xA339 +#define fd_pilot_ma_len_pos 0 +#define fd_pilot_ma_len_len 6 +#define fd_pilot_ma_len_lsb 0 +#define xd_p_fd_tps_ma_len 0xA33A +#define fd_tps_ma_len_pos 0 +#define fd_tps_ma_len_len 6 +#define fd_tps_ma_len_lsb 0 +#define xd_p_fd_sqi_s3 0xA33B +#define fd_sqi_s3_pos 0 +#define fd_sqi_s3_len 8 +#define fd_sqi_s3_lsb 0 +#define xd_p_fd_sqi_dummy_reg_0 0xA33C +#define fd_sqi_dummy_reg_0_pos 0 +#define fd_sqi_dummy_reg_0_len 1 +#define fd_sqi_dummy_reg_0_lsb 0 +#define xd_p_fd_sqi_debug_sel 0xA33C +#define fd_sqi_debug_sel_pos 1 +#define fd_sqi_debug_sel_len 2 +#define fd_sqi_debug_sel_lsb 0 +#define xd_p_fd_sqi_s2 0xA33C +#define fd_sqi_s2_pos 3 +#define fd_sqi_s2_len 5 +#define fd_sqi_s2_lsb 0 +#define xd_p_fd_sqi_dummy_reg_1 0xA33D +#define fd_sqi_dummy_reg_1_pos 0 +#define fd_sqi_dummy_reg_1_len 1 +#define fd_sqi_dummy_reg_1_lsb 0 +#define xd_p_fd_inr_ignore 0xA33D +#define fd_inr_ignore_pos 1 +#define fd_inr_ignore_len 1 +#define fd_inr_ignore_lsb 0 +#define xd_p_fd_pilot_ignore 0xA33D +#define fd_pilot_ignore_pos 2 +#define fd_pilot_ignore_len 1 +#define fd_pilot_ignore_lsb 0 +#define xd_p_fd_etps_ignore 0xA33D +#define fd_etps_ignore_pos 3 +#define fd_etps_ignore_len 1 +#define fd_etps_ignore_lsb 0 +#define xd_p_fd_sqi_s1 0xA33D +#define fd_sqi_s1_pos 4 +#define fd_sqi_s1_len 4 +#define fd_sqi_s1_lsb 0 +#define xd_p_reg_fste_ehw_7_0 0xA33E +#define reg_fste_ehw_7_0_pos 0 +#define reg_fste_ehw_7_0_len 8 +#define reg_fste_ehw_7_0_lsb 0 +#define xd_p_reg_fste_ehw_9_8 0xA33F +#define reg_fste_ehw_9_8_pos 0 +#define reg_fste_ehw_9_8_len 2 +#define reg_fste_ehw_9_8_lsb 8 +#define xd_p_reg_fste_i_adj_vld 0xA33F +#define reg_fste_i_adj_vld_pos 2 +#define reg_fste_i_adj_vld_len 1 +#define reg_fste_i_adj_vld_lsb 0 +#define xd_p_reg_fste_phase_ini_7_0 0xA340 +#define reg_fste_phase_ini_7_0_pos 0 +#define reg_fste_phase_ini_7_0_len 8 +#define reg_fste_phase_ini_7_0_lsb 0 +#define xd_p_reg_fste_phase_ini_11_8 0xA341 +#define reg_fste_phase_ini_11_8_pos 0 +#define reg_fste_phase_ini_11_8_len 4 +#define reg_fste_phase_ini_11_8_lsb 8 +#define xd_p_reg_fste_phase_inc_3_0 0xA341 +#define reg_fste_phase_inc_3_0_pos 4 +#define reg_fste_phase_inc_3_0_len 4 +#define reg_fste_phase_inc_3_0_lsb 0 +#define xd_p_reg_fste_phase_inc_11_4 0xA342 +#define reg_fste_phase_inc_11_4_pos 0 +#define reg_fste_phase_inc_11_4_len 8 +#define reg_fste_phase_inc_11_4_lsb 4 +#define xd_p_reg_fste_acum_cost_cnt_max 0xA343 +#define reg_fste_acum_cost_cnt_max_pos 0 +#define reg_fste_acum_cost_cnt_max_len 4 +#define reg_fste_acum_cost_cnt_max_lsb 0 +#define xd_p_reg_fste_step_size_std 0xA343 +#define reg_fste_step_size_std_pos 4 +#define reg_fste_step_size_std_len 4 +#define reg_fste_step_size_std_lsb 0 +#define xd_p_reg_fste_step_size_max 0xA344 +#define reg_fste_step_size_max_pos 0 +#define reg_fste_step_size_max_len 4 +#define reg_fste_step_size_max_lsb 0 +#define xd_p_reg_fste_step_size_min 0xA344 +#define reg_fste_step_size_min_pos 4 +#define reg_fste_step_size_min_len 4 +#define reg_fste_step_size_min_lsb 0 +#define xd_p_reg_fste_frac_step_size_7_0 0xA345 +#define reg_fste_frac_step_size_7_0_pos 0 +#define reg_fste_frac_step_size_7_0_len 8 +#define reg_fste_frac_step_size_7_0_lsb 0 +#define xd_p_reg_fste_frac_step_size_15_8 0xA346 +#define reg_fste_frac_step_size_15_8_pos 0 +#define reg_fste_frac_step_size_15_8_len 8 +#define reg_fste_frac_step_size_15_8_lsb 8 +#define xd_p_reg_fste_frac_step_size_19_16 0xA347 +#define reg_fste_frac_step_size_19_16_pos 0 +#define reg_fste_frac_step_size_19_16_len 4 +#define reg_fste_frac_step_size_19_16_lsb 16 +#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347 +#define reg_fste_rpd_dir_cnt_max_pos 4 +#define reg_fste_rpd_dir_cnt_max_len 4 +#define reg_fste_rpd_dir_cnt_max_lsb 0 +#define xd_p_reg_fste_ehs 0xA348 +#define reg_fste_ehs_pos 0 +#define reg_fste_ehs_len 4 +#define reg_fste_ehs_lsb 0 +#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348 +#define reg_fste_frac_cost_cnt_max_3_0_pos 4 +#define reg_fste_frac_cost_cnt_max_3_0_len 4 +#define reg_fste_frac_cost_cnt_max_3_0_lsb 0 +#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349 +#define reg_fste_frac_cost_cnt_max_9_4_pos 0 +#define reg_fste_frac_cost_cnt_max_9_4_len 6 +#define reg_fste_frac_cost_cnt_max_9_4_lsb 4 +#define xd_p_reg_fste_w0_7_0 0xA34A +#define reg_fste_w0_7_0_pos 0 +#define reg_fste_w0_7_0_len 8 +#define reg_fste_w0_7_0_lsb 0 +#define xd_p_reg_fste_w0_11_8 0xA34B +#define reg_fste_w0_11_8_pos 0 +#define reg_fste_w0_11_8_len 4 +#define reg_fste_w0_11_8_lsb 8 +#define xd_p_reg_fste_w1_3_0 0xA34B +#define reg_fste_w1_3_0_pos 4 +#define reg_fste_w1_3_0_len 4 +#define reg_fste_w1_3_0_lsb 0 +#define xd_p_reg_fste_w1_11_4 0xA34C +#define reg_fste_w1_11_4_pos 0 +#define reg_fste_w1_11_4_len 8 +#define reg_fste_w1_11_4_lsb 4 +#define xd_p_reg_fste_w2_7_0 0xA34D +#define reg_fste_w2_7_0_pos 0 +#define reg_fste_w2_7_0_len 8 +#define reg_fste_w2_7_0_lsb 0 +#define xd_p_reg_fste_w2_11_8 0xA34E +#define reg_fste_w2_11_8_pos 0 +#define reg_fste_w2_11_8_len 4 +#define reg_fste_w2_11_8_lsb 8 +#define xd_p_reg_fste_w3_3_0 0xA34E +#define reg_fste_w3_3_0_pos 4 +#define reg_fste_w3_3_0_len 4 +#define reg_fste_w3_3_0_lsb 0 +#define xd_p_reg_fste_w3_11_4 0xA34F +#define reg_fste_w3_11_4_pos 0 +#define reg_fste_w3_11_4_len 8 +#define reg_fste_w3_11_4_lsb 4 +#define xd_p_reg_fste_w4_7_0 0xA350 +#define reg_fste_w4_7_0_pos 0 +#define reg_fste_w4_7_0_len 8 +#define reg_fste_w4_7_0_lsb 0 +#define xd_p_reg_fste_w4_11_8 0xA351 +#define reg_fste_w4_11_8_pos 0 +#define reg_fste_w4_11_8_len 4 +#define reg_fste_w4_11_8_lsb 8 +#define xd_p_reg_fste_w5_3_0 0xA351 +#define reg_fste_w5_3_0_pos 4 +#define reg_fste_w5_3_0_len 4 +#define reg_fste_w5_3_0_lsb 0 +#define xd_p_reg_fste_w5_11_4 0xA352 +#define reg_fste_w5_11_4_pos 0 +#define reg_fste_w5_11_4_len 8 +#define reg_fste_w5_11_4_lsb 4 +#define xd_p_reg_fste_w6_7_0 0xA353 +#define reg_fste_w6_7_0_pos 0 +#define reg_fste_w6_7_0_len 8 +#define reg_fste_w6_7_0_lsb 0 +#define xd_p_reg_fste_w6_11_8 0xA354 +#define reg_fste_w6_11_8_pos 0 +#define reg_fste_w6_11_8_len 4 +#define reg_fste_w6_11_8_lsb 8 +#define xd_p_reg_fste_w7_3_0 0xA354 +#define reg_fste_w7_3_0_pos 4 +#define reg_fste_w7_3_0_len 4 +#define reg_fste_w7_3_0_lsb 0 +#define xd_p_reg_fste_w7_11_4 0xA355 +#define reg_fste_w7_11_4_pos 0 +#define reg_fste_w7_11_4_len 8 +#define reg_fste_w7_11_4_lsb 4 +#define xd_p_reg_fste_w8_7_0 0xA356 +#define reg_fste_w8_7_0_pos 0 +#define reg_fste_w8_7_0_len 8 +#define reg_fste_w8_7_0_lsb 0 +#define xd_p_reg_fste_w8_11_8 0xA357 +#define reg_fste_w8_11_8_pos 0 +#define reg_fste_w8_11_8_len 4 +#define reg_fste_w8_11_8_lsb 8 +#define xd_p_reg_fste_w9_3_0 0xA357 +#define reg_fste_w9_3_0_pos 4 +#define reg_fste_w9_3_0_len 4 +#define reg_fste_w9_3_0_lsb 0 +#define xd_p_reg_fste_w9_11_4 0xA358 +#define reg_fste_w9_11_4_pos 0 +#define reg_fste_w9_11_4_len 8 +#define reg_fste_w9_11_4_lsb 4 +#define xd_p_reg_fste_wa_7_0 0xA359 +#define reg_fste_wa_7_0_pos 0 +#define reg_fste_wa_7_0_len 8 +#define reg_fste_wa_7_0_lsb 0 +#define xd_p_reg_fste_wa_11_8 0xA35A +#define reg_fste_wa_11_8_pos 0 +#define reg_fste_wa_11_8_len 4 +#define reg_fste_wa_11_8_lsb 8 +#define xd_p_reg_fste_wb_3_0 0xA35A +#define reg_fste_wb_3_0_pos 4 +#define reg_fste_wb_3_0_len 4 +#define reg_fste_wb_3_0_lsb 0 +#define xd_p_reg_fste_wb_11_4 0xA35B +#define reg_fste_wb_11_4_pos 0 +#define reg_fste_wb_11_4_len 8 +#define reg_fste_wb_11_4_lsb 4 +#define xd_r_fd_fste_i_adj 0xA35C +#define fd_fste_i_adj_pos 0 +#define fd_fste_i_adj_len 5 +#define fd_fste_i_adj_lsb 0 +#define xd_r_fd_fste_f_adj_7_0 0xA35D +#define fd_fste_f_adj_7_0_pos 0 +#define fd_fste_f_adj_7_0_len 8 +#define fd_fste_f_adj_7_0_lsb 0 +#define xd_r_fd_fste_f_adj_15_8 0xA35E +#define fd_fste_f_adj_15_8_pos 0 +#define fd_fste_f_adj_15_8_len 8 +#define fd_fste_f_adj_15_8_lsb 8 +#define xd_r_fd_fste_f_adj_19_16 0xA35F +#define fd_fste_f_adj_19_16_pos 0 +#define fd_fste_f_adj_19_16_len 4 +#define fd_fste_f_adj_19_16_lsb 16 +#define xd_p_reg_feq_Leak_Bypass 0xA366 +#define reg_feq_Leak_Bypass_pos 0 +#define reg_feq_Leak_Bypass_len 1 +#define reg_feq_Leak_Bypass_lsb 0 +#define xd_p_reg_feq_Leak_Mneg1 0xA366 +#define reg_feq_Leak_Mneg1_pos 1 +#define reg_feq_Leak_Mneg1_len 3 +#define reg_feq_Leak_Mneg1_lsb 0 +#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366 +#define reg_feq_Leak_B_ShiftQ_pos 4 +#define reg_feq_Leak_B_ShiftQ_len 4 +#define reg_feq_Leak_B_ShiftQ_lsb 0 +#define xd_p_reg_feq_Leak_B_Float0 0xA367 +#define reg_feq_Leak_B_Float0_pos 0 +#define reg_feq_Leak_B_Float0_len 8 +#define reg_feq_Leak_B_Float0_lsb 0 +#define xd_p_reg_feq_Leak_B_Float1 0xA368 +#define reg_feq_Leak_B_Float1_pos 0 +#define reg_feq_Leak_B_Float1_len 8 +#define reg_feq_Leak_B_Float1_lsb 0 +#define xd_p_reg_feq_Leak_B_Float2 0xA369 +#define reg_feq_Leak_B_Float2_pos 0 +#define reg_feq_Leak_B_Float2_len 8 +#define reg_feq_Leak_B_Float2_lsb 0 +#define xd_p_reg_feq_Leak_B_Float3 0xA36A +#define reg_feq_Leak_B_Float3_pos 0 +#define reg_feq_Leak_B_Float3_len 8 +#define reg_feq_Leak_B_Float3_lsb 0 +#define xd_p_reg_feq_Leak_B_Float4 0xA36B +#define reg_feq_Leak_B_Float4_pos 0 +#define reg_feq_Leak_B_Float4_len 8 +#define reg_feq_Leak_B_Float4_lsb 0 +#define xd_p_reg_feq_Leak_B_Float5 0xA36C +#define reg_feq_Leak_B_Float5_pos 0 +#define reg_feq_Leak_B_Float5_len 8 +#define reg_feq_Leak_B_Float5_lsb 0 +#define xd_p_reg_feq_Leak_B_Float6 0xA36D +#define reg_feq_Leak_B_Float6_pos 0 +#define reg_feq_Leak_B_Float6_len 8 +#define reg_feq_Leak_B_Float6_lsb 0 +#define xd_p_reg_feq_Leak_B_Float7 0xA36E +#define reg_feq_Leak_B_Float7_pos 0 +#define reg_feq_Leak_B_Float7_len 8 +#define reg_feq_Leak_B_Float7_lsb 0 +#define xd_r_reg_feq_data_h2_7_0 0xA36F +#define reg_feq_data_h2_7_0_pos 0 +#define reg_feq_data_h2_7_0_len 8 +#define reg_feq_data_h2_7_0_lsb 0 +#define xd_r_reg_feq_data_h2_9_8 0xA370 +#define reg_feq_data_h2_9_8_pos 0 +#define reg_feq_data_h2_9_8_len 2 +#define reg_feq_data_h2_9_8_lsb 8 +#define xd_p_reg_feq_leak_use_slice_tps 0xA371 +#define reg_feq_leak_use_slice_tps_pos 0 +#define reg_feq_leak_use_slice_tps_len 1 +#define reg_feq_leak_use_slice_tps_lsb 0 +#define xd_p_reg_feq_read_update 0xA371 +#define reg_feq_read_update_pos 1 +#define reg_feq_read_update_len 1 +#define reg_feq_read_update_lsb 0 +#define xd_p_reg_feq_data_vld 0xA371 +#define reg_feq_data_vld_pos 2 +#define reg_feq_data_vld_len 1 +#define reg_feq_data_vld_lsb 0 +#define xd_p_reg_feq_tone_idx_4_0 0xA371 +#define reg_feq_tone_idx_4_0_pos 3 +#define reg_feq_tone_idx_4_0_len 5 +#define reg_feq_tone_idx_4_0_lsb 0 +#define xd_p_reg_feq_tone_idx_12_5 0xA372 +#define reg_feq_tone_idx_12_5_pos 0 +#define reg_feq_tone_idx_12_5_len 8 +#define reg_feq_tone_idx_12_5_lsb 5 +#define xd_r_reg_feq_data_re_7_0 0xA373 +#define reg_feq_data_re_7_0_pos 0 +#define reg_feq_data_re_7_0_len 8 +#define reg_feq_data_re_7_0_lsb 0 +#define xd_r_reg_feq_data_re_10_8 0xA374 +#define reg_feq_data_re_10_8_pos 0 +#define reg_feq_data_re_10_8_len 3 +#define reg_feq_data_re_10_8_lsb 8 +#define xd_r_reg_feq_data_im_7_0 0xA375 +#define reg_feq_data_im_7_0_pos 0 +#define reg_feq_data_im_7_0_len 8 +#define reg_feq_data_im_7_0_lsb 0 +#define xd_r_reg_feq_data_im_10_8 0xA376 +#define reg_feq_data_im_10_8_pos 0 +#define reg_feq_data_im_10_8_len 3 +#define reg_feq_data_im_10_8_lsb 8 +#define xd_r_reg_feq_y_re 0xA377 +#define reg_feq_y_re_pos 0 +#define reg_feq_y_re_len 8 +#define reg_feq_y_re_lsb 0 +#define xd_r_reg_feq_y_im 0xA378 +#define reg_feq_y_im_pos 0 +#define reg_feq_y_im_len 8 +#define reg_feq_y_im_lsb 0 +#define xd_r_reg_feq_h_re_7_0 0xA379 +#define reg_feq_h_re_7_0_pos 0 +#define reg_feq_h_re_7_0_len 8 +#define reg_feq_h_re_7_0_lsb 0 +#define xd_r_reg_feq_h_re_8 0xA37A +#define reg_feq_h_re_8_pos 0 +#define reg_feq_h_re_8_len 1 +#define reg_feq_h_re_8_lsb 0 +#define xd_r_reg_feq_h_im_7_0 0xA37B +#define reg_feq_h_im_7_0_pos 0 +#define reg_feq_h_im_7_0_len 8 +#define reg_feq_h_im_7_0_lsb 0 +#define xd_r_reg_feq_h_im_8 0xA37C +#define reg_feq_h_im_8_pos 0 +#define reg_feq_h_im_8_len 1 +#define reg_feq_h_im_8_lsb 0 +#define xd_p_fec_super_frm_unit_7_0 0xA380 +#define fec_super_frm_unit_7_0_pos 0 +#define fec_super_frm_unit_7_0_len 8 +#define fec_super_frm_unit_7_0_lsb 0 +#define xd_p_fec_super_frm_unit_15_8 0xA381 +#define fec_super_frm_unit_15_8_pos 0 +#define fec_super_frm_unit_15_8_len 8 +#define fec_super_frm_unit_15_8_lsb 8 +#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382 +#define fec_vtb_err_bit_cnt_7_0_pos 0 +#define fec_vtb_err_bit_cnt_7_0_len 8 +#define fec_vtb_err_bit_cnt_7_0_lsb 0 +#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383 +#define fec_vtb_err_bit_cnt_15_8_pos 0 +#define fec_vtb_err_bit_cnt_15_8_len 8 +#define fec_vtb_err_bit_cnt_15_8_lsb 8 +#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384 +#define fec_vtb_err_bit_cnt_23_16_pos 0 +#define fec_vtb_err_bit_cnt_23_16_len 8 +#define fec_vtb_err_bit_cnt_23_16_lsb 16 +#define xd_p_fec_rsd_packet_unit_7_0 0xA385 +#define fec_rsd_packet_unit_7_0_pos 0 +#define fec_rsd_packet_unit_7_0_len 8 +#define fec_rsd_packet_unit_7_0_lsb 0 +#define xd_p_fec_rsd_packet_unit_15_8 0xA386 +#define fec_rsd_packet_unit_15_8_pos 0 +#define fec_rsd_packet_unit_15_8_len 8 +#define fec_rsd_packet_unit_15_8_lsb 8 +#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387 +#define fec_rsd_bit_err_cnt_7_0_pos 0 +#define fec_rsd_bit_err_cnt_7_0_len 8 +#define fec_rsd_bit_err_cnt_7_0_lsb 0 +#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388 +#define fec_rsd_bit_err_cnt_15_8_pos 0 +#define fec_rsd_bit_err_cnt_15_8_len 8 +#define fec_rsd_bit_err_cnt_15_8_lsb 8 +#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389 +#define fec_rsd_bit_err_cnt_23_16_pos 0 +#define fec_rsd_bit_err_cnt_23_16_len 8 +#define fec_rsd_bit_err_cnt_23_16_lsb 16 +#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A +#define fec_rsd_abort_packet_cnt_7_0_pos 0 +#define fec_rsd_abort_packet_cnt_7_0_len 8 +#define fec_rsd_abort_packet_cnt_7_0_lsb 0 +#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B +#define fec_rsd_abort_packet_cnt_15_8_pos 0 +#define fec_rsd_abort_packet_cnt_15_8_len 8 +#define fec_rsd_abort_packet_cnt_15_8_lsb 8 +#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0 +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8 +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0 +#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0 +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8 +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8 +#define xd_p_fec_RS_TH_1_7_0 0xA38E +#define fec_RS_TH_1_7_0_pos 0 +#define fec_RS_TH_1_7_0_len 8 +#define fec_RS_TH_1_7_0_lsb 0 +#define xd_p_fec_RS_TH_1_15_8 0xA38F +#define fec_RS_TH_1_15_8_pos 0 +#define fec_RS_TH_1_15_8_len 8 +#define fec_RS_TH_1_15_8_lsb 8 +#define xd_p_fec_RS_TH_2 0xA390 +#define fec_RS_TH_2_pos 0 +#define fec_RS_TH_2_len 8 +#define fec_RS_TH_2_lsb 0 +#define xd_p_fec_mon_en 0xA391 +#define fec_mon_en_pos 0 +#define fec_mon_en_len 1 +#define fec_mon_en_lsb 0 +#define xd_p_reg_b8to47 0xA391 +#define reg_b8to47_pos 1 +#define reg_b8to47_len 1 +#define reg_b8to47_lsb 0 +#define xd_p_reg_rsd_sync_rep 0xA391 +#define reg_rsd_sync_rep_pos 2 +#define reg_rsd_sync_rep_len 1 +#define reg_rsd_sync_rep_lsb 0 +#define xd_p_fec_rsd_retrain_rst 0xA391 +#define fec_rsd_retrain_rst_pos 3 +#define fec_rsd_retrain_rst_len 1 +#define fec_rsd_retrain_rst_lsb 0 +#define xd_r_fec_rsd_ber_rdy 0xA391 +#define fec_rsd_ber_rdy_pos 4 +#define fec_rsd_ber_rdy_len 1 +#define fec_rsd_ber_rdy_lsb 0 +#define xd_p_fec_rsd_ber_rst 0xA391 +#define fec_rsd_ber_rst_pos 5 +#define fec_rsd_ber_rst_len 1 +#define fec_rsd_ber_rst_lsb 0 +#define xd_r_fec_vtb_ber_rdy 0xA391 +#define fec_vtb_ber_rdy_pos 6 +#define fec_vtb_ber_rdy_len 1 +#define fec_vtb_ber_rdy_lsb 0 +#define xd_p_fec_vtb_ber_rst 0xA391 +#define fec_vtb_ber_rst_pos 7 +#define fec_vtb_ber_rst_len 1 +#define fec_vtb_ber_rst_lsb 0 +#define xd_p_reg_vtb_clk40en 0xA392 +#define reg_vtb_clk40en_pos 0 +#define reg_vtb_clk40en_len 1 +#define reg_vtb_clk40en_lsb 0 +#define xd_p_fec_vtb_rsd_mon_en 0xA392 +#define fec_vtb_rsd_mon_en_pos 1 +#define fec_vtb_rsd_mon_en_len 1 +#define fec_vtb_rsd_mon_en_lsb 0 +#define xd_p_reg_fec_data_en 0xA392 +#define reg_fec_data_en_pos 2 +#define reg_fec_data_en_len 1 +#define reg_fec_data_en_lsb 0 +#define xd_p_fec_dummy_reg_2 0xA392 +#define fec_dummy_reg_2_pos 3 +#define fec_dummy_reg_2_len 3 +#define fec_dummy_reg_2_lsb 0 +#define xd_p_reg_sync_chk 0xA392 +#define reg_sync_chk_pos 6 +#define reg_sync_chk_len 1 +#define reg_sync_chk_lsb 0 +#define xd_p_fec_rsd_bypass 0xA392 +#define fec_rsd_bypass_pos 7 +#define fec_rsd_bypass_len 1 +#define fec_rsd_bypass_lsb 0 +#define xd_p_fec_sw_rst 0xA393 +#define fec_sw_rst_pos 0 +#define fec_sw_rst_len 1 +#define fec_sw_rst_lsb 0 +#define xd_r_fec_vtb_pm_crc 0xA394 +#define fec_vtb_pm_crc_pos 0 +#define fec_vtb_pm_crc_len 8 +#define fec_vtb_pm_crc_lsb 0 +#define xd_r_fec_vtb_tb_7_crc 0xA395 +#define fec_vtb_tb_7_crc_pos 0 +#define fec_vtb_tb_7_crc_len 8 +#define fec_vtb_tb_7_crc_lsb 0 +#define xd_r_fec_vtb_tb_6_crc 0xA396 +#define fec_vtb_tb_6_crc_pos 0 +#define fec_vtb_tb_6_crc_len 8 +#define fec_vtb_tb_6_crc_lsb 0 +#define xd_r_fec_vtb_tb_5_crc 0xA397 +#define fec_vtb_tb_5_crc_pos 0 +#define fec_vtb_tb_5_crc_len 8 +#define fec_vtb_tb_5_crc_lsb 0 +#define xd_r_fec_vtb_tb_4_crc 0xA398 +#define fec_vtb_tb_4_crc_pos 0 +#define fec_vtb_tb_4_crc_len 8 +#define fec_vtb_tb_4_crc_lsb 0 +#define xd_r_fec_vtb_tb_3_crc 0xA399 +#define fec_vtb_tb_3_crc_pos 0 +#define fec_vtb_tb_3_crc_len 8 +#define fec_vtb_tb_3_crc_lsb 0 +#define xd_r_fec_vtb_tb_2_crc 0xA39A +#define fec_vtb_tb_2_crc_pos 0 +#define fec_vtb_tb_2_crc_len 8 +#define fec_vtb_tb_2_crc_lsb 0 +#define xd_r_fec_vtb_tb_1_crc 0xA39B +#define fec_vtb_tb_1_crc_pos 0 +#define fec_vtb_tb_1_crc_len 8 +#define fec_vtb_tb_1_crc_lsb 0 +#define xd_r_fec_vtb_tb_0_crc 0xA39C +#define fec_vtb_tb_0_crc_pos 0 +#define fec_vtb_tb_0_crc_len 8 +#define fec_vtb_tb_0_crc_lsb 0 +#define xd_r_fec_rsd_bank0_crc 0xA39D +#define fec_rsd_bank0_crc_pos 0 +#define fec_rsd_bank0_crc_len 8 +#define fec_rsd_bank0_crc_lsb 0 +#define xd_r_fec_rsd_bank1_crc 0xA39E +#define fec_rsd_bank1_crc_pos 0 +#define fec_rsd_bank1_crc_len 8 +#define fec_rsd_bank1_crc_lsb 0 +#define xd_r_fec_idi_vtb_crc 0xA39F +#define fec_idi_vtb_crc_pos 0 +#define fec_idi_vtb_crc_len 8 +#define fec_idi_vtb_crc_lsb 0 +#define xd_g_reg_tpsd_txmod 0xA3C0 +#define reg_tpsd_txmod_pos 0 +#define reg_tpsd_txmod_len 2 +#define reg_tpsd_txmod_lsb 0 +#define xd_g_reg_tpsd_gi 0xA3C0 +#define reg_tpsd_gi_pos 2 +#define reg_tpsd_gi_len 2 +#define reg_tpsd_gi_lsb 0 +#define xd_g_reg_tpsd_hier 0xA3C0 +#define reg_tpsd_hier_pos 4 +#define reg_tpsd_hier_len 3 +#define reg_tpsd_hier_lsb 0 +#define xd_g_reg_bw 0xA3C1 +#define reg_bw_pos 2 +#define reg_bw_len 2 +#define reg_bw_lsb 0 +#define xd_g_reg_dec_pri 0xA3C1 +#define reg_dec_pri_pos 4 +#define reg_dec_pri_len 1 +#define reg_dec_pri_lsb 0 +#define xd_g_reg_tpsd_const 0xA3C1 +#define reg_tpsd_const_pos 6 +#define reg_tpsd_const_len 2 +#define reg_tpsd_const_lsb 0 +#define xd_g_reg_tpsd_hpcr 0xA3C2 +#define reg_tpsd_hpcr_pos 0 +#define reg_tpsd_hpcr_len 3 +#define reg_tpsd_hpcr_lsb 0 +#define xd_g_reg_tpsd_lpcr 0xA3C2 +#define reg_tpsd_lpcr_pos 3 +#define reg_tpsd_lpcr_len 3 +#define reg_tpsd_lpcr_lsb 0 +#define xd_g_reg_ofsm_clk 0xA3D0 +#define reg_ofsm_clk_pos 0 +#define reg_ofsm_clk_len 3 +#define reg_ofsm_clk_lsb 0 +#define xd_g_reg_fclk_cfg 0xA3D1 +#define reg_fclk_cfg_pos 0 +#define reg_fclk_cfg_len 1 +#define reg_fclk_cfg_lsb 0 +#define xd_g_reg_fclk_idi 0xA3D1 +#define reg_fclk_idi_pos 1 +#define reg_fclk_idi_len 1 +#define reg_fclk_idi_lsb 0 +#define xd_g_reg_fclk_odi 0xA3D1 +#define reg_fclk_odi_pos 2 +#define reg_fclk_odi_len 1 +#define reg_fclk_odi_lsb 0 +#define xd_g_reg_fclk_rsd 0xA3D1 +#define reg_fclk_rsd_pos 3 +#define reg_fclk_rsd_len 1 +#define reg_fclk_rsd_lsb 0 +#define xd_g_reg_fclk_vtb 0xA3D1 +#define reg_fclk_vtb_pos 4 +#define reg_fclk_vtb_len 1 +#define reg_fclk_vtb_lsb 0 +#define xd_g_reg_fclk_cste 0xA3D1 +#define reg_fclk_cste_pos 5 +#define reg_fclk_cste_len 1 +#define reg_fclk_cste_lsb 0 +#define xd_g_reg_fclk_mp2if 0xA3D1 +#define reg_fclk_mp2if_pos 6 +#define reg_fclk_mp2if_len 1 +#define reg_fclk_mp2if_lsb 0 +#define xd_I2C_i2c_m_slave_addr 0xA400 +#define i2c_m_slave_addr_pos 0 +#define i2c_m_slave_addr_len 8 +#define i2c_m_slave_addr_lsb 0 +#define xd_I2C_i2c_m_data1 0xA401 +#define i2c_m_data1_pos 0 +#define i2c_m_data1_len 8 +#define i2c_m_data1_lsb 0 +#define xd_I2C_i2c_m_data2 0xA402 +#define i2c_m_data2_pos 0 +#define i2c_m_data2_len 8 +#define i2c_m_data2_lsb 0 +#define xd_I2C_i2c_m_data3 0xA403 +#define i2c_m_data3_pos 0 +#define i2c_m_data3_len 8 +#define i2c_m_data3_lsb 0 +#define xd_I2C_i2c_m_data4 0xA404 +#define i2c_m_data4_pos 0 +#define i2c_m_data4_len 8 +#define i2c_m_data4_lsb 0 +#define xd_I2C_i2c_m_data5 0xA405 +#define i2c_m_data5_pos 0 +#define i2c_m_data5_len 8 +#define i2c_m_data5_lsb 0 +#define xd_I2C_i2c_m_data6 0xA406 +#define i2c_m_data6_pos 0 +#define i2c_m_data6_len 8 +#define i2c_m_data6_lsb 0 +#define xd_I2C_i2c_m_data7 0xA407 +#define i2c_m_data7_pos 0 +#define i2c_m_data7_len 8 +#define i2c_m_data7_lsb 0 +#define xd_I2C_i2c_m_data8 0xA408 +#define i2c_m_data8_pos 0 +#define i2c_m_data8_len 8 +#define i2c_m_data8_lsb 0 +#define xd_I2C_i2c_m_data9 0xA409 +#define i2c_m_data9_pos 0 +#define i2c_m_data9_len 8 +#define i2c_m_data9_lsb 0 +#define xd_I2C_i2c_m_data10 0xA40A +#define i2c_m_data10_pos 0 +#define i2c_m_data10_len 8 +#define i2c_m_data10_lsb 0 +#define xd_I2C_i2c_m_data11 0xA40B +#define i2c_m_data11_pos 0 +#define i2c_m_data11_len 8 +#define i2c_m_data11_lsb 0 +#define xd_I2C_i2c_m_cmd_rw 0xA40C +#define i2c_m_cmd_rw_pos 0 +#define i2c_m_cmd_rw_len 1 +#define i2c_m_cmd_rw_lsb 0 +#define xd_I2C_i2c_m_cmd_rwlen 0xA40C +#define i2c_m_cmd_rwlen_pos 3 +#define i2c_m_cmd_rwlen_len 4 +#define i2c_m_cmd_rwlen_lsb 0 +#define xd_I2C_i2c_m_status_cmd_exe 0xA40D +#define i2c_m_status_cmd_exe_pos 0 +#define i2c_m_status_cmd_exe_len 1 +#define i2c_m_status_cmd_exe_lsb 0 +#define xd_I2C_i2c_m_status_wdat_done 0xA40D +#define i2c_m_status_wdat_done_pos 1 +#define i2c_m_status_wdat_done_len 1 +#define i2c_m_status_wdat_done_lsb 0 +#define xd_I2C_i2c_m_status_wdat_fail 0xA40D +#define i2c_m_status_wdat_fail_pos 2 +#define i2c_m_status_wdat_fail_len 1 +#define i2c_m_status_wdat_fail_lsb 0 +#define xd_I2C_i2c_m_period 0xA40E +#define i2c_m_period_pos 0 +#define i2c_m_period_len 8 +#define i2c_m_period_lsb 0 +#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F +#define i2c_m_reg_msb_lsb_pos 0 +#define i2c_m_reg_msb_lsb_len 1 +#define i2c_m_reg_msb_lsb_lsb 0 +#define xd_I2C_reg_ofdm_rst 0xA40F +#define reg_ofdm_rst_pos 1 +#define reg_ofdm_rst_len 1 +#define reg_ofdm_rst_lsb 0 +#define xd_I2C_reg_sample_period_on_tuner 0xA40F +#define reg_sample_period_on_tuner_pos 2 +#define reg_sample_period_on_tuner_len 1 +#define reg_sample_period_on_tuner_lsb 0 +#define xd_I2C_reg_rst_i2c 0xA40F +#define reg_rst_i2c_pos 3 +#define reg_rst_i2c_len 1 +#define reg_rst_i2c_lsb 0 +#define xd_I2C_reg_ofdm_rst_en 0xA40F +#define reg_ofdm_rst_en_pos 4 +#define reg_ofdm_rst_en_len 1 +#define reg_ofdm_rst_en_lsb 0 +#define xd_I2C_reg_tuner_sda_sync_on 0xA40F +#define reg_tuner_sda_sync_on_pos 5 +#define reg_tuner_sda_sync_on_len 1 +#define reg_tuner_sda_sync_on_lsb 0 +#define xd_p_mp2if_data_access_disable_ofsm 0xA500 +#define mp2if_data_access_disable_ofsm_pos 0 +#define mp2if_data_access_disable_ofsm_len 1 +#define mp2if_data_access_disable_ofsm_lsb 0 +#define xd_p_reg_mp2_sw_rst_ofsm 0xA500 +#define reg_mp2_sw_rst_ofsm_pos 1 +#define reg_mp2_sw_rst_ofsm_len 1 +#define reg_mp2_sw_rst_ofsm_lsb 0 +#define xd_p_reg_mp2if_clk_en_ofsm 0xA500 +#define reg_mp2if_clk_en_ofsm_pos 2 +#define reg_mp2if_clk_en_ofsm_len 1 +#define reg_mp2if_clk_en_ofsm_lsb 0 +#define xd_r_mp2if_sync_byte_locked 0xA500 +#define mp2if_sync_byte_locked_pos 3 +#define mp2if_sync_byte_locked_len 1 +#define mp2if_sync_byte_locked_lsb 0 +#define xd_r_mp2if_ts_not_188 0xA500 +#define mp2if_ts_not_188_pos 4 +#define mp2if_ts_not_188_len 1 +#define mp2if_ts_not_188_lsb 0 +#define xd_r_mp2if_psb_empty 0xA500 +#define mp2if_psb_empty_pos 5 +#define mp2if_psb_empty_len 1 +#define mp2if_psb_empty_lsb 0 +#define xd_r_mp2if_psb_overflow 0xA500 +#define mp2if_psb_overflow_pos 6 +#define mp2if_psb_overflow_len 1 +#define mp2if_psb_overflow_lsb 0 +#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500 +#define mp2if_keep_sf_sync_byte_ofsm_pos 7 +#define mp2if_keep_sf_sync_byte_ofsm_len 1 +#define mp2if_keep_sf_sync_byte_ofsm_lsb 0 +#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501 +#define mp2if_psb_mp2if_num_pkt_pos 0 +#define mp2if_psb_mp2if_num_pkt_len 6 +#define mp2if_psb_mp2if_num_pkt_lsb 0 +#define xd_p_reg_mpeg_full_speed_ofsm 0xA501 +#define reg_mpeg_full_speed_ofsm_pos 6 +#define reg_mpeg_full_speed_ofsm_len 1 +#define reg_mpeg_full_speed_ofsm_lsb 0 +#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501 +#define mp2if_mpeg_ser_mode_ofsm_pos 7 +#define mp2if_mpeg_ser_mode_ofsm_len 1 +#define mp2if_mpeg_ser_mode_ofsm_lsb 0 +#define xd_p_reg_sw_mon51 0xA600 +#define reg_sw_mon51_pos 0 +#define reg_sw_mon51_len 8 +#define reg_sw_mon51_lsb 0 +#define xd_p_reg_top_pcsel 0xA601 +#define reg_top_pcsel_pos 0 +#define reg_top_pcsel_len 1 +#define reg_top_pcsel_lsb 0 +#define xd_p_reg_top_rs232 0xA601 +#define reg_top_rs232_pos 1 +#define reg_top_rs232_len 1 +#define reg_top_rs232_lsb 0 +#define xd_p_reg_top_pcout 0xA601 +#define reg_top_pcout_pos 2 +#define reg_top_pcout_len 1 +#define reg_top_pcout_lsb 0 +#define xd_p_reg_top_debug 0xA601 +#define reg_top_debug_pos 3 +#define reg_top_debug_len 1 +#define reg_top_debug_lsb 0 +#define xd_p_reg_top_adcdly 0xA601 +#define reg_top_adcdly_pos 4 +#define reg_top_adcdly_len 2 +#define reg_top_adcdly_lsb 0 +#define xd_p_reg_top_pwrdw 0xA601 +#define reg_top_pwrdw_pos 6 +#define reg_top_pwrdw_len 1 +#define reg_top_pwrdw_lsb 0 +#define xd_p_reg_top_pwrdw_inv 0xA601 +#define reg_top_pwrdw_inv_pos 7 +#define reg_top_pwrdw_inv_len 1 +#define reg_top_pwrdw_inv_lsb 0 +#define xd_p_reg_top_int_inv 0xA602 +#define reg_top_int_inv_pos 0 +#define reg_top_int_inv_len 1 +#define reg_top_int_inv_lsb 0 +#define xd_p_reg_top_dio_sel 0xA602 +#define reg_top_dio_sel_pos 1 +#define reg_top_dio_sel_len 1 +#define reg_top_dio_sel_lsb 0 +#define xd_p_reg_top_gpioon0 0xA603 +#define reg_top_gpioon0_pos 0 +#define reg_top_gpioon0_len 1 +#define reg_top_gpioon0_lsb 0 +#define xd_p_reg_top_gpioon1 0xA603 +#define reg_top_gpioon1_pos 1 +#define reg_top_gpioon1_len 1 +#define reg_top_gpioon1_lsb 0 +#define xd_p_reg_top_gpioon2 0xA603 +#define reg_top_gpioon2_pos 2 +#define reg_top_gpioon2_len 1 +#define reg_top_gpioon2_lsb 0 +#define xd_p_reg_top_gpioon3 0xA603 +#define reg_top_gpioon3_pos 3 +#define reg_top_gpioon3_len 1 +#define reg_top_gpioon3_lsb 0 +#define xd_p_reg_top_lockon1 0xA603 +#define reg_top_lockon1_pos 4 +#define reg_top_lockon1_len 1 +#define reg_top_lockon1_lsb 0 +#define xd_p_reg_top_lockon2 0xA603 +#define reg_top_lockon2_pos 5 +#define reg_top_lockon2_len 1 +#define reg_top_lockon2_lsb 0 +#define xd_p_reg_top_gpioo0 0xA604 +#define reg_top_gpioo0_pos 0 +#define reg_top_gpioo0_len 1 +#define reg_top_gpioo0_lsb 0 +#define xd_p_reg_top_gpioo1 0xA604 +#define reg_top_gpioo1_pos 1 +#define reg_top_gpioo1_len 1 +#define reg_top_gpioo1_lsb 0 +#define xd_p_reg_top_gpioo2 0xA604 +#define reg_top_gpioo2_pos 2 +#define reg_top_gpioo2_len 1 +#define reg_top_gpioo2_lsb 0 +#define xd_p_reg_top_gpioo3 0xA604 +#define reg_top_gpioo3_pos 3 +#define reg_top_gpioo3_len 1 +#define reg_top_gpioo3_lsb 0 +#define xd_p_reg_top_lock1 0xA604 +#define reg_top_lock1_pos 4 +#define reg_top_lock1_len 1 +#define reg_top_lock1_lsb 0 +#define xd_p_reg_top_lock2 0xA604 +#define reg_top_lock2_pos 5 +#define reg_top_lock2_len 1 +#define reg_top_lock2_lsb 0 +#define xd_p_reg_top_gpioen0 0xA605 +#define reg_top_gpioen0_pos 0 +#define reg_top_gpioen0_len 1 +#define reg_top_gpioen0_lsb 0 +#define xd_p_reg_top_gpioen1 0xA605 +#define reg_top_gpioen1_pos 1 +#define reg_top_gpioen1_len 1 +#define reg_top_gpioen1_lsb 0 +#define xd_p_reg_top_gpioen2 0xA605 +#define reg_top_gpioen2_pos 2 +#define reg_top_gpioen2_len 1 +#define reg_top_gpioen2_lsb 0 +#define xd_p_reg_top_gpioen3 0xA605 +#define reg_top_gpioen3_pos 3 +#define reg_top_gpioen3_len 1 +#define reg_top_gpioen3_lsb 0 +#define xd_p_reg_top_locken1 0xA605 +#define reg_top_locken1_pos 4 +#define reg_top_locken1_len 1 +#define reg_top_locken1_lsb 0 +#define xd_p_reg_top_locken2 0xA605 +#define reg_top_locken2_pos 5 +#define reg_top_locken2_len 1 +#define reg_top_locken2_lsb 0 +#define xd_r_reg_top_gpioi0 0xA606 +#define reg_top_gpioi0_pos 0 +#define reg_top_gpioi0_len 1 +#define reg_top_gpioi0_lsb 0 +#define xd_r_reg_top_gpioi1 0xA606 +#define reg_top_gpioi1_pos 1 +#define reg_top_gpioi1_len 1 +#define reg_top_gpioi1_lsb 0 +#define xd_r_reg_top_gpioi2 0xA606 +#define reg_top_gpioi2_pos 2 +#define reg_top_gpioi2_len 1 +#define reg_top_gpioi2_lsb 0 +#define xd_r_reg_top_gpioi3 0xA606 +#define reg_top_gpioi3_pos 3 +#define reg_top_gpioi3_len 1 +#define reg_top_gpioi3_lsb 0 +#define xd_r_reg_top_locki1 0xA606 +#define reg_top_locki1_pos 4 +#define reg_top_locki1_len 1 +#define reg_top_locki1_lsb 0 +#define xd_r_reg_top_locki2 0xA606 +#define reg_top_locki2_pos 5 +#define reg_top_locki2_len 1 +#define reg_top_locki2_lsb 0 +#define xd_p_reg_dummy_7_0 0xA608 +#define reg_dummy_7_0_pos 0 +#define reg_dummy_7_0_len 8 +#define reg_dummy_7_0_lsb 0 +#define xd_p_reg_dummy_15_8 0xA609 +#define reg_dummy_15_8_pos 0 +#define reg_dummy_15_8_len 8 +#define reg_dummy_15_8_lsb 8 +#define xd_p_reg_dummy_23_16 0xA60A +#define reg_dummy_23_16_pos 0 +#define reg_dummy_23_16_len 8 +#define reg_dummy_23_16_lsb 16 +#define xd_p_reg_dummy_31_24 0xA60B +#define reg_dummy_31_24_pos 0 +#define reg_dummy_31_24_len 8 +#define reg_dummy_31_24_lsb 24 +#define xd_p_reg_dummy_39_32 0xA60C +#define reg_dummy_39_32_pos 0 +#define reg_dummy_39_32_len 8 +#define reg_dummy_39_32_lsb 32 +#define xd_p_reg_dummy_47_40 0xA60D +#define reg_dummy_47_40_pos 0 +#define reg_dummy_47_40_len 8 +#define reg_dummy_47_40_lsb 40 +#define xd_p_reg_dummy_55_48 0xA60E +#define reg_dummy_55_48_pos 0 +#define reg_dummy_55_48_len 8 +#define reg_dummy_55_48_lsb 48 +#define xd_p_reg_dummy_63_56 0xA60F +#define reg_dummy_63_56_pos 0 +#define reg_dummy_63_56_len 8 +#define reg_dummy_63_56_lsb 56 +#define xd_p_reg_dummy_71_64 0xA610 +#define reg_dummy_71_64_pos 0 +#define reg_dummy_71_64_len 8 +#define reg_dummy_71_64_lsb 64 +#define xd_p_reg_dummy_79_72 0xA611 +#define reg_dummy_79_72_pos 0 +#define reg_dummy_79_72_len 8 +#define reg_dummy_79_72_lsb 72 +#define xd_p_reg_dummy_87_80 0xA612 +#define reg_dummy_87_80_pos 0 +#define reg_dummy_87_80_len 8 +#define reg_dummy_87_80_lsb 80 +#define xd_p_reg_dummy_95_88 0xA613 +#define reg_dummy_95_88_pos 0 +#define reg_dummy_95_88_len 8 +#define reg_dummy_95_88_lsb 88 +#define xd_p_reg_dummy_103_96 0xA614 +#define reg_dummy_103_96_pos 0 +#define reg_dummy_103_96_len 8 +#define reg_dummy_103_96_lsb 96 + +#define xd_p_reg_unplug_flag 0xA615 +#define reg_unplug_flag_pos 0 +#define reg_unplug_flag_len 1 +#define reg_unplug_flag_lsb 104 + +#define xd_p_reg_api_dca_stes_request 0xA615 +#define reg_api_dca_stes_request_pos 1 +#define reg_api_dca_stes_request_len 1 +#define reg_api_dca_stes_request_lsb 0 + +#define xd_p_reg_back_to_dca_flag 0xA615 +#define reg_back_to_dca_flag_pos 2 +#define reg_back_to_dca_flag_len 1 +#define reg_back_to_dca_flag_lsb 106 + +#define xd_p_reg_api_retrain_request 0xA615 +#define reg_api_retrain_request_pos 3 +#define reg_api_retrain_request_len 1 +#define reg_api_retrain_request_lsb 0 + +#define xd_p_reg_Dyn_Top_Try_flag 0xA615 +#define reg_Dyn_Top_Try_flag_pos 3 +#define reg_Dyn_Top_Try_flag_len 1 +#define reg_Dyn_Top_Try_flag_lsb 107 + +#define xd_p_reg_API_retrain_freeze_flag 0xA615 +#define reg_API_retrain_freeze_flag_pos 4 +#define reg_API_retrain_freeze_flag_len 1 +#define reg_API_retrain_freeze_flag_lsb 108 + +#define xd_p_reg_dummy_111_104 0xA615 +#define reg_dummy_111_104_pos 0 +#define reg_dummy_111_104_len 8 +#define reg_dummy_111_104_lsb 104 +#define xd_p_reg_dummy_119_112 0xA616 +#define reg_dummy_119_112_pos 0 +#define reg_dummy_119_112_len 8 +#define reg_dummy_119_112_lsb 112 +#define xd_p_reg_dummy_127_120 0xA617 +#define reg_dummy_127_120_pos 0 +#define reg_dummy_127_120_len 8 +#define reg_dummy_127_120_lsb 120 +#define xd_p_reg_dummy_135_128 0xA618 +#define reg_dummy_135_128_pos 0 +#define reg_dummy_135_128_len 8 +#define reg_dummy_135_128_lsb 128 + +#define xd_p_reg_dummy_143_136 0xA619 +#define reg_dummy_143_136_pos 0 +#define reg_dummy_143_136_len 8 +#define reg_dummy_143_136_lsb 136 + +#define xd_p_reg_CCIR_dis 0xA619 +#define reg_CCIR_dis_pos 0 +#define reg_CCIR_dis_len 1 +#define reg_CCIR_dis_lsb 0 + +#define xd_p_reg_dummy_151_144 0xA61A +#define reg_dummy_151_144_pos 0 +#define reg_dummy_151_144_len 8 +#define reg_dummy_151_144_lsb 144 + +#define xd_p_reg_dummy_159_152 0xA61B +#define reg_dummy_159_152_pos 0 +#define reg_dummy_159_152_len 8 +#define reg_dummy_159_152_lsb 152 + +#define xd_p_reg_dummy_167_160 0xA61C +#define reg_dummy_167_160_pos 0 +#define reg_dummy_167_160_len 8 +#define reg_dummy_167_160_lsb 160 + +#define xd_p_reg_dummy_175_168 0xA61D +#define reg_dummy_175_168_pos 0 +#define reg_dummy_175_168_len 8 +#define reg_dummy_175_168_lsb 168 + +#define xd_p_reg_dummy_183_176 0xA61E +#define reg_dummy_183_176_pos 0 +#define reg_dummy_183_176_len 8 +#define reg_dummy_183_176_lsb 176 + +#define xd_p_reg_ofsm_read_rbc_en 0xA61E +#define reg_ofsm_read_rbc_en_pos 2 +#define reg_ofsm_read_rbc_en_len 1 +#define reg_ofsm_read_rbc_en_lsb 0 + +#define xd_p_reg_ce_filter_selection_dis 0xA61E +#define reg_ce_filter_selection_dis_pos 1 +#define reg_ce_filter_selection_dis_len 1 +#define reg_ce_filter_selection_dis_lsb 0 + +#define xd_p_reg_OFSM_version_control_7_0 0xA611 +#define reg_OFSM_version_control_7_0_pos 0 +#define reg_OFSM_version_control_7_0_len 8 +#define reg_OFSM_version_control_7_0_lsb 0 + +#define xd_p_reg_OFSM_version_control_15_8 0xA61F +#define reg_OFSM_version_control_15_8_pos 0 +#define reg_OFSM_version_control_15_8_len 8 +#define reg_OFSM_version_control_15_8_lsb 0 + +#define xd_p_reg_OFSM_version_control_23_16 0xA620 +#define reg_OFSM_version_control_23_16_pos 0 +#define reg_OFSM_version_control_23_16_len 8 +#define reg_OFSM_version_control_23_16_lsb 0 + +#define xd_p_reg_dummy_191_184 0xA61F +#define reg_dummy_191_184_pos 0 +#define reg_dummy_191_184_len 8 +#define reg_dummy_191_184_lsb 184 + +#define xd_p_reg_dummy_199_192 0xA620 +#define reg_dummy_199_192_pos 0 +#define reg_dummy_199_192_len 8 +#define reg_dummy_199_192_lsb 192 + +#define xd_p_reg_ce_en 0xABC0 +#define reg_ce_en_pos 0 +#define reg_ce_en_len 1 +#define reg_ce_en_lsb 0 +#define xd_p_reg_ce_fctrl_en 0xABC0 +#define reg_ce_fctrl_en_pos 1 +#define reg_ce_fctrl_en_len 1 +#define reg_ce_fctrl_en_lsb 0 +#define xd_p_reg_ce_fste_tdi 0xABC0 +#define reg_ce_fste_tdi_pos 2 +#define reg_ce_fste_tdi_len 1 +#define reg_ce_fste_tdi_lsb 0 +#define xd_p_reg_ce_dynamic 0xABC0 +#define reg_ce_dynamic_pos 3 +#define reg_ce_dynamic_len 1 +#define reg_ce_dynamic_lsb 0 +#define xd_p_reg_ce_conf 0xABC0 +#define reg_ce_conf_pos 4 +#define reg_ce_conf_len 2 +#define reg_ce_conf_lsb 0 +#define xd_p_reg_ce_dyn12 0xABC0 +#define reg_ce_dyn12_pos 6 +#define reg_ce_dyn12_len 1 +#define reg_ce_dyn12_lsb 0 +#define xd_p_reg_ce_derot_en 0xABC0 +#define reg_ce_derot_en_pos 7 +#define reg_ce_derot_en_len 1 +#define reg_ce_derot_en_lsb 0 +#define xd_p_reg_ce_dynamic_th_7_0 0xABC1 +#define reg_ce_dynamic_th_7_0_pos 0 +#define reg_ce_dynamic_th_7_0_len 8 +#define reg_ce_dynamic_th_7_0_lsb 0 +#define xd_p_reg_ce_dynamic_th_15_8 0xABC2 +#define reg_ce_dynamic_th_15_8_pos 0 +#define reg_ce_dynamic_th_15_8_len 8 +#define reg_ce_dynamic_th_15_8_lsb 8 +#define xd_p_reg_ce_s1 0xABC3 +#define reg_ce_s1_pos 0 +#define reg_ce_s1_len 5 +#define reg_ce_s1_lsb 0 +#define xd_p_reg_ce_var_forced_value 0xABC3 +#define reg_ce_var_forced_value_pos 5 +#define reg_ce_var_forced_value_len 3 +#define reg_ce_var_forced_value_lsb 0 +#define xd_p_reg_ce_data_im_7_0 0xABC4 +#define reg_ce_data_im_7_0_pos 0 +#define reg_ce_data_im_7_0_len 8 +#define reg_ce_data_im_7_0_lsb 0 +#define xd_p_reg_ce_data_im_8 0xABC5 +#define reg_ce_data_im_8_pos 0 +#define reg_ce_data_im_8_len 1 +#define reg_ce_data_im_8_lsb 0 +#define xd_p_reg_ce_data_re_6_0 0xABC5 +#define reg_ce_data_re_6_0_pos 1 +#define reg_ce_data_re_6_0_len 7 +#define reg_ce_data_re_6_0_lsb 0 +#define xd_p_reg_ce_data_re_8_7 0xABC6 +#define reg_ce_data_re_8_7_pos 0 +#define reg_ce_data_re_8_7_len 2 +#define reg_ce_data_re_8_7_lsb 7 +#define xd_p_reg_ce_tone_5_0 0xABC6 +#define reg_ce_tone_5_0_pos 2 +#define reg_ce_tone_5_0_len 6 +#define reg_ce_tone_5_0_lsb 0 +#define xd_p_reg_ce_tone_12_6 0xABC7 +#define reg_ce_tone_12_6_pos 0 +#define reg_ce_tone_12_6_len 7 +#define reg_ce_tone_12_6_lsb 6 +#define xd_p_reg_ce_centroid_drift_th 0xABC8 +#define reg_ce_centroid_drift_th_pos 0 +#define reg_ce_centroid_drift_th_len 8 +#define reg_ce_centroid_drift_th_lsb 0 +#define xd_p_reg_ce_centroid_count_max 0xABC9 +#define reg_ce_centroid_count_max_pos 0 +#define reg_ce_centroid_count_max_len 4 +#define reg_ce_centroid_count_max_lsb 0 +#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA +#define reg_ce_centroid_bias_inc_7_0_pos 0 +#define reg_ce_centroid_bias_inc_7_0_len 8 +#define reg_ce_centroid_bias_inc_7_0_lsb 0 +#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB +#define reg_ce_centroid_bias_inc_8_pos 0 +#define reg_ce_centroid_bias_inc_8_len 1 +#define reg_ce_centroid_bias_inc_8_lsb 0 +#define xd_p_reg_ce_var_th0_7_0 0xABCC +#define reg_ce_var_th0_7_0_pos 0 +#define reg_ce_var_th0_7_0_len 8 +#define reg_ce_var_th0_7_0_lsb 0 +#define xd_p_reg_ce_var_th0_15_8 0xABCD +#define reg_ce_var_th0_15_8_pos 0 +#define reg_ce_var_th0_15_8_len 8 +#define reg_ce_var_th0_15_8_lsb 8 +#define xd_p_reg_ce_var_th1_7_0 0xABCE +#define reg_ce_var_th1_7_0_pos 0 +#define reg_ce_var_th1_7_0_len 8 +#define reg_ce_var_th1_7_0_lsb 0 +#define xd_p_reg_ce_var_th1_15_8 0xABCF +#define reg_ce_var_th1_15_8_pos 0 +#define reg_ce_var_th1_15_8_len 8 +#define reg_ce_var_th1_15_8_lsb 8 +#define xd_p_reg_ce_var_th2_7_0 0xABD0 +#define reg_ce_var_th2_7_0_pos 0 +#define reg_ce_var_th2_7_0_len 8 +#define reg_ce_var_th2_7_0_lsb 0 +#define xd_p_reg_ce_var_th2_15_8 0xABD1 +#define reg_ce_var_th2_15_8_pos 0 +#define reg_ce_var_th2_15_8_len 8 +#define reg_ce_var_th2_15_8_lsb 8 +#define xd_p_reg_ce_var_th3_7_0 0xABD2 +#define reg_ce_var_th3_7_0_pos 0 +#define reg_ce_var_th3_7_0_len 8 +#define reg_ce_var_th3_7_0_lsb 0 +#define xd_p_reg_ce_var_th3_15_8 0xABD3 +#define reg_ce_var_th3_15_8_pos 0 +#define reg_ce_var_th3_15_8_len 8 +#define reg_ce_var_th3_15_8_lsb 8 +#define xd_p_reg_ce_var_th4_7_0 0xABD4 +#define reg_ce_var_th4_7_0_pos 0 +#define reg_ce_var_th4_7_0_len 8 +#define reg_ce_var_th4_7_0_lsb 0 +#define xd_p_reg_ce_var_th4_15_8 0xABD5 +#define reg_ce_var_th4_15_8_pos 0 +#define reg_ce_var_th4_15_8_len 8 +#define reg_ce_var_th4_15_8_lsb 8 +#define xd_p_reg_ce_var_th5_7_0 0xABD6 +#define reg_ce_var_th5_7_0_pos 0 +#define reg_ce_var_th5_7_0_len 8 +#define reg_ce_var_th5_7_0_lsb 0 +#define xd_p_reg_ce_var_th5_15_8 0xABD7 +#define reg_ce_var_th5_15_8_pos 0 +#define reg_ce_var_th5_15_8_len 8 +#define reg_ce_var_th5_15_8_lsb 8 +#define xd_p_reg_ce_var_th6_7_0 0xABD8 +#define reg_ce_var_th6_7_0_pos 0 +#define reg_ce_var_th6_7_0_len 8 +#define reg_ce_var_th6_7_0_lsb 0 +#define xd_p_reg_ce_var_th6_15_8 0xABD9 +#define reg_ce_var_th6_15_8_pos 0 +#define reg_ce_var_th6_15_8_len 8 +#define reg_ce_var_th6_15_8_lsb 8 +#define xd_p_reg_ce_fctrl_reset 0xABDA +#define reg_ce_fctrl_reset_pos 0 +#define reg_ce_fctrl_reset_len 1 +#define reg_ce_fctrl_reset_lsb 0 +#define xd_p_reg_ce_cent_auto_clr_en 0xABDA +#define reg_ce_cent_auto_clr_en_pos 1 +#define reg_ce_cent_auto_clr_en_len 1 +#define reg_ce_cent_auto_clr_en_lsb 0 +#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA +#define reg_ce_fctrl_auto_reset_en_pos 2 +#define reg_ce_fctrl_auto_reset_en_len 1 +#define reg_ce_fctrl_auto_reset_en_lsb 0 +#define xd_p_reg_ce_var_forced_en 0xABDA +#define reg_ce_var_forced_en_pos 3 +#define reg_ce_var_forced_en_len 1 +#define reg_ce_var_forced_en_lsb 0 +#define xd_p_reg_ce_cent_forced_en 0xABDA +#define reg_ce_cent_forced_en_pos 4 +#define reg_ce_cent_forced_en_len 1 +#define reg_ce_cent_forced_en_lsb 0 +#define xd_p_reg_ce_var_max 0xABDA +#define reg_ce_var_max_pos 5 +#define reg_ce_var_max_len 3 +#define reg_ce_var_max_lsb 0 +#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB +#define reg_ce_cent_forced_value_7_0_pos 0 +#define reg_ce_cent_forced_value_7_0_len 8 +#define reg_ce_cent_forced_value_7_0_lsb 0 +#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC +#define reg_ce_cent_forced_value_11_8_pos 0 +#define reg_ce_cent_forced_value_11_8_len 4 +#define reg_ce_cent_forced_value_11_8_lsb 8 +#define xd_p_reg_ce_fctrl_rd 0xABDD +#define reg_ce_fctrl_rd_pos 0 +#define reg_ce_fctrl_rd_len 1 +#define reg_ce_fctrl_rd_lsb 0 +#define xd_p_reg_ce_centroid_max_6_0 0xABDD +#define reg_ce_centroid_max_6_0_pos 1 +#define reg_ce_centroid_max_6_0_len 7 +#define reg_ce_centroid_max_6_0_lsb 0 +#define xd_p_reg_ce_centroid_max_11_7 0xABDE +#define reg_ce_centroid_max_11_7_pos 0 +#define reg_ce_centroid_max_11_7_len 5 +#define reg_ce_centroid_max_11_7_lsb 7 +#define xd_p_reg_ce_var 0xABDF +#define reg_ce_var_pos 0 +#define reg_ce_var_len 3 +#define reg_ce_var_lsb 0 +#define xd_p_reg_ce_fctrl_rdy 0xABDF +#define reg_ce_fctrl_rdy_pos 3 +#define reg_ce_fctrl_rdy_len 1 +#define reg_ce_fctrl_rdy_lsb 0 +#define xd_p_reg_ce_centroid_out_3_0 0xABDF +#define reg_ce_centroid_out_3_0_pos 4 +#define reg_ce_centroid_out_3_0_len 4 +#define reg_ce_centroid_out_3_0_lsb 0 +#define xd_p_reg_ce_centroid_out_11_4 0xABE0 +#define reg_ce_centroid_out_11_4_pos 0 +#define reg_ce_centroid_out_11_4_len 8 +#define reg_ce_centroid_out_11_4_lsb 4 +#define xd_p_reg_ce_bias_7_0 0xABE1 +#define reg_ce_bias_7_0_pos 0 +#define reg_ce_bias_7_0_len 8 +#define reg_ce_bias_7_0_lsb 0 +#define xd_p_reg_ce_bias_11_8 0xABE2 +#define reg_ce_bias_11_8_pos 0 +#define reg_ce_bias_11_8_len 4 +#define reg_ce_bias_11_8_lsb 8 +#define xd_p_reg_ce_m1_3_0 0xABE2 +#define reg_ce_m1_3_0_pos 4 +#define reg_ce_m1_3_0_len 4 +#define reg_ce_m1_3_0_lsb 0 +#define xd_p_reg_ce_m1_11_4 0xABE3 +#define reg_ce_m1_11_4_pos 0 +#define reg_ce_m1_11_4_len 8 +#define reg_ce_m1_11_4_lsb 4 +#define xd_p_reg_ce_rh0_7_0 0xABE4 +#define reg_ce_rh0_7_0_pos 0 +#define reg_ce_rh0_7_0_len 8 +#define reg_ce_rh0_7_0_lsb 0 +#define xd_p_reg_ce_rh0_15_8 0xABE5 +#define reg_ce_rh0_15_8_pos 0 +#define reg_ce_rh0_15_8_len 8 +#define reg_ce_rh0_15_8_lsb 8 +#define xd_p_reg_ce_rh0_23_16 0xABE6 +#define reg_ce_rh0_23_16_pos 0 +#define reg_ce_rh0_23_16_len 8 +#define reg_ce_rh0_23_16_lsb 16 +#define xd_p_reg_ce_rh0_31_24 0xABE7 +#define reg_ce_rh0_31_24_pos 0 +#define reg_ce_rh0_31_24_len 8 +#define reg_ce_rh0_31_24_lsb 24 +#define xd_p_reg_ce_rh3_real_7_0 0xABE8 +#define reg_ce_rh3_real_7_0_pos 0 +#define reg_ce_rh3_real_7_0_len 8 +#define reg_ce_rh3_real_7_0_lsb 0 +#define xd_p_reg_ce_rh3_real_15_8 0xABE9 +#define reg_ce_rh3_real_15_8_pos 0 +#define reg_ce_rh3_real_15_8_len 8 +#define reg_ce_rh3_real_15_8_lsb 8 +#define xd_p_reg_ce_rh3_real_23_16 0xABEA +#define reg_ce_rh3_real_23_16_pos 0 +#define reg_ce_rh3_real_23_16_len 8 +#define reg_ce_rh3_real_23_16_lsb 16 +#define xd_p_reg_ce_rh3_real_31_24 0xABEB +#define reg_ce_rh3_real_31_24_pos 0 +#define reg_ce_rh3_real_31_24_len 8 +#define reg_ce_rh3_real_31_24_lsb 24 +#define xd_p_reg_ce_rh3_imag_7_0 0xABEC +#define reg_ce_rh3_imag_7_0_pos 0 +#define reg_ce_rh3_imag_7_0_len 8 +#define reg_ce_rh3_imag_7_0_lsb 0 +#define xd_p_reg_ce_rh3_imag_15_8 0xABED +#define reg_ce_rh3_imag_15_8_pos 0 +#define reg_ce_rh3_imag_15_8_len 8 +#define reg_ce_rh3_imag_15_8_lsb 8 +#define xd_p_reg_ce_rh3_imag_23_16 0xABEE +#define reg_ce_rh3_imag_23_16_pos 0 +#define reg_ce_rh3_imag_23_16_len 8 +#define reg_ce_rh3_imag_23_16_lsb 16 +#define xd_p_reg_ce_rh3_imag_31_24 0xABEF +#define reg_ce_rh3_imag_31_24_pos 0 +#define reg_ce_rh3_imag_31_24_len 8 +#define reg_ce_rh3_imag_31_24_lsb 24 +#define xd_p_reg_feq_fix_eh2_7_0 0xABF0 +#define reg_feq_fix_eh2_7_0_pos 0 +#define reg_feq_fix_eh2_7_0_len 8 +#define reg_feq_fix_eh2_7_0_lsb 0 +#define xd_p_reg_feq_fix_eh2_15_8 0xABF1 +#define reg_feq_fix_eh2_15_8_pos 0 +#define reg_feq_fix_eh2_15_8_len 8 +#define reg_feq_fix_eh2_15_8_lsb 8 +#define xd_p_reg_feq_fix_eh2_23_16 0xABF2 +#define reg_feq_fix_eh2_23_16_pos 0 +#define reg_feq_fix_eh2_23_16_len 8 +#define reg_feq_fix_eh2_23_16_lsb 16 +#define xd_p_reg_feq_fix_eh2_31_24 0xABF3 +#define reg_feq_fix_eh2_31_24_pos 0 +#define reg_feq_fix_eh2_31_24_len 8 +#define reg_feq_fix_eh2_31_24_lsb 24 +#define xd_p_reg_ce_m2_central_7_0 0xABF4 +#define reg_ce_m2_central_7_0_pos 0 +#define reg_ce_m2_central_7_0_len 8 +#define reg_ce_m2_central_7_0_lsb 0 +#define xd_p_reg_ce_m2_central_15_8 0xABF5 +#define reg_ce_m2_central_15_8_pos 0 +#define reg_ce_m2_central_15_8_len 8 +#define reg_ce_m2_central_15_8_lsb 8 +#define xd_p_reg_ce_fftshift 0xABF6 +#define reg_ce_fftshift_pos 0 +#define reg_ce_fftshift_len 4 +#define reg_ce_fftshift_lsb 0 +#define xd_p_reg_ce_fftshift1 0xABF6 +#define reg_ce_fftshift1_pos 4 +#define reg_ce_fftshift1_len 4 +#define reg_ce_fftshift1_lsb 0 +#define xd_p_reg_ce_fftshift2 0xABF7 +#define reg_ce_fftshift2_pos 0 +#define reg_ce_fftshift2_len 4 +#define reg_ce_fftshift2_lsb 0 +#define xd_p_reg_ce_top_mobile 0xABF7 +#define reg_ce_top_mobile_pos 4 +#define reg_ce_top_mobile_len 1 +#define reg_ce_top_mobile_lsb 0 +#define xd_p_reg_strong_sginal_detected 0xA2BC +#define reg_strong_sginal_detected_pos 2 +#define reg_strong_sginal_detected_len 1 +#define reg_strong_sginal_detected_lsb 0 + +#define XD_MP2IF_BASE 0xB000 +#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE) +#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE) +#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE) + +extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d); +extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, + u8 * value); +extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, + u8 value); +extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 addr, u8 * values, int len); +extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, + u8 pos, u8 len, u8 * value); +extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, + u8 pos, u8 len, u8 value); +extern int af9005_send_command(struct dvb_usb_device *d, u8 command, + u8 * wbuf, int wlen, u8 * rbuf, int rlen); +extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, + u8 * values, int len); +extern int af9005_tuner_attach(struct dvb_usb_adapter *adap); +extern int af9005_led_control(struct dvb_usb_device *d, int onoff); + +extern u8 regmask[8]; + +/* remote control decoder */ +extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, + u32 * event, int *state); +extern struct rc_map_table rc_map_af9005_table[]; +extern int rc_map_af9005_table_size; + +#endif diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c new file mode 100644 index 00000000000..5e45ae60542 --- /dev/null +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -0,0 +1,1182 @@ +/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027) + * receiver. + * + * Copyright (C) 2009 Adams.Xu + * + * 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 "az6027.h" + +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" + +#include "stb6100.h" +#include "stb6100_cfg.h" +#include "dvb_ca_en50221.h" + +int dvb_usb_az6027_debug; +module_param_named(debug, dvb_usb_az6027_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct az6027_device_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; + u8 power_state; +}; + +static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = { + + /* 0x0000000b, SYSREG */ + { STB0899_DEV_ID , 0x30 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x99 }, + { STB0899_DISF22RX , 0xa8 }, + /* SYSREG ? */ + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0xfe }, + { STB0899_IRQSTATUS_2 , 0x03 }, + { STB0899_IRQSTATUS_1 , 0x7c }, + { STB0899_IRQSTATUS_0 , 0xf4 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x33 }, + { STB0899_IOPVALUE3 , 0x6d }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x60 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x01 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x01 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x23 }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xf7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xf1 }, + { STB0899_LDT2 , 0xe3 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfd }, + { STB0899_QDCCOMP , 0xff }, + { STB0899_POWERI , 0x0c }, + { STB0899_POWERQ , 0x0f }, + { STB0899_RCOMP , 0x6c }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x06 }, + { STB0899_AGC2I2 , 0x00 }, + { STB0899_TLIR , 0x30 }, + { STB0899_RTF , 0x7f }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xbc }, + { STB0899_CFRM , 0xea }, + { STB0899_CFRL , 0x31 }, + { STB0899_NIRM , 0x2b }, + { STB0899_NIRL , 0x80 }, + { STB0899_ISYMB , 0x1d }, + { STB0899_QSYMB , 0xa6 }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0x02 }, + { STB0899_EQUAQ1 , 0xff }, + { STB0899_EQUAI2 , 0x04 }, + { STB0899_EQUAQ2 , 0x05 }, + { STB0899_EQUAI3 , 0x02 }, + { STB0899_EQUAQ3 , 0xfd }, + { STB0899_EQUAI4 , 0x03 }, + { STB0899_EQUAQ4 , 0x07 }, + { STB0899_EQUAI5 , 0x08 }, + { STB0899_EQUAQ5 , 0xf5 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0x86 }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x0a }, + { STB0899_ECNT3L , 0xad }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xb0 }, + { STB0899_VTH23 , 0x7a }, + { STB0899_VTH34 , 0x58 }, + { STB0899_VTH56 , 0x38 }, + { STB0899_VTH67 , 0x34 }, + { STB0899_VTH78 , 0x24 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x41 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x00 }, + { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x1b }, + { STB0899_TSLLSTKL , 0xb3 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0x00 }, + { STB0899_PCKLENUL , 0xbc }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xbd }, + { STB0899_TSSTATUS , 0x90 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x95 }, + { STB0899_ERRCTRL3 , 0x8d }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x19 }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0xf0 }, + { STB0899_MATSTRL , 0x02 }, + { STB0899_UPLSTRM , 0x45 }, + { STB0899_UPLSTRL , 0x60 }, + { STB0899_DFLSTRM , 0xe3 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x47 }, + { STB0899_SYNCDSTRM , 0x05 }, + { STB0899_SYNCDSTRL , 0x18 }, + { STB0899_CFGPDELSTATUS1 , 0x19 }, + { STB0899_CFGPDELSTATUS2 , 0x2b }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x01 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + + + +struct stb0899_config az6027_stb0899_config = { + .init_dev = az6027_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = az6027_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, +}; + +struct stb6100_config az6027_stb6100_config = { + .tuner_address = 0xc0, + .refclock = 27000000, +}; + + +/* check for mutex FIXME */ +int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = -1; + if (mutex_lock_interruptible(&d->usb_mutex)) + return -EAGAIN; + + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value, + index, + b, + blen, + 2000); + + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); + debug_dump(b, blen, deb_xfer); + + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int az6027_usb_out_op(struct dvb_usb_device *d, + u8 req, + u16 value, + u16 index, + u8 *b, + int blen) +{ + int ret; + + deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); + debug_dump(b, blen, deb_xfer); + + if (mutex_lock_interruptible(&d->usb_mutex)) + return -EAGAIN; + + ret = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value, + index, + b, + blen, + 2000); + + if (ret != blen) { + warn("usb out operation failed. (%d)", ret); + mutex_unlock(&d->usb_mutex); + return -EIO; + } else{ + mutex_unlock(&d->usb_mutex); + return 0; + } +} + +static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + deb_info("%s %d", __func__, onoff); + + req = 0xBC; + value = onoff; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + warn("usb out operation failed. (%d)", ret); + + return ret; +} + +/* keys for the enclosed remote control */ +static struct rc_map_table rc_map_az6027_table[] = { + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, +}; + +/* remote control stuff (does not work with my box) */ +static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + return 0; +} + +/* +int az6027_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 v = onoff; + return az6027_usb_out_op(d,0xBC,v,3,NULL,1); +} +*/ + +static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, + int address) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + if (slot != 0) + return -EINVAL; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + mutex_lock(&state->ca_mutex); + + req = 0xC1; + value = address; + index = 0; + blen = 1; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EINVAL; + } else { + ret = b[0]; + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + +static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, + int address, + u8 value) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value1; + u16 index; + int blen; + + deb_info("%s %d", __func__, slot); + if (slot != 0) + return -EINVAL; + + mutex_lock(&state->ca_mutex); + req = 0xC2; + value1 = address; + index = value; + blen = 0; + + ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); + if (ret != 0) + warn("usb out operation failed. (%d)", ret); + + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + if (slot != 0) + return -EINVAL; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + mutex_lock(&state->ca_mutex); + + req = 0xC3; + value = address; + index = 0; + blen = 2; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EINVAL; + } else { + if (b[0] == 0) + warn("Read CI IO error"); + + ret = b[1]; + deb_info("read cam data = %x from 0x%x", b[1], value); + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + +static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address, + u8 value) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value1; + u16 index; + int blen; + + if (slot != 0) + return -EINVAL; + + mutex_lock(&state->ca_mutex); + req = 0xC4; + value1 = address; + index = value; + blen = 0; + + ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + req = 0xC8; + value = 0; + index = 0; + blen = 1; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else{ + ret = b[0]; + } + kfree(b); + return ret; +} + +static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret, i; + u8 req; + u16 value; + u16 index; + int blen; + + mutex_lock(&state->ca_mutex); + + req = 0xC6; + value = 1; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(d, req, value, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + + msleep(500); + req = 0xC6; + value = 0; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(d, req, value, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + + for (i = 0; i < 15; i++) { + msleep(100); + + if (CI_CamReady(ca, slot)) { + deb_info("CAM Ready"); + break; + } + } + msleep(5000); + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return 0; +} + +static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + deb_info("%s", __func__); + mutex_lock(&state->ca_mutex); + req = 0xC7; + value = 1; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(d, req, value, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + mutex_lock(&state->ca_mutex); + + req = 0xC5; + value = 0; + index = 0; + blen = 1; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else + ret = 0; + + if (!ret && b[0] == 1) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + + +static void az6027_ci_uninit(struct dvb_usb_device *d) +{ + struct az6027_device_state *state; + + deb_info("%s", __func__); + + if (NULL == d) + return; + + state = (struct az6027_device_state *)d->priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + + +static int az6027_ci_init(struct dvb_usb_adapter *a) +{ + struct dvb_usb_device *d = a->dev; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + int ret; + + deb_info("%s", __func__); + + mutex_init(&state->ca_mutex); + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = az6027_ci_read_attribute_mem; + state->ca.write_attribute_mem = az6027_ci_write_attribute_mem; + state->ca.read_cam_control = az6027_ci_read_cam_control; + state->ca.write_cam_control = az6027_ci_write_cam_control; + state->ca.slot_reset = az6027_ci_slot_reset; + state->ca.slot_shutdown = az6027_ci_slot_shutdown; + state->ca.slot_ts_enable = az6027_ci_slot_ts_enable; + state->ca.poll_slot_status = az6027_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&a->dvb_adap, + &state->ca, + 0, /* flags */ + 1);/* n_slots */ + if (ret != 0) { + err("Cannot initialize CI: Error %d.", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + deb_info("CI initialized."); + + return 0; +} + +/* +static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) +{ + az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6); + return 0; +} +*/ + +static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + + u8 buf; + struct dvb_usb_adapter *adap = fe->dvb->priv; + + struct i2c_msg i2c_msg = { + .addr = 0x99, + .flags = 0, + .buf = &buf, + .len = 1 + }; + + /* + * 2 --18v + * 1 --13v + * 0 --off + */ + switch (voltage) { + case SEC_VOLTAGE_13: + buf = 1; + i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + break; + + case SEC_VOLTAGE_18: + buf = 2; + i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + break; + + case SEC_VOLTAGE_OFF: + buf = 0; + i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + break; + + default: + return -EINVAL; + } + return 0; +} + + +static int az6027_frontend_poweron(struct dvb_usb_adapter *adap) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + req = 0xBC; + value = 1; /* power on */ + index = 3; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + return 0; +} +static int az6027_frontend_reset(struct dvb_usb_adapter *adap) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + /* reset demodulator */ + req = 0xC0; + value = 1; /* high */ + index = 3; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + req = 0xC0; + value = 0; /* low */ + index = 3; + blen = 0; + msleep_interruptible(200); + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + msleep_interruptible(200); + + req = 0xC0; + value = 1; /*high */ + index = 3; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + msleep_interruptible(200); + return 0; +} + +static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + /* TS passthrough */ + req = 0xC7; + value = onoff; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + return 0; +} + +static int az6027_frontend_attach(struct dvb_usb_adapter *adap) +{ + + az6027_frontend_poweron(adap); + az6027_frontend_reset(adap); + + deb_info("adap = %p, dev = %p\n", adap, adap->dev); + adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); + + if (adap->fe_adap[0].fe) { + deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); + if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { + deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); + adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage; + az6027_ci_init(adap); + } else { + adap->fe_adap[0].fe = NULL; + } + } else + warn("no front-end attached\n"); + + az6027_frontend_tsbypass(adap, 0); + + return 0; +} + +static struct dvb_usb_device_properties az6027_properties; + +static void az6027_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + az6027_ci_uninit(d); + dvb_usb_device_exit(intf); +} + + +static int az6027_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, + &az6027_properties, + THIS_MODULE, + NULL, + adapter_nr); +} + +/* I2C */ +static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0, j = 0, len = 0; + u16 index; + u16 value; + int length; + u8 req; + u8 *data; + + data = kmalloc(256, GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) { + kfree(data); + return -EAGAIN; + } + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + + if (msg[i].addr == 0x99) { + req = 0xBE; + index = 0; + value = msg[i].buf[0] & 0x00ff; + length = 1; + az6027_usb_out_op(d, req, value, index, data, length); + } + + if (msg[i].addr == 0xd0) { + /* write/read request */ + if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { + req = 0xB9; + index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); + value = msg[i].addr + (msg[i].len << 8); + length = msg[i + 1].len + 6; + az6027_usb_in_op(d, req, value, index, data, length); + len = msg[i + 1].len; + for (j = 0; j < len; j++) + msg[i + 1].buf[j] = data[j + 5]; + + i++; + } else { + + /* demod 16bit addr */ + req = 0xBD; + index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); + value = msg[i].addr + (2 << 8); + length = msg[i].len - 2; + len = msg[i].len - 2; + for (j = 0; j < len; j++) + data[j] = msg[i].buf[j + 2]; + az6027_usb_out_op(d, req, value, index, data, length); + } + } + + if (msg[i].addr == 0xc0) { + if (msg[i].flags & I2C_M_RD) { + + req = 0xB9; + index = 0x0; + value = msg[i].addr; + length = msg[i].len + 6; + az6027_usb_in_op(d, req, value, index, data, length); + len = msg[i].len; + for (j = 0; j < len; j++) + msg[i].buf[j] = data[j + 5]; + + } else { + + req = 0xBD; + index = msg[i].buf[0] & 0x00FF; + value = msg[i].addr + (1 << 8); + length = msg[i].len - 1; + len = msg[i].len - 1; + + for (j = 0; j < len; j++) + data[j] = msg[i].buf[j + 1]; + + az6027_usb_out_op(d, req, value, index, data, length); + } + } + } + mutex_unlock(&d->i2c_mutex); + kfree(data); + + return i; +} + + +static u32 az6027_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm az6027_i2c_algo = { + .master_xfer = az6027_i2c_xfer, + .functionality = az6027_i2c_func, +}; + +int az6027_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + u8 *b; + s16 ret; + + b = kmalloc(16, GFP_KERNEL); + if (!b) + return -ENOMEM; + + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0xb7, + USB_TYPE_VENDOR | USB_DIR_IN, + 6, + 0, + b, + 6, + USB_CTRL_GET_TIMEOUT); + + *cold = ret <= 0; + kfree(b); + deb_info("cold: %d\n", *cold); + return 0; +} + + +static struct usb_device_id az6027_usb_table[] = { + { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V1) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, + { }, +}; + +MODULE_DEVICE_TABLE(usb, az6027_usb_table); + +static struct dvb_usb_device_properties az6027_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-az6027-03.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct az6027_device_state), + .identify_state = az6027_identify_state, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = az6027_streaming_ctrl, + .frontend_attach = az6027_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, +/* + .power_ctrl = az6027_power_ctrl, + .read_mac_address = az6027_read_mac_addr, + */ + .rc.legacy = { + .rc_map_table = rc_map_az6027_table, + .rc_map_size = ARRAY_SIZE(rc_map_az6027_table), + .rc_interval = 400, + .rc_query = az6027_rc_query, + }, + + .i2c_algo = &az6027_i2c_algo, + + .num_device_descs = 6, + .devices = { + { + .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", + .cold_ids = { &az6027_usb_table[0], NULL }, + .warm_ids = { NULL }, + }, { + .name = "TERRATEC S7", + .cold_ids = { &az6027_usb_table[1], NULL }, + .warm_ids = { NULL }, + }, { + .name = "TERRATEC S7 MKII", + .cold_ids = { &az6027_usb_table[2], NULL }, + .warm_ids = { NULL }, + }, { + .name = "Technisat SkyStar USB 2 HD CI", + .cold_ids = { &az6027_usb_table[3], NULL }, + .warm_ids = { NULL }, + }, { + .name = "Technisat SkyStar USB 2 HD CI", + .cold_ids = { &az6027_usb_table[4], NULL }, + .warm_ids = { NULL }, + }, { + .name = "Elgato EyeTV Sat", + .cold_ids = { &az6027_usb_table[5], NULL }, + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver az6027_usb_driver = { + .name = "dvb_usb_az6027", + .probe = az6027_usb_probe, + .disconnect = az6027_usb_disconnect, + .id_table = az6027_usb_table, +}; + +module_usb_driver(az6027_usb_driver); + +MODULE_AUTHOR("Adams Xu "); +MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/az6027.h b/drivers/media/usb/dvb-usb/az6027.h new file mode 100644 index 00000000000..f3afe17f3f3 --- /dev/null +++ b/drivers/media/usb/dvb-usb/az6027.h @@ -0,0 +1,14 @@ +#ifndef _DVB_USB_VP6027_H_ +#define _DVB_USB_VP6027_H_ + +#define DVB_USB_LOG_PREFIX "az6027" +#include "dvb-usb.h" + + +extern int dvb_usb_az6027_debug; +#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args) +#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args) + +#endif diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c new file mode 100644 index 00000000000..0a98548ecd1 --- /dev/null +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -0,0 +1,254 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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 "cinergyT2.h" + + +/* debug */ +int dvb_usb_cinergyt2_debug; + +module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " + "(or-able))."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct cinergyt2_state { + u8 rc_counter; +}; + +/* We are missing a release hook with usb_device data */ +static struct dvb_usb_device *cinergyt2_usb_device; + +static struct dvb_usb_device_properties cinergyt2_properties; + +static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) +{ + char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; + char result[64]; + return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, + sizeof(result), 0); +} + +static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) +{ + char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; + char state[3]; + return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); +} + +static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) +{ + char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; + char state[3]; + int ret; + + adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev); + + ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, + sizeof(state), 0); + if (ret < 0) { + deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " + "state info\n"); + } + + /* Copy this pointer as we are gonna need it in the release phase */ + cinergyt2_usb_device = adap->dev; + + return 0; +} + +static struct rc_map_table rc_map_cinergyt2_table[] = { + { 0x0401, KEY_POWER }, + { 0x0402, KEY_1 }, + { 0x0403, KEY_2 }, + { 0x0404, KEY_3 }, + { 0x0405, KEY_4 }, + { 0x0406, KEY_5 }, + { 0x0407, KEY_6 }, + { 0x0408, KEY_7 }, + { 0x0409, KEY_8 }, + { 0x040a, KEY_9 }, + { 0x040c, KEY_0 }, + { 0x040b, KEY_VIDEO }, + { 0x040d, KEY_REFRESH }, + { 0x040e, KEY_SELECT }, + { 0x040f, KEY_EPG }, + { 0x0410, KEY_UP }, + { 0x0414, KEY_DOWN }, + { 0x0411, KEY_LEFT }, + { 0x0413, KEY_RIGHT }, + { 0x0412, KEY_OK }, + { 0x0415, KEY_TEXT }, + { 0x0416, KEY_INFO }, + { 0x0417, KEY_RED }, + { 0x0418, KEY_GREEN }, + { 0x0419, KEY_YELLOW }, + { 0x041a, KEY_BLUE }, + { 0x041c, KEY_VOLUMEUP }, + { 0x041e, KEY_VOLUMEDOWN }, + { 0x041d, KEY_MUTE }, + { 0x041b, KEY_CHANNELUP }, + { 0x041f, KEY_CHANNELDOWN }, + { 0x0440, KEY_PAUSE }, + { 0x044c, KEY_PLAY }, + { 0x0458, KEY_RECORD }, + { 0x0454, KEY_PREVIOUS }, + { 0x0448, KEY_STOP }, + { 0x045c, KEY_NEXT } +}; + +/* Number of keypresses to ignore before detect repeating */ +#define RC_REPEAT_DELAY 3 + +static int repeatable_keys[] = { + KEY_UP, + KEY_DOWN, + KEY_LEFT, + KEY_RIGHT, + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + KEY_CHANNELUP, + KEY_CHANNELDOWN +}; + +static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct cinergyt2_state *st = d->priv; + u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; + int i; + + *state = REMOTE_NO_KEY_PRESSED; + + dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); + if (key[4] == 0xff) { + /* key repeat */ + st->rc_counter++; + if (st->rc_counter > RC_REPEAT_DELAY) { + for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { + if (d->last_event == repeatable_keys[i]) { + *state = REMOTE_KEY_REPEAT; + *event = d->last_event; + deb_rc("repeat key, event %x\n", + *event); + return 0; + } + } + deb_rc("repeated key (non repeatable)\n"); + } + return 0; + } + + /* hack to pass checksum on the custom field */ + key[2] = ~key[1]; + dvb_usb_nec_rc_key_to_event(d, key, event, state); + if (key[0] != 0) { + if (*event != d->last_event) + st->rc_counter = 0; + + deb_rc("key: %x %x %x %x %x\n", + key[0], key[1], key[2], key[3], key[4]); + } + return 0; +} + +static int cinergyt2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &cinergyt2_properties, + THIS_MODULE, NULL, adapter_nr); +} + + +static struct usb_device_id cinergyt2_usb_table[] = { + { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); + +static struct dvb_usb_device_properties cinergyt2_properties = { + .size_of_priv = sizeof(struct cinergyt2_state), + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cinergyt2_streaming_ctrl, + .frontend_attach = cinergyt2_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + } + }, + + .power_ctrl = cinergyt2_power_ctrl, + + .rc.legacy = { + .rc_interval = 50, + .rc_map_table = rc_map_cinergyt2_table, + .rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table), + .rc_query = cinergyt2_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 1, + + .num_device_descs = 1, + .devices = { + { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", + .cold_ids = {NULL}, + .warm_ids = { &cinergyt2_usb_table[0], NULL }, + }, + { NULL }, + } +}; + + +static struct usb_driver cinergyt2_driver = { + .name = "cinergyT2", + .probe = cinergyt2_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cinergyt2_usb_table +}; + +module_usb_driver(cinergyt2_driver); + +MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tomi Orava"); diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c new file mode 100644 index 00000000000..1efc028a76c --- /dev/null +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -0,0 +1,356 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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 "cinergyT2.h" + + +/** + * convert linux-dvb frontend parameter set into TPS. + * See ETSI ETS-300744, section 4.6.2, table 9 for details. + * + * This function is probably reusable and may better get placed in a support + * library. + * + * We replace errornous fields by default TPS fields (the ones with value 0). + */ + +static uint16_t compute_tps(struct dtv_frontend_properties *op) +{ + uint16_t tps = 0; + + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 7) */; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 4) */; + } + + switch (op->modulation) { + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + case QPSK: + default: + /* tps |= (0 << 13) */; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + case TRANSMISSION_MODE_2K: + default: + /* tps |= (0 << 0) */; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + case GUARD_INTERVAL_1_32: + default: + /* tps |= (0 << 2) */; + } + + switch (op->hierarchy) { + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + case HIERARCHY_NONE: + default: + /* tps |= (0 << 10) */; + } + + return tps; +} + +struct cinergyt2_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; +}; + +static int cinergyt2_fe_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg result; + u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, + sizeof(result), 0); + if (ret < 0) + return ret; + + *status = 0; + + if (0xffff - le16_to_cpu(result.gain) > 30) + *status |= FE_HAS_SIGNAL; + if (result.lock_bits & (1 << 6)) + *status |= FE_HAS_LOCK; + if (result.lock_bits & (1 << 5)) + *status |= FE_HAS_SYNC; + if (result.lock_bits & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (result.lock_bits & (1 << 1)) + *status |= FE_HAS_VITERBI; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) + return ret; + + *ber = le32_to_cpu(status.viterbi_error_rate); + return 0; +} + +static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", + ret); + return ret; + } + *unc = le32_to_cpu(status.uncorrected_block_count); + return 0; +} + +static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_signal_strength() Failed!" + " (Error=%d)\n", ret); + return ret; + } + *strength = (0xffff - le16_to_cpu(status.gain)); + return 0; +} + +static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); + return ret; + } + *snr = (status.snr << 8) | status.snr; + return 0; +} + +static int cinergyt2_fe_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int cinergyt2_fe_sleep(struct dvb_frontend *fe) +{ + deb_info("cinergyt2_fe_sleep() Called\n"); + return 0; +} + +static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_set_parameters_msg param; + char result[2]; + int err; + + param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param.tps = cpu_to_le16(compute_tps(fep)); + param.freq = cpu_to_le32(fep->frequency / 1000); + param.flags = 0; + + switch (fep->bandwidth_hz) { + default: + case 8000000: + param.bandwidth = 8; + break; + case 7000000: + param.bandwidth = 7; + break; + case 6000000: + param.bandwidth = 6; + break; + } + + err = dvb_usb_generic_rw(state->d, + (char *)¶m, sizeof(param), + result, sizeof(result), 0); + if (err < 0) + err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); + + return (err < 0) ? err : 0; +} + +static void cinergyt2_fe_release(struct dvb_frontend *fe) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + if (state != NULL) + kfree(state); +} + +static struct dvb_frontend_ops cinergyt2_fe_ops; + +struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) +{ + struct cinergyt2_fe_state *s = kzalloc(sizeof( + struct cinergyt2_fe_state), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->d = d; + memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + return &s->fe; +} + + +static struct dvb_frontend_ops cinergyt2_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = DRIVER_NAME, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 + | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 + | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 + | FE_CAN_FEC_AUTO | FE_CAN_QPSK + | FE_CAN_QAM_16 | FE_CAN_QAM_64 + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .release = cinergyt2_fe_release, + + .init = cinergyt2_fe_init, + .sleep = cinergyt2_fe_sleep, + + .set_frontend = cinergyt2_fe_set_frontend, + .get_tune_settings = cinergyt2_fe_get_tune_settings, + + .read_status = cinergyt2_fe_read_status, + .read_ber = cinergyt2_fe_read_ber, + .read_signal_strength = cinergyt2_fe_read_signal_strength, + .read_snr = cinergyt2_fe_read_snr, + .read_ucblocks = cinergyt2_fe_read_unc_blocks, +}; diff --git a/drivers/media/usb/dvb-usb/cinergyT2.h b/drivers/media/usb/dvb-usb/cinergyT2.h new file mode 100644 index 00000000000..84efe03771e --- /dev/null +++ b/drivers/media/usb/dvb-usb/cinergyT2.h @@ -0,0 +1,95 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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 _DVB_USB_CINERGYT2_H_ +#define _DVB_USB_CINERGYT2_H_ + +#include + +#define DVB_USB_LOG_PREFIX "cinergyT2" +#include "dvb-usb.h" + +#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" + +extern int dvb_usb_cinergyt2_debug; + +#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args) +#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args) +#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args) +#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args) +#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args) +#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args) +#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args) +#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args) +#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args) + + + +enum cinergyt2_ep1_cmd { + CINERGYT2_EP1_PID_TABLE_RESET = 0x01, + CINERGYT2_EP1_PID_SETUP = 0x02, + CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, + CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, + CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, + CINERGYT2_EP1_START_SCAN = 0x06, + CINERGYT2_EP1_CONTINUE_SCAN = 0x07, + CINERGYT2_EP1_GET_RC_EVENTS = 0x08, + CINERGYT2_EP1_SLEEP_MODE = 0x09, + CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A +}; + + +struct dvbt_get_status_msg { + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; + __le16 gain; + uint8_t snr; + __le32 viterbi_error_rate; + uint32_t rs_error_rate; + __le32 uncorrected_block_count; + uint8_t lock_bits; + uint8_t prev_lock_bits; +} __attribute__((packed)); + + +struct dvbt_set_parameters_msg { + uint8_t cmd; + __le32 freq; + uint8_t bandwidth; + __le16 tps; + uint8_t flags; +} __attribute__((packed)); + + +extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d); + +#endif /* _DVB_USB_CINERGYT2_H_ */ + diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c new file mode 100644 index 00000000000..3940bb0f9ef --- /dev/null +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -0,0 +1,2043 @@ +/* DVB USB compliant linux driver for Conexant USB reference design. + * + * The Conexant reference design I saw on their website was only for analogue + * capturing (using the cx25842). The box I took to write this driver (reverse + * engineered) is the one labeled Medion MD95700. In addition to the cx25842 + * for analogue capturing it also has a cx22702 DVB-T demodulator on the main + * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard. + * + * Maybe it is a little bit premature to call this driver cxusb, but I assume + * the USB protocol is identical or at least inherited from the reference + * design, so it can be reused for the "analogue-only" device (if it will + * appear at all). + * + * TODO: Use the cx25840-driver for the analogue part + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) + * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * + * 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 +#include +#include + +#include "cxusb.h" + +#include "cx22702.h" +#include "lgdt330x.h" +#include "mt352.h" +#include "mt352_priv.h" +#include "zl10353.h" +#include "tuner-xc2028.h" +#include "tuner-simple.h" +#include "mxl5005s.h" +#include "max2165.h" +#include "dib7000p.h" +#include "dib0070.h" +#include "lgs8gxx.h" +#include "atbm8830.h" + +/* debug */ +static int dvb_usb_cxusb_debug; +module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) +#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) + +static int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 sndbuf[1+wlen]; + memset(sndbuf, 0, 1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1], wbuf, wlen); + if (wo) + return dvb_usb_generic_write(d, sndbuf, 1+wlen); + else + return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); +} + +/* GPIO */ +static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) +{ + struct cxusb_state *st = d->priv; + u8 o[2], i; + + if (st->gpio_write_state[GPIO_TUNER] == onoff) + return; + + o[0] = GPIO_TUNER; + o[1] = onoff; + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (i != 0x01) + deb_info("gpio_write failed.\n"); + + st->gpio_write_state[GPIO_TUNER] = onoff; +} + +static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, + u8 newval) +{ + u8 o[2], gpio_state; + int rc; + + o[0] = 0xff & ~changemask; /* mask of bits to keep */ + o[1] = newval & changemask; /* new values for bits */ + + rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); + if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) + deb_info("bluebird_gpio_write failed.\n"); + + return rc < 0 ? rc : gpio_state; +} + +static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) +{ + cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); + msleep(5); + cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); +} + +static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) +{ + cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); +} + +static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, + u8 addr, int onoff) +{ + u8 o[2] = {addr, onoff}; + u8 i; + int rc; + + rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (rc < 0) + return rc; + if (i == 0x01) + return 0; + else { + deb_info("gpio_write failed.\n"); + return -EIO; + } +} + +/* I2C */ +static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + + if (d->udev->descriptor.idVendor == USB_VID_MEDION) + switch (msg[i].addr) { + case 0x63: + cxusb_gpio_tuner(d, 0); + break; + default: + cxusb_gpio_tuner(d, 1); + break; + } + + if (msg[i].flags & I2C_M_RD) { + /* read only */ + u8 obuf[3], ibuf[1+msg[i].len]; + obuf[0] = 0; + obuf[1] = msg[i].len; + obuf[2] = msg[i].addr; + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3, + ibuf, 1+msg[i].len) < 0) { + warn("i2c read failed"); + break; + } + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && + msg[i].addr == msg[i+1].addr) { + /* write to then read from same address */ + u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; + obuf[0] = msg[i].len; + obuf[1] = msg[i+1].len; + obuf[2] = msg[i].addr; + memcpy(&obuf[3], msg[i].buf, msg[i].len); + + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3+msg[i].len, + ibuf, 1+msg[i+1].len) < 0) + break; + + if (ibuf[0] != 0x08) + deb_i2c("i2c read may have failed\n"); + + memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + + i++; + } else { + /* write only */ + u8 obuf[2+msg[i].len], ibuf; + obuf[0] = msg[i].addr; + obuf[1] = msg[i].len; + memcpy(&obuf[2], msg[i].buf, msg[i].len); + + if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, + 2+msg[i].len, &ibuf,1) < 0) + break; + if (ibuf != 0x08) + deb_i2c("i2c write may have failed\n"); + } + } + + mutex_unlock(&d->i2c_mutex); + return i == num ? num : -EREMOTEIO; +} + +static u32 cxusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm cxusb_i2c_algo = { + .master_xfer = cxusb_i2c_xfer, + .functionality = cxusb_i2c_func, +}; + +static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); +} + +static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + if (!onoff) + return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); + if (d->state == DVB_USB_STATE_INIT && + usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + if (!ret) { + /* FIXME: We don't know why, but we need to configure the + * lgdt3303 with the register settings below on resume */ + int i; + u8 buf, bufs[] = { + 0x0e, 0x2, 0x00, 0x7f, + 0x0e, 0x2, 0x02, 0xfe, + 0x0e, 0x2, 0x02, 0x01, + 0x0e, 0x2, 0x00, 0x03, + 0x0e, 0x2, 0x0d, 0x40, + 0x0e, 0x2, 0x0e, 0x87, + 0x0e, 0x2, 0x0f, 0x8e, + 0x0e, 0x2, 0x10, 0x01, + 0x0e, 0x2, 0x14, 0xd7, + 0x0e, 0x2, 0x47, 0x88, + }; + msleep(20); + for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) { + ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, + bufs+i, 4, &buf, 1); + if (ret) + break; + if (buf != 0x8) + return -EREMOTEIO; + } + } + return ret; +} + +static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return 0; +} + +static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int rc = 0; + + rc = cxusb_power_ctrl(d, onoff); + if (!onoff) + cxusb_nano2_led(d, 0); + + return rc; +} + +static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 b; + ret = cxusb_power_ctrl(d, onoff); + if (!onoff) + return ret; + + msleep(128); + cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); + msleep(100); + return ret; +} + +static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 buf[2] = { 0x03, 0x00 }; + if (onoff) + cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); + else + cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + + return 0; +} + +static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) + cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0); + else + cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF, + NULL, 0, NULL, 0); + return 0; +} + +static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) +{ + int ep = d->props.generic_bulk_ctrl_endpoint; + const int timeout = 100; + const int junk_len = 32; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) +{ + struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream; + const int timeout = 100; + const int junk_len = p->u.bulk.buffersize; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static int cxusb_d680_dmb_streaming_ctrl( + struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) { + u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); + return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, + buf, sizeof(buf), NULL, 0); + } else { + int ret = cxusb_ctrl_msg(adap->dev, + CMD_STREAMING_OFF, NULL, 0, NULL, 0); + return ret; + } +} + +static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + u8 ircode[4]; + int i; + + cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&keymap[i]) == ircode[2] && + rc5_data(&keymap[i]) == ircode[3]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) + return 0; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&keymap[i]) == ircode[1] && + rc5_data(&keymap[i]) == ircode[2]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + u8 ircode[2]; + int i; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) + return 0; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&keymap[i]) == ircode[0] && + rc5_data(&keymap[i]) == ircode[1]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +static struct rc_map_table rc_map_dvico_mce_table[] = { + { 0xfe02, KEY_TV }, + { 0xfe0e, KEY_MP3 }, + { 0xfe1a, KEY_DVD }, + { 0xfe1e, KEY_FAVORITES }, + { 0xfe16, KEY_SETUP }, + { 0xfe46, KEY_POWER2 }, + { 0xfe0a, KEY_EPG }, + { 0xfe49, KEY_BACK }, + { 0xfe4d, KEY_MENU }, + { 0xfe51, KEY_UP }, + { 0xfe5b, KEY_LEFT }, + { 0xfe5f, KEY_RIGHT }, + { 0xfe53, KEY_DOWN }, + { 0xfe5e, KEY_OK }, + { 0xfe59, KEY_INFO }, + { 0xfe55, KEY_TAB }, + { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ + { 0xfe12, KEY_NEXTSONG }, /* Skip */ + { 0xfe42, KEY_ENTER }, /* Windows/Start */ + { 0xfe15, KEY_VOLUMEUP }, + { 0xfe05, KEY_VOLUMEDOWN }, + { 0xfe11, KEY_CHANNELUP }, + { 0xfe09, KEY_CHANNELDOWN }, + { 0xfe52, KEY_CAMERA }, + { 0xfe5a, KEY_TUNER }, /* Live */ + { 0xfe19, KEY_OPEN }, + { 0xfe0b, KEY_1 }, + { 0xfe17, KEY_2 }, + { 0xfe1b, KEY_3 }, + { 0xfe07, KEY_4 }, + { 0xfe50, KEY_5 }, + { 0xfe54, KEY_6 }, + { 0xfe48, KEY_7 }, + { 0xfe4c, KEY_8 }, + { 0xfe58, KEY_9 }, + { 0xfe13, KEY_ANGLE }, /* Aspect */ + { 0xfe03, KEY_0 }, + { 0xfe1f, KEY_ZOOM }, + { 0xfe43, KEY_REWIND }, + { 0xfe47, KEY_PLAYPAUSE }, + { 0xfe4f, KEY_FASTFORWARD }, + { 0xfe57, KEY_MUTE }, + { 0xfe0d, KEY_STOP }, + { 0xfe01, KEY_RECORD }, + { 0xfe4e, KEY_POWER }, +}; + +static struct rc_map_table rc_map_dvico_portable_table[] = { + { 0xfc02, KEY_SETUP }, /* Profile */ + { 0xfc43, KEY_POWER2 }, + { 0xfc06, KEY_EPG }, + { 0xfc5a, KEY_BACK }, + { 0xfc05, KEY_MENU }, + { 0xfc47, KEY_INFO }, + { 0xfc01, KEY_TAB }, + { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ + { 0xfc49, KEY_VOLUMEUP }, + { 0xfc09, KEY_VOLUMEDOWN }, + { 0xfc54, KEY_CHANNELUP }, + { 0xfc0b, KEY_CHANNELDOWN }, + { 0xfc16, KEY_CAMERA }, + { 0xfc40, KEY_TUNER }, /* ATV/DTV */ + { 0xfc45, KEY_OPEN }, + { 0xfc19, KEY_1 }, + { 0xfc18, KEY_2 }, + { 0xfc1b, KEY_3 }, + { 0xfc1a, KEY_4 }, + { 0xfc58, KEY_5 }, + { 0xfc59, KEY_6 }, + { 0xfc15, KEY_7 }, + { 0xfc14, KEY_8 }, + { 0xfc17, KEY_9 }, + { 0xfc44, KEY_ANGLE }, /* Aspect */ + { 0xfc55, KEY_0 }, + { 0xfc07, KEY_ZOOM }, + { 0xfc0a, KEY_REWIND }, + { 0xfc08, KEY_PLAYPAUSE }, + { 0xfc4b, KEY_FASTFORWARD }, + { 0xfc5b, KEY_MUTE }, + { 0xfc04, KEY_STOP }, + { 0xfc56, KEY_RECORD }, + { 0xfc57, KEY_POWER }, + { 0xfc41, KEY_UNKNOWN }, /* INPUT */ + { 0xfc00, KEY_UNKNOWN }, /* HD */ +}; + +static struct rc_map_table rc_map_d680_dmb_table[] = { + { 0x0038, KEY_UNKNOWN }, /* TV/AV */ + { 0x080c, KEY_ZOOM }, + { 0x0800, KEY_0 }, + { 0x0001, KEY_1 }, + { 0x0802, KEY_2 }, + { 0x0003, KEY_3 }, + { 0x0804, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0806, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0808, KEY_8 }, + { 0x0009, KEY_9 }, + { 0x000a, KEY_MUTE }, + { 0x0829, KEY_BACK }, + { 0x0012, KEY_CHANNELUP }, + { 0x0813, KEY_CHANNELDOWN }, + { 0x002b, KEY_VOLUMEUP }, + { 0x082c, KEY_VOLUMEDOWN }, + { 0x0020, KEY_UP }, + { 0x0821, KEY_DOWN }, + { 0x0011, KEY_LEFT }, + { 0x0810, KEY_RIGHT }, + { 0x000d, KEY_OK }, + { 0x081f, KEY_RECORD }, + { 0x0017, KEY_PLAYPAUSE }, + { 0x0816, KEY_PLAYPAUSE }, + { 0x000b, KEY_STOP }, + { 0x0827, KEY_FASTFORWARD }, + { 0x0026, KEY_REWIND }, + { 0x081e, KEY_UNKNOWN }, /* Time Shift */ + { 0x000e, KEY_UNKNOWN }, /* Snapshot */ + { 0x082d, KEY_UNKNOWN }, /* Mouse Cursor */ + { 0x000f, KEY_UNKNOWN }, /* Minimize/Maximize */ + { 0x0814, KEY_UNKNOWN }, /* Shuffle */ + { 0x0025, KEY_POWER }, +}; + +static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) +{ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +static int cxusb_mt352_demod_init(struct dvb_frontend* fe) +{ /* used in both lgz201 and th7579 */ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + return 0; +} + +static struct cx22702_config cxusb_cx22702_config = { + .demod_address = 0x63, + .output_mode = CX22702_PARALLEL_OUTPUT, +}; + +static struct lgdt330x_config cxusb_lgdt3303_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, +}; + +static struct lgdt330x_config cxusb_aver_lgdt3303_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .clock_polarity_flip = 2, +}; + +static struct mt352_config cxusb_dee1601_config = { + .demod_address = 0x0f, + .demod_init = cxusb_dee1601_demod_init, +}; + +static struct zl10353_config cxusb_zl10353_dee1601_config = { + .demod_address = 0x0f, + .parallel_ts = 1, +}; + +static struct mt352_config cxusb_mt352_config = { + /* used in both lgz201 and th7579 */ + .demod_address = 0x0f, + .demod_init = cxusb_mt352_demod_init, +}; + +static struct zl10353_config cxusb_zl10353_xc3028_config = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, +}; + +static struct mt352_config cxusb_mt352_xc3028_config = { + .demod_address = 0x0f, + .if2 = 4560, + .no_tuner = 1, + .demod_init = cxusb_mt352_demod_init, +}; + +/* FIXME: needs tweaking */ +static struct mxl5005s_config aver_a868r_tuner = { + .i2c_address = 0x63, + .if_freq = 6000000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +/* FIXME: needs tweaking */ +static struct mxl5005s_config d680_dmb_tuner = { + .i2c_address = 0x63, + .if_freq = 36125000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct max2165_config mygica_d689_max2165_cfg = { + .i2c_address = 0x60, + .osc_clk = 20 +}; + +/* Callbacks for DVB USB */ +static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3); + return 0; +} + +static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, + NULL, DVB_PLL_THOMSON_DTT7579); + return 0; +} + +static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201); + return 0; +} + +static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, + NULL, DVB_PLL_THOMSON_DTT7579); + return 0; +} + +static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); + return 0; +} + +static int dvico_bluebird_xc2028_callback(void *ptr, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = ptr; + struct dvb_usb_device *d = adap->dev; + + switch (command) { + case XC2028_TUNER_RESET: + deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg); + cxusb_bluebird_gpio_pulse(d, 0x01, 1); + break; + case XC2028_RESET_CLK: + deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg); + break; + default: + deb_info("%s: unknown command %d, arg %d\n", __func__, + command, arg); + return -EINVAL; + } + + return 0; +} + +static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &adap->dev->i2c_adap, + .i2c_addr = 0x61, + }; + static struct xc2028_ctrl ctl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + }; + + /* FIXME: generalize & move to common area */ + adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback; + + fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg); + if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) + return -EIO; + + fe->ops.tuner_ops.set_config(fe, &ctl); + + return 0; +} + +static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &aver_a868r_tuner); + return 0; +} + +static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &d680_dmb_tuner); + return (fe == NULL) ? -EIO : 0; +} + +static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); + return (fe == NULL) ? -EIO : 0; +} + +static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 b; + if (usb_set_interface(adap->dev->udev, 0, 6) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); + + adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 7) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, + &cxusb_lgdt3303_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, + &adap->dev->i2c_adap); + if (adap->fe_adap[0].fe != NULL) + return 0; + + return -EIO; +} + +static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + /* used in both lgz201 and th7579 */ + if (usb_set_interface(adap->dev->udev, 0, 0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_dee1601_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + adap->fe_adap[0].fe = + dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config_no_i2c_gate, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) + return -EIO; + + /* try to determine if there is no IR decoder on the I2C bus */ + for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) { + msleep(20); + if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) + goto no_IR; + if (ircode[0] == 0 && ircode[1] == 0) + continue; + if (ircode[2] + ircode[3] != 0xff) { +no_IR: + adap->dev->props.rc.legacy.rc_map_table = NULL; + info("No IR receiver detected on this device."); + break; + } + } + + return 0; +} + +static struct dibx000_agc_config dib7070_agc_config = { + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + + /* + * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 + */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + .inv_gain = 600, + .time_stabiliz = 10, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, + .agc1_max = 65535, + .agc1_min = 0, + .agc2_max = 65535, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 40, + .agc1_pt3 = 183, + .agc1_slope1 = 206, + .agc1_slope2 = 255, + .agc2_pt1 = 72, + .agc2_pt2 = 152, + .agc2_slope1 = 88, + .agc2_slope2 = 90, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 0, +}; + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + /* refsel, sel, freq_15k */ + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 12000000, +}; + +static struct dib7000p_config cxusb_dualdig4_rev2_config = { + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = 0xfcef, + .gpio_val = 0x0110, + + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &cxusb_dualdig4_rev2_config) < 0) { + printk(KERN_WARNING "Unable to enumerate dib7000p\n"); + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config); + if (adap->fe_adap[0].fe == NULL) + return -EIO; + + return 0; +} + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return 0; +} + +static struct dib0070_config dib7070p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, +}; + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *); +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + default: + case BAND_UHF: offset = 550; break; + } + + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + + return state->set_param_save(fe); +} + +static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7000p_get_i2c_master(adap->fe_adap[0].fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, + &dib7070p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + adap->fe_adap[0].fe = dvb_attach(mt352_attach, + &cxusb_mt352_xc3028_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + return -EIO; +} + +static struct lgs8gxx_config d680_lgs8gl5_cfg = { + .prod = LGS8GXX_PROD_LGS8GL5, + .demod_address = 0x19, + .serial_ts = 0, + .ts_clk_pol = 0, + .ts_clk_gated = 1, + .if_clk_freq = 30400, /* 30.4 MHz */ + .if_freq = 5725, /* 5.725 MHz */ + .if_neg_center = 0, + .ext_adc = 0, + .adc_signed = 0, + .if_neg_edge = 0, +}; + +static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + int n; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); + + /* Drain USB pipes to avoid hang after reboot */ + for (n = 0; n < 5; n++) { + cxusb_d680_dmb_drain_message(d); + cxusb_d680_dmb_drain_video(d); + msleep(200); + } + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe_adap[0].fe == NULL) + return -EIO; + + return 0; +} + +static struct atbm8830_config mygica_d689_atbm8830_cfg = { + .prod = ATBM8830_PROD_8830, + .demod_address = 0x40, + .serial_ts = 0, + .ts_sampling_edge = 1, + .ts_clk_gated = 0, + .osc_clk_freq = 30400, /* in kHz */ + .if_freq = 0, /* zero IF */ + .zif_swap_iq = 1, + .agc_min = 0x2E, + .agc_max = 0x90, + .agc_hold_loop = 0, +}; + +static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); + + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, + &d->i2c_adap); + if (adap->fe_adap[0].fe == NULL) + return -EIO; + + return 0; +} + +/* + * DViCO has shipped two devices with the same USB ID, but only one of them + * needs a firmware download. Check the device class details to see if they + * have non-default values to decide whether the device is actually cold or + * not, and forget a match if it turns out we selected the wrong device. + */ +static int bluebird_fx2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int wascold = *cold; + + *cold = udev->descriptor.bDeviceClass == 0xff && + udev->descriptor.bDeviceSubClass == 0xff && + udev->descriptor.bDeviceProtocol == 0xff; + + if (*cold && !wascold) + *desc = NULL; + + return 0; +} + +/* + * DViCO bluebird firmware needs the "warm" product ID to be patched into the + * firmware file before download. + */ + +static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; +static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, + const struct firmware *fw) +{ + int pos; + + for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { + int idoff = dvico_firmware_id_offsets[pos]; + + if (fw->size < idoff + 4) + continue; + + if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && + fw->data[idoff + 1] == USB_VID_DVICO >> 8) { + struct firmware new_fw; + u8 *new_fw_data = vmalloc(fw->size); + int ret; + + if (!new_fw_data) + return -ENOMEM; + + memcpy(new_fw_data, fw->data, fw->size); + new_fw.size = fw->size; + new_fw.data = new_fw_data; + + new_fw_data[idoff + 2] = + le16_to_cpu(udev->descriptor.idProduct) + 1; + new_fw_data[idoff + 3] = + le16_to_cpu(udev->descriptor.idProduct) >> 8; + + ret = usb_cypress_load_firmware(udev, &new_fw, + CYPRESS_FX2); + vfree(new_fw_data); + return ret; + } + } + + return -EINVAL; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties cxusb_medion_properties; +static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; +static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; +static struct dvb_usb_device_properties cxusb_aver_a868r_properties; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties; +static struct dvb_usb_device_properties cxusb_mygica_d689_properties; + +static int cxusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_nano2_needsfirmware_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, + THIS_MODULE, NULL, adapter_nr) || + 0) + return 0; + + return -EINVAL; +} + +static struct usb_device_id cxusb_table [] = { + { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, cxusb_table); + +static struct dvb_usb_device_properties cxusb_medion_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_cx22702_frontend_attach, + .tuner_attach = cxusb_fmd1216me_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + .power_ctrl = cxusb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Medion MD95700 (MDUSBTV-HYBRID)", + { NULL }, + { &cxusb_table[0], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_lgdt3303_frontend_attach, + .tuner_attach = cxusb_lgh064f_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV5 USB Gold", + { &cxusb_table[1], NULL }, + { &cxusb_table[2], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dee1601_frontend_attach, + .tuner_attach = cxusb_dee1601_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 150, + .rc_map_table = rc_map_dvico_mce_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 3, + .devices = { + { "DViCO FusionHDTV DVB-T Dual USB", + { &cxusb_table[3], NULL }, + { &cxusb_table[4], NULL }, + }, + { "DigitalNow DVB-T Dual USB", + { &cxusb_table[9], NULL }, + { &cxusb_table[10], NULL }, + }, + { "DViCO FusionHDTV DVB-T Dual Digital 2", + { &cxusb_table[11], NULL }, + { &cxusb_table[12], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_lgz201_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T USB (LGZ201)", + { &cxusb_table[5], NULL }, + { &cxusb_table[6], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_dtt7579_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T USB (TH7579)", + { &cxusb_table[7], NULL }, + { &cxusb_table[8], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_mce_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_query = cxusb_bluebird2_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4", + { NULL }, + { &cxusb_table[13], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_bluebird2_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2", + { NULL }, + { &cxusb_table[14], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-02.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", + { &cxusb_table[14], NULL }, + { &cxusb_table[15], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_aver_streaming_ctrl, + .frontend_attach = cxusb_aver_lgdt3303_frontend_attach, + .tuner_attach = cxusb_mxl5003s_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + .power_ctrl = cxusb_aver_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "AVerMedia AVerTVHD Volar (A868R)", + { NULL }, + { &cxusb_table[16], NULL }, + }, + } +}; + +static +struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .size_of_priv = sizeof(struct dib0700_adapter_state), + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_mce_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_query = cxusb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", + { NULL }, + { &cxusb_table[17], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_d680_dmb_frontend_attach, + .tuner_attach = cxusb_d680_dmb_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_d680_dmb_table, + .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), + .rc_query = cxusb_d680_dmb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { + "Conexant DMB-TH Stick", + { NULL }, + { &cxusb_table[18], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_mygica_d689_frontend_attach, + .tuner_attach = cxusb_mygica_d689_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_d680_dmb_table, + .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), + .rc_query = cxusb_d680_dmb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { + "Mygica D689 DMB-TH", + { NULL }, + { &cxusb_table[19], NULL }, + }, + } +}; + +static struct usb_driver cxusb_driver = { + .name = "dvb_usb_cxusb", + .probe = cxusb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cxusb_table, +}; + +module_usb_driver(cxusb_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Michael Krufky "); +MODULE_AUTHOR("Chris Pascoe "); +MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h new file mode 100644 index 00000000000..1a51eafd31b --- /dev/null +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -0,0 +1,35 @@ +#ifndef _DVB_USB_CXUSB_H_ +#define _DVB_USB_CXUSB_H_ + +#define DVB_USB_LOG_PREFIX "cxusb" +#include "dvb-usb.h" + +/* usb commands - some of it are guesses, don't have a reference yet */ +#define CMD_BLUEBIRD_GPIO_RW 0x05 + +#define CMD_I2C_WRITE 0x08 +#define CMD_I2C_READ 0x09 + +#define CMD_GPIO_READ 0x0d +#define CMD_GPIO_WRITE 0x0e +#define GPIO_TUNER 0x02 + +#define CMD_POWER_OFF 0xdc +#define CMD_POWER_ON 0xde + +#define CMD_STREAMING_ON 0x36 +#define CMD_STREAMING_OFF 0x37 + +#define CMD_AVER_STREAM_ON 0x18 +#define CMD_AVER_STREAM_OFF 0x19 + +#define CMD_GET_IR_CODE 0x47 + +#define CMD_ANALOG 0x50 +#define CMD_DIGITAL 0x51 + +struct cxusb_state { + u8 gpio_write_state[3]; +}; + +#endif diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h new file mode 100644 index 00000000000..7de125c0b36 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dib0700.h @@ -0,0 +1,75 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#ifndef _DIB0700_H_ +#define _DIB0700_H_ + +#define DVB_USB_LOG_PREFIX "dib0700" +#include "dvb-usb.h" + +#include "dib07x0.h" + +extern int dvb_usb_dib0700_debug; +#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) +#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) +#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) +#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) + +#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ + /* higher than 1.21 */ +#define REQUEST_I2C_READ 0x2 +#define REQUEST_I2C_WRITE 0x3 +#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ +#define REQUEST_JUMPRAM 0x8 +#define REQUEST_SET_CLOCK 0xB +#define REQUEST_SET_GPIO 0xC +#define REQUEST_ENABLE_VIDEO 0xF + // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) + // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) + // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_I2C_PARAM 0x10 +#define REQUEST_SET_RC 0x11 +#define REQUEST_NEW_I2C_READ 0x12 +#define REQUEST_NEW_I2C_WRITE 0x13 +#define REQUEST_GET_VERSION 0x15 + +struct dib0700_state { + u8 channel_state; + u16 mt2060_if1[2]; + u8 rc_toggle; + u8 rc_counter; + u8 is_dib7000pc; + u8 fw_use_new_i2c_api; + u8 disable_streaming_master_mode; + u32 fw_version; + u32 nb_packet_buffer_size; + int (*read_status)(struct dvb_frontend *, fe_status_t *); + int (*sleep)(struct dvb_frontend* fe); + u8 buf[255]; +}; + +extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype); +extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); +extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); +extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); +extern int dib0700_rc_setup(struct dvb_usb_device *d); +extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); +extern struct i2c_algorithm dib0700_i2c_algo; +extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold); +extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type); +extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); + +extern int dib0700_device_count; +extern int dvb_usb_dib0700_ir_proto; +extern struct dvb_usb_device_properties dib0700_devices[]; +extern struct usb_device_id dib0700_usb_id_table[]; + +#endif diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c new file mode 100644 index 00000000000..ef87229de6a --- /dev/null +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -0,0 +1,845 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#include "dib0700.h" + +/* debug */ +int dvb_usb_dib0700_debug; +module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); + +static int nb_packet_buffer_size = 21; +module_param(nb_packet_buffer_size, int, 0644); +MODULE_PARM_DESC(nb_packet_buffer_size, + "Set the dib0700 driver data buffer size. This parameter " + "corresponds to the number of TS packets. The actual size of " + "the data buffer corresponds to this parameter " + "multiplied by 188 (default: 21)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + + +int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype) +{ + struct dib0700_state *st = d->priv; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + st->buf, 16, USB_CTRL_GET_TIMEOUT); + if (hwversion != NULL) + *hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) | + (st->buf[2] << 8) | st->buf[3]; + if (romversion != NULL) + *romversion = (st->buf[4] << 24) | (st->buf[5] << 16) | + (st->buf[6] << 8) | st->buf[7]; + if (ramversion != NULL) + *ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) | + (st->buf[10] << 8) | st->buf[11]; + if (fwtype != NULL) + *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) | + (st->buf[14] << 8) | st->buf[15]; + mutex_unlock(&d->usb_mutex); + return ret; +} + +/* expecting rx buffer: request data[0] data[1] ... data[2] */ +static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) +{ + int status; + + deb_data(">>> "); + debug_dump(tx, txlen, deb_data); + + status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), + tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, + USB_CTRL_GET_TIMEOUT); + + if (status != txlen) + deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen); + + return status < 0 ? status : 0; +} + +/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ +int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +{ + u16 index, value; + int status; + + if (txlen < 2) { + err("tx buffer length is smaller than 2. Makes no sense."); + return -EINVAL; + } + if (txlen > 4) { + err("tx buffer length is larger than 4. Not supported."); + return -EINVAL; + } + + deb_data(">>> "); + debug_dump(tx,txlen,deb_data); + + value = ((txlen - 2) << 8) | tx[1]; + index = 0; + if (txlen > 2) + index |= (tx[2] << 8); + if (txlen > 3) + index |= tx[3]; + + status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], + USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, + USB_CTRL_GET_TIMEOUT); + + if (status < 0) + deb_info("ep 0 read error (status = %d)\n",status); + + deb_data("<<< "); + debug_dump(rx, rxlen, deb_data); + + return status; /* length in case of success */ +} + +int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) +{ + struct dib0700_state *st = d->priv; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + st->buf[0] = REQUEST_SET_GPIO; + st->buf[1] = gpio; + st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6); + + ret = dib0700_ctrl_wr(d, st->buf, 3); + + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) +{ + struct dib0700_state *st = d->priv; + int ret; + + if (st->fw_version >= 0x10201) { + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + st->buf[0] = REQUEST_SET_USB_XFER_LEN; + st->buf[1] = (nb_ts_packets >> 8) & 0xff; + st->buf[2] = nb_ts_packets & 0xff; + + deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); + + ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); + } else { + deb_info("this firmware does not allow to change the USB xfer len\n"); + ret = -EIO; + } + + return ret; +} + +/* + * I2C master xfer function (supported in 1.20 firmware) + */ +static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + /* The new i2c firmware messages are more reliable and in particular + properly support i2c read calls not preceded by a write */ + + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ + uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ + uint8_t en_start = 0; + uint8_t en_stop = 0; + int result, i; + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EINTR; + + for (i = 0; i < num; i++) { + if (i == 0) { + /* First message in the transaction */ + en_start = 1; + } else if (!(msg[i].flags & I2C_M_NOSTART)) { + /* Device supports repeated-start */ + en_start = 1; + } else { + /* Not the first packet and device doesn't support + repeated start */ + en_start = 0; + } + if (i == (num - 1)) { + /* Last message in the transaction */ + en_stop = 1; + } + + if (msg[i].flags & I2C_M_RD) { + /* Read request */ + u16 index, value; + uint8_t i2c_dest; + + i2c_dest = (msg[i].addr << 1); + value = ((en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F)) << 8 | i2c_dest; + /* I2C ctrl + FE bus; */ + index = ((gen_mode << 6) & 0xC0) | + ((bus_mode << 4) & 0x30); + + result = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_READ, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, msg[i].buf, + msg[i].len, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + deb_info("i2c read error (status = %d)\n", result); + break; + } + + deb_data("<<< "); + debug_dump(msg[i].buf, msg[i].len, deb_data); + + } else { + /* Write request */ + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + mutex_unlock(&d->i2c_mutex); + return -EINTR; + } + st->buf[0] = REQUEST_NEW_I2C_WRITE; + st->buf[1] = msg[i].addr << 1; + st->buf[2] = (en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F); + /* I2C ctrl + FE bus; */ + st->buf[3] = ((gen_mode << 6) & 0xC0) | + ((bus_mode << 4) & 0x30); + /* The Actual i2c payload */ + memcpy(&st->buf[4], msg[i].buf, msg[i].len); + + deb_data(">>> "); + debug_dump(st->buf, msg[i].len + 4, deb_data); + + result = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_WRITE, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, st->buf, msg[i].len + 4, + USB_CTRL_GET_TIMEOUT); + mutex_unlock(&d->usb_mutex); + if (result < 0) { + deb_info("i2c write error (status = %d)\n", result); + break; + } + } + } + mutex_unlock(&d->i2c_mutex); + return i; +} + +/* + * I2C master xfer function (pre-1.20 firmware) + */ +static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, + struct i2c_msg *msg, int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + int i,len; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EINTR; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + mutex_unlock(&d->i2c_mutex); + return -EINTR; + } + + for (i = 0; i < num; i++) { + /* fill in the address */ + st->buf[1] = msg[i].addr << 1; + /* fill the buffer */ + memcpy(&st->buf[2], msg[i].buf, msg[i].len); + + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + st->buf[0] = REQUEST_I2C_READ; + st->buf[1] |= 1; + + /* special thing in the current firmware: when length is zero the read-failed */ + len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2, + msg[i+1].buf, msg[i+1].len); + if (len <= 0) { + deb_info("I2C read failed on address 0x%02x\n", + msg[i].addr); + break; + } + + msg[i+1].len = len; + + i++; + } else { + st->buf[0] = REQUEST_I2C_WRITE; + if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0) + break; + } + } + mutex_unlock(&d->usb_mutex); + mutex_unlock(&d->i2c_mutex); + + return i; +} + +static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + + if (st->fw_use_new_i2c_api == 1) { + /* User running at least fw 1.20 */ + return dib0700_i2c_xfer_new(adap, msg, num); + } else { + /* Use legacy calls */ + return dib0700_i2c_xfer_legacy(adap, msg, num); + } +} + +static u32 dib0700_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm dib0700_i2c_algo = { + .master_xfer = dib0700_i2c_xfer, + .functionality = dib0700_i2c_func, +}; + +int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + s16 ret; + u8 *b; + + b = kmalloc(16, GFP_KERNEL); + if (!b) + return -ENOMEM; + + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT); + + deb_info("FW GET_VERSION length: %d\n",ret); + + *cold = ret <= 0; + deb_info("cold: %d\n", *cold); + + kfree(b); + return 0; +} + +static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, + u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv, + u16 pll_loopdiv, u16 free_div, u16 dsuScaler) +{ + struct dib0700_state *st = d->priv; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + st->buf[0] = REQUEST_SET_CLOCK; + st->buf[1] = (en_pll << 7) | (pll_src << 6) | + (pll_range << 5) | (clock_gpio3 << 4); + st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */ + st->buf[3] = pll_prediv & 0xff; /* LSB */ + st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */ + st->buf[5] = pll_loopdiv & 0xff; /* LSB */ + st->buf[6] = (free_div >> 8) & 0xff; /* MSB */ + st->buf[7] = free_div & 0xff; /* LSB */ + st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */ + st->buf[9] = dsuScaler & 0xff; /* LSB */ + + ret = dib0700_ctrl_wr(d, st->buf, 10); + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) +{ + struct dib0700_state *st = d->priv; + u16 divider; + int ret; + + if (scl_kHz == 0) + return -EINVAL; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + st->buf[0] = REQUEST_SET_I2C_PARAM; + divider = (u16) (30000 / scl_kHz); + st->buf[1] = 0; + st->buf[2] = (u8) (divider >> 8); + st->buf[3] = (u8) (divider & 0xff); + divider = (u16) (72000 / scl_kHz); + st->buf[4] = (u8) (divider >> 8); + st->buf[5] = (u8) (divider & 0xff); + divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */ + st->buf[6] = (u8) (divider >> 8); + st->buf[7] = (u8) (divider & 0xff); + + deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", + (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) | + st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz); + + ret = dib0700_ctrl_wr(d, st->buf, 8); + mutex_unlock(&d->usb_mutex); + + return ret; +} + + +int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3) +{ + switch (clk_MHz) { + case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break; + default: return -EINVAL; + } + return 0; +} + +static int dib0700_jumpram(struct usb_device *udev, u32 address) +{ + int ret = 0, actlen; + u8 *buf; + + buf = kmalloc(8, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf[0] = REQUEST_JUMPRAM; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + buf[4] = (address >> 24) & 0xff; + buf[5] = (address >> 16) & 0xff; + buf[6] = (address >> 8) & 0xff; + buf[7] = address & 0xff; + + if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { + deb_fw("jumpram to 0x%x failed\n",address); + goto out; + } + if (actlen != 8) { + deb_fw("jumpram to 0x%x failed\n",address); + ret = -EIO; + goto out; + } +out: + kfree(buf); + return ret; +} + +int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) +{ + struct hexline hx; + int pos = 0, ret, act_len, i, adap_num; + u8 *buf; + u32 fw_version; + + buf = kmalloc(260, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { + deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n", + hx.addr, hx.len, hx.chk); + + buf[0] = hx.len; + buf[1] = (hx.addr >> 8) & 0xff; + buf[2] = hx.addr & 0xff; + buf[3] = hx.type; + memcpy(&buf[4],hx.data,hx.len); + buf[4+hx.len] = hx.chk; + + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x01), + buf, + hx.len + 5, + &act_len, + 1000); + + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); + goto out; + } + } + + if (ret == 0) { + /* start the firmware */ + if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) { + info("firmware started successfully."); + msleep(500); + } + } else + ret = -EIO; + + /* the number of ts packet has to be at least 1 */ + if (nb_packet_buffer_size < 1) + nb_packet_buffer_size = 1; + + /* get the fimware version */ + usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + buf, 16, USB_CTRL_GET_TIMEOUT); + fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; + + /* set the buffer size - DVB-USB is allocating URB buffers + * only after the firwmare download was successful */ + for (i = 0; i < dib0700_device_count; i++) { + for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; + adap_num++) { + if (fw_version >= 0x10201) { + dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; + } else { + /* for fw version older than 1.20.1, + * the buffersize has to be n times 512 */ + dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; + if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512) + dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512; + } + } + } +out: + kfree(buf); + return ret; +} + +int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dib0700_state *st = adap->dev->priv; + int ret; + + if ((onoff != 0) && (st->fw_version >= 0x10201)) { + /* for firmware later than 1.20.1, + * the USB xfer length can be set */ + ret = dib0700_set_usb_xfer_len(adap->dev, + st->nb_packet_buffer_size); + if (ret < 0) { + deb_info("can not set the USB xfer len\n"); + return ret; + } + } + + if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + st->buf[0] = REQUEST_ENABLE_VIDEO; + /* this bit gives a kind of command, + * rather than enabling something or not */ + st->buf[1] = (onoff << 4) | 0x00; + + if (st->disable_streaming_master_mode == 1) + st->buf[2] = 0x00; + else + st->buf[2] = 0x01 << 4; /* Master mode */ + + st->buf[3] = 0x00; + + deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); + + st->channel_state &= ~0x3; + if ((adap->fe_adap[0].stream.props.endpoint != 2) + && (adap->fe_adap[0].stream.props.endpoint != 3)) { + deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint); + if (onoff) + st->channel_state |= 1 << (adap->id); + else + st->channel_state |= 1 << ~(adap->id); + } else { + if (onoff) + st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2); + else + st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint); + } + + st->buf[2] |= st->channel_state; + + deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); + + ret = dib0700_ctrl_wr(adap->dev, st->buf, 4); + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) +{ + struct dvb_usb_device *d = rc->priv; + struct dib0700_state *st = d->priv; + int new_proto, ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + err("could not acquire lock"); + return -EINTR; + } + + st->buf[0] = REQUEST_SET_RC; + st->buf[1] = 0; + st->buf[2] = 0; + + /* Set the IR mode */ + if (rc_type == RC_TYPE_RC5) + new_proto = 1; + else if (rc_type == RC_TYPE_NEC) + new_proto = 0; + else if (rc_type == RC_TYPE_RC6) { + if (st->fw_version < 0x10200) { + ret = -EINVAL; + goto out; + } + + new_proto = 2; + } else { + ret = -EINVAL; + goto out; + } + + st->buf[1] = new_proto; + + ret = dib0700_ctrl_wr(d, st->buf, 3); + if (ret < 0) { + err("ir protocol setup failed"); + goto out; + } + + d->props.rc.core.protocol = rc_type; + +out: + mutex_unlock(&d->usb_mutex); + return ret; +} + +/* Number of keypresses to ignore before start repeating */ +#define RC_REPEAT_DELAY_V1_20 10 + +/* This is the structure of the RC response packet starting in firmware 1.20 */ +struct dib0700_rc_response { + u8 report_id; + u8 data_state; + union { + u16 system16; + struct { + u8 not_system; + u8 system; + }; + }; + u8 data; + u8 not_data; +}; +#define RC_MSG_SIZE_V1_20 6 + +static void dib0700_rc_urb_completion(struct urb *purb) +{ + struct dvb_usb_device *d = purb->context; + struct dib0700_rc_response *poll_reply; + u32 uninitialized_var(keycode); + u8 toggle; + + deb_info("%s()\n", __func__); + if (d->rc_dev == NULL) { + /* This will occur if disable_rc_polling=1 */ + kfree(purb->transfer_buffer); + usb_free_urb(purb); + return; + } + + poll_reply = purb->transfer_buffer; + + if (purb->status < 0) { + deb_info("discontinuing polling\n"); + kfree(purb->transfer_buffer); + usb_free_urb(purb); + return; + } + + if (purb->actual_length != RC_MSG_SIZE_V1_20) { + deb_info("malformed rc msg size=%d\n", purb->actual_length); + goto resubmit; + } + + deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n", + poll_reply->report_id, poll_reply->data_state, + poll_reply->system, poll_reply->not_system, + poll_reply->data, poll_reply->not_data, + purb->actual_length); + + switch (d->props.rc.core.protocol) { + case RC_TYPE_NEC: + toggle = 0; + + /* NEC protocol sends repeat code as 0 0 0 FF */ + if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00) + && (poll_reply->not_data == 0xff)) { + poll_reply->data_state = 2; + break; + } + + if ((poll_reply->system ^ poll_reply->not_system) != 0xff) { + deb_data("NEC extended protocol\n"); + /* NEC extended code - 24 bits */ + keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data; + } else { + deb_data("NEC normal protocol\n"); + /* normal NEC code - 16 bits */ + keycode = poll_reply->system << 8 | poll_reply->data; + } + + break; + default: + deb_data("RC5 protocol\n"); + /* RC5 Protocol */ + toggle = poll_reply->report_id; + keycode = poll_reply->system << 8 | poll_reply->data; + + break; + } + + if ((poll_reply->data + poll_reply->not_data) != 0xff) { + /* Key failed integrity check */ + err("key failed integrity check: %04x %02x %02x", + poll_reply->system, + poll_reply->data, poll_reply->not_data); + goto resubmit; + } + + rc_keydown(d->rc_dev, keycode, toggle); + +resubmit: + /* Clean the buffer before we requeue */ + memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20); + + /* Requeue URB */ + usb_submit_urb(purb, GFP_ATOMIC); +} + +int dib0700_rc_setup(struct dvb_usb_device *d) +{ + struct dib0700_state *st = d->priv; + struct urb *purb; + int ret; + + /* Poll-based. Don't initialize bulk mode */ + if (st->fw_version < 0x10200) + return 0; + + /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ + purb = usb_alloc_urb(0, GFP_KERNEL); + if (purb == NULL) { + err("rc usb alloc urb failed"); + return -ENOMEM; + } + + purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL); + if (purb->transfer_buffer == NULL) { + err("rc kzalloc failed"); + usb_free_urb(purb); + return -ENOMEM; + } + + purb->status = -EINPROGRESS; + usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), + purb->transfer_buffer, RC_MSG_SIZE_V1_20, + dib0700_rc_urb_completion, d); + + ret = usb_submit_urb(purb, GFP_ATOMIC); + if (ret) { + err("rc submit urb failed"); + kfree(purb->transfer_buffer); + usb_free_urb(purb); + } + + return ret; +} + +static int dib0700_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int i; + struct dvb_usb_device *dev; + + for (i = 0; i < dib0700_device_count; i++) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, + &dev, adapter_nr) == 0) { + struct dib0700_state *st = dev->priv; + u32 hwversion, romversion, fw_version, fwtype; + + dib0700_get_version(dev, &hwversion, &romversion, + &fw_version, &fwtype); + + deb_info("Firmware version: %x, %d, 0x%x, %d\n", + hwversion, romversion, fw_version, fwtype); + + st->fw_version = fw_version; + st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; + + /* Disable polling mode on newer firmwares */ + if (st->fw_version >= 0x10200) + dev->props.rc.core.bulk_mode = true; + else + dev->props.rc.core.bulk_mode = false; + + dib0700_rc_setup(dev); + + return 0; + } + + return -ENODEV; +} + +static struct usb_driver dib0700_driver = { + .name = "dvb_usb_dib0700", + .probe = dib0700_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dib0700_usb_id_table, +}; + +module_usb_driver(dib0700_driver); + +MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c new file mode 100644 index 00000000000..510001da6e8 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -0,0 +1,4813 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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. + * + * Copyright (C) 2005-9 DiBcom, SA et al + */ +#include "dib0700.h" + +#include "dib3000mc.h" +#include "dib7000m.h" +#include "dib7000p.h" +#include "dib8000.h" +#include "dib9000.h" +#include "mt2060.h" +#include "mt2266.h" +#include "tuner-xc2028.h" +#include "xc5000.h" +#include "xc4000.h" +#include "s5h1411.h" +#include "dib0070.h" +#include "dib0090.h" +#include "lgdt3305.h" +#include "mxl5007t.h" + +static int force_lna_activation; +module_param(force_lna_activation, int, 0644); +MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " + "if applicable for the device (default: 0=automatic/off)."); + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *); + const struct firmware *frontend_firmware; +}; + +/* Hauppauge Nova-T 500 (aka Bristol) + * has a LNA on GPIO0 which is enabled by setting 1 */ +static struct mt2060_config bristol_mt2060_config[2] = { + { + .i2c_address = 0x60, + .clock_out = 3, + }, { + .i2c_address = 0x61, + } +}; + + +static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 42598, + .agc1_min = 17694, + .agc2_max = 45875, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 59, + + .agc1_slope1 = 0, + .agc1_slope2 = 69, + + .agc2_pt1 = 0, + .agc2_pt2 = 59, + + .agc2_slope1 = 111, + .agc2_slope2 = 28, +}; + +static struct dib3000mc_config bristol_dib3000mc_config[2] = { + { .agc = &bristol_dib3000p_mt2060_agc_config, + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + .output_mpeg2_in_188_bytes = 1, + }, + { .agc = &bristol_dib3000p_mt2060_agc_config, + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + .output_mpeg2_in_188_bytes = 1, + } +}; + +static int bristol_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); + + if (force_lna_activation) + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + else + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + + if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); + return -ENODEV; + } + } + st->mt2060_if1[adap->id] = 1220; + return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, + (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; +} + +static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) +{ + struct i2c_msg msg[2] = { + { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, + }; + if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; + return 0; +} + +static int bristol_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && + adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { + if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; + } + return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, + &bristol_mt2060_config[adap->id], if1) == NULL ? + -ENODEV : 0; +} + +/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ + +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 1130, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 33770, + 65535, + 23592, + + 0, + 62, + 255, + 64, + 64, + 132, + 192, + 80, + 80, + + 17, + 27, + 23, + 51, + + 1, + }, { + BAND_VHF | BAND_LBAND, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 2372, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 0, + 65535, + 23592, + + 0, + 128, + 128, + 128, + 0, + 128, + 253, + 81, + 0, + + 17, + 27, + 23, + 51, + + 1, + } +}; + +static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + 0, + 20452225, +}; + +static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + }, + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + } +}; + +static struct mt2266_config stk7700d_mt2266_config[2] = { + { .i2c_address = 0x60 + }, + { .i2c_address = 0x60 + } +}; + +static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + stk7700d_dib7000p_mt2266_config) + != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + } + + adap->fe_adap[0].fe = + dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80 + (adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, + stk7700d_dib7000p_mt2266_config) + != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + } + + adap->fe_adap[0].fe = + dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80 + (adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c, + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; +} + +/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */ +static struct dibx000_agc_config xc3028_agc_config = { + BAND_VHF | BAND_UHF, /* band_caps */ + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | + (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ + + 712, /* inv_gain */ + 21, /* time_stabiliz */ + + 0, /* alpha_level */ + 118, /* thlock */ + + 0, /* wbd_inv */ + 2867, /* wbd_ref */ + 0, /* wbd_sel */ + 2, /* wbd_alpha */ + + 0, /* agc1_max */ + 0, /* agc1_min */ + 39718, /* agc2_max */ + 9930, /* agc2_min */ + 0, /* agc1_pt1 */ + 0, /* agc1_pt2 */ + 0, /* agc1_pt3 */ + 0, /* agc1_slope1 */ + 0, /* agc1_slope2 */ + 0, /* agc2_pt1 */ + 128, /* agc2_pt2 */ + 29, /* agc2_slope1 */ + 29, /* agc2_slope2 */ + + 17, /* alpha_mant */ + 27, /* alpha_exp */ + 23, /* beta_mant */ + 51, /* beta_exp */ + + 1, /* perform_agc_softsplit */ +}; + +/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */ +static struct dibx000_bandwidth_config xc3028_bw_config = { + 60000, 30000, /* internal, sampling */ + 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ + 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, + modulo */ + (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ + (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ + 20452225, /* timf */ + 30000000, /* xtal_hz */ +}; + +static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { + .output_mpeg2_in_188_bytes = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 1, + .agc = &xc3028_agc_config, + .bw = &xc3028_bw_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, +}; + +static int stk7700ph_xc3028_callback(void *ptr, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = ptr; + + switch (command) { + case XC2028_TUNER_RESET: + /* Send the tuner in then out of reset */ + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + break; + case XC2028_RESET_CLK: + break; + default: + err("%s: unknown command %d, arg %d\n", __func__, + command, arg); + return -EINVAL; + } + return 0; +} + +static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_DIBCOM52, +}; + +static struct xc2028_config stk7700ph_xc3028_config = { + .i2c_addr = 0x61, + .ctrl = &stk7700ph_xc3028_ctrl, +}; + +static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device_descriptor *desc = &adap->dev->udev->descriptor; + + if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) && + desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX)) + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + else + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + msleep(10); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &stk7700ph_dib7700_xc3028_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &stk7700ph_dib7700_xc3028_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + stk7700ph_xc3028_config.i2c_adap = tun_i2c; + + /* FIXME: generalize & move to common area */ + adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback; + + return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config) + == NULL ? -ENODEV : 0; +} + +#define DEFAULT_RC_INTERVAL 50 + +static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; + +/* Number of keypresses to ignore before start repeating */ +#define RC_REPEAT_DELAY 6 + +/* + * This function is used only when firmware is < 1.20 version. Newer + * firmwares use bulk mode, with functions implemented at dib0700_core, + * at dib0700_rc_urb_completion() + */ +static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) +{ + u8 key[4]; + u32 keycode; + u8 toggle; + int i; + struct dib0700_state *st = d->priv; + + if (st->fw_version >= 0x10200) { + /* For 1.20 firmware , We need to keep the RC polling + callback so we can reuse the input device setup in + dvb-usb-remote.c. However, the actual work is being done + in the bulk URB completion handler. */ + return 0; + } + + i = dib0700_ctrl_rd(d, rc_request, 2, key, 4); + if (i <= 0) { + err("RC Query Failed"); + return -1; + } + + /* losing half of KEY_0 events from Philipps rc5 remotes.. */ + if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0) + return 0; + + /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ + + dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ + + d->last_event = 0; + switch (d->props.rc.core.protocol) { + case RC_TYPE_NEC: + /* NEC protocol sends repeat code as 0 0 0 FF */ + if ((key[3-2] == 0x00) && (key[3-3] == 0x00) && + (key[3] == 0xff)) + keycode = d->last_event; + else { + keycode = key[3-2] << 8 | key[3-3]; + d->last_event = keycode; + } + + rc_keydown(d->rc_dev, keycode, 0); + break; + default: + /* RC-5 protocol changes toggle bit on new keypress */ + keycode = key[3-2] << 8 | key[3-3]; + toggle = key[3-1]; + rc_keydown(d->rc_dev, keycode, toggle); + + break; + } + return 0; +} + +/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ +static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { + BAND_UHF | BAND_VHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 712, + 41, + + 0, + 118, + + 0, + 4095, + 0, + 0, + + 42598, + 17694, + 45875, + 2621, + 0, + 76, + 139, + 52, + 59, + 107, + 172, + 57, + 70, + + 21, + 25, + 28, + 48, + + 1, + { 0, + 107, + 51800, + 24700 + }, +}; + +static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { + BAND_UHF | BAND_VHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 712, + 41, + + 0, + 118, + + 0, + 4095, + 0, + 0, + + 42598, + 16384, + 42598, + 0, + + 0, + 137, + 255, + + 0, + 255, + + 0, + 0, + + 0, + 41, + + 15, + 25, + + 28, + 48, + + 0, +}; + +static struct dibx000_bandwidth_config stk7700p_pll_config = { + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 0, + (3 << 14) | (1 << 12) | (524 << 0), + 60258167, + 20452225, + 30000000, +}; + +static struct dib7000m_config stk7700p_dib7000m_config = { + .dvbt_mode = 1, + .output_mpeg2_in_188_bytes = 1, + .quartz_direct = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000m_mt2060_agc_config, + .bw = &stk7700p_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +static struct dib7000p_config stk7700p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000p_mt2060_agc_config, + .bw = &stk7700p_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + /* unless there is no real power management in DVB - we leave the device on GPIO6 */ + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); + dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100); + + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + st->mt2060_if1[0] = 1220; + + if (dib7000pc_detection(&adap->dev->i2c_adap)) { + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + st->is_dib7000pc = 1; + } else + adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static struct mt2060_config stk7700p_mt2060_config = { + 0x60 +}; + +static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *tun_i2c; + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && + adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) { + if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; + } + if (st->is_dib7000pc) + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + else + tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config, + if1) == NULL ? -ENODEV : 0; +} + +/* DIB7070 generic */ +static struct dibx000_agc_config dib7070_agc_config = { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 600, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 40, + 183, + 206, + 255, + 72, + 152, + 88, + 90, + + 17, + 27, + 23, + 51, + + 0, +}; + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + deb_info("reset: %d", onoff); + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + deb_info("sleep: %d", onoff); + return dib7000p_set_gpio(fe, 9, 0, onoff); +} + +static struct dib0070_config dib7070p_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4, + .charge_pump = 2, + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .charge_pump = 2, + } +}; + +static struct dib0070_config dib7770p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 0, + .flip_chip = 1, + .charge_pump = 2, +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe); +} + +static int dib7770_set_param_override(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + switch (band) { + case BAND_VHF: + dib7000p_set_gpio(fe, 0, 0, 1); + offset = 850; + break; + case BAND_UHF: + default: + dib7000p_set_gpio(fe, 0, 0, 0); + offset = 250; + break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe); +} + +static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, + &dib7770p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override; + return 0; +} + +static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, + u16 pid, int onoff) +{ + struct dib0700_state *st = adapter->dev->priv; + if (st->is_dib7000pc) + return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); + return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); +} + +static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + struct dib0700_state *st = adapter->dev->priv; + if (st->is_dib7000pc) + return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); + return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); +} + +static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); +} + +static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); +} + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + 60000, 15000, + 1, 20, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 12000000, +}; + +static struct dib7000p_config dib7070p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +/* STK7070P */ +static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device_descriptor *p = &adap->dev->udev->descriptor; + if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && + p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + else + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &dib7070p_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &dib7070p_dib7000p_config); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +/* STK7770P */ +static struct dib7000p_config dib7770p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .enable_current_mirror = 1, + .disable_sample_and_hold = 0, +}; + +static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device_descriptor *p = &adap->dev->udev->descriptor; + if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && + p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + else + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &dib7770p_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &dib7770p_dib7000p_config); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +/* DIB807x generic */ +static struct dibx000_agc_config dib807x_agc_config[2] = { + { + BAND_VHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + * P_agc_write=0 */ + (0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | + (0 << 0), /* setup*/ + + 600, /* inv_gain*/ + 10, /* time_stabiliz*/ + + 0, /* alpha_level*/ + 118, /* thlock*/ + + 0, /* wbd_inv*/ + 3530, /* wbd_ref*/ + 1, /* wbd_sel*/ + 5, /* wbd_alpha*/ + + 65535, /* agc1_max*/ + 0, /* agc1_min*/ + + 65535, /* agc2_max*/ + 0, /* agc2_min*/ + + 0, /* agc1_pt1*/ + 40, /* agc1_pt2*/ + 183, /* agc1_pt3*/ + 206, /* agc1_slope1*/ + 255, /* agc1_slope2*/ + 72, /* agc2_pt1*/ + 152, /* agc2_pt2*/ + 88, /* agc2_slope1*/ + 90, /* agc2_slope2*/ + + 17, /* alpha_mant*/ + 27, /* alpha_exp*/ + 23, /* beta_mant*/ + 51, /* beta_exp*/ + + 0, /* perform_agc_softsplit*/ + }, { + BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + * P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | + (0 << 0), /* setup */ + + 600, /* inv_gain*/ + 10, /* time_stabiliz*/ + + 0, /* alpha_level*/ + 118, /* thlock*/ + + 0, /* wbd_inv*/ + 3530, /* wbd_ref*/ + 1, /* wbd_sel*/ + 5, /* wbd_alpha*/ + + 65535, /* agc1_max*/ + 0, /* agc1_min*/ + + 65535, /* agc2_max*/ + 0, /* agc2_min*/ + + 0, /* agc1_pt1*/ + 40, /* agc1_pt2*/ + 183, /* agc1_pt3*/ + 206, /* agc1_slope1*/ + 255, /* agc1_slope2*/ + 72, /* agc2_pt1*/ + 152, /* agc2_pt2*/ + 88, /* agc2_slope1*/ + 90, /* agc2_slope2*/ + + 17, /* alpha_mant*/ + 27, /* alpha_exp*/ + 23, /* beta_mant*/ + 51, /* beta_exp*/ + + 0, /* perform_agc_softsplit*/ + } +}; + +static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = { + 60000, 15000, /* internal, sampling*/ + 1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/ + 0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core, + ADClkSrc, modulo */ + (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ + (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ + 18179755, /* timf*/ + 12000000, /* xtal_hz*/ +}; + +static struct dib8000_config dib807x_dib8000_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib807x_agc_config, + .pll = &dib807x_bw_config_12_mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 1, + .agc_control = &dib0070_ctrl_agc_filter, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib807x_agc_config, + .pll = &dib807x_bw_config_12_mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .agc_control = &dib0070_ctrl_agc_filter, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + } +}; + +static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib8000_set_gpio(fe, 5, 0, !onoff); +} + +static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib8000_set_gpio(fe, 0, 0, onoff); +} + +static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { + { 240, 7}, + { 0xffff, 6}, +}; + +static struct dib0070_config dib807x_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4, + .vga_filter = 1, + .force_crystal_mode = 1, + .enable_third_order_filter = 1, + .charge_pump = 0, + .wbd_gain = dib8070_wbd_gain_cfg, + .osc_buffer_state = 0, + .freq_offset_khz_uhf = -100, + .freq_offset_khz_vhf = -100, + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 2, + .vga_filter = 1, + .force_crystal_mode = 1, + .enable_third_order_filter = 1, + .charge_pump = 0, + .wbd_gain = dib8070_wbd_gain_cfg, + .osc_buffer_state = 0, + .freq_offset_khz_uhf = -25, + .freq_offset_khz_vhf = -25, + } +}; + +static int dib807x_set_param_override(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset = dib0070_wbd_offset(fe); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + switch (band) { + case BAND_VHF: + offset += 750; + break; + case BAND_UHF: /* fall-thru wanted */ + default: + offset += 250; break; + } + deb_info("WBD for DiB8000: %d\n", offset); + dib8000_set_wbd_ref(fe, offset); + + return state->set_param_save(fe); +} + +static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, + &dib807x_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, + &dib807x_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override; + return 0; +} + +static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, + u16 pid, int onoff) +{ + return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); +} + +static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, + int onoff) +{ + return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); +} + +/* STK807x */ +static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + 0x80, 0); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + &dib807x_dib8000_config[0]); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +/* STK807xPVR */ +static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(500); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + /* initialize IC 0 */ + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + &dib807x_dib8000_config[0]); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) +{ + /* initialize IC 1 */ + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, + &dib807x_dib8000_config[1]); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +/* STK8096GP */ +static struct dibx000_agc_config dib8090_agc_config[2] = { + { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + }, + { + BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 0, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + } +}; + +static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { + 54000, 13500, + 1, 18, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (599 << 0), + (0 << 25) | 0, + 20199727, + 12000000, +}; + +static int dib8090_get_adc_power(struct dvb_frontend *fe) +{ + return dib8000_get_adc_power(fe, 1); +} + +static struct dib8000_config dib809x_dib8000_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + .diversity_delay = 48, + .refclksel = 3, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_DIVERSITY, + .drives = 0x2d08, + .diversity_delay = 1, + .refclksel = 3, + } +}; + +static struct dib0090_wbd_slope dib8090_wbd_table[] = { + /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */ + { 120, 0, 500, 0, 500, 4 }, /* CBAND */ + { 170, 0, 450, 0, 450, 4 }, /* CBAND */ + { 380, 48, 373, 28, 259, 6 }, /* VHF */ + { 860, 34, 700, 36, 616, 6 }, /* high UHF */ + { 0xFFFF, 34, 700, 36, 616, 6 }, /* default */ +}; + +static struct dib0090_config dib809x_dib0090_config = { + .io.pll_bypass = 1, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 20, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 12000, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 1, + .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, + .use_pwm_agc = 1, + .clkoutdrive = 1, + .get_adc_power = dib8090_get_adc_power, + .freq_offset_khz_uhf = -63, + .freq_offset_khz_vhf = -143, + .wbd = dib8090_wbd_table, + .fref_clock_ratio = 6, +}; + +static int dib8096_set_param_override(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + u16 target; + int ret = 0; + enum frontend_tune_state tune_state = CT_SHUTDOWN; + u16 ltgain, rf_gain_limit; + + ret = state->set_param_save(fe); + if (ret < 0) + return ret; + + target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + + + if (band == BAND_CBAND) { + deb_info("tuning in CBAND - soft-AGC startup\n"); + dib0090_set_tune_state(fe, CT_AGC_START); + do { + ret = dib0090_gain_control(fe); + msleep(ret); + tune_state = dib0090_get_tune_state(fe); + if (tune_state == CT_AGC_STEP_0) + dib8000_set_gpio(fe, 6, 0, 1); + else if (tune_state == CT_AGC_STEP_1) { + dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); + if (rf_gain_limit == 0) + dib8000_set_gpio(fe, 6, 0, 0); + } + } while (tune_state < CT_AGC_STOP); + dib0090_pwm_gain_reset(fe); + dib8000_pwm_agc_reset(fe); + dib8000_set_tune_state(fe, CT_DEMOD_START); + } else { + deb_info("not tuning in CBAND - standard AGC startup\n"); + dib0090_pwm_gain_reset(fe); + } + + return 0; +} + +static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override; + return 0; +} + +static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c; + struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1); + + if (fe_slave) { + tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + fe_slave->dvb = adap->fe_adap[0].fe->dvb; + fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; + } + tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override; + + return 0; +} + +static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe_slave; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(1000); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + if (adap->fe_adap[0].fe == NULL) + return -ENODEV; + + fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); + dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); + + return fe_slave == NULL ? -ENODEV : 0; +} + +/* TFE8096P */ +static struct dibx000_agc_config dib8096p_agc_config[2] = { + { + .band_caps = BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) + | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) + | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 684, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 32767, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 105, + .agc1_slope1 = 0, + .agc1_slope2 = 156, + .agc2_pt1 = 105, + .agc2_pt2 = 255, + .agc2_slope1 = 54, + .agc2_slope2 = 0, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, + } , { + .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) + | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) + | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 732, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 32767, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 98, + .agc1_slope1 = 0, + .agc1_slope2 = 167, + .agc2_pt1 = 98, + .agc2_pt2 = 255, + .agc2_slope1 = 52, + .agc2_slope2 = 0, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, + } +}; + +static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = { + 108000, 13500, + 1, 9, 1, 0, 0, + 0, 0, 0, 0, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20199729, + 12000000, +}; + +static struct dib8000_config tfe8096p_dib8000_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib8096p_agc_config, + .pll = &dib8096p_clock_config_12_mhz, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .agc_control = NULL, + .diversity_delay = 48, + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static struct dib0090_wbd_slope dib8096p_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 860, 51, 866, 21, 375, 4}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static const struct dib0090_config tfe8096p_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib8096p_tuner_sleep, + .sleep = dib8096p_tuner_sleep, + + .freq_offset_khz_uhf = -143, + .freq_offset_khz_vhf = -143, + + .get_adc_power = dib8090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 1, + + .wbd = dib8096p_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 0, +}; + +struct dibx090p_adc { + u32 freq; /* RF freq MHz */ + u32 timf; /* New Timf */ + u32 pll_loopdiv; /* New prediv */ + u32 pll_prediv; /* New loopdiv */ +}; + +struct dibx090p_adc dib8090p_adc_tab[] = { + { 50000, 17043521, 16, 3}, /* 64 MHz */ + {878000, 20199729, 9, 1}, /* 60 MHz */ + {0xffffffff, 0, 0, 0}, /* 60 MHz */ +}; + +static int dib8096p_agc_startup(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + struct dibx000_bandwidth_config pll; + u16 target; + int better_sampling_freq = 0, ret; + struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0]; + + ret = state->set_param_save(fe); + if (ret < 0) + return ret; + memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); + + dib0090_pwm_gain_reset(fe); + /* dib0090_get_wbd_target is returning any possible + temperature compensated wbd-target */ + target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + + + while (p->frequency / 1000 > adc_table->freq) { + better_sampling_freq = 1; + adc_table++; + } + + if ((adc_table->freq != 0xffffffff) && better_sampling_freq) { + pll.pll_ratio = adc_table->pll_loopdiv; + pll.pll_prediv = adc_table->pll_prediv; + dib8000_update_pll(fe, &pll); + dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf); + } + return 0; +} + +static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, + &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe8096p_dib0090_config) == NULL) + return -ENODEV; + + dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup; + return 0; +} + +/* STK9090M */ +static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); +} + +static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); +} + +static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib9000_set_gpio(fe, 5, 0, !onoff); +} + +static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib9000_set_gpio(fe, 0, 0, onoff); +} + +static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) +{ + u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 }; + u8 rb[2]; + struct i2c_msg msg[2] = { + {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2}, + {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, + }; + u8 index_data; + + dibx000_i2c_set_speed(i2c, 250); + + if (i2c_transfer(i2c, msg, 2) != 2) + return -EIO; + + switch (rb[0] << 8 | rb[1]) { + case 0: + deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n"); + return -EIO; + case 1: + deb_info("Found DiB0170 rev2"); + break; + case 2: + deb_info("Found DiB0190 rev2"); + break; + default: + deb_info("DiB01x0 not found"); + return -EIO; + } + + for (index_data = 0; index_data < len; index_data += 2) { + wb[2] = (data[index_data + 1] >> 8) & 0xff; + wb[3] = (data[index_data + 1]) & 0xff; + + if (data[index_data] == 0) { + wb[0] = (data[index_data] >> 8) & 0xff; + wb[1] = (data[index_data]) & 0xff; + msg[0].len = 2; + if (i2c_transfer(i2c, msg, 2) != 2) + return -EIO; + wb[2] |= rb[0]; + wb[3] |= rb[1] & ~(3 << 4); + } + + wb[0] = (data[index_data] >> 8)&0xff; + wb[1] = (data[index_data])&0xff; + msg[0].len = 4; + if (i2c_transfer(i2c, &msg[0], 1) != 1) + return -EIO; + } + return 0; +} + +static struct dib9000_config stk9090m_config = { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_MPEG2_FIFO, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + .subband = { + 2, + { + { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */ + { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */ + { 0 }, + }, + }, + .gpio_function = { + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, + }, +}; + +static struct dib9000_config nim9090md_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_MPEG2_FIFO, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + }, { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_DIVERSITY, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + .subband = { + 2, + { + { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */ + { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */ + { 0 }, + }, + }, + .gpio_function = { + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, + }, + } +}; + +static struct dib0090_config dib9090_dib0090_config = { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 0, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, +}; + +static struct dib0090_config nim9090md_dib0090_config[2] = { + { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + }, { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 0, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + } +}; + + +static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct dib0700_state *st = adap->dev->priv; + u32 fw_version; + + /* Make use of the new i2c functions from FW 1.20 */ + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_i2c_speed(adap->dev, 340); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80); + + if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { + deb_info("%s: Upload failed. (file not found?)\n", __func__); + return -ENODEV; + } else { + deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); + } + stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; + stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; + + adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); + u16 data_dib190[10] = { + 1, 0x1374, + 2, 0x01a2, + 7, 0x0020, + 0, 0x00ef, + 8, 0x0486, + }; + + if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL) + return -ENODEV; + i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) + return -ENODEV; + dib0700_set_i2c_speed(adap->dev, 1500); + if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) + return -ENODEV; + release_firmware(state->frontend_firmware); + return 0; +} + +static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *i2c; + struct dvb_frontend *fe_slave; + u32 fw_version; + + /* Make use of the new i2c functions from FW 1.20 */ + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_i2c_speed(adap->dev, 340); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { + deb_info("%s: Upload failed. (file not found?)\n", __func__); + return -EIO; + } else { + deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); + } + nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size; + nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data; + nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size; + nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; + + dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); + adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); + + if (adap->fe_adap[0].fe == NULL) + return -ENODEV; + + i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); + dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); + + fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); + dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); + + return fe_slave == NULL ? -ENODEV : 0; +} + +static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct i2c_adapter *i2c; + struct dvb_frontend *fe_slave; + u16 data_dib190[10] = { + 1, 0x5374, + 2, 0x01ae, + 7, 0x0020, + 0, 0x00ef, + 8, 0x0406, + }; + i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); + if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL) + return -ENODEV; + i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) + return -ENODEV; + + dib0700_set_i2c_speed(adap->dev, 1500); + if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) + return -ENODEV; + + fe_slave = dib9000_get_slave_frontend(adap->fe_adap[0].fe, 1); + if (fe_slave != NULL) { + i2c = dib9000_get_component_bus_interface(adap->fe_adap[0].fe); + dib9000_set_i2c_adapter(fe_slave, i2c); + + i2c = dib9000_get_tuner_interface(fe_slave); + if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) + return -ENODEV; + fe_slave->dvb = adap->fe_adap[0].fe->dvb; + dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500); + if (dib9000_firmware_post_pll_init(fe_slave) < 0) + return -ENODEV; + } + release_firmware(state->frontend_firmware); + + return 0; +} + +/* NIM7090 */ +struct dib7090p_best_adc { + u32 timf; + u32 pll_loopdiv; + u32 pll_prediv; +}; + +static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc) +{ + u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; + + u16 xtal = 12000; + u32 fcp_min = 1900; /* PLL Minimum Frequency comparator KHz */ + u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */ + u32 fdem_max = 76000; + u32 fdem_min = 69500; + u32 fcp = 0, fs = 0, fdem = 0; + u32 harmonic_id = 0; + + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = 0; + + deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min); + + /* Find Min and Max prediv */ + while ((xtal/max_prediv) >= fcp_min) + max_prediv++; + + max_prediv--; + min_prediv = max_prediv; + while ((xtal/min_prediv) <= fcp_max) { + min_prediv--; + if (min_prediv == 1) + break; + } + deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); + + min_prediv = 2; + + for (prediv = min_prediv ; prediv < max_prediv; prediv++) { + fcp = xtal / prediv; + if (fcp > fcp_min && fcp < fcp_max) { + for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { + fdem = ((xtal/prediv) * loopdiv); + fs = fdem / 4; + /* test min/max system restrictions */ + + if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { + spur = 0; + /* test fs harmonics positions */ + for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { + if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { + spur = 1; + break; + } + } + + if (!spur) { + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = 2396745143UL/fdem*(1 << 9); + adc->timf += ((2396745143UL%fdem) << 9)/fdem; + deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf); + break; + } + } + } + } + if (!spur) + break; + } + + + if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0) + return -EINVAL; + else + return 0; +} + +static int dib7090_agc_startup(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + struct dibx000_bandwidth_config pll; + u16 target; + struct dib7090p_best_adc adc; + int ret; + + ret = state->set_param_save(fe); + if (ret < 0) + return ret; + + memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); + dib0090_pwm_gain_reset(fe); + target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; + dib7000p_set_wbd_ref(fe, target); + + if (dib7090p_get_best_sampling(fe, &adc) == 0) { + pll.pll_ratio = adc.pll_loopdiv; + pll.pll_prediv = adc.pll_prediv; + + dib7000p_update_pll(fe, &pll); + dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); + } + return 0; +} + +static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + deb_info("AGC restart callback: %d", restart); + if (restart == 0) /* before AGC startup */ + dib0090_set_dc_servo(fe, 1); + return 0; +} + +static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global) +{ + u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1; + s16 wbd_delta; + + if ((fe->dtv_property_cache.frequency) < 400000000) + threshold_agc1 = 25000; + else + threshold_agc1 = 30000; + + wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2; + wbd_offset = dib0090_get_wbd_offset(fe); + dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd); + wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ; + + deb_info("update lna, agc_global=%d agc1=%d agc2=%d", + agc_global, agc1, agc2); + deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d", + wbd, wbd_target, wbd_offset, wbd_delta); + + if ((agc1 < threshold_agc1) && (wbd_delta > 0)) { + dib0090_set_switch(fe, 1, 1, 1); + dib0090_set_vga(fe, 0); + dib0090_update_rframp_7090(fe, 0); + dib0090_update_tuning_table_7090(fe, 0); + } else { + dib0090_set_vga(fe, 1); + dib0090_update_rframp_7090(fe, 1); + dib0090_update_tuning_table_7090(fe, 1); + dib0090_set_switch(fe, 0, 0, 0); + } + + return 0; +} + +static struct dib0090_wbd_slope dib7090_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 860, 51, 866, 21, 375, 4}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static struct dib0090_wbd_slope dib7090e_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 700, 51, 866, 21, 320, 4}, + { 860, 48, 666, 18, 330, 6}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static struct dibx000_agc_config dib7090_agc_config[2] = { + { + .band_caps = BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 687, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 65535, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 32, + .agc1_pt3 = 114, + .agc1_slope1 = 143, + .agc1_slope2 = 144, + .agc2_pt1 = 114, + .agc2_pt2 = 227, + .agc2_slope1 = 116, + .agc2_slope2 = 117, + + .alpha_mant = 18, + .alpha_exp = 0, + .beta_mant = 20, + .beta_exp = 59, + + .perform_agc_softsplit = 0, + } , { + .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 732, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 65535, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 98, + .agc1_slope1 = 0, + .agc1_slope2 = 167, + .agc2_pt1 = 98, + .agc2_pt2 = 255, + .agc2_slope1 = 104, + .agc2_slope2 = 0, + + .alpha_mant = 18, + .alpha_exp = 0, + .beta_mant = 20, + .beta_exp = 59, + + .perform_agc_softsplit = 0, + } +}; + +static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { + 60000, 15000, + 1, 5, 0, 0, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 15000000, +}; + +static struct dib7000p_config nim7090_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .default_i2c_addr = 0x90, + .enMpegOutput = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .default_i2c_addr = 0x92, + .enMpegOutput = 0, + } +}; + +static struct dib7000p_config tfe7090e_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = dib7090e_update_lna, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static const struct dib0090_config nim7090_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, +}; + +static const struct dib0090_config tfe7090e_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090e_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 1, + .is_dib7090e = 1, +}; + +static struct dib7000p_config tfe7790e_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = dib7090e_update_lna, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .enMpegOutput = 1, +}; + +static const struct dib0090_config tfe7790e_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090e_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 1, + .is_dib7090e = 1, + .force_crystal_mode = 1, +}; + +static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { + { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 50, + .freq_offset_khz_vhf = 70, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + }, { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = -50, + .freq_offset_khz_vhf = -70, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + } +}; + +static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* The TFE7090 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + /* initialize IC 0 */ + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + + dib0700_set_i2c_speed(adap->dev, 340); + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); + if (adap->fe_adap[0].fe == NULL) + return -ENODEV; + + dib7090_slave_reset(adap->fe_adap[0].fe); + + return 0; +} + +static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *i2c; + + if (adap->dev->adapter[0].fe_adap[0].fe == NULL) { + err("the master dib7090 has to be initialized first"); + return -ENODEV; /* the master device has not been initialized */ + } + + i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + dib0700_set_i2c_speed(adap->dev, 200); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + 1, 0x10, &tfe7090e_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80, &tfe7090e_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* The TFE7790E requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(20); + dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + 1, 0x10, &tfe7790e_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80, &tfe7790e_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe7790e_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe7090e_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +/* STK7070PD */ +static struct dib7000p_config stk7070pd_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + } +}; + +static void stk7070pd_init(struct dvb_usb_device *dev) +{ + dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(dev, 72, 1); + + msleep(10); + dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1); +} + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + stk7070pd_init(adap->dev); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, + stk7070pd_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) +{ + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int novatd_read_status_override(struct dvb_frontend *fe, + fe_status_t *stat) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *dev = adap->dev; + struct dib0700_state *state = dev->priv; + int ret; + + ret = state->read_status(fe, stat); + + if (!ret) + dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, + !!(*stat & FE_HAS_LOCK)); + + return ret; +} + +static int novatd_sleep_override(struct dvb_frontend* fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *dev = adap->dev; + struct dib0700_state *state = dev->priv; + + /* turn off LED */ + dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0); + + return state->sleep(fe); +} + +/** + * novatd_frontend_attach - Nova-TD specific attach + * + * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for + * information purposes. + */ +static int novatd_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *dev = adap->dev; + struct dib0700_state *st = dev->priv; + + if (adap->id == 0) { + stk7070pd_init(dev); + + /* turn the power LED on, the other two off (just in case) */ + dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0); + dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0); + dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18, + stk7070pd_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap, + adap->id == 0 ? 0x80 : 0x82, + &stk7070pd_dib7000p_config[adap->id]); + + if (adap->fe_adap[0].fe == NULL) + return -ENODEV; + + st->read_status = adap->fe_adap[0].fe->ops.read_status; + adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override; + st->sleep = adap->fe_adap[0].fe->ops.sleep; + adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override; + + return 0; +} + +/* S5H1411 */ +static struct s5h1411_config pinnacle_801e_config = { + .output_mode = S5H1411_PARALLEL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING +}; + +/* Pinnacle PCTV HD Pro 801e GPIOs map: + GPIO0 - currently unknown + GPIO1 - xc5000 tuner reset + GPIO2 - CX25843 sleep + GPIO3 - currently unknown + GPIO4 - currently unknown + GPIO6 - currently unknown + GPIO7 - currently unknown + GPIO9 - currently unknown + GPIO10 - CX25843 reset + */ +static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Make use of the new i2c functions from FW 1.20 */ + st->fw_use_new_i2c_api = 1; + + /* The s5h1411 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + /* All msleep values taken from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(400); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(60); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); + msleep(30); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* GPIOs are initialized, do the attach */ + adap->fe_adap[0].fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + &adap->dev->i2c_adap); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int dib0700_xc5000_tuner_callback(void *priv, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + if (command == XC5000_TUNER_RESET) { + /* Reset the tuner */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); + msleep(10); + } else { + err("xc5000: unknown tuner callback command: %d\n", command); + return -EINVAL; + } + + return 0; +} + +static struct xc5000_config s5h1411_xc5000_tunerconfig = { + .i2c_address = 0x64, + .if_khz = 5380, +}; + +static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) +{ + /* FIXME: generalize & move to common area */ + adap->fe_adap[0].fe->callback = dib0700_xc5000_tuner_callback; + + return dvb_attach(xc5000_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, + &s5h1411_xc5000_tunerconfig) + == NULL ? -ENODEV : 0; +} + +static int dib0700_xc4000_tuner_callback(void *priv, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + if (command == XC4000_TUNER_RESET) { + /* Reset the tuner */ + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); + msleep(10); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + } else { + err("xc4000: unknown tuner callback command: %d\n", command); + return -EINVAL; + } + + return 0; +} + +static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = { + .band_caps = BAND_UHF | BAND_VHF, + .setup = 0x64, + .inv_gain = 0x02c8, + .time_stabiliz = 0x15, + .alpha_level = 0x00, + .thlock = 0x76, + .wbd_inv = 0x01, + .wbd_ref = 0x0b33, + .wbd_sel = 0x00, + .wbd_alpha = 0x02, + .agc1_max = 0x00, + .agc1_min = 0x00, + .agc2_max = 0x9b26, + .agc2_min = 0x26ca, + .agc1_pt1 = 0x00, + .agc1_pt2 = 0x00, + .agc1_pt3 = 0x00, + .agc1_slope1 = 0x00, + .agc1_slope2 = 0x00, + .agc2_pt1 = 0x00, + .agc2_pt2 = 0x80, + .agc2_slope1 = 0x1d, + .agc2_slope2 = 0x1d, + .alpha_mant = 0x11, + .alpha_exp = 0x1b, + .beta_mant = 0x17, + .beta_exp = 0x33, + .perform_agc_softsplit = 0x00, +}; + +static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = { + 60000, 30000, /* internal, sampling */ + 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ + 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, */ + /* ADClkSrc, modulo */ + (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */ + 39370534, /* ifreq */ + 20452225, /* timf */ + 30000000 /* xtal */ +}; + +/* FIXME: none of these inputs are validated yet */ +static struct dib7000p_config pctv_340e_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000p_xc4000_agc_config, + .bw = &stk7700p_xc4000_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +/* PCTV 340e GPIOs map: + dib0700: + GPIO2 - CX25843 sleep + GPIO3 - CS5340 reset + GPIO5 - IRD + GPIO6 - Power Supply + GPIO8 - LNA (1=off 0=on) + GPIO10 - CX25843 reset + dib7000: + GPIO8 - xc4000 reset + */ +static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Power Supply on */ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(50); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(100); /* Allow power supply to settle before probing */ + + /* cx25843 reset */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(1); /* cx25843 datasheet say 350us required */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + + /* LNA off for now */ + dib0700_set_gpio(adap->dev, GPIO8, GPIO_OUT, 1); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* FIXME: not verified yet */ + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(500); + + if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) { + /* Demodulator not found for some reason? */ + return -ENODEV; + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + &pctv_340e_config); + st->is_dib7000pc = 1; + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static struct xc4000_config dib7000p_xc4000_tunerconfig = { + .i2c_address = 0x61, + .default_pm = 1, + .dvb_amplitude = 0, + .set_smoothedcvbs = 0, + .if_khz = 5400 +}; + +static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + + /* The xc4000 is not on the main i2c bus */ + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + if (tun_i2c == NULL) { + printk(KERN_ERR "Could not reach tuner i2c bus\n"); + return 0; + } + + /* Setup the reset callback */ + adap->fe_adap[0].fe->callback = dib0700_xc4000_tuner_callback; + + return dvb_attach(xc4000_attach, adap->fe_adap[0].fe, tun_i2c, + &dib7000p_xc4000_tunerconfig) + == NULL ? -ENODEV : 0; +} + +static struct lgdt3305_config hcw_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_PARALLEL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_LOW, + .deny_i2c_rptr = 0, + .spectral_inversion = 1, + .qam_if_khz = 6000, + .vsb_if_khz = 6000, + .usref_8vsb = 0x0500, +}; + +static struct mxl5007t_config hcw_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_25_MHZ, + .if_freq_hz = MxL_IF_6_MHZ, + .invert_if = 1, +}; + +/* TIGER-ATSC map: + GPIO0 - LNA_CTR (H: LNA power enabled, L: LNA power disabled) + GPIO1 - ANT_SEL (H: VPA, L: MCX) + GPIO4 - SCL2 + GPIO6 - EN_TUNER + GPIO7 - SDA2 + GPIO10 - DEM_RST + + MXL is behind LG's i2c repeater. LG is on SCL2/SDA2 gpios on the DIB + */ +static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Make use of the new i2c functions from FW 1.20 */ + st->fw_use_new_i2c_api = 1; + + st->disable_streaming_master_mode = 1; + + /* fe power enable */ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(30); + + /* demod reset */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + + adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach, + &hcw_lgdt3305_config, + &adap->dev->i2c_adap); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0x60, + &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; +} + + +/* DVB-USB and USB stuff follows */ +struct usb_device_id dib0700_usb_id_table[] = { +/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, +/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, + { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, +/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, + { USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, +/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, + USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, +/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, +/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_USB_XE) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_EXPRESSCARD_320CX) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV72E) }, +/* 30 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73E) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_EC372S) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, +/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, +/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, + { USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) }, + { USB_DEVICE(USB_VID_SONY, USB_PID_SONY_PLAYTV) }, +/* 45 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_PD378S) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, +/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, +/* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, +/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, + { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) }, + { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, +/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DIVERSITY) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090M) }, +/* 70 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM8096MD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, +/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) }, +/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, + { 0 } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); + +#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ + .usb_ctrl = DEVICE_SPECIFIC, \ + .firmware = "dvb-usb-dib0700-1.20.fw", \ + .download_firmware = dib0700_download_firmware, \ + .no_reconnect = 1, \ + .size_of_priv = sizeof(struct dib0700_state), \ + .i2c_algo = &dib0700_i2c_algo, \ + .identify_state = dib0700_identify_state + +#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ + .streaming_ctrl = dib0700_streaming_ctrl, \ + .stream = { \ + .type = USB_BULK, \ + .count = 4, \ + .endpoint = ep, \ + .u = { \ + .bulk = { \ + .buffersize = 39480, \ + } \ + } \ + } + +struct dvb_usb_device_properties dib0700_devices[] = { + { + DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk7700p_pid_filter, + .pid_filter_ctrl = stk7700p_pid_filter_ctrl, + .frontend_attach = stk7700p_frontend_attach, + .tuner_attach = stk7700p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + }, + }, + + .num_device_descs = 8, + .devices = { + { "DiBcom STK7700P reference design", + { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL }, + { NULL }, + }, + { "AVerMedia AVerTV DVB-T Volar", + { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] }, + { NULL }, + }, + { "Compro Videomate U500", + { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, + { NULL }, + }, + { "Uniwill STK7700P based (Hama and others)", + { &dib0700_usb_id_table[7], NULL }, + { NULL }, + }, + { "Leadtek Winfast DTV Dongle (STK7700P based)", + { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] }, + { NULL }, + }, + { "AVerMedia AVerTV DVB-T Express", + { &dib0700_usb_id_table[20] }, + { NULL }, + }, + { "Gigabyte U7000", + { &dib0700_usb_id_table[21], NULL }, + { NULL }, + } + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = bristol_frontend_attach, + .tuner_attach = bristol_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + }, { + .num_frontends = 1, + .fe = {{ + .frontend_attach = bristol_frontend_attach, + .tuner_attach = bristol_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + } + }, + + .num_device_descs = 1, + .devices = { + { "Hauppauge Nova-T 500 Dual DVB-T", + { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + }, { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + } + }, + + .num_device_descs = 5, + .devices = { + { "Pinnacle PCTV 2000e", + { &dib0700_usb_id_table[11], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT XS Diversity", + { &dib0700_usb_id_table[12], NULL }, + { NULL }, + }, + { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", + { &dib0700_usb_id_table[13], NULL }, + { NULL }, + }, + { "DiBcom STK7700D reference design", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, + { "YUAN High-Tech DiBcom STK7700D", + { &dib0700_usb_id_table[55], NULL }, + { NULL }, + }, + + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700P2_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + }, + }, + + .num_device_descs = 3, + .devices = { + { "ASUS My Cinema U3000 Mini DVBT Tuner", + { &dib0700_usb_id_table[23], NULL }, + { NULL }, + }, + { "Yuan EC372S", + { &dib0700_usb_id_table[31], NULL }, + { NULL }, + }, + { "Terratec Cinergy T Express", + { &dib0700_usb_id_table[42], NULL }, + { NULL }, + } + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 12, + .devices = { + { "DiBcom STK7070P reference design", + { &dib0700_usb_id_table[15], NULL }, + { NULL }, + }, + { "Pinnacle PCTV DVB-T Flash Stick", + { &dib0700_usb_id_table[16], NULL }, + { NULL }, + }, + { "Artec T14BR DVB-T", + { &dib0700_usb_id_table[22], NULL }, + { NULL }, + }, + { "ASUS My Cinema U3100 Mini DVBT Tuner", + { &dib0700_usb_id_table[24], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[25], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T MyTV.t", + { &dib0700_usb_id_table[26], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 72e", + { &dib0700_usb_id_table[29], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 73e", + { &dib0700_usb_id_table[30], NULL }, + { NULL }, + }, + { "Elgato EyeTV DTT", + { &dib0700_usb_id_table[49], NULL }, + { NULL }, + }, + { "Yuan PD378S", + { &dib0700_usb_id_table[45], NULL }, + { NULL }, + }, + { "Elgato EyeTV Dtt Dlx PD378S", + { &dib0700_usb_id_table[50], NULL }, + { NULL }, + }, + { "Elgato EyeTV DTT rev. 2", + { &dib0700_usb_id_table[81], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 3, + .devices = { + { "Pinnacle PCTV 73A", + { &dib0700_usb_id_table[56], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 73e SE", + { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 282e", + { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = novatd_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = novatd_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 1, + .devices = { + { "Hauppauge Nova-TD Stick (52009)", + { &dib0700_usb_id_table[35], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 5, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Dual DVB-T Diversity Stick", + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, + { "Hauppauge Nova-TD-500 (84xxx)", + { &dib0700_usb_id_table[36], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT USB XS Diversity/ T5", + { &dib0700_usb_id_table[43], + &dib0700_usb_id_table[53], NULL}, + { NULL }, + }, + { "Sony PlayTV", + { &dib0700_usb_id_table[44], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 1, + .devices = { + { "Elgato EyeTV Diversity", + { &dib0700_usb_id_table[68], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_NEC_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700ph_frontend_attach, + .tuner_attach = stk7700ph_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 9, + .devices = { + { "Terratec Cinergy HT USB XE", + { &dib0700_usb_id_table[27], NULL }, + { NULL }, + }, + { "Pinnacle Expresscard 320cx", + { &dib0700_usb_id_table[28], NULL }, + { NULL }, + }, + { "Terratec Cinergy HT Express", + { &dib0700_usb_id_table[32], NULL }, + { NULL }, + }, + { "Gigabyte U8000-RH", + { &dib0700_usb_id_table[37], NULL }, + { NULL }, + }, + { "YUAN High-Tech STK7700PH", + { &dib0700_usb_id_table[38], NULL }, + { NULL }, + }, + { "Asus My Cinema-U3000Hybrid", + { &dib0700_usb_id_table[39], NULL }, + { NULL }, + }, + { "YUAN High-Tech MC770", + { &dib0700_usb_id_table[48], NULL }, + { NULL }, + }, + { "Leadtek WinFast DTV Dongle H", + { &dib0700_usb_id_table[51], NULL }, + { NULL }, + }, + { "YUAN High-Tech STK7700D", + { &dib0700_usb_id_table[54], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = s5h1411_frontend_attach, + .tuner_attach = xc5000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Pinnacle PCTV HD Pro USB Stick", + { &dib0700_usb_id_table[40], NULL }, + { NULL }, + }, + { "Pinnacle PCTV HD USB Stick", + { &dib0700_usb_id_table[41], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = lgdt3305_frontend_attach, + .tuner_attach = mxl5007t_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Hauppauge ATSC MiniCard (B200)", + { &dib0700_usb_id_table[46], NULL }, + { NULL }, + }, + { "Hauppauge ATSC MiniCard (B210)", + { &dib0700_usb_id_table[47], NULL }, + { NULL }, + }, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7770p_frontend_attach, + .tuner_attach = dib7770p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 4, + .devices = { + { "DiBcom STK7770P reference design", + { &dib0700_usb_id_table[59], NULL }, + { NULL }, + }, + { "Terratec Cinergy T USB XXS (HD)/ T3", + { &dib0700_usb_id_table[33], + &dib0700_usb_id_table[52], + &dib0700_usb_id_table[60], NULL}, + { NULL }, + }, + { "TechniSat AirStar TeleStick 2", + { &dib0700_usb_id_table[74], NULL }, + { NULL }, + }, + { "Medion CTX1921 DVB-T USB", + { &dib0700_usb_id_table[75], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk807x_frontend_attach, + .tuner_attach = dib807x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 3, + .devices = { + { "DiBcom STK807xP reference design", + { &dib0700_usb_id_table[62], NULL }, + { NULL }, + }, + { "Prolink Pixelview SBTVD", + { &dib0700_usb_id_table[63], NULL }, + { NULL }, + }, + { "EvolutePC TVWay+", + { &dib0700_usb_id_table[64], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_NEC_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk807xpvr_frontend_attach0, + .tuner_attach = dib807x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk807xpvr_frontend_attach1, + .tuner_attach = dib807x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK807xPVR reference design", + { &dib0700_usb_id_table[61], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk809x_frontend_attach, + .tuner_attach = dib809x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK8096GP reference design", + { &dib0700_usb_id_table[67], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = dib90x0_pid_filter, + .pid_filter_ctrl = dib90x0_pid_filter_ctrl, + .frontend_attach = stk9090m_frontend_attach, + .tuner_attach = dib9090_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK9090M reference design", + { &dib0700_usb_id_table[69], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = nim8096md_frontend_attach, + .tuner_attach = nim8096md_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM8096MD reference design", + { &dib0700_usb_id_table[70], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = dib90x0_pid_filter, + .pid_filter_ctrl = dib90x0_pid_filter_ctrl, + .frontend_attach = nim9090md_frontend_attach, + .tuner_attach = nim9090md_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM9090MD reference design", + { &dib0700_usb_id_table[71], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = nim7090_frontend_attach, + .tuner_attach = nim7090_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM7090 reference design", + { &dib0700_usb_id_table[72], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090pvr_frontend0_attach, + .tuner_attach = tfe7090pvr_tuner0_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090pvr_frontend1_attach, + .tuner_attach = tfe7090pvr_tuner1_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7090PVR reference design", + { &dib0700_usb_id_table[73], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = pctv340e_frontend_attach, + .tuner_attach = xc4000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Pinnacle PCTV 340e HD Pro USB Stick", + { &dib0700_usb_id_table[76], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Hybrid Stick Solo", + { &dib0700_usb_id_table[77], NULL }, + { NULL }, + }, + }, + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090e_frontend_attach, + .tuner_attach = tfe7090e_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7090E reference design", + { &dib0700_usb_id_table[78], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7790e_frontend_attach, + .tuner_attach = tfe7790e_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7790E reference design", + { &dib0700_usb_id_table[79], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = tfe8096p_frontend_attach, + .tuner_attach = tfe8096p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE8096P reference design", + { &dib0700_usb_id_table[80], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, +}; + +int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/usb/dvb-usb/dib07x0.h b/drivers/media/usb/dvb-usb/dib07x0.h new file mode 100644 index 00000000000..7e62c101852 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dib07x0.h @@ -0,0 +1,21 @@ +#ifndef _DIB07X0_H_ +#define _DIB07X0_H_ + +enum dib07x0_gpios { + GPIO0 = 0, + GPIO1 = 2, + GPIO2 = 3, + GPIO3 = 4, + GPIO4 = 5, + GPIO5 = 6, + GPIO6 = 8, + GPIO7 = 10, + GPIO8 = 11, + GPIO9 = 14, + GPIO10 = 15, +}; + +#define GPIO_IN 0 +#define GPIO_OUT 1 + +#endif diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c new file mode 100644 index 00000000000..a76bbb29ca3 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -0,0 +1,479 @@ +/* Common methods for dibusb-based-receivers. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); +MODULE_LICENSE("GPL"); + +#define deb_info(args...) dprintk(debug,0x01,args) + +/* common stuff used by the different dibusb modules */ +int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.fifo_ctrl != NULL) + if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) { + err("error while controlling the fifo of the demod."); + return -ENODEV; + } + } + return 0; +} +EXPORT_SYMBOL(dibusb_streaming_ctrl); + +int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.pid_ctrl != NULL) + st->ops.pid_ctrl(adap->fe_adap[0].fe, + index, pid, onoff); + } + return 0; +} +EXPORT_SYMBOL(dibusb_pid_filter); + +int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.pid_parse != NULL) + if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0) + err("could not handle pid_parser"); + } + return 0; +} +EXPORT_SYMBOL(dibusb_pid_filter_ctrl); + +int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b[3]; + int ret; + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; + b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; + ret = dvb_usb_generic_write(d,b,3); + msleep(10); + return ret; +} +EXPORT_SYMBOL(dibusb_power_ctrl); + +int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 b[3] = { 0 }; + int ret; + + if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) + return ret; + + if (onoff) { + b[0] = DIBUSB_REQ_SET_STREAMING_MODE; + b[1] = 0x00; + if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) + return ret; + } + + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; + return dvb_usb_generic_write(adap->dev,b,3); +} +EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); + +int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + if (onoff) { + u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; + return dvb_usb_generic_write(d,b,3); + } else + return 0; +} +EXPORT_SYMBOL(dibusb2_0_power_ctrl); + +static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ + /* write only ? */ + int wo = (rbuf == NULL || rlen == 0), + len = 2 + wlen + (wo ? 0 : 2); + + sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; + sndbuf[1] = (addr << 1) | (wo ? 0 : 1); + + memcpy(&sndbuf[2],wbuf,wlen); + + if (!wo) { + sndbuf[wlen+2] = (rlen >> 8) & 0xff; + sndbuf[wlen+3] = rlen & 0xff; + } + + return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); +} + +/* + * I2C master xfer function + */ +static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + 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].flags & I2C_M_RD) == 0 + && (msg[i+1].flags & I2C_M_RD)) { + if (dibusb_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 ((msg[i].flags & I2C_M_RD) == 0) { + if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) + break; + } else if (msg[i].addr != 0x50) { + /* 0x50 is the address of the eeprom - we need to protect it + * from dibusb's bad i2c implementation: reads without + * writing the offset before are forbidden */ + if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) + break; + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 dibusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm dibusb_i2c_algo = { + .master_xfer = dibusb_i2c_xfer, + .functionality = dibusb_i2c_func, +}; +EXPORT_SYMBOL(dibusb_i2c_algo); + +int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) +{ + u8 wbuf[1] = { offs }; + return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); +} +EXPORT_SYMBOL(dibusb_read_eeprom_byte); + +/* 3000MC/P stuff */ +// Config Adjacent channels Perf -cal22 +static struct dibx000_agc_config dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 48497, + .agc1_min = 23593, + .agc2_max = 46531, + .agc2_min = 24904, + + .agc1_pt1 = 0x65, + .agc1_pt2 = 0x69, + + .agc1_slope1 = 0x51, + .agc1_slope2 = 0x27, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x33, + + .agc2_slope1 = 0x35, + .agc2_slope2 = 0x37, +}; + +static struct dib3000mc_config stk3000p_dib3000p_config = { + &dib3000p_mt2060_agc_config, + + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +static struct dibx000_agc_config dib3000p_panasonic_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 56361, + .agc1_min = 22282, + .agc2_max = 47841, + .agc2_min = 36045, + + .agc1_pt1 = 0x3b, + .agc1_pt2 = 0x6b, + + .agc1_slope1 = 0x55, + .agc1_slope2 = 0x1d, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x0a, + + .agc2_slope1 = 0x95, + .agc2_slope2 = 0x1e, +}; + +#if defined(CONFIG_DVB_DIB3000MC) || \ + (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) + +static struct dib3000mc_config mod3000p_dib3000p_config = { + &dib3000p_panasonic_agc_config, + + .max_time = 0x51, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == + USB_PID_LITEON_DVB_T_WARM) { + msleep(1000); + } + + adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, + &adap->dev->i2c_adap, + DEFAULT_DIB3000P_I2C_ADDRESS, + &mod3000p_dib3000p_config); + if ((adap->fe_adap[0].fe) == NULL) + adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, + &adap->dev->i2c_adap, + DEFAULT_DIB3000MC_I2C_ADDRESS, + &mod3000p_dib3000p_config); + if ((adap->fe_adap[0].fe) != NULL) { + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + st->ops.pid_parse = dib3000mc_pid_parse; + st->ops.pid_ctrl = dib3000mc_pid_control; + } + return 0; + } + return -ENODEV; +} +EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); + +static struct mt2060_config stk3000p_mt2060_config = { + 0x60 +}; + +int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + u8 a,b; + u16 if1 = 1220; + struct i2c_adapter *tun_i2c; + + // First IF calibration for Liteon Sticks + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { + + dibusb_read_eeprom_byte(adap->dev,0x7E,&a); + dibusb_read_eeprom_byte(adap->dev,0x7F,&b); + + if (a == 0x00) + if1 += b; + else if (a == 0x80) + if1 -= b; + else + warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); + + } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && + adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { + u8 desc; + dibusb_read_eeprom_byte(adap->dev, 7, &desc); + if (desc == 2) { + a = 127; + do { + dibusb_read_eeprom_byte(adap->dev, a, &desc); + a--; + } while (a > 7 && (desc == 0xff || desc == 0x00)); + if (desc & 0x80) + if1 -= (0xff - desc); + else + if1 += desc; + } + } + + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); + if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { + /* not found - use panasonic pll parameters */ + if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) + return -ENOMEM; + } else { + st->mt2060_present = 1; + /* set the correct parameters for the dib3000p */ + dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config); + } + return 0; +} +EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); +#endif + +/* + * common remote control stuff + */ +struct rc_map_table rc_map_dibusb_table[] = { + /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ + { 0x0016, KEY_POWER }, + { 0x0010, KEY_MUTE }, + { 0x0003, KEY_1 }, + { 0x0001, KEY_2 }, + { 0x0006, KEY_3 }, + { 0x0009, KEY_4 }, + { 0x001d, KEY_5 }, + { 0x001f, KEY_6 }, + { 0x000d, KEY_7 }, + { 0x0019, KEY_8 }, + { 0x001b, KEY_9 }, + { 0x0015, KEY_0 }, + { 0x0005, KEY_CHANNELUP }, + { 0x0002, KEY_CHANNELDOWN }, + { 0x001e, KEY_VOLUMEUP }, + { 0x000a, KEY_VOLUMEDOWN }, + { 0x0011, KEY_RECORD }, + { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x0014, KEY_PLAY }, + { 0x001a, KEY_STOP }, + { 0x0040, KEY_REWIND }, + { 0x0012, KEY_FASTFORWARD }, + { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x004c, KEY_PAUSE }, + { 0x004d, KEY_SCREEN }, /* Full screen mode. */ + { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ + { 0x000c, KEY_CANCEL }, /* Cancel */ + { 0x001c, KEY_EPG }, /* EPG */ + { 0x0000, KEY_TAB }, /* Tab */ + { 0x0048, KEY_INFO }, /* Preview */ + { 0x0004, KEY_LIST }, /* RecordList */ + { 0x000f, KEY_TEXT }, /* Teletext */ + /* Key codes for the KWorld/ADSTech/JetWay remote. */ + { 0x8612, KEY_POWER }, + { 0x860f, KEY_SELECT }, /* source */ + { 0x860c, KEY_UNKNOWN }, /* scan */ + { 0x860b, KEY_EPG }, + { 0x8610, KEY_MUTE }, + { 0x8601, KEY_1 }, + { 0x8602, KEY_2 }, + { 0x8603, KEY_3 }, + { 0x8604, KEY_4 }, + { 0x8605, KEY_5 }, + { 0x8606, KEY_6 }, + { 0x8607, KEY_7 }, + { 0x8608, KEY_8 }, + { 0x8609, KEY_9 }, + { 0x860a, KEY_0 }, + { 0x8618, KEY_ZOOM }, + { 0x861c, KEY_UNKNOWN }, /* preview */ + { 0x8613, KEY_UNKNOWN }, /* snap */ + { 0x8600, KEY_UNDO }, + { 0x861d, KEY_RECORD }, + { 0x860d, KEY_STOP }, + { 0x860e, KEY_PAUSE }, + { 0x8616, KEY_PLAY }, + { 0x8611, KEY_BACK }, + { 0x8619, KEY_FORWARD }, + { 0x8614, KEY_UNKNOWN }, /* pip */ + { 0x8615, KEY_ESC }, + { 0x861a, KEY_UP }, + { 0x861e, KEY_DOWN }, + { 0x861f, KEY_LEFT }, + { 0x861b, KEY_RIGHT }, + + /* Key codes for the DiBcom MOD3000 remote. */ + { 0x8000, KEY_MUTE }, + { 0x8001, KEY_TEXT }, + { 0x8002, KEY_HOME }, + { 0x8003, KEY_POWER }, + + { 0x8004, KEY_RED }, + { 0x8005, KEY_GREEN }, + { 0x8006, KEY_YELLOW }, + { 0x8007, KEY_BLUE }, + + { 0x8008, KEY_DVD }, + { 0x8009, KEY_AUDIO }, + { 0x800a, KEY_IMAGES }, /* Pictures */ + { 0x800b, KEY_VIDEO }, + + { 0x800c, KEY_BACK }, + { 0x800d, KEY_UP }, + { 0x800e, KEY_RADIO }, + { 0x800f, KEY_EPG }, + + { 0x8010, KEY_LEFT }, + { 0x8011, KEY_OK }, + { 0x8012, KEY_RIGHT }, + { 0x8013, KEY_UNKNOWN }, /* SAP */ + + { 0x8014, KEY_TV }, + { 0x8015, KEY_DOWN }, + { 0x8016, KEY_MENU }, /* DVD Menu */ + { 0x8017, KEY_LAST }, + + { 0x8018, KEY_RECORD }, + { 0x8019, KEY_STOP }, + { 0x801a, KEY_PAUSE }, + { 0x801b, KEY_PLAY }, + + { 0x801c, KEY_PREVIOUS }, + { 0x801d, KEY_REWIND }, + { 0x801e, KEY_FASTFORWARD }, + { 0x801f, KEY_NEXT}, + + { 0x8040, KEY_1 }, + { 0x8041, KEY_2 }, + { 0x8042, KEY_3 }, + { 0x8043, KEY_CHANNELUP }, + + { 0x8044, KEY_4 }, + { 0x8045, KEY_5 }, + { 0x8046, KEY_6 }, + { 0x8047, KEY_CHANNELDOWN }, + + { 0x8048, KEY_7 }, + { 0x8049, KEY_8 }, + { 0x804a, KEY_9 }, + { 0x804b, KEY_VOLUMEUP }, + + { 0x804c, KEY_CLEAR }, + { 0x804d, KEY_0 }, + { 0x804e, KEY_ENTER }, + { 0x804f, KEY_VOLUMEDOWN }, +}; +EXPORT_SYMBOL(rc_map_dibusb_table); + +int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; + dvb_usb_generic_rw(d,&cmd,1,key,5,0); + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} +EXPORT_SYMBOL(dibusb_rc_query); diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c new file mode 100644 index 00000000000..a4ac37e0e98 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dibusb-mb.c @@ -0,0 +1,471 @@ +/* DVB USB compliant linux driver for mobile DVB-T USB devices based on + * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DiBcom, which has + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dibusb_state *st = adap->priv; + + return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr); +} + +static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib3000_config demod_cfg; + struct dibusb_state *st = adap->priv; + + demod_cfg.demod_address = 0x8; + + adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg, + &adap->dev->i2c_adap, &st->ops); + if ((adap->fe_adap[0].fe) == NULL) + return -ENODEV; + + adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; + + return 0; +} + +static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + + st->tuner_addr = 0x61; + + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, + DVB_PLL_TUA6010XS); + return 0; +} + +static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + + st->tuner_addr = 0x60; + + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, + DVB_PLL_TDA665X); + return 0; +} + +/* Some of the Artec 1.1 device aren't equipped with the default tuner + * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures + * this out. */ +static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) +{ + u8 b[2] = { 0,0 }, b2[1]; + int ret = 0; + struct i2c_msg msg[2] = { + { .flags = 0, .buf = b, .len = 2 }, + { .flags = I2C_M_RD, .buf = b2, .len = 1 }, + }; + struct dibusb_state *st = adap->priv; + + /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ + msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; + + if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) + adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); + + if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { + err("tuner i2c write failed."); + ret = -EREMOTEIO; + } + + if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) + adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); + + if (b2[0] == 0xfe) { + info("This device has the Thomson Cable onboard. Which is default."); + ret = dibusb_thomson_tuner_attach(adap); + } else { + info("This device has the Panasonic ENV77H11D5 onboard."); + ret = dibusb_panasonic_tuner_attach(adap); + } + + return ret; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties dibusb1_1_properties; +static struct dvb_usb_device_properties dibusb1_1_an2235_properties; +static struct dvb_usb_device_properties dibusb2_0b_properties; +static struct dvb_usb_device_properties artec_t1_usb2_properties; + +static int dibusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dibusb2_0b_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -EINVAL; +} + +/* do not change the order of the ID table */ +static struct usb_device_id dibusb_dib3000mb_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, +/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, +/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, +/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, +/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, +/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, +/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, +/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, +/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, +/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, +/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, +/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, +/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, +/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, +/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) }, +/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, +/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, +/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, +/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, +/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, +/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, +/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, +/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, + +/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ +/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, +/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, +/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, + +/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, + +/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, + +/* + * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices + * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that + * have been left on the device. If you don't have such a device but an Artec + * device that's supposed to work with this driver but is not detected by it, + * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. + */ + +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY +/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +#endif + + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); + +static struct dvb_usb_device_properties dibusb1_1_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_AN2135, + + .firmware = "dvb-usb-dibusb-5.0.0.11.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + + .power_ctrl = dibusb_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 9, + .devices = { + { "AVerMedia AverTV DVBT USB1.1", + { &dibusb_dib3000mb_table[0], NULL }, + { &dibusb_dib3000mb_table[1], NULL }, + }, + { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", + { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL}, + { &dibusb_dib3000mb_table[3], NULL }, + }, + { "DiBcom USB1.1 DVB-T reference design (MOD3000)", + { &dibusb_dib3000mb_table[5], NULL }, + { &dibusb_dib3000mb_table[6], NULL }, + }, + { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", + { &dibusb_dib3000mb_table[7], NULL }, + { &dibusb_dib3000mb_table[8], NULL }, + }, + { "Grandtec USB1.1 DVB-T", + { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL }, + { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL }, + }, + { "Unknown USB1.1 DVB-T device ???? please report the name to the author", + { &dibusb_dib3000mb_table[13], NULL }, + { &dibusb_dib3000mb_table[14], NULL }, + }, + { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device", + { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL}, + { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL}, + }, + { "Artec T1 USB1.1 TVBOX with AN2135", + { &dibusb_dib3000mb_table[19], NULL }, + { &dibusb_dib3000mb_table[20], NULL }, + }, + { "VideoWalker DVB-T USB", + { &dibusb_dib3000mb_table[25], NULL }, + { &dibusb_dib3000mb_table[26], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_AN2235, + + .firmware = "dvb-usb-dibusb-an2235-01.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + }, + }, + .power_ctrl = dibusb_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY + .num_device_descs = 2, +#else + .num_device_descs = 1, +#endif + .devices = { + { "Artec T1 USB1.1 TVBOX with AN2235", + { &dibusb_dib3000mb_table[21], NULL }, + { &dibusb_dib3000mb_table[22], NULL }, + }, +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY + { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", + { &dibusb_dib3000mb_table[30], NULL }, + { NULL }, + }, + { NULL }, +#endif + } +}; + +static struct dvb_usb_device_properties dibusb2_0b_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .firmware = "dvb-usb-adstech-usb2-02.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_thomson_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb2_0_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 2, + .devices = { + { "KWorld/ADSTech Instant DVB-T USB2.0", + { &dibusb_dib3000mb_table[23], NULL }, + { &dibusb_dib3000mb_table[24], NULL }, + }, + { "KWorld Xpert DVB-T USB2.0", + { &dibusb_dib3000mb_table[27], NULL }, + { NULL } + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties artec_t1_usb2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .firmware = "dvb-usb-dibusb-6.0.0.8.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb2_0_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Artec T1 USB2.0", + { &dibusb_dib3000mb_table[28], NULL }, + { &dibusb_dib3000mb_table[29], NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver dibusb_driver = { + .name = "dvb_usb_dibusb_mb", + .probe = dibusb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dibusb_dib3000mb_table, +}; + +module_usb_driver(dibusb_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c new file mode 100644 index 00000000000..9d1a59d09c5 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dibusb-mc.c @@ -0,0 +1,149 @@ +/* DVB USB compliant linux driver for mobile DVB-T USB devices based on + * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DiBcom, which has + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* USB Driver stuff */ +static struct dvb_usb_device_properties dibusb_mc_properties; + +static int dibusb_mc_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE, + NULL, adapter_nr); +} + +/* do not change the order of the ID table */ +static struct usb_device_id dibusb_dib3000mc_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, +/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) +/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, +/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, +/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, +/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, +/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, +/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, +/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, +/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, +/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, +/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, +/* 14 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) }, +/* 15 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); + +static struct dvb_usb_device_properties dibusb_mc_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-dibusb-6.0.0.8.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb2_0_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* FIXME */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 8, + .devices = { + { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", + { &dibusb_dib3000mc_table[0], NULL }, + { &dibusb_dib3000mc_table[1], NULL }, + }, + { "Artec T1 USB2.0 TVBOX (please check the warm ID)", + { &dibusb_dib3000mc_table[2], NULL }, + { &dibusb_dib3000mc_table[3], NULL }, + }, + { "LITE-ON USB2.0 DVB-T Tuner", + /* Also rebranded as Intuix S800, Toshiba */ + { &dibusb_dib3000mc_table[4], NULL }, + { &dibusb_dib3000mc_table[5], NULL }, + }, + { "MSI Digivox Mini SL", + { &dibusb_dib3000mc_table[6], NULL }, + { &dibusb_dib3000mc_table[7], NULL }, + }, + { "GRAND - USB2.0 DVB-T adapter", + { &dibusb_dib3000mc_table[8], NULL }, + { &dibusb_dib3000mc_table[9], NULL }, + }, + { "Artec T14 - USB2.0 DVB-T", + { &dibusb_dib3000mc_table[10], NULL }, + { &dibusb_dib3000mc_table[11], NULL }, + }, + { "Leadtek - USB2.0 Winfast DTV dongle", + { &dibusb_dib3000mc_table[12], NULL }, + { &dibusb_dib3000mc_table[13], NULL }, + }, + { "Humax/Coex DVB-T USB Stick 2.0 High Speed", + { &dibusb_dib3000mc_table[14], NULL }, + { &dibusb_dib3000mc_table[15], NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver dibusb_mc_driver = { + .name = "dvb_usb_dibusb_mc", + .probe = dibusb_mc_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dibusb_dib3000mc_table, +}; + +module_usb_driver(dibusb_mc_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dibusb.h b/drivers/media/usb/dvb-usb/dibusb.h new file mode 100644 index 00000000000..e47c321b3ff --- /dev/null +++ b/drivers/media/usb/dvb-usb/dibusb.h @@ -0,0 +1,131 @@ +/* Header file for all dibusb-based-receivers. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_DIBUSB_H_ +#define _DVB_USB_DIBUSB_H_ + +#ifndef DVB_USB_LOG_PREFIX + #define DVB_USB_LOG_PREFIX "dibusb" +#endif +#include "dvb-usb.h" + +#include "dib3000.h" +#include "dib3000mc.h" +#include "mt2060.h" + +/* + * protocol of all dibusb related devices + */ + +/* + * bulk msg to/from endpoint 0x01 + * + * general structure: + * request_byte parameter_bytes + */ + +#define DIBUSB_REQ_START_READ 0x00 +#define DIBUSB_REQ_START_DEMOD 0x01 + +/* + * i2c read + * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word + * bulk read: byte_buffer (length_word bytes) + */ +#define DIBUSB_REQ_I2C_READ 0x02 + +/* + * i2c write + * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes + */ +#define DIBUSB_REQ_I2C_WRITE 0x03 + +/* + * polling the value of the remote control + * bulk write: 0x04 + * bulk read: byte_buffer (5 bytes) + */ +#define DIBUSB_REQ_POLL_REMOTE 0x04 + +/* additional status values for Hauppauge Remote Control Protocol */ +#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01 +#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03 + +/* streaming mode: + * bulk write: 0x05 mode_byte + * + * mode_byte is mostly 0x00 + */ +#define DIBUSB_REQ_SET_STREAMING_MODE 0x05 + +/* interrupt the internal read loop, when blocking */ +#define DIBUSB_REQ_INTR_READ 0x06 + +/* io control + * 0x07 cmd_byte param_bytes + * + * param_bytes can be up to 32 bytes + * + * cmd_byte function parameter name + * 0x00 power mode + * 0x00 sleep + * 0x01 wakeup + * + * 0x01 enable streaming + * 0x02 disable streaming + * + * + */ +#define DIBUSB_REQ_SET_IOCTL 0x07 + +/* IOCTL commands */ + +/* change the power mode in firmware */ +#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00 +#define DIBUSB_IOCTL_POWER_SLEEP 0x00 +#define DIBUSB_IOCTL_POWER_WAKEUP 0x01 + +/* modify streaming of the FX2 */ +#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01 +#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02 + +struct dibusb_state { + struct dib_fe_xfer_ops ops; + int mt2060_present; + u8 tuner_addr; +}; + +struct dibusb_device_state { + /* for RC5 remote control */ + int old_toggle; + int last_repeat_count; +}; + +extern struct i2c_algorithm dibusb_i2c_algo; + +extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *); +extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *); + +extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int); +extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int); +extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int); +extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int); + +extern int dibusb_power_ctrl(struct dvb_usb_device *, int); +extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int); + +#define DEFAULT_RC_INTERVAL 150 +//#define DEFAULT_RC_INTERVAL 100000 + +extern struct rc_map_table rc_map_dibusb_table[]; +extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *); +extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *); + +#endif diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c new file mode 100644 index 00000000000..ff34419a4c8 --- /dev/null +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -0,0 +1,354 @@ +/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 + * receiver + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * + * partly based on the SDK published by Nebula Electronics + * + * 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 "digitv.h" + +#include "mt352.h" +#include "nxt6000.h" + +/* debug */ +static int dvb_usb_digitv_debug; +module_param_named(debug,dvb_usb_digitv_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) + +static int digitv_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 sndbuf[7],rcvbuf[7]; + memset(sndbuf,0,7); memset(rcvbuf,0,7); + + sndbuf[0] = cmd; + sndbuf[1] = vv; + sndbuf[2] = wo ? wlen : rlen; + + if (wo) { + memcpy(&sndbuf[3],wbuf,wlen); + dvb_usb_generic_write(d,sndbuf,7); + } else { + dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); + memcpy(rbuf,&rcvbuf[3],rlen); + } + return 0; +} + +/* I2C */ +static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, + msg[i+1].buf,msg[i+1].len) < 0) + break; + i++; + } else + if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], + &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 digitv_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm digitv_i2c_algo = { + .master_xfer = digitv_i2c_xfer, + .functionality = digitv_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int digitv_identify_state (struct usb_device *udev, struct + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; + return 0; +} + +static int digitv_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; + static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, + 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, + 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, + 0x75, 0x32 }; + int i; + + for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) + mt352_write(fe, &reset_buf[i], 2); + + msleep(1); + + for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) + mt352_write(fe, &init_buf[i], 2); + + return 0; +} + +static struct mt352_config digitv_mt352_config = { + .demod_init = digitv_mt352_demod_init, +}; + +static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + u8 b[5]; + + fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b)); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); +} + +static struct nxt6000_config digitv_nxt6000_config = { + .clock_inversion = 1, +}; + +static int digitv_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct digitv_state *st = adap->dev->priv; + + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) { + st->is_nxt6000 = 0; + return 0; + } + adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, + &digitv_nxt6000_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) { + st->is_nxt6000 = 1; + return 0; + } + return -EIO; +} + +static int digitv_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct digitv_state *st = adap->dev->priv; + + if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4)) + return -ENODEV; + + if (st->is_nxt6000) + adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + + return 0; +} + +static struct rc_map_table rc_map_digitv_table[] = { + { 0x5f55, KEY_0 }, + { 0x6f55, KEY_1 }, + { 0x9f55, KEY_2 }, + { 0xaf55, KEY_3 }, + { 0x5f56, KEY_4 }, + { 0x6f56, KEY_5 }, + { 0x9f56, KEY_6 }, + { 0xaf56, KEY_7 }, + { 0x5f59, KEY_8 }, + { 0x6f59, KEY_9 }, + { 0x9f59, KEY_TV }, + { 0xaf59, KEY_AUX }, + { 0x5f5a, KEY_DVD }, + { 0x6f5a, KEY_POWER }, + { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ + { 0xaf5a, KEY_AUDIO }, + { 0x5f65, KEY_INFO }, + { 0x6f65, KEY_F13 }, /* 16:9 */ + { 0x9f65, KEY_F14 }, /* 14:9 */ + { 0xaf65, KEY_EPG }, + { 0x5f66, KEY_EXIT }, + { 0x6f66, KEY_MENU }, + { 0x9f66, KEY_UP }, + { 0xaf66, KEY_DOWN }, + { 0x5f69, KEY_LEFT }, + { 0x6f69, KEY_RIGHT }, + { 0x9f69, KEY_ENTER }, + { 0xaf69, KEY_CHANNELUP }, + { 0x5f6a, KEY_CHANNELDOWN }, + { 0x6f6a, KEY_VOLUMEUP }, + { 0x9f6a, KEY_VOLUMEDOWN }, + { 0xaf6a, KEY_RED }, + { 0x5f95, KEY_GREEN }, + { 0x6f95, KEY_YELLOW }, + { 0x9f95, KEY_BLUE }, + { 0xaf95, KEY_SUBTITLE }, + { 0x5f96, KEY_F15 }, /* AD */ + { 0x6f96, KEY_TEXT }, + { 0x9f96, KEY_MUTE }, + { 0xaf96, KEY_REWIND }, + { 0x5f99, KEY_STOP }, + { 0x6f99, KEY_PLAY }, + { 0x9f99, KEY_FASTFORWARD }, + { 0xaf99, KEY_F16 }, /* chapter */ + { 0x5f9a, KEY_PAUSE }, + { 0x6f9a, KEY_PLAY }, + { 0x9f9a, KEY_RECORD }, + { 0xaf9a, KEY_F17 }, /* picture in picture */ + { 0x5fa5, KEY_KPPLUS }, /* zoom in */ + { 0x6fa5, KEY_KPMINUS }, /* zoom out */ + { 0x9fa5, KEY_F18 }, /* capture */ + { 0xafa5, KEY_F19 }, /* web */ + { 0x5fa6, KEY_EMAIL }, + { 0x6fa6, KEY_PHONE }, + { 0x9fa6, KEY_PC }, +}; + +static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + int i; + u8 key[5]; + u8 b[4] = { 0 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); + + /* Tell the device we've read the remote. Not sure how necessary + this is, but the Nebula SDK does it. */ + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + + /* if something is inside the buffer, simulate key press */ + if (key[1] != 0) + { + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] && + rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) { + *event = d->props.rc.legacy.rc_map_table[i].keycode; + *state = REMOTE_KEY_PRESSED; + return 0; + } + } + } + + if (key[0] != 0) + deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties digitv_properties; + +static int digitv_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d, + adapter_nr); + if (ret == 0) { + u8 b[4] = { 0 }; + + if (d != NULL) { /* do that only when the firmware is loaded */ + b[0] = 1; + digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); + + b[0] = 0; + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + } + } + return ret; +} + +static struct usb_device_id digitv_table [] = { + { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, digitv_table); + +static struct dvb_usb_device_properties digitv_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-digitv-02.fw", + + .size_of_priv = sizeof(struct digitv_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = digitv_frontend_attach, + .tuner_attach = digitv_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .identify_state = digitv_identify_state, + + .rc.legacy = { + .rc_interval = 1000, + .rc_map_table = rc_map_digitv_table, + .rc_map_size = ARRAY_SIZE(rc_map_digitv_table), + .rc_query = digitv_rc_query, + }, + + .i2c_algo = &digitv_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Nebula Electronics uDigiTV DVB-T USB2.0)", + { &digitv_table[0], NULL }, + { NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver digitv_driver = { + .name = "dvb_usb_digitv", + .probe = digitv_probe, + .disconnect = dvb_usb_device_exit, + .id_table = digitv_table, +}; + +module_usb_driver(digitv_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/digitv.h b/drivers/media/usb/dvb-usb/digitv.h new file mode 100644 index 00000000000..908c09f4966 --- /dev/null +++ b/drivers/media/usb/dvb-usb/digitv.h @@ -0,0 +1,66 @@ +#ifndef _DVB_USB_DIGITV_H_ +#define _DVB_USB_DIGITV_H_ + +#define DVB_USB_LOG_PREFIX "digitv" +#include "dvb-usb.h" + +struct digitv_state { + int is_nxt6000; +}; + +/* protocol (from usblogging and the SDK: + * + * Always 7 bytes bulk message(s) for controlling + * + * First byte describes the command. Reads are 2 consecutive transfer (as always). + * + * General structure: + * + * write or first message of a read: + * VV B0 B1 B2 B3 + * + * second message of a read + * VV R0 R1 R2 R3 + * + * whereas 0 < len <= 4 + * + * I2C address is stored somewhere inside the device. + * + * 0x01 read from EEPROM + * VV = offset; B* = 0; R* = value(s) + * + * 0x02 read register of the COFDM + * VV = register; B* = 0; R* = value(s) + * + * 0x05 write register of the COFDM + * VV = register; B* = value(s); + * + * 0x06 write to the tuner (only for NXT6000) + * VV = 0; B* = PLL data; len = 4; + * + * 0x03 read remote control + * VV = 0; B* = 0; len = 4; R* = key + * + * 0x07 write to the remote (don't know why one should this, resetting ?) + * VV = 0; B* = key; len = 4; + * + * 0x08 write remote type + * VV = 0; B[0] = 0x01, len = 4 + * + * 0x09 write device init + * TODO + */ +#define USB_READ_EEPROM 1 + +#define USB_READ_COFDM 2 +#define USB_WRITE_COFDM 5 + +#define USB_WRITE_TUNER 6 + +#define USB_READ_REMOTE 3 +#define USB_WRITE_REMOTE 7 +#define USB_WRITE_REMOTE_TYPE 8 + +#define USB_DEV_INIT 9 + +#endif diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c new file mode 100644 index 00000000000..3d81daa4917 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c @@ -0,0 +1,210 @@ +/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. + * + * Copyright (C) 2005 Patrick Boettcher + * + * 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 "dtt200u.h" + +struct dtt200u_fe_state { + struct dvb_usb_device *d; + + fe_status_t stat; + + struct dtv_frontend_properties fep; + struct dvb_frontend frontend; +}; + +static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 st = GET_TUNE_STATUS, b[3]; + + dvb_usb_generic_rw(state->d,&st,1,b,3,0); + + switch (b[0]) { + case 0x01: + *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + break; + case 0x00: /* pending */ + *stat = FE_TIMEDOUT; /* during set_frontend */ + break; + default: + case 0x02: /* failed */ + *stat = 0; + break; + } + return 0; +} + +static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_VIT_ERR_CNT,b[3]; + dvb_usb_generic_rw(state->d,&bw,1,b,3,0); + *ber = (b[0] << 16) | (b[1] << 8) | b[2]; + return 0; +} + +static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_RS_UNCOR_BLK_CNT,b[2]; + + dvb_usb_generic_rw(state->d,&bw,1,b,2,0); + *unc = (b[0] << 8) | b[1]; + return 0; +} + +static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_AGC, b; + dvb_usb_generic_rw(state->d,&bw,1,&b,1,0); + *strength = (b << 8) | b; + return 0; +} + +static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_SNR,br; + dvb_usb_generic_rw(state->d,&bw,1,&br,1,0); + *snr = ~((br << 8) | br); + return 0; +} + +static int dtt200u_fe_init(struct dvb_frontend* fe) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 b = SET_INIT; + return dvb_usb_generic_write(state->d,&b,1); +} + +static int dtt200u_fe_sleep(struct dvb_frontend* fe) +{ + return dtt200u_fe_init(fe); +} + +static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1500; + tune->step_size = 0; + tune->max_drift = 0; + return 0; +} + +static int dtt200u_fe_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct dtt200u_fe_state *state = fe->demodulator_priv; + int i; + fe_status_t st; + u16 freq = fep->frequency / 250000; + u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; + + switch (fep->bandwidth_hz) { + case 8000000: + bwbuf[1] = 8; + break; + case 7000000: + bwbuf[1] = 7; + break; + case 6000000: + bwbuf[1] = 6; + break; + default: + return -EINVAL; + } + + dvb_usb_generic_write(state->d,bwbuf,2); + + freqbuf[1] = freq & 0xff; + freqbuf[2] = (freq >> 8) & 0xff; + dvb_usb_generic_write(state->d,freqbuf,3); + + for (i = 0; i < 30; i++) { + msleep(20); + dtt200u_fe_read_status(fe, &st); + if (st & FE_TIMEDOUT) + continue; + } + + return 0; +} + +static int dtt200u_fe_get_frontend(struct dvb_frontend* fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct dtt200u_fe_state *state = fe->demodulator_priv; + memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties)); + return 0; +} + +static void dtt200u_fe_release(struct dvb_frontend* fe) +{ + struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops dtt200u_fe_ops; + +struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) +{ + struct dtt200u_fe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL); + if (state == NULL) + goto error; + + deb_info("attaching frontend dtt200u\n"); + + state->d = d; + + memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + return NULL; +} + +static struct dvb_frontend_ops dtt200u_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "WideView USB DVB-T", + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dtt200u_fe_release, + + .init = dtt200u_fe_init, + .sleep = dtt200u_fe_sleep, + + .set_frontend = dtt200u_fe_set_frontend, + .get_frontend = dtt200u_fe_get_frontend, + .get_tune_settings = dtt200u_fe_get_tune_settings, + + .read_status = dtt200u_fe_read_status, + .read_ber = dtt200u_fe_read_ber, + .read_signal_strength = dtt200u_fe_read_signal_strength, + .read_snr = dtt200u_fe_read_snr, + .read_ucblocks = dtt200u_fe_read_unc_blocks, +}; diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c new file mode 100644 index 00000000000..66f205c112b --- /dev/null +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -0,0 +1,368 @@ +/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Steve Chang from WideView for providing support for the WT-220U. + * + * 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 "dtt200u.h" + +/* debug */ +int dvb_usb_dtt200u_debug; +module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = SET_INIT; + + if (onoff) + dvb_usb_generic_write(d,&b,2); + + return 0; +} + +static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 b_streaming[2] = { SET_STREAMING, onoff }; + u8 b_rst_pid = RESET_PID_FILTER; + + dvb_usb_generic_write(adap->dev, b_streaming, 2); + + if (onoff == 0) + dvb_usb_generic_write(adap->dev, &b_rst_pid, 1); + return 0; +} + +static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + u8 b_pid[4]; + pid = onoff ? pid : 0; + + b_pid[0] = SET_PID_FILTER; + b_pid[1] = index; + b_pid[2] = pid & 0xff; + b_pid[3] = (pid >> 8) & 0x1f; + + return dvb_usb_generic_write(adap->dev, b_pid, 4); +} + +/* remote control */ +/* key list for the tiny remote control (Yakumo, don't know about the others) */ +static struct rc_map_table rc_map_dtt200u_table[] = { + { 0x8001, KEY_MUTE }, + { 0x8002, KEY_CHANNELDOWN }, + { 0x8003, KEY_VOLUMEDOWN }, + { 0x8004, KEY_1 }, + { 0x8005, KEY_2 }, + { 0x8006, KEY_3 }, + { 0x8007, KEY_4 }, + { 0x8008, KEY_5 }, + { 0x8009, KEY_6 }, + { 0x800a, KEY_7 }, + { 0x800c, KEY_ZOOM }, + { 0x800d, KEY_0 }, + { 0x800e, KEY_SELECT }, + { 0x8012, KEY_POWER }, + { 0x801a, KEY_CHANNELUP }, + { 0x801b, KEY_8 }, + { 0x801e, KEY_VOLUMEUP }, + { 0x801f, KEY_9 }, +}; + +static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd = GET_RC_CODE; + dvb_usb_generic_rw(d,&cmd,1,key,5,0); + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} + +static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev); + return 0; +} + +static struct dvb_usb_device_properties dtt200u_properties; +static struct dvb_usb_device_properties wt220u_fc_properties; +static struct dvb_usb_device_properties wt220u_properties; +static struct dvb_usb_device_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties wt220u_miglia_properties; + +static int dtt200u_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &dtt200u_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_fc_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_miglia_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -ENODEV; +} + +static struct usb_device_id dtt200u_usb_table [] = { + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, + { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); + +static struct dvb_usb_device_properties dtt200u_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-dtt200u-01.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", + .cold_ids = { &dtt200u_usb_table[0], NULL }, + .warm_ids = { &dtt200u_usb_table[1], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-02.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", + .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, + .warm_ids = { &dtt200u_usb_table[3], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_fc_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-fc03.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", + .cold_ids = { &dtt200u_usb_table[6], NULL }, + .warm_ids = { &dtt200u_usb_table[7], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_zl0353_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-zl0353-01.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (based on ZL353)", + .cold_ids = { &dtt200u_usb_table[4], NULL }, + .warm_ids = { &dtt200u_usb_table[5], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_miglia_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-miglia-01.fw", + + .num_adapters = 1, + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Miglia)", + .cold_ids = { &dtt200u_usb_table[9], NULL }, + /* This device turns into WT220U_ZL0353_WARM when fw + has been uploaded */ + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver dtt200u_usb_driver = { + .name = "dvb_usb_dtt200u", + .probe = dtt200u_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dtt200u_usb_table, +}; + +module_usb_driver(dtt200u_usb_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dtt200u.h b/drivers/media/usb/dvb-usb/dtt200u.h new file mode 100644 index 00000000000..005b0a7df35 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dtt200u.h @@ -0,0 +1,57 @@ +/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_DTT200U_H_ +#define _DVB_USB_DTT200U_H_ + +#define DVB_USB_LOG_PREFIX "dtt200u" + +#include "dvb-usb.h" + +extern int dvb_usb_dtt200u_debug; +#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args) + +/* guessed protocol description (reverse engineered): + * read + * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 + * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal) + */ + +#define GET_SPEED 0x00 +#define GET_TUNE_STATUS 0x81 +#define GET_RC_CODE 0x84 +#define GET_CONFIGURATION 0x88 +#define GET_AGC 0x89 +#define GET_SNR 0x8a +#define GET_VIT_ERR_CNT 0x8c +#define GET_RS_ERR_CNT 0x8d +#define GET_RS_UNCOR_BLK_CNT 0x8e + +/* write + * 01 - init + * 02 - frequency (divided by 250000) + * 03 - bandwidth + * 04 - pid table (index pid(7:0) pid(12:8)) + * 05 - reset the pid table + * 08 - transfer switch + */ + +#define SET_INIT 0x01 +#define SET_RF_FREQ 0x02 +#define SET_BANDWIDTH 0x03 +#define SET_PID_FILTER 0x04 +#define RESET_PID_FILTER 0x05 +#define SET_STREAMING 0x08 + +extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); + +#endif diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c new file mode 100644 index 00000000000..3d11df41cac --- /dev/null +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -0,0 +1,224 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * Inspired by gl861.c and au6610.c drivers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "dtv5100.h" +#include "zl10353.h" +#include "qt1010.h" + +/* debug */ +static int dvb_usb_dtv5100_debug; +module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 request; + u8 type; + u16 value; + u16 index; + + switch (wlen) { + case 1: + /* write { reg }, read { value } */ + request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : + DTV5100_TUNER_READ); + type = USB_TYPE_VENDOR | USB_DIR_IN; + value = 0; + break; + case 2: + /* write { reg, value } */ + request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : + DTV5100_TUNER_WRITE); + type = USB_TYPE_VENDOR | USB_DIR_OUT; + value = wbuf[1]; + break; + default: + warn("wlen = %x, aborting.", wlen); + return -EINVAL; + } + index = (addr << 8) + wbuf[0]; + + msleep(1); /* avoid I2C errors */ + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, + type, value, index, rbuf, rlen, + DTV5100_USB_TIMEOUT); +} + +/* I2C */ +static int dtv5100_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 (dtv5100_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 (dtv5100_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 dtv5100_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dtv5100_i2c_algo = { + .master_xfer = dtv5100_i2c_xfer, + .functionality = dtv5100_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config dtv5100_zl10353_config = { + .demod_address = DTV5100_DEMOD_ADDR, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe_adap[0].fe == NULL) + return -EIO; + + /* disable i2c gate, or it won't work... is this safe? */ + adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; + + return 0; +} + +static struct qt1010_config dtv5100_qt1010_config = { + .i2c_address = DTV5100_TUNER_ADDR +}; + +static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe_adap[0].fe, &adap->dev->i2c_adap, + &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties dtv5100_properties; + +static int dtv5100_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int i, ret; + struct usb_device *udev = interface_to_usbdev(intf); + + /* initialize non qt1010/zl10353 part? */ + for (i = 0; dtv5100_init[i].request; i++) { + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + dtv5100_init[i].request, + USB_TYPE_VENDOR | USB_DIR_OUT, + dtv5100_init[i].value, + dtv5100_init[i].index, NULL, 0, + DTV5100_USB_TIMEOUT); + if (ret) + return ret; + } + + ret = dvb_usb_device_init(intf, &dtv5100_properties, + THIS_MODULE, NULL, adapter_nr); + if (ret) + return ret; + + return 0; +} + +static struct usb_device_id dtv5100_table[] = { + { USB_DEVICE(0x06be, 0xa232) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, dtv5100_table); + +static struct dvb_usb_device_properties dtv5100_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + .frontend_attach = dtv5100_frontend_attach, + .tuner_attach = dtv5100_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } }, + + .i2c_algo = &dtv5100_i2c_algo, + + .num_device_descs = 1, + .devices = { + { + .name = "AME DTV-5100 USB2.0 DVB-T", + .cold_ids = { NULL }, + .warm_ids = { &dtv5100_table[0], NULL }, + }, + } +}; + +static struct usb_driver dtv5100_driver = { + .name = "dvb_usb_dtv5100", + .probe = dtv5100_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dtv5100_table, +}; + +module_usb_driver(dtv5100_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dtv5100.h b/drivers/media/usb/dvb-usb/dtv5100.h new file mode 100644 index 00000000000..93e96e04a82 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dtv5100.h @@ -0,0 +1,51 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _DVB_USB_DTV5100_H_ +#define _DVB_USB_DTV5100_H_ + +#define DVB_USB_LOG_PREFIX "dtv5100" +#include "dvb-usb.h" + +#define DTV5100_USB_TIMEOUT 500 + +#define DTV5100_DEMOD_ADDR 0x00 +#define DTV5100_DEMOD_WRITE 0xc0 +#define DTV5100_DEMOD_READ 0xc1 + +#define DTV5100_TUNER_ADDR 0xc4 +#define DTV5100_TUNER_WRITE 0xc7 +#define DTV5100_TUNER_READ 0xc8 + +#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" +#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" + +static struct { + u8 request; + u8 value; + u16 index; +} dtv5100_init[] = { + { 0x000000c5, 0x00000000, 0x00000001 }, + { 0x000000c5, 0x00000001, 0x00000001 }, + { } /* Terminating entry */ +}; + +#endif diff --git a/drivers/media/usb/dvb-usb/dvb-usb-common.h b/drivers/media/usb/dvb-usb/dvb-usb-common.h new file mode 100644 index 00000000000..6b7b2a89242 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-common.h @@ -0,0 +1,52 @@ +/* dvb-usb-common.h is part of the DVB USB library. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * a header file containing prototypes and types for internal use of the dvb-usb-lib + */ +#ifndef _DVB_USB_COMMON_H_ +#define _DVB_USB_COMMON_H_ + +#define DVB_USB_LOG_PREFIX "dvb-usb" +#include "dvb-usb.h" + +extern int dvb_usb_debug; +extern int dvb_usb_disable_rc_polling; + +#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) +#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) +#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) +#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) +#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) +#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) +#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) +#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) +#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) + +/* commonly used methods */ +extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); + +extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); + +extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); +extern int usb_urb_exit(struct usb_data_stream *stream); +extern int usb_urb_submit(struct usb_data_stream *stream); +extern int usb_urb_kill(struct usb_data_stream *stream); + +extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); + +extern int dvb_usb_i2c_init(struct dvb_usb_device *); +extern int dvb_usb_i2c_exit(struct dvb_usb_device *); + +extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, + short *adapter_nums); +extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); + +extern int dvb_usb_remote_init(struct dvb_usb_device *); +extern int dvb_usb_remote_exit(struct dvb_usb_device *); + +#endif diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c new file mode 100644 index 00000000000..719413b15f2 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c @@ -0,0 +1,288 @@ +/* dvb-usb-dvb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing and handling the + * linux-dvb API. + */ +#include "dvb-usb-common.h" + +/* does the complete input transfer handling */ +static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + int newfeedcount, ret; + + if (adap == NULL) + return -ENODEV; + + if ((adap->active_fe < 0) || + (adap->active_fe >= adap->num_frontends_initialized)) { + return -EINVAL; + } + + newfeedcount = adap->feedcount + (onoff ? 1 : -1); + + /* stop feed before setting a new pid if there will be no pid anymore */ + if (newfeedcount == 0) { + deb_ts("stop feeding\n"); + usb_urb_kill(&adap->fe_adap[adap->active_fe].stream); + + if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0); + if (ret < 0) { + err("error while stopping stream."); + return ret; + } + } + } + + adap->feedcount = newfeedcount; + + /* activate the pid on the device specific pid_filter */ + deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n", + adap->fe_adap[adap->active_fe].pid_filtering ? + "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, + dvbdmxfeed->index, onoff ? "on" : "off"); + if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->fe_adap[adap->active_fe].pid_filtering && + adap->props.fe[adap->active_fe].pid_filter != NULL) + adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); + + /* start the feed if this was the first feed and there is still a feed + * for reception. + */ + if (adap->feedcount == onoff && adap->feedcount > 0) { + deb_ts("submitting all URBs\n"); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); + + deb_ts("controlling pid parser\n"); + if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props.fe[adap->active_fe].caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap, + adap->fe_adap[adap->active_fe].pid_filtering); + if (ret < 0) { + err("could not handle pid_parser"); + return ret; + } + } + deb_ts("start feeding\n"); + if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1); + if (ret < 0) { + err("error while enabling fifo."); + return ret; + } + } + + } + return 0; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed,1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed,0); +} + +int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) +{ + int i; + int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, + adap->dev->owner, &adap->dev->udev->dev, + adapter_nums); + + if (ret < 0) { + deb_info("dvb_register_adapter failed: error %d", ret); + goto err; + } + adap->dvb_adap.priv = adap; + + if (adap->dev->props.read_mac_address) { + if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) + info("MAC address: %pM",adap->dvb_adap.proposed_mac); + else + err("MAC address reading failed."); + } + + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + + adap->demux.filternum = 0; + for (i = 0; i < adap->props.num_frontends; i++) { + if (adap->demux.filternum < adap->fe_adap[i].max_feed_count) + adap->demux.filternum = adap->fe_adap[i].max_feed_count; + } + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + if ((ret = dvb_dmx_init(&adap->demux)) < 0) { + err("dvb_dmx_init failed: error %d",ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { + err("dvb_dmxdev_init failed: error %d",ret); + goto err_dmx_dev; + } + + if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, + &adap->demux.dmx)) < 0) { + err("dvb_net_init failed: error %d",ret); + goto err_net_init; + } + + adap->state |= DVB_USB_ADAP_STATE_DVB; + return 0; + +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + return ret; +} + +int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + if (adap->state & DVB_USB_ADAP_STATE_DVB) { + deb_info("unregistering DVB part\n"); + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + adap->state &= ~DVB_USB_ADAP_STATE_DVB; + } + return 0; +} + +static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + int ret = (adap->props.frontend_ctrl) ? + adap->props.frontend_ctrl(fe, onoff) : 0; + + if (ret < 0) { + err("frontend_ctrl request failed"); + return ret; + } + if (onoff) + adap->active_fe = fe->id; + + return 0; +} + +static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + dvb_usb_device_power_ctrl(adap->dev, 1); + + dvb_usb_set_active_fe(fe, 1); + + if (adap->fe_adap[fe->id].fe_init) + adap->fe_adap[fe->id].fe_init(fe); + + return 0; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + if (adap->fe_adap[fe->id].fe_sleep) + adap->fe_adap[fe->id].fe_sleep(fe); + + dvb_usb_set_active_fe(fe, 0); + + return dvb_usb_device_power_ctrl(adap->dev, 0); +} + +int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i; + + /* register all given adapter frontends */ + for (i = 0; i < adap->props.num_frontends; i++) { + + if (adap->props.fe[i].frontend_attach == NULL) { + err("strange: '%s' #%d,%d " + "doesn't want to attach a frontend.", + adap->dev->desc->name, adap->id, i); + + return 0; + } + + ret = adap->props.fe[i].frontend_attach(adap); + if (ret || adap->fe_adap[i].fe == NULL) { + /* only print error when there is no FE at all */ + if (i == 0) + err("no frontend was attached by '%s'", + adap->dev->desc->name); + + return 0; + } + + adap->fe_adap[i].fe->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init; + adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup; + adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; + adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) { + err("Frontend %d registration failed.", i); + dvb_frontend_detach(adap->fe_adap[i].fe); + adap->fe_adap[i].fe = NULL; + /* In error case, do not try register more FEs, + * still leaving already registered FEs alive. */ + if (i == 0) + return -ENODEV; + else + return 0; + } + + /* only attach the tuner if the demod is there */ + if (adap->props.fe[i].tuner_attach != NULL) + adap->props.fe[i].tuner_attach(adap); + + adap->num_frontends_initialized++; + } + + return 0; +} + +int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i = adap->num_frontends_initialized - 1; + + /* unregister all given adapter frontends */ + for (; i >= 0; i--) { + if (adap->fe_adap[i].fe != NULL) { + dvb_unregister_frontend(adap->fe_adap[i].fe); + dvb_frontend_detach(adap->fe_adap[i].fe); + } + } + adap->num_frontends_initialized = 0; + + return 0; +} diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c new file mode 100644 index 00000000000..733a7ff7b20 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c @@ -0,0 +1,146 @@ +/* dvb-usb-firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. + * + * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem. + */ +#include "dvb-usb-common.h" + +#include + +struct usb_cypress_controller { + int id; + const char *name; /* name of the usb controller */ + u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ +}; + +static struct usb_cypress_controller cypress[] = { + { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) +{ + struct hexline hx; + u8 reset; + int ret,pos=0; + + /* stop the CPU */ + reset = 1; + if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + err("could not stop the USB controller CPU."); + + while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); + ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + + if (ret != hx.len) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", + ret,hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ + reset = 0; + if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + } else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(usb_cypress_load_firmware); + +int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) +{ + int ret; + const struct firmware *fw = NULL; + + if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + props->firmware,ret); + return ret; + } + + info("downloading firmware from file '%s'",props->firmware); + + switch (props->usb_ctrl) { + case CYPRESS_AN2135: + case CYPRESS_AN2235: + case CYPRESS_FX2: + ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl); + break; + case DEVICE_SPECIFIC: + if (props->download_firmware) + ret = props->download_firmware(udev,fw); + else { + err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + release_firmware(fw); + return ret; +} + +int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + if (*pos >= fw->size) + return 0; + + memset(hx,0,sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); +/* hx->len -= 2; + data_offs += 2; */ + } + memcpy(hx->data,&b[data_offs],hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usb_get_hexline); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c new file mode 100644 index 00000000000..88e4a62abc4 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c @@ -0,0 +1,43 @@ +/* dvb-usb-i2c.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for (de-)initializing an I2C adapter. + */ +#include "dvb-usb-common.h" + +int dvb_usb_i2c_init(struct dvb_usb_device *d) +{ + int ret = 0; + + if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER)) + return 0; + + if (d->props.i2c_algo == NULL) { + err("no i2c algorithm specified"); + return -EINVAL; + } + + strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props.i2c_algo; + d->i2c_adap.algo_data = NULL; + d->i2c_adap.dev.parent = &d->udev->dev; + + i2c_set_adapdata(&d->i2c_adap, d); + + if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) + err("could not add i2c adapter"); + + d->state |= DVB_USB_STATE_I2C; + + return ret; +} + +int dvb_usb_i2c_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_I2C) + i2c_del_adapter(&d->i2c_adap); + d->state &= ~DVB_USB_STATE_I2C; + return 0; +} diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c new file mode 100644 index 00000000000..169196ec2d4 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -0,0 +1,304 @@ +/* + * DVB USB library - provides a generic interface for a DVB USB device driver. + * + * dvb-usb-init.c + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dvb-usb-common.h" + +/* debug */ +int dvb_usb_debug; +module_param_named(debug, dvb_usb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); + +int dvb_usb_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); + +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); + +static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) +{ + struct dvb_usb_adapter *adap; + int ret, n, o; + + for (n = 0; n < d->props.num_adapters; n++) { + adap = &d->adapter[n]; + adap->dev = d; + adap->id = n; + + memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); + + for (o = 0; o < adap->props.num_frontends; o++) { + struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o]; + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); + return -ENODEV; + } + + if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = props->pid_filter_count; + } else { + info("will pass the complete MPEG2 transport stream to the software demuxer."); + adap->fe_adap[o].pid_filtering = 0; + adap->fe_adap[o].max_feed_count = 255; + } + + if (!adap->fe_adap[o].pid_filtering && + dvb_usb_force_pid_filter_usage && + props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + info("pid filter enabled by module option."); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = props->pid_filter_count; + } + + if (props->size_of_priv > 0) { + adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); + if (adap->fe_adap[o].priv == NULL) { + err("no memory for priv for adapter %d fe %d.", n, o); + return -ENOMEM; + } + } + } + + if (adap->props.size_of_priv > 0) { + adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); + if (adap->priv == NULL) { + err("no memory for priv for adapter %d.", n); + return -ENOMEM; + } + } + + if ((ret = dvb_usb_adapter_stream_init(adap)) || + (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || + (ret = dvb_usb_adapter_frontend_init(adap))) { + return ret; + } + + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe_adap[1].fe) + adap->dvb_adap.mfe_shared = 1; + + d->num_adapters_initialized++; + d->state |= DVB_USB_STATE_DVB; + } + + /* + * when reloading the driver w/o replugging the device + * sometimes a timeout occures, this helps + */ + if (d->props.generic_bulk_ctrl_endpoint != 0) { + usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + } + + return 0; +} + +static int dvb_usb_adapter_exit(struct dvb_usb_device *d) +{ + int n; + + for (n = 0; n < d->num_adapters_initialized; n++) { + dvb_usb_adapter_frontend_exit(&d->adapter[n]); + dvb_usb_adapter_dvb_exit(&d->adapter[n]); + dvb_usb_adapter_stream_exit(&d->adapter[n]); + kfree(d->adapter[n].priv); + } + d->num_adapters_initialized = 0; + d->state &= ~DVB_USB_STATE_DVB; + return 0; +} + + +/* general initialization functions */ +static int dvb_usb_exit(struct dvb_usb_device *d) +{ + deb_info("state before exiting everything: %x\n", d->state); + dvb_usb_remote_exit(d); + dvb_usb_adapter_exit(d); + dvb_usb_i2c_exit(d); + deb_info("state should be zero now: %x\n", d->state); + d->state = DVB_USB_STATE_INIT; + kfree(d->priv); + kfree(d); + return 0; +} + +static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) +{ + int ret = 0; + + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + + d->state = DVB_USB_STATE_INIT; + + if (d->props.size_of_priv > 0) { + d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + return -ENOMEM; + } + } + + /* check the capabilities and set appropriate variables */ + dvb_usb_device_power_ctrl(d, 1); + + if ((ret = dvb_usb_i2c_init(d)) || + (ret = dvb_usb_adapter_init(d, adapter_nums))) { + dvb_usb_exit(d); + return ret; + } + + if ((ret = dvb_usb_remote_init(d))) + err("could not initialize remote control."); + + dvb_usb_device_power_ctrl(d, 0); + + return 0; +} + +/* determine the name and the state of the just found USB device */ +static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) +{ + int i, j; + struct dvb_usb_device_description *desc = NULL; + + *cold = -1; + + for (i = 0; i < props->num_device_descs; i++) { + + for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { + deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); + if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + *cold = 1; + desc = &props->devices[i]; + break; + } + } + + if (desc != NULL) + break; + + for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { + deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); + if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + *cold = 0; + desc = &props->devices[i]; + break; + } + } + } + + if (desc != NULL && props->identify_state != NULL) + props->identify_state(udev, props, &desc, cold); + + return desc; +} + +int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ + deb_info("power control: %d\n", onoff); + if (d->props.power_ctrl) + return d->props.power_ctrl(d, onoff); + } + return 0; +} + +/* + * USB + */ +int dvb_usb_device_init(struct usb_interface *intf, + struct dvb_usb_device_properties *props, + struct module *owner, struct dvb_usb_device **du, + short *adapter_nums) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct dvb_usb_device *d = NULL; + struct dvb_usb_device_description *desc = NULL; + + int ret = -ENOMEM, cold = 0; + + if (du != NULL) + *du = NULL; + + if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { + deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); + return -ENODEV; + } + + if (cold) { + info("found a '%s' in cold state, will try to load a firmware", desc->name); + ret = dvb_usb_download_firmware(udev, props); + if (!props->no_reconnect || ret != 0) + return ret; + } + + info("found a '%s' in warm state.", desc->name); + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (d == NULL) { + err("no memory for 'struct dvb_usb_device'"); + return -ENOMEM; + } + + d->udev = udev; + memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + d->desc = desc; + d->owner = owner; + + usb_set_intfdata(intf, d); + + if (du != NULL) + *du = d; + + ret = dvb_usb_init(d, adapter_nums); + + if (ret == 0) + info("%s successfully initialized and connected.", desc->name); + else + info("%s error while loading driver (%d)", desc->name, ret); + return ret; +} +EXPORT_SYMBOL(dvb_usb_device_init); + +void dvb_usb_device_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + const char *name = "generic DVB-USB module"; + + usb_set_intfdata(intf, NULL); + if (d != NULL && d->desc != NULL) { + name = d->desc->name; + dvb_usb_exit(d); + } + info("%s successfully deinitialized and disconnected.", name); + +} +EXPORT_SYMBOL(dvb_usb_device_exit); + +MODULE_VERSION("1.0"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c new file mode 100644 index 00000000000..41bacff2496 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c @@ -0,0 +1,391 @@ +/* dvb-usb-remote.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing the input-device and for handling remote-control-queries. + */ +#include "dvb-usb-common.h" +#include + +static unsigned int +legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, + struct rc_map_table *keymap, + unsigned int keymap_size) +{ + unsigned int index; + unsigned int scancode; + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) { + index = ke->index; + } else { + if (input_scancode_to_scalar(ke, &scancode)) + return keymap_size; + + /* See if we can match the raw key code. */ + for (index = 0; index < keymap_size; index++) + if (keymap[index].scancode == scancode) + break; + + /* See if there is an unused hole in the map */ + if (index >= keymap_size) { + for (index = 0; index < keymap_size; index++) { + if (keymap[index].keycode == KEY_RESERVED || + keymap[index].keycode == KEY_UNKNOWN) { + break; + } + } + } + } + + return index; +} + +static int legacy_dvb_usb_getkeycode(struct input_dev *dev, + struct input_keymap_entry *ke) +{ + struct dvb_usb_device *d = input_get_drvdata(dev); + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + unsigned int keymap_size = d->props.rc.legacy.rc_map_size; + unsigned int index; + + index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); + if (index >= keymap_size) + return -EINVAL; + + ke->keycode = keymap[index].keycode; + if (ke->keycode == KEY_UNKNOWN) + ke->keycode = KEY_RESERVED; + ke->len = sizeof(keymap[index].scancode); + memcpy(&ke->scancode, &keymap[index].scancode, ke->len); + ke->index = index; + + return 0; +} + +static int legacy_dvb_usb_setkeycode(struct input_dev *dev, + const struct input_keymap_entry *ke, + unsigned int *old_keycode) +{ + struct dvb_usb_device *d = input_get_drvdata(dev); + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + unsigned int keymap_size = d->props.rc.legacy.rc_map_size; + unsigned int index; + + index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); + /* + * FIXME: Currently, it is not possible to increase the size of + * scancode table. For it to happen, one possibility + * would be to allocate a table with key_map_size + 1, + * copying data, appending the new key on it, and freeing + * the old one - or maybe just allocating some spare space + */ + if (index >= keymap_size) + return -EINVAL; + + *old_keycode = keymap[index].keycode; + keymap->keycode = ke->keycode; + __set_bit(ke->keycode, dev->keybit); + + if (*old_keycode != KEY_RESERVED) { + __clear_bit(*old_keycode, dev->keybit); + for (index = 0; index < keymap_size; index++) { + if (keymap[index].keycode == *old_keycode) { + __set_bit(*old_keycode, dev->keybit); + break; + } + } + } + + return 0; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void legacy_dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); + u32 event; + int state; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the driver was running */ + if (dvb_usb_disable_rc_polling) + return; + + if (d->props.rc.legacy.rc_query(d,&event,&state)) { + err("error while querying for an remote control event."); + goto schedule; + } + + + switch (state) { + case REMOTE_NO_KEY_PRESSED: + break; + case REMOTE_KEY_PRESSED: + deb_rc("key pressed\n"); + d->last_event = event; + case REMOTE_KEY_REPEAT: + deb_rc("key repeated\n"); + input_event(d->input_dev, EV_KEY, event, 1); + input_sync(d->input_dev); + input_event(d->input_dev, EV_KEY, d->last_event, 0); + input_sync(d->input_dev); + break; + default: + break; + } + +/* improved repeat handling ??? + switch (state) { + case REMOTE_NO_KEY_PRESSED: + deb_rc("NO KEY PRESSED\n"); + if (d->last_state != REMOTE_NO_KEY_PRESSED) { + deb_rc("releasing event %d\n",d->last_event); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); + } + d->last_state = REMOTE_NO_KEY_PRESSED; + d->last_event = 0; + break; + case REMOTE_KEY_PRESSED: + deb_rc("KEY PRESSED\n"); + deb_rc("pressing event %d\n",event); + + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_sync(d->rc_input_dev); + + d->last_event = event; + d->last_state = REMOTE_KEY_PRESSED; + break; + case REMOTE_KEY_REPEAT: + deb_rc("KEY_REPEAT\n"); + if (d->last_state != REMOTE_NO_KEY_PRESSED) { + deb_rc("repeating event %d\n",d->last_event); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); + input_sync(d->rc_input_dev); + d->last_state = REMOTE_KEY_REPEAT; + } + default: + break; + } +*/ + +schedule: + schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); +} + +static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int i, err, rc_interval; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->name = "IR-receiver inside an USB DVB receiver"; + input_dev->phys = d->rc_phys; + usb_to_input_id(d->udev, &input_dev->id); + input_dev->dev.parent = &d->udev->dev; + d->input_dev = input_dev; + d->rc_dev = NULL; + + input_dev->getkeycode = legacy_dvb_usb_getkeycode; + input_dev->setkeycode = legacy_dvb_usb_setkeycode; + + /* set the bits for the keys */ + deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + deb_rc("setting bit for event %d item %d\n", + d->props.rc.legacy.rc_map_table[i].keycode, i); + set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); + } + + /* setting these two values to non-zero, we have to manage key repeats */ + input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; + input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; + + input_set_drvdata(input_dev, d); + + err = input_register_device(input_dev); + if (err) + input_free_device(input_dev); + + rc_interval = d->props.rc.legacy.rc_interval; + + INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); + + info("schedule remote query interval to %d msecs.", rc_interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(rc_interval)); + + d->state |= DVB_USB_STATE_REMOTE; + + return err; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); + int err; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init + */ + if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) + return; + + err = d->props.rc.core.rc_query(d); + if (err) + err("error %d while querying for an remote control event.", err); + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->props.rc.core.rc_interval)); +} + +static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int err, rc_interval; + struct rc_dev *dev; + + dev = rc_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->driver_name = d->props.rc.core.module_name; + dev->map_name = d->props.rc.core.rc_codes; + dev->change_protocol = d->props.rc.core.change_protocol; + dev->allowed_protos = d->props.rc.core.allowed_protos; + dev->driver_type = d->props.rc.core.driver_type; + usb_to_input_id(d->udev, &dev->input_id); + dev->input_name = "IR-receiver inside an USB DVB receiver"; + dev->input_phys = d->rc_phys; + dev->dev.parent = &d->udev->dev; + dev->priv = d; + + err = rc_register_device(dev); + if (err < 0) { + rc_free_device(dev); + return err; + } + + d->input_dev = NULL; + d->rc_dev = dev; + + if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) + return 0; + + /* Polling mode - initialize a work queue for handling it */ + INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); + + rc_interval = d->props.rc.core.rc_interval; + + info("schedule remote query interval to %d msecs.", rc_interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(rc_interval)); + + return 0; +} + +int dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int err; + + if (dvb_usb_disable_rc_polling) + return 0; + + if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) + d->props.rc.mode = DVB_RC_LEGACY; + else if (d->props.rc.core.rc_codes) + d->props.rc.mode = DVB_RC_CORE; + else + return 0; + + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + + /* Start the remote-control polling. */ + if (d->props.rc.legacy.rc_interval < 40) + d->props.rc.legacy.rc_interval = 100; /* default */ + + if (d->props.rc.mode == DVB_RC_LEGACY) + err = legacy_dvb_usb_remote_init(d); + else + err = rc_core_dvb_usb_remote_init(d); + if (err) + return err; + + d->state |= DVB_USB_STATE_REMOTE; + + return 0; +} + +int dvb_usb_remote_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); + if (d->props.rc.mode == DVB_RC_LEGACY) + input_unregister_device(d->input_dev); + else + rc_unregister_device(d->rc_dev); + } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; +} + +#define DVB_USB_RC_NEC_EMPTY 0x00 +#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 +#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 +int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, + u8 keybuf[5], u32 *event, int *state) +{ + int i; + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + switch (keybuf[0]) { + case DVB_USB_RC_NEC_EMPTY: + break; + case DVB_USB_RC_NEC_KEY_PRESSED: + if ((u8) ~keybuf[1] != keybuf[2] || + (u8) ~keybuf[3] != keybuf[4]) { + deb_err("remote control checksum failed.\n"); + break; + } + /* See if we can match the raw key code. */ + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) + if (rc5_custom(&keymap[i]) == keybuf[1] && + rc5_data(&keymap[i]) == keybuf[3]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + return 0; + } + deb_err("key mapping failed - no appropriate key found in keymapping\n"); + break; + case DVB_USB_RC_NEC_KEY_REPEATED: + *state = REMOTE_KEY_REPEAT; + break; + default: + deb_err("unknown type of remote status: %d\n",keybuf[0]); + break; + } + return 0; +} +EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-urb.c b/drivers/media/usb/dvb-usb/dvb-usb-urb.c new file mode 100644 index 00000000000..5c8f651344f --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb-urb.c @@ -0,0 +1,121 @@ +/* dvb-usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * USB and URB stuff. + */ +#include "dvb-usb-common.h" + +int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen, int delay_ms) +{ + int actlen,ret = -ENOMEM; + + if (!d || wbuf == NULL || wlen == 0) + return -EINVAL; + + if (d->props.generic_bulk_ctrl_endpoint == 0) { + err("endpoint for generic control not specified."); + return -EINVAL; + } + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + deb_xfer(">>> "); + debug_dump(wbuf,wlen,deb_xfer); + + ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, + 2000); + + if (ret) + err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); + else + ret = actlen != wlen ? -1 : 0; + + /* an answer is expected, and no error before */ + if (!ret && rbuf && rlen) { + if (delay_ms) + msleep(delay_ms); + + ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint_response ? + d->props.generic_bulk_ctrl_endpoint_response : + d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, + 2000); + + if (ret) + err("recv bulk message failed: %d",ret); + else { + deb_xfer("<<< "); + debug_dump(rbuf,actlen,deb_xfer); + } + } + + mutex_unlock(&d->usb_mutex); + return ret; +} +EXPORT_SYMBOL(dvb_usb_generic_rw); + +int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) +{ + return dvb_usb_generic_rw(d,buf,len,NULL,0,0); +} +EXPORT_SYMBOL(dvb_usb_generic_write); + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_204(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, + u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_raw(&adap->demux, buffer, length); +} + +int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + int i, ret = 0; + for (i = 0; i < adap->props.num_frontends; i++) { + + adap->fe_adap[i].stream.udev = adap->dev->udev; + if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->fe_adap[i].stream.complete = + dvb_usb_data_complete_204; + else + if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) + adap->fe_adap[i].stream.complete = + dvb_usb_data_complete_raw; + else + adap->fe_adap[i].stream.complete = dvb_usb_data_complete; + adap->fe_adap[i].stream.user_priv = adap; + ret = usb_urb_init(&adap->fe_adap[i].stream, + &adap->props.fe[i].stream); + if (ret < 0) + break; + } + return ret; +} + +int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + int i; + for (i = 0; i < adap->props.num_frontends; i++) + usb_urb_exit(&adap->fe_adap[i].stream); + return 0; +} diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h new file mode 100644 index 00000000000..aab0f99bc89 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -0,0 +1,483 @@ +/* dvb-usb.h is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * the headerfile, all dvb-usb-drivers have to include. + * + * TODO: clean-up the structures for unused fields and update the comments + */ +#ifndef __DVB_USB_H__ +#define __DVB_USB_H__ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "dmxdev.h" + +#include "dvb-pll.h" + +#include "dvb-usb-ids.h" + +/* debug */ +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var,level,args...) \ + do { if ((var & level)) { printk(args); } } while (0) + +#define debug_dump(b,l,func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ + func("\n");\ +} +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b,l,func) + +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" + +#endif + +/* generic log methods - taken from usb.h */ +#ifndef DVB_USB_LOG_PREFIX + #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)" +#endif + +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +/** + * struct dvb_usb_device_description - name and its according USB IDs + * @name: real name of the box, regardless which DVB USB device class is in use + * @cold_ids: array of struct usb_device_id which describe the device in + * pre-firmware state + * @warm_ids: array of struct usb_device_id which describe the device in + * post-firmware state + * + * Each DVB USB device class can have one or more actual devices, this struct + * assigns a name to it. + */ +struct dvb_usb_device_description { + const char *name; + +#define DVB_USB_ID_MAX_NUM 15 + struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; + struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; +}; + +static inline u8 rc5_custom(struct rc_map_table *key) +{ + return (key->scancode >> 8) & 0xff; +} + +static inline u8 rc5_data(struct rc_map_table *key) +{ + return key->scancode & 0xff; +} + +static inline u16 rc5_scan(struct rc_map_table *key) +{ + return key->scancode & 0xffff; +} + +struct dvb_usb_device; +struct dvb_usb_adapter; +struct usb_data_stream; + +/** + * Properties of USB streaming - TODO this structure should be somewhere else + * describes the kind of USB transfer used for data-streaming. + * (BULK or ISOC) + */ +struct usb_data_stream_properties { +#define USB_BULK 1 +#define USB_ISOC 2 + int type; + int count; + int endpoint; + + union { + struct { + int buffersize; /* per URB */ + } bulk; + struct { + int framesperurb; + int framesize; + int interval; + } isoc; + } u; +}; + +/** + * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. + * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. + * @caps: capabilities of the DVB USB device. + * @pid_filter_count: number of PID filter position in the optional hardware + * PID-filter. + * @num_frontends: number of frontends of the DVB USB adapter. + * @frontend_ctrl: called to power on/off active frontend. + * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the + * device (not URB submitting/killing). + * @pid_filter_ctrl: called to en/disable the PID filter, if any. + * @pid_filter: called to set/unset a PID for filtering. + * @frontend_attach: called to attach the possible frontends (fill fe-field + * of struct dvb_usb_device). + * @tuner_attach: called to attach the correct tuner and to fill pll_addr, + * pll_desc and pll_init_buf of struct dvb_usb_device). + * @stream: configuration of the USB streaming + */ +struct dvb_usb_adapter_fe_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 +#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 +#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 + int caps; + int pid_filter_count; + + int (*streaming_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + + struct usb_data_stream_properties stream; + + int size_of_priv; +}; + +#define MAX_NO_OF_FE_PER_ADAP 3 +struct dvb_usb_adapter_properties { + int size_of_priv; + + int (*frontend_ctrl) (struct dvb_frontend *, int); + + int num_frontends; + struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; +}; + +/** + * struct dvb_rc_legacy - old properties of remote controller + * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable + * remote control handling). + * @rc_map_size: number of items in @rc_map_table. + * @rc_query: called to query an event event. + * @rc_interval: time in ms between two queries. + */ +struct dvb_rc_legacy { +/* remote control properties */ +#define REMOTE_NO_KEY_PRESSED 0x00 +#define REMOTE_KEY_PRESSED 0x01 +#define REMOTE_KEY_REPEAT 0x02 + struct rc_map_table *rc_map_table; + int rc_map_size; + int (*rc_query) (struct dvb_usb_device *, u32 *, int *); + int rc_interval; +}; + +/** + * struct dvb_rc properties of remote controller, using rc-core + * @rc_codes: name of rc codes table + * @protocol: type of protocol(s) currently used by the driver + * @allowed_protos: protocol(s) supported by the driver + * @driver_type: Used to point if a device supports raw mode + * @change_protocol: callback to change protocol + * @rc_query: called to query an event event. + * @rc_interval: time in ms between two queries. + * @bulk_mode: device supports bulk mode for RC (disable polling mode) + */ +struct dvb_rc { + char *rc_codes; + u64 protocol; + u64 allowed_protos; + enum rc_driver_type driver_type; + int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + char *module_name; + int (*rc_query) (struct dvb_usb_device *d); + int rc_interval; + bool bulk_mode; /* uses bulk mode */ +}; + +/** + * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one + * based on rc-core + * This is initialized/used only inside dvb-usb-remote.c. + * It shouldn't be set by the drivers. + */ +enum dvb_usb_mode { + DVB_RC_LEGACY, + DVB_RC_CORE, +}; + +/** + * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @usb_ctrl: which USB device-side controller is in use. Needed for firmware + * download. + * @firmware: name of the firmware file. + * @download_firmware: called to download the firmware when the usb_ctrl is + * DEVICE_SPECIFIC. + * @no_reconnect: device doesn't do a reconnect after downloading the firmware, + * so do the warm initialization right after it + * + * @size_of_priv: how many bytes shall be allocated for the private field + * of struct dvb_usb_device. + * + * @power_ctrl: called to enable/disable power of the device. + * @read_mac_address: called to read the MAC address of the device. + * @identify_state: called to determine the state (cold or warm), when it + * is not distinguishable by the USB IDs. + * + * @rc: remote controller properties + * + * @i2c_algo: i2c_algorithm if the device has I2CoverUSB. + * + * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic + * endpoint which received control messages with bulk transfers. When this + * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- + * helper functions. + * + * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate + * endpoint for responses to control messages sent with bulk transfers via + * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used + * instead of the generic_bulk_ctrl_endpoint when reading usb responses in + * the dvb_usb_generic_rw helper function. + * + * @num_device_descs: number of struct dvb_usb_device_description in @devices + * @devices: array of struct dvb_usb_device_description compatibles with these + * properties. + */ +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 +struct dvb_usb_device_properties { + +#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 + int caps; + +#define DEVICE_SPECIFIC 0 +#define CYPRESS_AN2135 1 +#define CYPRESS_AN2235 2 +#define CYPRESS_FX2 3 + int usb_ctrl; + int (*download_firmware) (struct usb_device *, const struct firmware *); + const char *firmware; + int no_reconnect; + + int size_of_priv; + + int num_adapters; + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + int (*power_ctrl) (struct dvb_usb_device *, int); + int (*read_mac_address) (struct dvb_usb_device *, u8 []); + int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, + struct dvb_usb_device_description **, int *); + + struct { + enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ + struct dvb_rc_legacy legacy; + struct dvb_rc core; + } rc; + + struct i2c_algorithm *i2c_algo; + + int generic_bulk_ctrl_endpoint; + int generic_bulk_ctrl_endpoint_response; + + int num_device_descs; + struct dvb_usb_device_description devices[12]; +}; + +/** + * struct usb_data_stream - generic object of an USB stream + * @buf_num: number of buffer allocated. + * @buf_size: size of each buffer in buf_list. + * @buf_list: array containing all allocate buffers for streaming. + * @dma_addr: list of dma_addr_t for each buffer in buf_list. + * + * @urbs_initialized: number of URBs initialized. + * @urbs_submitted: number of URBs submitted. + */ +#define MAX_NO_URBS_FOR_DATA_STREAM 10 +struct usb_data_stream { + struct usb_device *udev; + struct usb_data_stream_properties props; + +#define USB_STATE_INIT 0x00 +#define USB_STATE_URB_BUF 0x01 + int state; + + void (*complete) (struct usb_data_stream *, u8 *, size_t); + + struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; + dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; + + int urbs_initialized; + int urbs_submitted; + + void *user_priv; +}; + +/** + * struct dvb_usb_adapter - a DVB adapter on a USB device + * @id: index of this adapter (starting with 0). + * + * @feedcount: number of reqested feeds (used for streaming-activation) + * @pid_filtering: is hardware pid_filtering used or not. + * + * @pll_addr: I2C address of the tuner for programming + * @pll_init: array containing the initialization buffer + * @pll_desc: pointer to the appropriate struct dvb_pll_desc + * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board + * + * @dvb_adap: device's dvb_adapter. + * @dmxdev: device's dmxdev. + * @demux: device's software demuxer. + * @dvb_net: device's dvb_net interfaces. + * @dvb_frontend: device's frontend. + * @max_feed_count: how many feeds can be handled simultaneously by this + * device + * + * @fe_init: rerouted frontend-init (wakeup) function. + * @fe_sleep: rerouted frontend-sleep function. + * + * @stream: the usb data stream. + */ +struct dvb_usb_fe_adapter { + struct dvb_frontend *fe; + + int (*fe_init) (struct dvb_frontend *); + int (*fe_sleep) (struct dvb_frontend *); + + struct usb_data_stream stream; + + int pid_filtering; + int max_feed_count; + + void *priv; +}; + +struct dvb_usb_adapter { + struct dvb_usb_device *dev; + struct dvb_usb_adapter_properties props; + +#define DVB_USB_ADAP_STATE_INIT 0x000 +#define DVB_USB_ADAP_STATE_DVB 0x001 + int state; + + u8 id; + + int feedcount; + + /* dvb */ + struct dvb_adapter dvb_adap; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvb_net; + + struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP]; + int active_fe; + int num_frontends_initialized; + + void *priv; +}; + +/** + * struct dvb_usb_device - object of a DVB USB device + * @props: copy of the struct dvb_usb_properties this device belongs to. + * @desc: pointer to the device's struct dvb_usb_device_description. + * @state: initialization and runtime state of the device. + * + * @powered: indicated whether the device is power or not. + * Powered is in/decremented for each call to modify the state. + * @udev: pointer to the device's struct usb_device. + * + * @usb_mutex: semaphore of USB control messages (reading needs two messages) + * @i2c_mutex: semaphore for i2c-transfers + * + * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB + * + * @rc_dev: rc device for the remote control (rc-core mode) + * @input_dev: input device for the remote control (legacy mode) + * @rc_query_work: struct work_struct frequent rc queries + * @last_event: last triggered event + * @last_state: last state (no, pressed, repeat) + * @owner: owner of the dvb_adapter + * @priv: private data of the actual driver (allocate by dvb-usb, size defined + * in size_of_priv of dvb_usb_properties). + */ +struct dvb_usb_device { + struct dvb_usb_device_properties props; + struct dvb_usb_device_description *desc; + + struct usb_device *udev; + +#define DVB_USB_STATE_INIT 0x000 +#define DVB_USB_STATE_I2C 0x001 +#define DVB_USB_STATE_DVB 0x002 +#define DVB_USB_STATE_REMOTE 0x004 + int state; + + int powered; + + /* locking */ + struct mutex usb_mutex; + + /* i2c */ + struct mutex i2c_mutex; + struct i2c_adapter i2c_adap; + + int num_adapters_initialized; + struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + /* remote control */ + struct rc_dev *rc_dev; + struct input_dev *input_dev; + char rc_phys[64]; + struct delayed_work rc_query_work; + u32 last_event; + int last_state; + + struct module *owner; + + void *priv; +}; + +extern int dvb_usb_device_init(struct usb_interface *, + struct dvb_usb_device_properties *, + struct module *, struct dvb_usb_device **, + short *adapter_nums); +extern void dvb_usb_device_exit(struct usb_interface *); + +/* the generic read/write method for device control */ +extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); +extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); + +/* commonly used remote control parsing */ +extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); +extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); + + +#endif diff --git a/drivers/media/usb/dvb-usb/dvb_usb_dvb.c b/drivers/media/usb/dvb-usb/dvb_usb_dvb.c new file mode 100644 index 00000000000..384fe8eec21 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb_usb_dvb.c @@ -0,0 +1,403 @@ +/* dvb-usb-dvb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing and handling the + * linux-dvb API. + */ +#include "dvb_usb_common.h" + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_204(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_raw(&adap->demux, buf, len); +} + +int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + + adap->stream.udev = adap_to_d(adap)->udev; + adap->stream.user_priv = adap; + adap->stream.complete = dvb_usb_data_complete; + + return usb_urb_initv2(&adap->stream, &adap->props->stream); +} + +int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + usb_urb_exitv2(&adap->stream); + + return 0; +} + +/* does the complete input transfer handling */ +static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \ + "%04x (%04d) at index %d '%s'\n", __func__, adap->id, + adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + (count == 1) ? "on" : "off"); + + if (adap->active_fe == -1) + return -EINVAL; + + adap->feed_count += count; + + /* stop feeding if it is last pid */ + if (adap->feed_count == 0) { + pr_debug("%s: stop feeding\n", __func__); + usb_urb_killv2(&adap->stream); + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 0); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + mutex_unlock(&adap->sync_mutex); + } + + /* activate the pid on the device pid filter */ + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props->pid_filter) + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, (count == 1) ? 1 : 0); + if (ret < 0) + pr_err("%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); + + /* start feeding if it is first pid */ + if (adap->feed_count == 1 && count == 1) { + struct usb_data_stream_properties stream_props; + mutex_lock(&adap->sync_mutex); + pr_debug("%s: start feeding\n", __func__); + + /* resolve input and output streaming paramters */ + if (d->props->get_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); + ret = d->props->get_stream_config( + adap->fe[adap->active_fe], + &adap->ts_type, &stream_props); + if (ret < 0) + goto err_mutex_unlock; + } else { + stream_props = adap->props->stream; + } + + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + + usb_urb_submitv2(&adap->stream, &stream_props); + + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props->caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, + adap->pid_filtering); + if (ret < 0) { + pr_err("%s: pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 1); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + } + + return 0; +err_mutex_unlock: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, -1); +} + +int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + pr_debug("%s: adap=%d\n", __func__, adap->id); + + ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, + &d->udev->dev, d->props->adapter_nr); + if (ret < 0) { + pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, + ret); + goto err; + } + + adap->dvb_adap.priv = adap; + + if (d->props->read_mac_address) { + ret = d->props->read_mac_address(adap, + adap->dvb_adap.proposed_mac); + if (ret < 0) + goto err_dmx; + + pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, + adap->dvb_adap.proposed_mac); + } + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.filternum = 0; + if (adap->demux.filternum < adap->max_feed_count) + adap->demux.filternum = adap->max_feed_count; + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, + ret); + goto err_dmx_dev; + } + + ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if (ret < 0) { + pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); + goto err_net_init; + } + + mutex_init(&adap->sync_mutex); + + return 0; +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + adap->dvb_adap.priv = NULL; + return ret; +} + +int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + + if (adap->dvb_adap.priv) { + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + } + + return 0; +} + +static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + + ret = dvb_usbv2_device_power_ctrl(d, 1); + if (ret < 0) + goto err; + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 1); + if (ret < 0) + goto err; + } + + if (adap->fe_init[fe->id]) { + ret = adap->fe_init[fe->id](fe); + if (ret < 0) + goto err; + } + + adap->active_fe = fe->id; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + + if (adap->fe_sleep[fe->id]) { + ret = adap->fe_sleep[fe->id](fe); + if (ret < 0) + goto err; + } + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 0); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_device_power_ctrl(d, 0); + if (ret < 0) + goto err; + + adap->active_fe = -1; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i, count_registered = 0; + struct dvb_usb_device *d = adap_to_d(adap); + pr_debug("%s: adap=%d\n", __func__, adap->id); + + memset(adap->fe, 0, sizeof(adap->fe)); + adap->active_fe = -1; + + if (d->props->frontend_attach) { + ret = d->props->frontend_attach(adap); + if (ret < 0) { + pr_debug("%s: frontend_attach() failed=%d\n", __func__, + ret); + goto err_dvb_frontend_detach; + } + } else { + pr_debug("%s: frontend_attach() do not exists\n", __func__); + ret = 0; + goto err; + } + + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { + adap->fe[i]->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); + if (ret < 0) { + pr_err("%s: frontend%d registration failed\n", + KBUILD_MODNAME, i); + goto err_dvb_unregister_frontend; + } + + count_registered++; + } + + if (d->props->tuner_attach) { + ret = d->props->tuner_attach(adap); + if (ret < 0) { + pr_debug("%s: tuner_attach() failed=%d\n", __func__, + ret); + goto err_dvb_unregister_frontend; + } + } + + return 0; + +err_dvb_unregister_frontend: + for (i = count_registered - 1; i >= 0; i--) + dvb_unregister_frontend(adap->fe[i]); + +err_dvb_frontend_detach: + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) + dvb_frontend_detach(adap->fe[i]); + } + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i; + pr_debug("%s: adap=%d\n", __func__, adap->id); + + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } + } + + return 0; +} diff --git a/drivers/media/usb/dvb-usb/dvb_usb_remote.c b/drivers/media/usb/dvb-usb/dvb_usb_remote.c new file mode 100644 index 00000000000..f856ab6648c --- /dev/null +++ b/drivers/media/usb/dvb-usb/dvb_usb_remote.c @@ -0,0 +1,117 @@ +/* dvb-usb-remote.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing the input-device and for + * handling remote-control-queries. + */ +#include "dvb_usb_common.h" +#include + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = container_of(work, + struct dvb_usb_device, rc_query_work.work); + int ret; + + /* TODO: need a lock here. We can simply skip checking for the remote + control if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init + */ + if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) + return; + + ret = d->rc.query(d); + if (ret < 0) + pr_err("%s: error %d while querying for an remote control " \ + "event\n", KBUILD_MODNAME, ret); + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); +} + +int dvb_usbv2_remote_init(struct dvb_usb_device *d) +{ + int ret; + struct rc_dev *dev; + + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) + return 0; + + ret = d->props->get_rc_config(d, &d->rc); + if (ret < 0) + goto err; + + dev = rc_allocate_device(); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->dev.parent = &d->udev->dev; + dev->input_name = "IR-receiver inside an USB DVB receiver"; + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + dev->input_phys = d->rc_phys; + usb_to_input_id(d->udev, &dev->input_id); + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props->driver_name; + dev->driver_type = d->rc.driver_type; + dev->allowed_protos = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; + dev->priv = d; + /* select used keymap */ + if (d->rc.map_name) + dev->map_name = d->rc.map_name; + else if (d->rc_map) + dev->map_name = d->rc_map; + else + dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ + + ret = rc_register_device(dev); + if (ret < 0) { + rc_free_device(dev); + goto err; + } + + d->input_dev = NULL; + d->rc_dev = dev; + + /* start polling if needed */ + if (d->rc.query && !d->rc.bulk_mode) { + /* initialize a work queue for handling polling */ + INIT_DELAYED_WORK(&d->rc_query_work, + dvb_usb_read_remote_control); + pr_info("%s: schedule remote query interval to %d msecs\n", + KBUILD_MODNAME, d->rc.interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + } + + d->state |= DVB_USB_STATE_REMOTE; + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_remote_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); + } + + d->state &= ~DVB_USB_STATE_REMOTE; + + return 0; +} diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c new file mode 100644 index 00000000000..9382895b1b8 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -0,0 +1,1951 @@ +/* DVB USB framework compliant Linux driver for the + * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, + * TeVii S600, S630, S650, S660, S480, + * Prof 1100, 7500, + * Geniatech SU3000 Cards + * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by) + * + * 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 "dw2102.h" +#include "si21xx.h" +#include "stv0299.h" +#include "z0194a.h" +#include "stv0288.h" +#include "stb6000.h" +#include "eds1547.h" +#include "cx24116.h" +#include "tda1002x.h" +#include "mt312.h" +#include "zl10039.h" +#include "ds3000.h" +#include "stv0900.h" +#include "stv6110.h" +#include "stb6100.h" +#include "stb6100_proc.h" + +#ifndef USB_PID_DW2102 +#define USB_PID_DW2102 0x2102 +#endif + +#ifndef USB_PID_DW2104 +#define USB_PID_DW2104 0x2104 +#endif + +#ifndef USB_PID_DW3101 +#define USB_PID_DW3101 0x3101 +#endif + +#ifndef USB_PID_CINERGY_S +#define USB_PID_CINERGY_S 0x0064 +#endif + +#ifndef USB_PID_TEVII_S630 +#define USB_PID_TEVII_S630 0xd630 +#endif + +#ifndef USB_PID_TEVII_S650 +#define USB_PID_TEVII_S650 0xd650 +#endif + +#ifndef USB_PID_TEVII_S660 +#define USB_PID_TEVII_S660 0xd660 +#endif + +#ifndef USB_PID_TEVII_S480_1 +#define USB_PID_TEVII_S480_1 0xd481 +#endif + +#ifndef USB_PID_TEVII_S480_2 +#define USB_PID_TEVII_S480_2 0xd482 +#endif + +#ifndef USB_PID_PROF_1100 +#define USB_PID_PROF_1100 0xb012 +#endif + +#define DW210X_READ_MSG 0 +#define DW210X_WRITE_MSG 1 + +#define REG_1F_SYMBOLRATE_BYTE0 0x1f +#define REG_20_SYMBOLRATE_BYTE1 0x20 +#define REG_21_SYMBOLRATE_BYTE2 0x21 +/* on my own*/ +#define DW2102_VOLTAGE_CTRL (0x1800) +#define SU3000_STREAM_CTRL (0x1900) +#define DW2102_RC_QUERY (0x1a00) +#define DW2102_LED_CTRL (0x1b00) + +#define err_str "did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for more details " \ + "on firmware-problems." + +struct rc_map_dvb_usb_table_table { + struct rc_map_table *rc_keys; + int rc_keys_size; +}; + +struct su3000_state { + u8 initialized; +}; + +struct s6x0_state { + int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); +}; + +/* debug */ +static int dvb_usb_dw2102_debug; +module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." + DVB_USB_DEBUG_STATUS); + +/* keymaps */ +static int ir_keymap; +module_param_named(keymap, ir_keymap, int, 0644); +MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." + " 256=none"); + +/* demod probe */ +static int demod_probe = 1; +module_param_named(demod, demod_probe, int, 0644); +MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " + "4=stv0903+stb6100(or-able))."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, + u16 index, u8 * data, u16 len, int flags) +{ + int ret; + u8 *u8buf; + unsigned int pipe = (flags == DW210X_READ_MSG) ? + usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); + u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; + + u8buf = kmalloc(len, GFP_KERNEL); + if (!u8buf) + return -ENOMEM; + + + if (flags == DW210X_WRITE_MSG) + memcpy(u8buf, data, len); + ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, + value, index , u8buf, len, 2000); + + if (flags == DW210X_READ_MSG) + memcpy(data, u8buf, len); + + kfree(u8buf); + return ret; +} + +/* I2C */ +static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0; + u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; + u16 value; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: + /* read stv0299 register */ + value = msg[0].buf[0];/* register */ + for (i = 0; i < msg[1].len; i++) { + dw210x_op_rw(d->udev, 0xb5, value + i, 0, + buf6, 2, DW210X_READ_MSG); + msg[1].buf[i] = buf6[0]; + } + break; + case 1: + switch (msg[0].addr) { + case 0x68: + /* write to stv0299 register */ + buf6[0] = 0x2a; + buf6[1] = msg[0].buf[0]; + buf6[2] = msg[0].buf[1]; + dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 3, DW210X_WRITE_MSG); + break; + case 0x60: + if (msg[0].flags == 0) { + /* write to tuner pll */ + buf6[0] = 0x2c; + buf6[1] = 5; + buf6[2] = 0xc0; + buf6[3] = msg[0].buf[0]; + buf6[4] = msg[0].buf[1]; + buf6[5] = msg[0].buf[2]; + buf6[6] = msg[0].buf[3]; + dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 7, DW210X_WRITE_MSG); + } else { + /* read from tuner */ + dw210x_op_rw(d->udev, 0xb5, 0, 0, + buf6, 1, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + } + break; + case (DW2102_RC_QUERY): + dw210x_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + msg[0].buf[1] = buf6[1]; + break; + case (DW2102_VOLTAGE_CTRL): + buf6[0] = 0x30; + buf6[1] = msg[0].buf[0]; + dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW210X_WRITE_MSG); + break; + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: + /* read si2109 register by number */ + buf6[0] = msg[0].addr << 1; + buf6[1] = msg[0].len; + buf6[2] = msg[0].buf[0]; + dw210x_op_rw(d->udev, 0xc2, 0, 0, + buf6, msg[0].len + 2, DW210X_WRITE_MSG); + /* read si2109 register */ + dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, + buf6, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, buf6 + 2, msg[1].len); + + break; + case 1: + switch (msg[0].addr) { + case 0x68: + /* write to si2109 register */ + buf6[0] = msg[0].addr << 1; + buf6[1] = msg[0].len; + memcpy(buf6 + 2, msg[0].buf, msg[0].len); + dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, + msg[0].len + 2, DW210X_WRITE_MSG); + break; + case(DW2102_RC_QUERY): + dw210x_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + msg[0].buf[1] = buf6[1]; + break; + case(DW2102_VOLTAGE_CTRL): + buf6[0] = 0x30; + buf6[1] = msg[0].buf[0]; + dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW210X_WRITE_MSG); + break; + } + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: { + /* read */ + /* first write first register number */ + u8 ibuf[msg[1].len + 2], obuf[3]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + /* second read registers */ + dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x68: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case 0x61: { + /* write to tuner */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + case(DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + obuf[0] = 0x30; + obuf[1] = msg[0].buf[0]; + dw210x_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int len, i, j; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (j = 0; j < num; j++) { + switch (msg[j].addr) { + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf , 2); + break; + } + case(DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + obuf[0] = 0x30; + obuf[1] = msg[j].buf[0]; + dw210x_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len + 2]; + dw210x_op_rw(d->udev, 0xc3, + (msg[j].addr << 1) + 1, 0, + ibuf, msg[j].len + 2, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 2, msg[j].len); + mdelay(10); + } else if (((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) || + ((msg[j].buf[0] == 0xf7) && + (msg[j].addr == 0x55))) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = msg[j].addr << 1; + obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j].addr << 1; + obuf[1] = msg[j].len; + memcpy(obuf + 2, msg[j].buf, msg[j].len); + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + } + break; + } + } + + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: { + /* read */ + /* first write first register number */ + u8 ibuf[msg[1].len + 2], obuf[3]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + /* second read registers */ + dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x60: + case 0x0c: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + } + + break; + } + + for (i = 0; i < num; i++) { + deb_xfer("%02x:%02x: %s ", i, msg[i].addr, + msg[i].flags == 0 ? ">>>" : "<<<"); + debug_dump(msg[i].buf, msg[i].len, deb_xfer); + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct usb_device *udev; + int len, i, j; + + if (!d) + return -ENODEV; + udev = d->udev; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (j = 0; j < num; j++) { + switch (msg[j].addr) { + case (DW2102_RC_QUERY): { + u8 ibuf[5]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 5, DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 3, 2); + break; + } + case (DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + + obuf[0] = 1; + obuf[1] = msg[j].buf[1];/* off-on */ + dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + obuf[0] = 3; + obuf[1] = msg[j].buf[0];/* 13v-18v */ + dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + case (DW2102_LED_CTRL): { + u8 obuf[2]; + + obuf[0] = 5; + obuf[1] = msg[j].buf[0]; + dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 + case 0xa0: eeprom */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len]; + dw210x_op_rw(d->udev, 0x91, 0, 0, + ibuf, msg[j].len, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf, msg[j].len); + break; + } else if ((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = (msg[j].len > 16 ? + 18 : msg[j].len + 1); + obuf[1] = msg[j].addr << 1; + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + dw210x_op_rw(d->udev, 0x80, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else if (j < (num - 1)) { + /* write register addr before read */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j + 1].len; + obuf[1] = (msg[j].addr << 1); + memcpy(obuf + 2, msg[j].buf, msg[j].len); + dw210x_op_rw(d->udev, + udev->descriptor.idProduct == + 0x7500 ? 0x92 : 0x90, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + break; + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j].len + 1; + obuf[1] = (msg[j].addr << 1); + memcpy(obuf + 2, msg[j].buf, msg[j].len); + dw210x_op_rw(d->udev, 0x80, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + break; + } + break; + } + } + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + u8 obuf[0x40], ibuf[0x40]; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 1: + switch (msg[0].addr) { + case SU3000_STREAM_CTRL: + obuf[0] = msg[0].buf[0] + 0x36; + obuf[1] = 3; + obuf[2] = 0; + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0) + err("i2c transfer failed."); + break; + case DW2102_RC_QUERY: + obuf[0] = 0x10; + if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0) + err("i2c transfer failed."); + msg[0].buf[1] = ibuf[0]; + msg[0].buf[0] = ibuf[1]; + break; + default: + /* always i2c write*/ + obuf[0] = 0x08; + obuf[1] = msg[0].addr; + obuf[2] = msg[0].len; + + memcpy(&obuf[3], msg[0].buf, msg[0].len); + + if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3, + ibuf, 1, 0) < 0) + err("i2c transfer failed."); + + } + break; + case 2: + /* always i2c read */ + obuf[0] = 0x09; + obuf[1] = msg[0].len; + obuf[2] = msg[1].len; + obuf[3] = msg[0].addr; + memcpy(&obuf[4], msg[0].buf, msg[0].len); + + if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4, + ibuf, msg[1].len + 1, 0) < 0) + err("i2c transfer failed."); + + memcpy(msg[1].buf, &ibuf[1], msg[1].len); + break; + default: + warn("more than 2 i2c messages at a time is not handled yet."); + break; + } + mutex_unlock(&d->i2c_mutex); + return num; +} + +static u32 dw210x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dw2102_i2c_algo = { + .master_xfer = dw2102_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2102_serit_i2c_algo = { + .master_xfer = dw2102_serit_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2102_earda_i2c_algo = { + .master_xfer = dw2102_earda_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2104_i2c_algo = { + .master_xfer = dw2104_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw3101_i2c_algo = { + .master_xfer = dw3101_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm s6x0_i2c_algo = { + .master_xfer = s6x0_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm su3000_i2c_algo = { + .master_xfer = su3000_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 ibuf[] = {0, 0}; + u8 eeprom[256], eepromline[16]; + + for (i = 0; i < 256; i++) { + if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { + err("read eeprom failed."); + return -1; + } else { + eepromline[i%16] = ibuf[0]; + eeprom[i] = ibuf[0]; + } + if ((i % 16) == 15) { + deb_xfer("%02x: ", i - 15); + debug_dump(eepromline, 16, deb_xfer); + } + } + + memcpy(mac, eeprom + 8, 6); + return 0; +}; + +static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i, ret; + u8 ibuf[] = { 0 }, obuf[] = { 0 }; + u8 eeprom[256], eepromline[16]; + struct i2c_msg msg[] = { + { + .addr = 0xa0 >> 1, + .flags = 0, + .buf = obuf, + .len = 1, + }, { + .addr = 0xa0 >> 1, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + } + }; + + for (i = 0; i < 256; i++) { + obuf[0] = i; + ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); + if (ret != 2) { + err("read eeprom failed."); + return -1; + } else { + eepromline[i % 16] = ibuf[0]; + eeprom[i] = ibuf[0]; + } + + if ((i % 16) == 15) { + deb_xfer("%02x: ", i - 15); + debug_dump(eepromline, 16, deb_xfer); + } + } + + memcpy(mac, eeprom + 16, 6); + return 0; +}; + +static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + static u8 command_start[] = {0x00}; + static u8 command_stop[] = {0x01}; + struct i2c_msg msg = { + .addr = SU3000_STREAM_CTRL, + .flags = 0, + .buf = onoff ? command_start : command_stop, + .len = 1 + }; + + i2c_transfer(&adap->dev->i2c_adap, &msg, 1); + + return 0; +} + +static int su3000_power_ctrl(struct dvb_usb_device *d, int i) +{ + struct su3000_state *state = (struct su3000_state *)d->priv; + u8 obuf[] = {0xde, 0}; + + info("%s: %d, initialized %d\n", __func__, i, state->initialized); + + if (i && !state->initialized) { + state->initialized = 1; + /* reset board */ + dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0); + } + + return 0; +} + +static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 obuf[] = { 0x1f, 0xf0 }; + u8 ibuf[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = 0x51, + .flags = 0, + .buf = obuf, + .len = 2, + }, { + .addr = 0x51, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + + } + }; + + for (i = 0; i < 6; i++) { + obuf[1] = 0xf0 + i; + if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) + break; + else + mac[i] = ibuf[0]; + + debug_dump(mac, 6, printk); + } + + return 0; +} + +static int su3000_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + info("%s\n", __func__); + + *cold = 0; + return 0; +} + +static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + static u8 command_13v[] = {0x00, 0x01}; + static u8 command_18v[] = {0x01, 0x01}; + static u8 command_off[] = {0x00, 0x00}; + struct i2c_msg msg = { + .addr = DW2102_VOLTAGE_CTRL, + .flags = 0, + .buf = command_off, + .len = 2, + }; + + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + if (voltage == SEC_VOLTAGE_18) + msg.buf = command_18v; + else if (voltage == SEC_VOLTAGE_13) + msg.buf = command_13v; + + i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); + + return 0; +} + +static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct dvb_usb_adapter *d = + (struct dvb_usb_adapter *)(fe->dvb->priv); + struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + + dw210x_set_voltage(fe, voltage); + if (st->old_set_voltage) + st->old_set_voltage(fe, voltage); + + return 0; +} + +static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) +{ + static u8 led_off[] = { 0 }; + static u8 led_on[] = { 1 }; + struct i2c_msg msg = { + .addr = DW2102_LED_CTRL, + .flags = 0, + .buf = led_off, + .len = 1 + }; + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + + if (offon) + msg.buf = led_on; + i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); +} + +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static struct cx24116_config dw2104_config = { + .demod_address = 0x55, + .mpg_clk_pos_pol = 0x01, +}; + +static struct si21xx_config serit_sp1511lhb_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + +}; + +static struct tda10023_config dw3101_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static struct mt312_config zl313_config = { + .demod_address = 0x0e, +}; + +static struct ds3000_config dw2104_ds3000_config = { + .demod_address = 0x68, +}; + +static struct stv0900_config dw2104a_stv0900_config = { + .demod_address = 0x6a, + .demod_mode = 0, + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, +}; + +static struct stb6100_config dw2104a_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static struct stv0900_config dw2104_stv0900_config = { + .demod_address = 0x68, + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1,/* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config dw2104_stv6110_config = { + .i2c_address = 0x60, + .mclk = 16000000, + .clk_div = 1, +}; + +static struct stv0900_config prof_7500_stv0900_config = { + .demod_address = 0x6a, + .demod_mode = 0, + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, + .tun1_type = 3, + .set_lock_led = dw210x_led_ctrl, +}; + +static struct ds3000_config su3000_ds3000_config = { + .demod_address = 0x68, + .ci_mode = 1, +}; + +static int dw2104_frontend_attach(struct dvb_usb_adapter *d) +{ + struct dvb_tuner_ops *tuner_ops = NULL; + + if (demod_probe & 4) { + d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(stb6100_attach, d->fe_adap[0].fe, + &dw2104a_stb6100_config, + &d->dev->i2c_adap)) { + tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops; + tuner_ops->set_frequency = stb6100_set_freq; + tuner_ops->get_frequency = stb6100_get_freq; + tuner_ops->set_bandwidth = stb6100_set_bandw; + tuner_ops->get_bandwidth = stb6100_get_bandw; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STB6100!\n"); + return 0; + } + } + } + + if (demod_probe & 2) { + d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(stv6110_attach, d->fe_adap[0].fe, + &dw2104_stv6110_config, + &d->dev->i2c_adap)) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STV6110A!\n"); + return 0; + } + } + } + + if (demod_probe & 1) { + d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached cx24116!\n"); + return 0; + } + } + + d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached DS3000!\n"); + return 0; + } + + return -EIO; +} + +static struct dvb_usb_device_properties dw2102_properties; +static struct dvb_usb_device_properties dw2104_properties; +static struct dvb_usb_device_properties s6x0_properties; + +static int dw2102_frontend_attach(struct dvb_usb_adapter *d) +{ + if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = NULL;*/ + d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached si21xx!\n"); + return 0; + } + } + + if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { + d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, + &d->dev->i2c_adap)) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288!\n"); + return 0; + } + } + } + + if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ + d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0299!\n"); + return 0; + } + } + return -EIO; +} + +static int dw3101_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + &d->dev->i2c_adap, 0x48); + if (d->fe_adap[0].fe != NULL) { + info("Attached tda10023!\n"); + return 0; + } + return -EIO; +} + +static int zl100313_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60, + &d->dev->i2c_adap)) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + info("Attached zl100313+zl10039!\n"); + return 0; + } + } + + return -EIO; +} + +static int stv0288_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[] = {7, 1}; + + d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + + if (d->fe_adap[0].fe == NULL) + return -EIO; + + if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap)) + return -EIO; + + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached stv0288+stb6000!\n"); + + return 0; + +} + +static int ds3000_frontend_attach(struct dvb_usb_adapter *d) +{ + struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + u8 obuf[] = {7, 1}; + + d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); + + if (d->fe_adap[0].fe == NULL) + return -EIO; + + st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage; + d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached ds3000+ds2020!\n"); + + return 0; +} + +static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[] = {7, 1}; + + d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe_adap[0].fe == NULL) + return -EIO; + + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached STV0900+STB6100A!\n"); + + return 0; +} + +static int su3000_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[3] = { 0xe, 0x80, 0 }; + u8 ibuf[] = { 0 }; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 0; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 1; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0x51; + + if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) + err("command 0x51 transfer failed."); + + d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, + &d->dev->i2c_adap); + if (d->fe_adap[0].fe == NULL) + return -EIO; + + info("Attached DS3000!\n"); + + return 0; +} + +static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_OPERA1); + return 0; +} + +static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_TUA6034); + + return 0; +} + +static struct rc_map_table rc_map_dw210x_table[] = { + { 0xf80a, KEY_POWER2 }, /*power*/ + { 0xf80c, KEY_MUTE }, /*mute*/ + { 0xf811, KEY_1 }, + { 0xf812, KEY_2 }, + { 0xf813, KEY_3 }, + { 0xf814, KEY_4 }, + { 0xf815, KEY_5 }, + { 0xf816, KEY_6 }, + { 0xf817, KEY_7 }, + { 0xf818, KEY_8 }, + { 0xf819, KEY_9 }, + { 0xf810, KEY_0 }, + { 0xf81c, KEY_CHANNELUP }, /*ch+*/ + { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ + { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ + { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ + { 0xf804, KEY_RECORD }, /*rec*/ + { 0xf809, KEY_FAVORITES }, /*fav*/ + { 0xf808, KEY_REWIND }, /*rewind*/ + { 0xf807, KEY_FASTFORWARD }, /*fast*/ + { 0xf80b, KEY_PAUSE }, /*pause*/ + { 0xf802, KEY_ESC }, /*cancel*/ + { 0xf803, KEY_TAB }, /*tab*/ + { 0xf800, KEY_UP }, /*up*/ + { 0xf81f, KEY_OK }, /*ok*/ + { 0xf801, KEY_DOWN }, /*down*/ + { 0xf805, KEY_CAMERA }, /*cap*/ + { 0xf806, KEY_STOP }, /*stop*/ + { 0xf840, KEY_ZOOM }, /*full*/ + { 0xf81e, KEY_TV }, /*tvmode*/ + { 0xf81b, KEY_LAST }, /*recall*/ +}; + +static struct rc_map_table rc_map_tevii_table[] = { + { 0xf80a, KEY_POWER }, + { 0xf80c, KEY_MUTE }, + { 0xf811, KEY_1 }, + { 0xf812, KEY_2 }, + { 0xf813, KEY_3 }, + { 0xf814, KEY_4 }, + { 0xf815, KEY_5 }, + { 0xf816, KEY_6 }, + { 0xf817, KEY_7 }, + { 0xf818, KEY_8 }, + { 0xf819, KEY_9 }, + { 0xf810, KEY_0 }, + { 0xf81c, KEY_MENU }, + { 0xf80f, KEY_VOLUMEDOWN }, + { 0xf81a, KEY_LAST }, + { 0xf80e, KEY_OPEN }, + { 0xf804, KEY_RECORD }, + { 0xf809, KEY_VOLUMEUP }, + { 0xf808, KEY_CHANNELUP }, + { 0xf807, KEY_PVR }, + { 0xf80b, KEY_TIME }, + { 0xf802, KEY_RIGHT }, + { 0xf803, KEY_LEFT }, + { 0xf800, KEY_UP }, + { 0xf81f, KEY_OK }, + { 0xf801, KEY_DOWN }, + { 0xf805, KEY_TUNER }, + { 0xf806, KEY_CHANNELDOWN }, + { 0xf840, KEY_PLAYPAUSE }, + { 0xf81e, KEY_REWIND }, + { 0xf81b, KEY_FAVORITES }, + { 0xf81d, KEY_BACK }, + { 0xf84d, KEY_FASTFORWARD }, + { 0xf844, KEY_EPG }, + { 0xf84c, KEY_INFO }, + { 0xf841, KEY_AB }, + { 0xf843, KEY_AUDIO }, + { 0xf845, KEY_SUBTITLE }, + { 0xf84a, KEY_LIST }, + { 0xf846, KEY_F1 }, + { 0xf847, KEY_F2 }, + { 0xf85e, KEY_F3 }, + { 0xf85c, KEY_F4 }, + { 0xf852, KEY_F5 }, + { 0xf85a, KEY_F6 }, + { 0xf856, KEY_MODE }, + { 0xf858, KEY_SWITCHVIDEOMODE }, +}; + +static struct rc_map_table rc_map_tbs_table[] = { + { 0xf884, KEY_POWER }, + { 0xf894, KEY_MUTE }, + { 0xf887, KEY_1 }, + { 0xf886, KEY_2 }, + { 0xf885, KEY_3 }, + { 0xf88b, KEY_4 }, + { 0xf88a, KEY_5 }, + { 0xf889, KEY_6 }, + { 0xf88f, KEY_7 }, + { 0xf88e, KEY_8 }, + { 0xf88d, KEY_9 }, + { 0xf892, KEY_0 }, + { 0xf896, KEY_CHANNELUP }, + { 0xf891, KEY_CHANNELDOWN }, + { 0xf893, KEY_VOLUMEUP }, + { 0xf88c, KEY_VOLUMEDOWN }, + { 0xf883, KEY_RECORD }, + { 0xf898, KEY_PAUSE }, + { 0xf899, KEY_OK }, + { 0xf89a, KEY_SHUFFLE }, + { 0xf881, KEY_UP }, + { 0xf890, KEY_LEFT }, + { 0xf882, KEY_RIGHT }, + { 0xf888, KEY_DOWN }, + { 0xf895, KEY_FAVORITES }, + { 0xf897, KEY_SUBTITLE }, + { 0xf89d, KEY_ZOOM }, + { 0xf89f, KEY_EXIT }, + { 0xf89e, KEY_MENU }, + { 0xf89c, KEY_EPG }, + { 0xf880, KEY_PREVIOUS }, + { 0xf89b, KEY_MODE } +}; + +static struct rc_map_table rc_map_su3000_table[] = { + { 0x25, KEY_POWER }, /* right-bottom Red */ + { 0x0a, KEY_MUTE }, /* -/-- */ + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x00, KEY_0 }, + { 0x20, KEY_UP }, /* CH+ */ + { 0x21, KEY_DOWN }, /* CH+ */ + { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ + { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ + { 0x1f, KEY_RECORD }, + { 0x17, KEY_PLAY }, + { 0x16, KEY_PAUSE }, + { 0x0b, KEY_STOP }, + { 0x27, KEY_FASTFORWARD },/* >> */ + { 0x26, KEY_REWIND }, /* << */ + { 0x0d, KEY_OK }, /* Mute */ + { 0x11, KEY_LEFT }, /* VOL- */ + { 0x10, KEY_RIGHT }, /* VOL+ */ + { 0x29, KEY_BACK }, /* button under 9 */ + { 0x2c, KEY_MENU }, /* TTX */ + { 0x2b, KEY_EPG }, /* EPG */ + { 0x1e, KEY_RED }, /* OSD */ + { 0x0e, KEY_GREEN }, /* Window */ + { 0x2d, KEY_YELLOW }, /* button under << */ + { 0x0f, KEY_BLUE }, /* bottom yellow button */ + { 0x14, KEY_AUDIO }, /* Snapshot */ + { 0x38, KEY_TV }, /* TV/Radio */ + { 0x0c, KEY_ESC } /* upper Red button */ +}; + +static struct rc_map_dvb_usb_table_table keys_tables[] = { + { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, + { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, + { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, + { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, +}; + +static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + int keymap_size = d->props.rc.legacy.rc_map_size; + u8 key[2]; + struct i2c_msg msg = { + .addr = DW2102_RC_QUERY, + .flags = I2C_M_RD, + .buf = key, + .len = 2 + }; + int i; + /* override keymap */ + if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { + keymap = keys_tables[ir_keymap - 1].rc_keys ; + keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; + } else if (ir_keymap > ARRAY_SIZE(keys_tables)) + return 0; /* none */ + + *state = REMOTE_NO_KEY_PRESSED; + if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { + for (i = 0; i < keymap_size ; i++) { + if (rc5_data(&keymap[i]) == msg.buf[0]) { + *state = REMOTE_KEY_PRESSED; + *event = keymap[i].keycode; + break; + } + + } + + if ((*state) == REMOTE_KEY_PRESSED) + deb_rc("%s: found rc key: %x, %x, event: %x\n", + __func__, key[0], key[1], (*event)); + else if (key[0] != 0xff) + deb_rc("%s: unknown rc key: %x, %x\n", + __func__, key[0], key[1]); + + } + + return 0; +} + +enum dw2102_table_entry { + CYPRESS_DW2102, + CYPRESS_DW2101, + CYPRESS_DW2104, + TEVII_S650, + TERRATEC_CINERGY_S, + CYPRESS_DW3101, + TEVII_S630, + PROF_1100, + TEVII_S660, + PROF_7500, + GENIATECH_SU3000, + TERRATEC_CINERGY_S2, + TEVII_S480_1, + TEVII_S480_2, + X3M_SPC1400HD, +}; + +static struct usb_device_id dw2102_table[] = { + [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, + [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, + [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, + [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, + [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, + [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, + [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, + [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, + [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, + [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)}, + [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)}, + [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, + [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, + [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, + [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, + { } +}; + +MODULE_DEVICE_TABLE(usb, dw2102_table); + +static int dw2102_load_firmware(struct usb_device *dev, + const struct firmware *frmwr) +{ + u8 *b, *p; + int ret = 0, i; + u8 reset; + u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; + const struct firmware *fw; + const char *fw_2101 = "dvb-usb-dw2101.fw"; + + switch (dev->descriptor.idProduct) { + case 0x2101: + ret = request_firmware(&fw, fw_2101, &dev->dev); + if (ret != 0) { + err(err_str, fw_2101); + return ret; + } + break; + default: + fw = frmwr; + break; + } + info("start downloading DW210X firmware"); + p = kmalloc(fw->size, GFP_KERNEL); + reset = 1; + /*stop the CPU*/ + dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); + + if (p != NULL) { + memcpy(p, fw->data, fw->size); + for (i = 0; i < fw->size; i += 0x40) { + b = (u8 *) p + i; + if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, + DW210X_WRITE_MSG) != 0x40) { + err("error while transferring firmware"); + ret = -EINVAL; + break; + } + } + /* restart the CPU */ + reset = 0; + if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, + DW210X_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, + DW210X_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + /* init registers */ + switch (dev->descriptor.idProduct) { + case USB_PID_TEVII_S650: + dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; + dw2104_properties.rc.legacy.rc_map_size = + ARRAY_SIZE(rc_map_tevii_table); + case USB_PID_DW2104: + reset = 1; + dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, + DW210X_WRITE_MSG); + /* break omitted intentionally */ + case USB_PID_DW3101: + reset = 0; + dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW210X_WRITE_MSG); + break; + case USB_PID_CINERGY_S: + case USB_PID_DW2102: + dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW210X_READ_MSG); + /* check STV0299 frontend */ + dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, + DW210X_READ_MSG); + if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { + dw2102_properties.i2c_algo = &dw2102_i2c_algo; + dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach; + break; + } else { + /* check STV0288 frontend */ + reset16[0] = 0xd0; + reset16[1] = 1; + reset16[2] = 0; + dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, + DW210X_READ_MSG); + if (reset16[2] == 0x11) { + dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; + break; + } + } + case 0x2101: + dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW210X_READ_MSG); + break; + } + + msleep(100); + kfree(p); + } + return ret; +} + +static struct dvb_usb_device_properties dw2102_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw2102.fw", + .no_reconnect = 1, + + .i2c_algo = &dw2102_serit_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_dw210x_table, + .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = dw2102_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .num_device_descs = 3, + .devices = { + {"DVBWorld DVB-S 2102 USB2.0", + {&dw2102_table[CYPRESS_DW2102], NULL}, + {NULL}, + }, + {"DVBWorld DVB-S 2101 USB2.0", + {&dw2102_table[CYPRESS_DW2101], NULL}, + {NULL}, + }, + {"TerraTec Cinergy S USB", + {&dw2102_table[TERRATEC_CINERGY_S], NULL}, + {NULL}, + }, + } +}; + +static struct dvb_usb_device_properties dw2104_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw2104.fw", + .no_reconnect = 1, + + .i2c_algo = &dw2104_i2c_algo, + .rc.legacy = { + .rc_map_table = rc_map_dw210x_table, + .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = dw2104_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .num_device_descs = 2, + .devices = { + { "DVBWorld DW2104 USB2.0", + {&dw2102_table[CYPRESS_DW2104], NULL}, + {NULL}, + }, + { "TeVii S650 USB2.0", + {&dw2102_table[TEVII_S650], NULL}, + {NULL}, + }, + } +}; + +static struct dvb_usb_device_properties dw3101_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw3101.fw", + .no_reconnect = 1, + + .i2c_algo = &dw3101_i2c_algo, + .rc.legacy = { + .rc_map_table = rc_map_dw210x_table, + .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = dw3101_frontend_attach, + .tuner_attach = dw3101_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .num_device_descs = 1, + .devices = { + { "DVBWorld DVB-C 3101 USB2.0", + {&dw2102_table[CYPRESS_DW3101], NULL}, + {NULL}, + }, + } +}; + +static struct dvb_usb_device_properties s6x0_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct s6x0_state), + .firmware = "dvb-usb-s630.fw", + .no_reconnect = 1, + + .i2c_algo = &s6x0_i2c_algo, + .rc.legacy = { + .rc_map_table = rc_map_tevii_table, + .rc_map_size = ARRAY_SIZE(rc_map_tevii_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = s6x0_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = zl100313_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .num_device_descs = 1, + .devices = { + {"TeVii S630 USB", + {&dw2102_table[TEVII_S630], NULL}, + {NULL}, + }, + } +}; + +struct dvb_usb_device_properties *p1100; +static struct dvb_usb_device_description d1100 = { + "Prof 1100 USB ", + {&dw2102_table[PROF_1100], NULL}, + {NULL}, +}; + +struct dvb_usb_device_properties *s660; +static struct dvb_usb_device_description d660 = { + "TeVii S660 USB", + {&dw2102_table[TEVII_S660], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_description d480_1 = { + "TeVii S480.1 USB", + {&dw2102_table[TEVII_S480_1], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_description d480_2 = { + "TeVii S480.2 USB", + {&dw2102_table[TEVII_S480_2], NULL}, + {NULL}, +}; + +struct dvb_usb_device_properties *p7500; +static struct dvb_usb_device_description d7500 = { + "Prof 7500 USB DVB-S2", + {&dw2102_table[PROF_7500], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_properties su3000_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct su3000_state), + .power_ctrl = su3000_power_ctrl, + .num_adapters = 1, + .identify_state = su3000_identify_state, + .i2c_algo = &su3000_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_su3000_table, + .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .read_mac_address = su3000_read_mac_address, + + .generic_bulk_ctrl_endpoint = 0x01, + + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = su3000_streaming_ctrl, + .frontend_attach = su3000_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + } + }}, + } + }, + .num_device_descs = 3, + .devices = { + { "SU3000HD DVB-S USB2.0", + { &dw2102_table[GENIATECH_SU3000], NULL }, + { NULL }, + }, + { "Terratec Cinergy S2 USB HD", + { &dw2102_table[TERRATEC_CINERGY_S2], NULL }, + { NULL }, + }, + { "X3M TV SPC1400HD PCI", + { &dw2102_table[X3M_SPC1400HD], NULL }, + { NULL }, + }, + } +}; + +static int dw2102_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + p1100 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!p1100) + return -ENOMEM; + /* copy default structure */ + /* fill only different fields */ + p1100->firmware = "dvb-usb-p1100.fw"; + p1100->devices[0] = d1100; + p1100->rc.legacy.rc_map_table = rc_map_tbs_table; + p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; + + s660 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!s660) { + kfree(p1100); + return -ENOMEM; + } + s660->firmware = "dvb-usb-s660.fw"; + s660->num_device_descs = 3; + s660->devices[0] = d660; + s660->devices[1] = d480_1; + s660->devices[2] = d480_2; + s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach; + + p7500 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!p7500) { + kfree(p1100); + kfree(s660); + return -ENOMEM; + } + p7500->firmware = "dvb-usb-p7500.fw"; + p7500->devices[0] = d7500; + p7500->rc.legacy.rc_map_table = rc_map_tbs_table; + p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; + + if (0 == dvb_usb_device_init(intf, &dw2102_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dw2104_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dw3101_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &s6x0_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, p1100, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, s660, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, p7500, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &su3000_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -ENODEV; +} + +static struct usb_driver dw2102_driver = { + .name = "dw2102", + .probe = dw2102_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dw2102_table, +}; + +module_usb_driver(dw2102_driver); + +MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," + " DVB-C 3101 USB2.0," + " TeVii S600, S630, S650, S660, S480," + " Prof 1100, 7500 USB2.0," + " Geniatech SU3000 devices"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/dw2102.h b/drivers/media/usb/dvb-usb/dw2102.h new file mode 100644 index 00000000000..5cd0b0eb6ce --- /dev/null +++ b/drivers/media/usb/dvb-usb/dw2102.h @@ -0,0 +1,9 @@ +#ifndef _DW2102_H_ +#define _DW2102_H_ + +#define DVB_USB_LOG_PREFIX "dw2102" +#include "dvb-usb.h" + +#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args) +#endif diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c new file mode 100644 index 00000000000..90a70c66a96 --- /dev/null +++ b/drivers/media/usb/dvb-usb/friio-fe.c @@ -0,0 +1,473 @@ +/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. + * + * Copyright (C) 2009 Akihiro Tsukada + * + * 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 +#include +#include + +#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, const 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 [+ 142857 (center freq. shift)] */ + f = freq / state->frontend.ops.info.frequency_stepsize; + /* add 399[1/7 MHZ] = 57MHz for the IF */ + f += 399; + /* add center frequency shift if necessary */ + if (f % 7 == 0) + f++; + 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_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; +} + + +/* filter out un-supported properties to notify users */ +static int jdvbt90502_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + int r = 0; + + switch (tvp->cmd) { + case DTV_DELIVERY_SYSTEM: + if (tvp->u.data != SYS_ISDBT) + r = -EINVAL; + break; + case DTV_CLEAR: + case DTV_TUNE: + case DTV_FREQUENCY: + break; + default: + r = -EINVAL; + } + return r; +} + +static int jdvbt90502_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + p->inversion = INVERSION_AUTO; + p->bandwidth_hz = 6000000; + p->code_rate_HP = FEC_AUTO; + p->code_rate_LP = FEC_AUTO; + p->modulation = QAM_64; + p->transmission_mode = TRANSMISSION_MODE_AUTO; + p->guard_interval = GUARD_INTERVAL_AUTO; + p->hierarchy = HIERARCHY_AUTO; + return 0; +} + +static int jdvbt90502_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + /** + * NOTE: ignore all the parameters 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); + + /* for recovery from DTV_CLEAN */ + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + + ret = jdvbt90502_pll_set_freq(state, p->frequency); + if (ret) { + deb_fe("%s:ret == %d\n", __func__, ret); + return -EREMOTEIO; + } + + 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}, +}; + +static const 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; + } + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + 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 = { + .delsys = { SYS_ISDBT }, + .info = { + .name = "Comtech JDVBT90502 ISDB-T", + .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, + .write = _jdvbt90502_write, + + .set_property = jdvbt90502_set_property, + + .set_frontend = jdvbt90502_set_frontend, + .get_frontend = jdvbt90502_get_frontend, + + .read_status = jdvbt90502_read_status, + .read_signal_strength = jdvbt90502_read_signal_strength, +}; diff --git a/drivers/media/usb/dvb-usb/friio.c b/drivers/media/usb/dvb-usb/friio.c new file mode 100644 index 00000000000..474a17e4db0 --- /dev/null +++ b/drivers/media/usb/dvb-usb/friio.c @@ -0,0 +1,522 @@ +/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. + * + * Copyright (C) 2009 Akihiro Tsukada + * + * 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; + u32 mask; + u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + 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); + + kfree(buf); + 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, *wbuf; + + deb_info("%s called.\n", __func__); + + wbuf = kmalloc(3, GFP_KERNEL); + if (!wbuf) + return -ENOMEM; + + rbuf = kmalloc(2, GFP_KERNEL); + if (!rbuf) { + kfree(wbuf); + return -ENOMEM; + } + + /* 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: + kfree(wbuf); + kfree(rbuf); + 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_adap[0].fe = jdvbt90502_attach(adap->dev); + if (adap->fe_adap[0].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, +}; + +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. */ + { + .num_frontends = 1, + .fe = {{ + .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_usb_driver(friio_driver); + +MODULE_AUTHOR("Akihiro Tsukada "); +MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver"); +MODULE_VERSION("0.2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/friio.h b/drivers/media/usb/dvb-usb/friio.h new file mode 100644 index 00000000000..0f461ca10cb --- /dev/null +++ b/drivers/media/usb/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 + * + * 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) control: 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/drivers/media/usb/dvb-usb/gp8psk-fe.c b/drivers/media/usb/dvb-usb/gp8psk-fe.c new file mode 100644 index 00000000000..67957dd99ed --- /dev/null +++ b/drivers/media/usb/dvb-usb/gp8psk-fe.c @@ -0,0 +1,369 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module + * + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 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 "gp8psk.h" + +struct gp8psk_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; + u8 lock; + u16 snr; + unsigned long next_status_check; + unsigned long status_check_interval; +}; + +static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 status; + gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); + return status & bmDCtuned; +} + +static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); +} + +static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) +{ + u8 buf[6]; + if (time_after(jiffies,st->next_status_check)) { + gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); + gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); + st->snr = (buf[1]) << 8 | buf[0]; + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + + if (st->lock) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 100; + return 0; +} + +/* not supported by this Frontend */ +static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + (void) fe; + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + (void) fe; + *unc = 0; + return 0; +} + +static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + *snr = st->snr; + return 0; +} + +static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (st->snr > 0xf00) + *strength = 0xffff; + else + *strength = (st->snr << 4) + st->snr; /* snr*17 */ + return 0; +} + +static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 cmd[10]; + u32 freq = c->frequency * 1000; + int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); + + deb_fe("%s()\n", __func__); + + cmd[4] = freq & 0xff; + cmd[5] = (freq >> 8) & 0xff; + cmd[6] = (freq >> 16) & 0xff; + cmd[7] = (freq >> 24) & 0xff; + + /* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */ + if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8) + c->delivery_system = SYS_TURBO; + + switch (c->delivery_system) { + case SYS_DVBS: + if (c->modulation != QPSK) { + deb_fe("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + c->fec_inner = FEC_AUTO; + break; + case SYS_DVBS2: /* kept for backwards compatibility */ + deb_fe("%s: DVB-S2 delivery system selected\n", __func__); + break; + case SYS_TURBO: + deb_fe("%s: Turbo-FEC delivery system selected\n", __func__); + break; + + default: + deb_fe("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + cmd[0] = c->symbol_rate & 0xff; + cmd[1] = (c->symbol_rate >> 8) & 0xff; + cmd[2] = (c->symbol_rate >> 16) & 0xff; + cmd[3] = (c->symbol_rate >> 24) & 0xff; + switch (c->modulation) { + case QPSK: + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_tuned_to_DCII(fe)) + gp8psk_bcm4500_reload(state->d); + switch (c->fec_inner) { + case FEC_1_2: + cmd[9] = 0; break; + case FEC_2_3: + cmd[9] = 1; break; + case FEC_3_4: + cmd[9] = 2; break; + case FEC_5_6: + cmd[9] = 3; break; + case FEC_7_8: + cmd[9] = 4; break; + case FEC_AUTO: + cmd[9] = 5; break; + default: + cmd[9] = 5; break; + } + if (c->delivery_system == SYS_TURBO) + cmd[8] = ADV_MOD_TURBO_QPSK; + else + cmd[8] = ADV_MOD_DVB_QPSK; + break; + case PSK_8: /* PSK_8 is for compatibility with DN */ + cmd[8] = ADV_MOD_TURBO_8PSK; + switch (c->fec_inner) { + case FEC_2_3: + cmd[9] = 0; break; + case FEC_3_4: + cmd[9] = 1; break; + case FEC_3_5: + cmd[9] = 2; break; + case FEC_5_6: + cmd[9] = 3; break; + case FEC_8_9: + cmd[9] = 4; break; + default: + cmd[9] = 0; break; + } + break; + case QAM_16: /* QAM_16 is for compatibility with DN */ + cmd[8] = ADV_MOD_TURBO_16QAM; + cmd[9] = 0; + break; + default: /* Unknown modulation */ + deb_fe("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + gp8psk_set_tuner_mode(fe, 0); + gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); + + state->lock = 0; + state->next_status_check = jiffies; + state->status_check_interval = 200; + + return 0; +} + +static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + + deb_fe("%s\n",__func__); + + if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, + m->msg, m->msg_len)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, + fe_sec_mini_cmd_t burst) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 cmd; + + deb_fe("%s\n",__func__); + + /* These commands are certainly wrong */ + cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; + + if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, + &cmd, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + + if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, + (tone == SEC_TONE_ON), 0, NULL, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + + if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, + voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); +} + +static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + u8 cmd = sw_cmd & 0x7f; + + if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, + NULL, 0)) { + return -EINVAL; + } + if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), + 0, NULL, 0)) { + return -EINVAL; + } + + return 0; +} + +static void gp8psk_fe_release(struct dvb_frontend* fe) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops gp8psk_fe_ops; + +struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) +{ + struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + goto success; +error: + return NULL; +success: + return &s->fe; +} + + +static struct dvb_frontend_ops gp8psk_fe_ops = { + .delsys = { SYS_DVBS }, + .info = { + .name = "Genpix DVB-S", + .frequency_min = 800000, + .frequency_max = 2250000, + .frequency_stepsize = 100, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + /* + * FE_CAN_QAM_16 is for compatibility + * (Myth incorrectly detects Turbo-QPSK as plain QAM-16) + */ + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC + }, + + .release = gp8psk_fe_release, + + .init = NULL, + .sleep = NULL, + + .set_frontend = gp8psk_fe_set_frontend, + + .get_tune_settings = gp8psk_fe_get_tune_settings, + + .read_status = gp8psk_fe_read_status, + .read_ber = gp8psk_fe_read_ber, + .read_signal_strength = gp8psk_fe_read_signal_strength, + .read_snr = gp8psk_fe_read_snr, + .read_ucblocks = gp8psk_fe_read_unc_blocks, + + .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, + .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, + .set_tone = gp8psk_fe_set_tone, + .set_voltage = gp8psk_fe_set_voltage, + .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, + .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage +}; diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c new file mode 100644 index 00000000000..5d0384dd45b --- /dev/null +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -0,0 +1,328 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module + * + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 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 "gp8psk.h" + +/* debug */ +static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; +int dvb_usb_gp8psk_debug; +module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) +{ + return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); +} + +static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) +{ + return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); +} + +static void gp8psk_info(struct dvb_usb_device *d) +{ + u8 fpga_vers, fw_vers[6]; + + if (!gp8psk_get_fw_version(d, fw_vers)) + info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", + fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), + 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); + else + info("failed to get FW version"); + + if (!gp8psk_get_fpga_version(d, &fpga_vers)) + info("FPGA Version = %i", fpga_vers); + else + info("failed to get FPGA version"); +} + +int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = 0,try = 0; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + while (ret >= 0 && ret != blen && try < 3) { + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value,index,b,blen, + 2000); + deb_info("reading number %d (ret: %d)\n",try,ret); + try++; + } + + if (ret < 0 || ret != blen) { + warn("usb in %d operation failed.", req); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000) != blen) { + warn("usb out operation failed."); + ret = -EIO; + } else + ret = 0; + mutex_unlock(&d->usb_mutex); + + return ret; +} + +static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) +{ + int ret; + const struct firmware *fw = NULL; + const u8 *ptr; + u8 *buf; + if ((ret = request_firmware(&fw, bcm4500_firmware, + &d->udev->dev)) != 0) { + err("did not find the bcm4500 firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + bcm4500_firmware,ret); + return ret; + } + + ret = -EINVAL; + + if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) + goto out_rel_fw; + + info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); + + ptr = fw->data; + buf = kmalloc(64, GFP_KERNEL | GFP_DMA); + if (!buf) { + ret = -ENOMEM; + goto out_rel_fw; + } + + while (ptr[0] != 0xff) { + u16 buflen = ptr[0] + 4; + if (ptr + buflen >= fw->data + fw->size) { + err("failed to load bcm4500 firmware."); + goto out_free; + } + memcpy(buf, ptr, buflen); + if (dvb_usb_generic_write(d, buf, buflen)) { + err("failed to load bcm4500 firmware."); + goto out_free; + } + ptr += buflen; + } + + ret = 0; + +out_free: + kfree(buf); +out_rel_fw: + release_firmware(fw); + + return ret; +} + +static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 status, buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + + if (onoff) { + gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + if (! (status & bm8pskStarted)) { /* started */ + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + gp8psk_info(d); + } + + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return -EINVAL; + + if (! (status & bmIntersilOn)) /* LNB Power */ + if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, + &buf, 1)) + return -EINVAL; + + /* Set DVB mode to 1 */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return -EINVAL; + /* Abort possible TS (if previous tune crashed) */ + if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) + return -EINVAL; + } else { + /* Turn off LNB power */ + if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); + } + return 0; +} + +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return -EINVAL; + return 0; +} + +static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); +} + +static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev); + return 0; +} + +static struct dvb_usb_device_properties gp8psk_properties; + +static int gp8psk_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ret = dvb_usb_device_init(intf, &gp8psk_properties, + THIS_MODULE, NULL, adapter_nr); + if (ret == 0) { + info("found Genpix USB device pID = %x (hex)", + le16_to_cpu(udev->descriptor.idProduct)); + } + return ret; +} + +static struct usb_device_id gp8psk_usb_table [] = { + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, +/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); + +static struct dvb_usb_device_properties gp8psk_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-gp8psk-01.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = gp8psk_streaming_ctrl, + .frontend_attach = gp8psk_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }}, + } + }, + .power_ctrl = gp8psk_power_ctrl, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 4, + .devices = { + { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", + .cold_ids = { &gp8psk_usb_table[0], NULL }, + .warm_ids = { &gp8psk_usb_table[1], NULL }, + }, + { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[2], NULL }, + }, + { .name = "Genpix SkyWalker-1 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[3], NULL }, + }, + { .name = "Genpix SkyWalker-2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[4], NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver gp8psk_usb_driver = { + .name = "dvb_usb_gp8psk", + .probe = gp8psk_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = gp8psk_usb_table, +}; + +module_usb_driver(gp8psk_usb_driver); + +MODULE_AUTHOR("Alan Nisota "); +MODULE_DESCRIPTION("Driver for Genpix DVB-S"); +MODULE_VERSION("1.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/gp8psk.h b/drivers/media/usb/dvb-usb/gp8psk.h new file mode 100644 index 00000000000..ed32b9da484 --- /dev/null +++ b/drivers/media/usb/dvb-usb/gp8psk.h @@ -0,0 +1,100 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module + * + * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 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_GP8PSK_H_ +#define _DVB_USB_GP8PSK_H_ + +#define DVB_USB_LOG_PREFIX "gp8psk" +#include "dvb-usb.h" + +extern int dvb_usb_gp8psk_debug; +#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args) + +/* Twinhan Vendor requests */ +#define TH_COMMAND_IN 0xC0 +#define TH_COMMAND_OUT 0xC1 + +/* gp8psk commands */ + +#define GET_8PSK_CONFIG 0x80 /* in */ +#define SET_8PSK_CONFIG 0x81 +#define I2C_WRITE 0x83 +#define I2C_READ 0x84 +#define ARM_TRANSFER 0x85 +#define TUNE_8PSK 0x86 +#define GET_SIGNAL_STRENGTH 0x87 /* in */ +#define LOAD_BCM4500 0x88 +#define BOOT_8PSK 0x89 /* in */ +#define START_INTERSIL 0x8A /* in */ +#define SET_LNB_VOLTAGE 0x8B +#define SET_22KHZ_TONE 0x8C +#define SEND_DISEQC_COMMAND 0x8D +#define SET_DVB_MODE 0x8E +#define SET_DN_SWITCH 0x8F +#define GET_SIGNAL_LOCK 0x90 /* in */ +#define GET_FW_VERS 0x92 +#define GET_SERIAL_NUMBER 0x93 /* in */ +#define USE_EXTRA_VOLT 0x94 +#define GET_FPGA_VERS 0x95 +#define CW3K_INIT 0x9d + +/* PSK_configuration bits */ +#define bm8pskStarted 0x01 +#define bm8pskFW_Loaded 0x02 +#define bmIntersilOn 0x04 +#define bmDVBmode 0x08 +#define bm22kHz 0x10 +#define bmSEL18V 0x20 +#define bmDCtuned 0x40 +#define bmArmed 0x80 + +/* Satellite modulation modes */ +#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ +#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ +#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ +#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ + +#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ +#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ +#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ +#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ +#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ +#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ + +#define GET_USB_SPEED 0x07 + +#define RESET_FX2 0x13 + +#define FW_VERSION_READ 0x0B +#define VENDOR_STRING_READ 0x0C +#define PRODUCT_STRING_READ 0x0D +#define FW_BCD_VERSION_READ 0x14 + +/* firmware revision id's */ +#define GP8PSK_FW_REV1 0x020604 +#define GP8PSK_FW_REV2 0x020704 +#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0]) + +extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); +extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); + +#endif diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c new file mode 100644 index 00000000000..288af29a8bb --- /dev/null +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -0,0 +1,1099 @@ +/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver + * + * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#include "m920x.h" + +#include "mt352.h" +#include "mt352_priv.h" +#include "qt1010.h" +#include "tda1004x.h" +#include "tda827x.h" + +#include +#include "tuner-simple.h" +#include + +/* debug */ +static int dvb_usb_m920x_debug; +module_param_named(debug,dvb_usb_m920x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid); + +static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, + u16 index, void *data, int size) +{ + int ret; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + request, USB_TYPE_VENDOR | USB_DIR_IN, + value, index, data, size, 2000); + if (ret < 0) { + printk(KERN_INFO "m920x_read = error: %d\n", ret); + return ret; + } + + if (ret != size) { + deb("m920x_read = no data\n"); + return -EIO; + } + + return 0; +} + +static inline int m920x_write(struct usb_device *udev, u8 request, + u16 value, u16 index) +{ + int ret; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + request, USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, NULL, 0, 2000); + + return ret; +} + +static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) +{ + int ret = 0, i, epi, flags = 0; + int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; + + /* Remote controller init. */ + if (d->props.rc.legacy.rc_query) { + deb("Initialising remote control\n"); + while (rc_seq->address) { + if ((ret = m920x_write(d->udev, M9206_CORE, + rc_seq->data, + rc_seq->address)) != 0) { + deb("Initialising remote control failed\n"); + return ret; + } + + rc_seq++; + } + + deb("Initialising remote control success\n"); + } + + for (i = 0; i < d->props.num_adapters; i++) + flags |= d->adapter[i].props.fe[0].caps; + + /* Some devices(Dposh) might crash if we attempt touch at all. */ + if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { + for (i = 0; i < d->props.num_adapters; i++) { + epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81; + + if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { + printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n"); + return -EINVAL; + } + + adap_enabled[epi] = 1; + } + + for (i = 0; i < M9206_MAX_ADAPTERS; i++) { + if (adap_enabled[i]) + continue; + + if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0) + return ret; + + if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0) + return ret; + } + } + + return ret; +} + +static int m920x_init_ep(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *alt; + + if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) { + deb("No alt found!\n"); + return -ENODEV; + } + + return usb_set_interface(udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); +} + +static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct m920x_state *m = d->priv; + int i, ret = 0; + u8 *rc_state; + + rc_state = kmalloc(2, GFP_KERNEL); + if (!rc_state) + return -ENOMEM; + + if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) + goto out; + + if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) + goto out; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) + if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) { + *event = d->props.rc.legacy.rc_map_table[i].keycode; + + switch(rc_state[0]) { + case 0x80: + *state = REMOTE_NO_KEY_PRESSED; + goto out; + + case 0x88: /* framing error or "invalid code" */ + case 0x99: + case 0xc0: + case 0xd8: + *state = REMOTE_NO_KEY_PRESSED; + m->rep_count = 0; + goto out; + + case 0x93: + case 0x92: + case 0x83: /* pinnacle PCTV310e */ + case 0x82: + m->rep_count = 0; + *state = REMOTE_KEY_PRESSED; + goto out; + + case 0x91: + case 0x81: /* pinnacle PCTV310e */ + /* prevent immediate auto-repeat */ + if (++m->rep_count > 2) + *state = REMOTE_KEY_REPEAT; + else + *state = REMOTE_NO_KEY_PRESSED; + goto out; + + default: + deb("Unexpected rc state %02x\n", rc_state[0]); + *state = REMOTE_NO_KEY_PRESSED; + goto out; + } + } + + if (rc_state[1] != 0) + deb("Unknown rc key %02x\n", rc_state[1]); + + *state = REMOTE_NO_KEY_PRESSED; + + out: + kfree(rc_state); + return ret; +} + +/* I2C */ +static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i, j; + int ret = 0; + + if (!num) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) { + /* For a 0 byte message, I think sending the address + * to index 0x80|0x40 would be the correct thing to + * do. However, zero byte messages are only used for + * probing, and since we don't know how to get the + * slave's ack, we can't probe. */ + ret = -ENOTSUPP; + goto unlock; + } + /* Send START & address/RW bit */ + if (!(msg[i].flags & I2C_M_NOSTART)) { + if ((ret = m920x_write(d->udev, M9206_I2C, + (msg[i].addr << 1) | + (msg[i].flags & I2C_M_RD ? 0x01 : 0), 0x80)) != 0) + goto unlock; + /* Should check for ack here, if we knew how. */ + } + if (msg[i].flags & I2C_M_RD) { + for (j = 0; j < msg[i].len; j++) { + /* Last byte of transaction? + * Send STOP, otherwise send ACK. */ + int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01; + + if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, + 0x20 | stop, + &msg[i].buf[j], 1)) != 0) + goto unlock; + } + } else { + for (j = 0; j < msg[i].len; j++) { + /* Last byte of transaction? Then send STOP. */ + int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00; + + if ((ret = m920x_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0) + goto unlock; + /* Should check for ack here too. */ + } + } + } + ret = num; + + unlock: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 m920x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm m920x_i2c_algo = { + .master_xfer = m920x_i2c_xfer, + .functionality = m920x_i2c_func, +}; + +/* pid filter */ +static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid) +{ + int ret = 0; + + if (pid >= 0x8000) + return -EINVAL; + + pid |= 0x8000; + + if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) + return ret; + + if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) + return ret; + + return ret; +} + +static int m920x_update_filters(struct dvb_usb_adapter *adap) +{ + struct m920x_state *m = adap->dev->priv; + int enabled = m->filtering_enabled[adap->id]; + int i, ret = 0, filter = 0; + int ep = adap->props.fe[0].stream.endpoint; + + for (i = 0; i < M9206_MAX_FILTERS; i++) + if (m->filters[adap->id][i] == 8192) + enabled = 0; + + /* Disable all filters */ + if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0) + return ret; + + for (i = 0; i < M9206_MAX_FILTERS; i++) + if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0) + return ret; + + /* Set */ + if (enabled) { + for (i = 0; i < M9206_MAX_FILTERS; i++) { + if (m->filters[adap->id][i] == 0) + continue; + + if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0) + return ret; + + filter++; + } + } + + return ret; +} + +static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct m920x_state *m = adap->dev->priv; + + m->filtering_enabled[adap->id] = onoff ? 1 : 0; + + return m920x_update_filters(adap); +} + +static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + struct m920x_state *m = adap->dev->priv; + + m->filters[adap->id][index] = onoff ? pid : 0; + + return m920x_update_filters(adap); +} + +static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw) +{ + u16 value, index, size; + u8 *read, *buff; + int i, pass, ret = 0; + + buff = kmalloc(65536, GFP_KERNEL); + if (buff == NULL) + return -ENOMEM; + + read = kmalloc(4, GFP_KERNEL); + if (!read) { + kfree(buff); + return -ENOMEM; + } + + if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) + goto done; + deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); + + if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) + goto done; + deb("%x\n", read[0]); + + for (pass = 0; pass < 2; pass++) { + for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { + value = get_unaligned_le16(fw->data + i); + i += sizeof(u16); + + index = get_unaligned_le16(fw->data + i); + i += sizeof(u16); + + size = get_unaligned_le16(fw->data + i); + i += sizeof(u16); + + if (pass == 1) { + /* Will stall if using fw->data ... */ + memcpy(buff, fw->data + i, size); + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + M9206_FW, + USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, buff, size, 20); + if (ret != size) { + deb("error while uploading fw!\n"); + ret = -EIO; + goto done; + } + msleep(3); + } + i += size; + } + if (i != fw->size) { + deb("bad firmware file!\n"); + ret = -EINVAL; + goto done; + } + } + + msleep(36); + + /* m920x will disconnect itself from the bus after this. */ + (void) m920x_write(udev, M9206_CORE, 0x01, M9206_FW_GO); + deb("firmware uploaded!\n"); + + done: + kfree(read); + kfree(buff); + + return ret; +} + +/* Callbacks for DVB USB */ +static int m920x_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + struct usb_host_interface *alt; + + alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1); + *cold = (alt == NULL) ? 1 : 0; + + return 0; +} + +/* demod configurations */ +static int m920x_mt352_demod_init(struct dvb_frontend *fe) +{ + int ret; + u8 config[] = { CONFIG, 0x3d }; + u8 clock[] = { CLOCK_CTL, 0x30 }; + u8 reset[] = { RESET, 0x80 }; + u8 adc_ctl[] = { ADC_CTL_1, 0x40 }; + u8 agc[] = { AGC_TARGET, 0x1c, 0x20 }; + u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 }; + u8 unk1[] = { 0x93, 0x1a }; + u8 unk2[] = { 0xb5, 0x7a }; + + deb("Demod init!\n"); + + if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0) + return ret; + if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0) + return ret; + if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0) + return ret; + if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0) + return ret; + if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0) + return ret; + if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0) + return ret; + if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0) + return ret; + if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0) + return ret; + + return 0; +} + +static struct mt352_config m920x_mt352_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .demod_init = m920x_mt352_demod_init, +}; + +static struct tda1004x_config m920x_tda10046_08_config = { + .demod_address = 0x08, + .invert = 0, + .invert_oclk = 0, + .ts_mode = TDA10046_TS_SERIAL, + .xtal_freq = TDA10046_XTAL_16M, + .if_freq = TDA10046_FREQ_045, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GPTRI, + .request_firmware = NULL, +}; + +static struct tda1004x_config m920x_tda10046_0b_config = { + .demod_address = 0x0b, + .invert = 0, + .invert_oclk = 0, + .ts_mode = TDA10046_TS_SERIAL, + .xtal_freq = TDA10046_XTAL_16M, + .if_freq = TDA10046_FREQ_045, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GPTRI, + .request_firmware = NULL, /* uses firmware EEPROM */ +}; + +/* tuner configurations */ +static struct qt1010_config m920x_qt1010_config = { + .i2c_address = 0x62 +}; + +/* Callbacks for DVB USB */ +static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + adap->fe_adap[0].fe = dvb_attach(mt352_attach, + &m920x_mt352_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) + return -EIO; + + return 0; +} + +static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + adap->fe_adap[0].fe = dvb_attach(tda10046_attach, + &m920x_tda10046_08_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) + return -EIO; + + return 0; +} + +static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + adap->fe_adap[0].fe = dvb_attach(tda10046_attach, + &m920x_tda10046_0b_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) + return -EIO; + + return 0; +} + +static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) + return -ENODEV; + + return 0; +} + +static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) + return -ENODEV; + + return 0; +} + +static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) + return -ENODEV; + + return 0; +} + +static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3); + return 0; +} + +/* device-specific initialization */ +static struct m920x_inits megasky_rc_init [] = { + { M9206_RC_INIT2, 0xa8 }, + { M9206_RC_INIT1, 0x51 }, + { } /* terminating entry */ +}; + +static struct m920x_inits tvwalkertwin_rc_init [] = { + { M9206_RC_INIT2, 0x00 }, + { M9206_RC_INIT1, 0xef }, + { 0xff28, 0x00 }, + { 0xff23, 0x00 }, + { 0xff21, 0x30 }, + { } /* terminating entry */ +}; + +static struct m920x_inits pinnacle310e_init[] = { + /* without these the tuner don't work */ + { 0xff20, 0x9b }, + { 0xff22, 0x70 }, + + /* rc settings */ + { 0xff50, 0x80 }, + { M9206_RC_INIT1, 0x00 }, + { M9206_RC_INIT2, 0xff }, + { } /* terminating entry */ +}; + +/* ir keymaps */ +static struct rc_map_table rc_map_megasky_table[] = { + { 0x0012, KEY_POWER }, + { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */ + { 0x0002, KEY_CHANNELUP }, + { 0x0005, KEY_CHANNELDOWN }, + { 0x0003, KEY_VOLUMEUP }, + { 0x0006, KEY_VOLUMEDOWN }, + { 0x0004, KEY_MUTE }, + { 0x0007, KEY_OK }, /* TS */ + { 0x0008, KEY_STOP }, + { 0x0009, KEY_MENU }, /* swap */ + { 0x000a, KEY_REWIND }, + { 0x001b, KEY_PAUSE }, + { 0x001f, KEY_FASTFORWARD }, + { 0x000c, KEY_RECORD }, + { 0x000d, KEY_CAMERA }, /* screenshot */ + { 0x000e, KEY_COFFEE }, /* "MTS" */ +}; + +static struct rc_map_table rc_map_tvwalkertwin_table[] = { + { 0x0001, KEY_ZOOM }, /* Full Screen */ + { 0x0002, KEY_CAMERA }, /* snapshot */ + { 0x0003, KEY_MUTE }, + { 0x0004, KEY_REWIND }, + { 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */ + { 0x0006, KEY_FASTFORWARD }, + { 0x0007, KEY_RECORD }, + { 0x0008, KEY_STOP }, + { 0x0009, KEY_TIME }, /* Timeshift */ + { 0x000c, KEY_COFFEE }, /* Recall */ + { 0x000e, KEY_CHANNELUP }, + { 0x0012, KEY_POWER }, + { 0x0015, KEY_MENU }, /* source */ + { 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */ + { 0x001a, KEY_CHANNELDOWN }, + { 0x001b, KEY_VOLUMEDOWN }, + { 0x001e, KEY_VOLUMEUP }, +}; + +static struct rc_map_table rc_map_pinnacle310e_table[] = { + { 0x16, KEY_POWER }, + { 0x17, KEY_FAVORITES }, + { 0x0f, KEY_TEXT }, + { 0x48, KEY_PROGRAM }, /* preview */ + { 0x1c, KEY_EPG }, + { 0x04, KEY_LIST }, /* record list */ + { 0x03, KEY_1 }, + { 0x01, KEY_2 }, + { 0x06, KEY_3 }, + { 0x09, KEY_4 }, + { 0x1d, KEY_5 }, + { 0x1f, KEY_6 }, + { 0x0d, KEY_7 }, + { 0x19, KEY_8 }, + { 0x1b, KEY_9 }, + { 0x15, KEY_0 }, + { 0x0c, KEY_CANCEL }, + { 0x4a, KEY_CLEAR }, + { 0x13, KEY_BACK }, + { 0x00, KEY_TAB }, + { 0x4b, KEY_UP }, + { 0x4e, KEY_LEFT }, + { 0x52, KEY_RIGHT }, + { 0x51, KEY_DOWN }, + { 0x4f, KEY_ENTER }, /* could also be KEY_OK */ + { 0x1e, KEY_VOLUMEUP }, + { 0x0a, KEY_VOLUMEDOWN }, + { 0x05, KEY_CHANNELUP }, + { 0x02, KEY_CHANNELDOWN }, + { 0x11, KEY_RECORD }, + { 0x14, KEY_PLAY }, + { 0x4c, KEY_PAUSE }, + { 0x1a, KEY_STOP }, + { 0x40, KEY_REWIND }, + { 0x12, KEY_FASTFORWARD }, + { 0x41, KEY_PREVIOUSSONG }, /* Replay */ + { 0x42, KEY_NEXTSONG }, /* Skip */ + { 0x54, KEY_CAMERA }, /* Capture */ +/* { 0x50, KEY_SAP }, */ /* Sap */ + { 0x47, KEY_CYCLEWINDOWS }, /* Pip */ + { 0x4d, KEY_SCREEN }, /* FullScreen */ + { 0x08, KEY_SUBTITLE }, + { 0x0e, KEY_MUTE }, +/* { 0x49, KEY_LR }, */ /* L/R */ + { 0x07, KEY_SLEEP }, /* Hibernate */ + { 0x08, KEY_VIDEO }, /* A/V */ + { 0x0e, KEY_MENU }, /* Recall */ + { 0x45, KEY_ZOOMIN }, + { 0x46, KEY_ZOOMOUT }, + { 0x18, KEY_RED }, /* Red */ + { 0x53, KEY_GREEN }, /* Green */ + { 0x5e, KEY_YELLOW }, /* Yellow */ + { 0x5f, KEY_BLUE }, /* Blue */ +}; + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties megasky_properties; +static struct dvb_usb_device_properties digivox_mini_ii_properties; +static struct dvb_usb_device_properties tvwalkertwin_properties; +static struct dvb_usb_device_properties dposh_properties; +static struct dvb_usb_device_properties pinnacle_pctv310e_properties; + +static int m920x_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d = NULL; + int ret; + struct m920x_inits *rc_init_seq = NULL; + int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; + + deb("Probing for m920x device at interface %d\n", bInterfaceNumber); + + if (bInterfaceNumber == 0) { + /* Single-tuner device, or first interface on + * multi-tuner device + */ + + ret = dvb_usb_device_init(intf, &megasky_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + rc_init_seq = megasky_rc_init; + goto found; + } + + ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + /* No remote control, so no rc_init_seq */ + goto found; + } + + /* This configures both tuners on the TV Walker Twin */ + ret = dvb_usb_device_init(intf, &tvwalkertwin_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + rc_init_seq = tvwalkertwin_rc_init; + goto found; + } + + ret = dvb_usb_device_init(intf, &dposh_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + /* Remote controller not supported yet. */ + goto found; + } + + ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + rc_init_seq = pinnacle310e_init; + goto found; + } + + return ret; + } else { + /* Another interface on a multi-tuner device */ + + /* The LifeView TV Walker Twin gets here, but struct + * tvwalkertwin_properties already configured both + * tuners, so there is nothing for us to do here + */ + } + + found: + if ((ret = m920x_init_ep(intf)) < 0) + return ret; + + if (d && (ret = m920x_init(d, rc_init_seq)) != 0) + return ret; + + return ret; +} + +static struct usb_device_id m920x_table [] = { + { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_MSI_DIGI_VOX_MINI_II) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) }, + { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) }, + { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, m920x_table); + +static struct dvb_usb_device_properties megasky_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-megasky-02.fw", + .download_firmware = m920x_firmware_download, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_megasky_table, + .rc_map_size = ARRAY_SIZE(rc_map_megasky_table), + .rc_query = m920x_rc_query, + }, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_mt352_frontend_attach, + .tuner_attach = m920x_qt1010_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "MSI Mega Sky 580 DVB-T USB2.0", + { &m920x_table[0], NULL }, + { NULL }, + } + } +}; + +static struct dvb_usb_device_properties digivox_mini_ii_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-digivox-02.fw", + .download_firmware = m920x_firmware_download, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_tda10046_08_frontend_attach, + .tuner_attach = m920x_tda8275_60_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 0x4000, + } + } + }, + }}, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "MSI DIGI VOX mini II DVB-T USB2.0", + { &m920x_table[1], NULL }, + { NULL }, + }, + } +}; + +/* LifeView TV Walker Twin support by Nick Andrew + * + * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A + * TDA10046 #0 is located at i2c address 0x08 + * TDA10046 #1 is located at i2c address 0x0b + * TDA8275A #0 is located at i2c address 0x60 + * TDA8275A #1 is located at i2c address 0x61 + */ +static struct dvb_usb_device_properties tvwalkertwin_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-tvwalkert.fw", + .download_firmware = m920x_firmware_download, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_tvwalkertwin_table, + .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table), + .rc_query = m920x_rc_query, + }, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 2, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_tda10046_08_frontend_attach, + .tuner_attach = m920x_tda8275_60_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }}, + }},{ + .num_frontends = 1, + .fe = {{ + + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_tda10046_0b_frontend_attach, + .tuner_attach = m920x_tda8275_61_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 512, + } + } + }}, + }, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { .name = "LifeView TV Walker Twin DVB-T USB2.0", + .cold_ids = { &m920x_table[2], NULL }, + .warm_ids = { &m920x_table[3], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties dposh_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dposh-01.fw", + .download_firmware = m920x_firmware_download, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + /* Hardware pid filters don't work with this device/firmware */ + + .frontend_attach = m920x_mt352_frontend_attach, + .tuner_attach = m920x_qt1010_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { .name = "Dposh DVB-T USB2.0", + .cold_ids = { &m920x_table[4], NULL }, + .warm_ids = { &m920x_table[5], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = NULL, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_pinnacle310e_table, + .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table), + .rc_query = m920x_rc_query, + }, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_mt352_frontend_attach, + .tuner_attach = m920x_fmd1216me_tuner_attach, + + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x84, + .u = { + .isoc = { + .framesperurb = 128, + .framesize = 564, + .interval = 1, + } + } + }, + }}, + } }, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "Pinnacle PCTV 310e", + { &m920x_table[6], NULL }, + { NULL }, + } + } +}; + +static struct usb_driver m920x_driver = { + .name = "dvb_usb_m920x", + .probe = m920x_probe, + .disconnect = dvb_usb_device_exit, + .id_table = m920x_table, +}; + +module_usb_driver(m920x_driver); + +MODULE_AUTHOR("Aapo Tahkola "); +MODULE_DESCRIPTION("DVB Driver for ULI M920x"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/usb/dvb-usb/m920x.h b/drivers/media/usb/dvb-usb/m920x.h new file mode 100644 index 00000000000..3c061518ffc --- /dev/null +++ b/drivers/media/usb/dvb-usb/m920x.h @@ -0,0 +1,77 @@ +#ifndef _DVB_USB_M920X_H_ +#define _DVB_USB_M920X_H_ + +#define DVB_USB_LOG_PREFIX "m920x" +#include "dvb-usb.h" + +#define deb(args...) dprintk(dvb_usb_m920x_debug,0x01,args) + +#define M9206_CORE 0x22 +#define M9206_RC_STATE 0xff51 +#define M9206_RC_KEY 0xff52 +#define M9206_RC_INIT1 0xff54 +#define M9206_RC_INIT2 0xff55 +#define M9206_FW_GO 0xff69 + +#define M9206_I2C 0x23 +#define M9206_FILTER 0x25 +#define M9206_FW 0x30 + +#define M9206_MAX_FILTERS 8 +#define M9206_MAX_ADAPTERS 4 + +/* +sequences found in logs: +[index value] +0x80 write addr +(0x00 out byte)* +0x40 out byte + +0x80 write addr +(0x00 out byte)* +0x80 read addr +(0x21 in byte)* +0x60 in byte + +this sequence works: +0x80 read addr +(0x21 in byte)* +0x60 in byte + +Guess at API of the I2C function: +I2C operation is done one byte at a time with USB control messages. The +index the messages is sent to is made up of a set of flags that control +the I2C bus state: +0x80: Send START condition. After a START condition, one would normally + always send the 7-bit slave I2C address as the 7 MSB, followed by + the read/write bit as the LSB. +0x40: Send STOP condition. This should be set on the last byte of an + I2C transaction. +0x20: Read a byte from the slave. As opposed to writing a byte to the + slave. The slave will normally not produce any data unless you + set the R/W bit to 1 when sending the slave's address after the + START condition. +0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read, + the master should send an ACK, that is pull SDA low during the 9th + clock cycle, after every byte but the last. This flags only makes + sense when bit 0x20 is set, indicating a read. + +What any other bits might mean, or how to get the slave's ACK/NACK +response to a write, is unknown. +*/ + +struct m920x_state { + u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS]; + int filtering_enabled[M9206_MAX_ADAPTERS]; + int rep_count; +}; + +/* Initialisation data for the m920x + */ + +struct m920x_inits { + u16 address; + u8 data; +}; + +#endif diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c new file mode 100644 index 00000000000..6c55384e2fc --- /dev/null +++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c @@ -0,0 +1,233 @@ +/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2 + * DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_rc(args...) dprintk(debug,0x01,args) +#define deb_ee(args...) dprintk(debug,0x02,args) + +/* Hauppauge NOVA-T USB2 keys */ +static struct rc_map_table rc_map_haupp_table[] = { + { 0x1e00, KEY_0 }, + { 0x1e01, KEY_1 }, + { 0x1e02, KEY_2 }, + { 0x1e03, KEY_3 }, + { 0x1e04, KEY_4 }, + { 0x1e05, KEY_5 }, + { 0x1e06, KEY_6 }, + { 0x1e07, KEY_7 }, + { 0x1e08, KEY_8 }, + { 0x1e09, KEY_9 }, + { 0x1e0a, KEY_KPASTERISK }, + { 0x1e0b, KEY_RED }, + { 0x1e0c, KEY_RADIO }, + { 0x1e0d, KEY_MENU }, + { 0x1e0e, KEY_GRAVE }, /* # */ + { 0x1e0f, KEY_MUTE }, + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + { 0x1e12, KEY_CHANNEL }, + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e18, KEY_VIDEO }, + { 0x1e19, KEY_AUDIO }, + { 0x1e1a, KEY_IMAGES }, + { 0x1e1b, KEY_EPG }, + { 0x1e1c, KEY_TV }, + { 0x1e1e, KEY_NEXT }, + { 0x1e1f, KEY_BACK }, + { 0x1e20, KEY_CHANNELUP }, + { 0x1e21, KEY_CHANNELDOWN }, + { 0x1e24, KEY_LAST }, /* Skip backwards */ + { 0x1e25, KEY_OK }, + { 0x1e29, KEY_BLUE}, + { 0x1e2e, KEY_GREEN }, + { 0x1e30, KEY_PAUSE }, + { 0x1e32, KEY_REWIND }, + { 0x1e34, KEY_FASTFORWARD }, + { 0x1e35, KEY_PLAY }, + { 0x1e36, KEY_STOP }, + { 0x1e37, KEY_RECORD }, + { 0x1e38, KEY_YELLOW }, + { 0x1e3b, KEY_GOTO }, + { 0x1e3d, KEY_POWER }, +}; + +/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key + * is delivered. No workaround yet, maybe a new firmware. + */ +static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; + u16 raw; + int i; + struct dibusb_device_state *st = d->priv; + + dvb_usb_generic_rw(d,cmd,2,key,5,0); + + *state = REMOTE_NO_KEY_PRESSED; + switch (key[0]) { + case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED: + raw = ((key[1] << 8) | key[2]) >> 3; + toggle = !!(raw & 0x800); + data = raw & 0x3f; + custom = (raw >> 6) & 0x1f; + + deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle); + + for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) { + if (rc5_data(&rc_map_haupp_table[i]) == data && + rc5_custom(&rc_map_haupp_table[i]) == custom) { + + deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]), + rc5_custom(&rc_map_haupp_table[i])); + + *event = rc_map_haupp_table[i].keycode; + *state = REMOTE_KEY_PRESSED; + if (st->old_toggle == toggle) { + if (st->last_repeat_count++ < 2) + *state = REMOTE_NO_KEY_PRESSED; + } else { + st->last_repeat_count = 0; + st->old_toggle = toggle; + } + break; + } + } + + break; + case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY: + default: + break; + } + + return 0; +} + +static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 b; + + mac[0] = 0x00; + mac[1] = 0x0d; + mac[2] = 0xfe; + + /* this is a complete guess, but works for my box */ + for (i = 136; i < 139; i++) { + dibusb_read_eeprom_byte(d,i, &b); + + mac[5 - (i - 136)] = b; + } + + return 0; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties nova_t_properties; + +static int nova_t_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &nova_t_properties, + THIS_MODULE, NULL, adapter_nr); +} + +/* do not change the order of the ID table */ +static struct usb_device_id nova_t_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, nova_t_table); + +static struct dvb_usb_device_properties nova_t_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-nova-t-usb2-02.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .size_of_priv = sizeof(struct dibusb_device_state), + + .power_ctrl = dibusb2_0_power_ctrl, + .read_mac_address = nova_t_read_mac_address, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_haupp_table, + .rc_map_size = ARRAY_SIZE(rc_map_haupp_table), + .rc_query = nova_t_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Hauppauge WinTV-NOVA-T usb2", + { &nova_t_table[0], NULL }, + { &nova_t_table[1], NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver nova_t_driver = { + .name = "dvb_usb_nova_t_usb2", + .probe = nova_t_probe, + .disconnect = dvb_usb_device_exit, + .id_table = nova_t_table, +}; + +module_usb_driver(nova_t_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c new file mode 100644 index 00000000000..c8a95042dfb --- /dev/null +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -0,0 +1,583 @@ +/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card +* +* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org) +* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the Free +* Software Foundation, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ + +#define DVB_USB_LOG_PREFIX "opera" + +#include "dvb-usb.h" +#include "stv0299.h" + +#define OPERA_READ_MSG 0 +#define OPERA_WRITE_MSG 1 +#define OPERA_I2C_TUNER 0xd1 + +#define READ_FX2_REG_REQ 0xba +#define READ_MAC_ADDR 0x08 +#define OPERA_WRITE_FX2 0xbb +#define OPERA_TUNER_REQ 0xb1 +#define REG_1F_SYMBOLRATE_BYTE0 0x1f +#define REG_20_SYMBOLRATE_BYTE1 0x20 +#define REG_21_SYMBOLRATE_BYTE2 0x21 + +#define ADDR_B600_VOLTAGE_13V (0x02) +#define ADDR_B601_VOLTAGE_18V (0x03) +#define ADDR_B1A6_STREAM_CTRL (0x04) +#define ADDR_B880_READ_REMOTE (0x05) + +struct opera1_state { + u32 last_key_pressed; +}; +struct rc_map_opera_table { + u32 keycode; + u32 event; +}; + +static int dvb_usb_opera1_debug; +module_param_named(debug, dvb_usb_opera1_debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." + DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + + +static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value, + u8 * data, u16 len, int flags) +{ + int ret; + u8 tmp; + u8 *buf; + unsigned int pipe = (flags == OPERA_READ_MSG) ? + usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0); + u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (flags == OPERA_WRITE_MSG) + memcpy(buf, data, len); + ret = usb_control_msg(dev, pipe, request, + request_type | USB_TYPE_VENDOR, value, 0x0, + buf, len, 2000); + + if (request == OPERA_TUNER_REQ) { + tmp = buf[0]; + if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR, + 0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) { + ret = 0; + goto out; + } + buf[0] = tmp; + } + if (flags == OPERA_READ_MSG) + memcpy(data, buf, len); +out: + kfree(buf); + return ret; +} + +/* I2C */ + +static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr, + u8 * buf, u16 len) +{ + int ret = 0; + u8 request; + u16 value; + + if (!dev) { + info("no usb_device"); + return -EINVAL; + } + if (mutex_lock_interruptible(&dev->usb_mutex) < 0) + return -EAGAIN; + + switch (addr>>1){ + case ADDR_B600_VOLTAGE_13V: + request=0xb6; + value=0x00; + break; + case ADDR_B601_VOLTAGE_18V: + request=0xb6; + value=0x01; + break; + case ADDR_B1A6_STREAM_CTRL: + request=0xb1; + value=0xa6; + break; + case ADDR_B880_READ_REMOTE: + request=0xb8; + value=0x80; + break; + default: + request=0xb1; + value=addr; + } + ret = opera1_xilinx_rw(dev->udev, request, + value, buf, len, + addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG); + + mutex_unlock(&dev->usb_mutex); + return ret; +} + +static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0, tmp = 0; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if ((tmp = opera1_usb_i2c_msgxfer(d, + (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), + msg[i].buf, + msg[i].len + )) != msg[i].len) { + break; + } + if (dvb_usb_opera1_debug & 0x10) + info("sending i2c mesage %d %d", tmp, msg[i].len); + } + mutex_unlock(&d->i2c_mutex); + return num; +} + +static u32 opera1_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm opera1_i2c_algo = { + .master_xfer = opera1_i2c_xfer, + .functionality = opera1_i2c_func, +}; + +static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + static u8 command_13v[1]={0x00}; + static u8 command_18v[1]={0x01}; + struct i2c_msg msg[] = { + {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, + }; + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + if (voltage == SEC_VOLTAGE_18) { + msg[0].addr = ADDR_B601_VOLTAGE_18V; + msg[0].buf = command_18v; + } + i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); + return 0; +} + +static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, + u32 ratio) +{ + stv0299_writereg(fe, 0x13, 0x98); + stv0299_writereg(fe, 0x14, 0x95); + stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff); + stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff); + stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0); + return 0; + +} +static u8 opera1_inittab[] = { + 0x00, 0xa1, + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, + 0x05, 0x05, + 0x06, 0x02, + 0x07, 0x00, + 0x0b, 0x00, + 0x0c, 0x01, + 0x0d, 0x81, + 0x0e, 0x44, + 0x0f, 0x19, + 0x10, 0x3f, + 0x11, 0x84, + 0x12, 0xda, + 0x13, 0x98, + 0x14, 0x95, + 0x15, 0xc9, + 0x16, 0xeb, + 0x17, 0x00, + 0x18, 0x19, + 0x19, 0x8b, + 0x1a, 0x00, + 0x1b, 0x82, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + REG_1F_SYMBOLRATE_BYTE0, 0x06, + REG_20_SYMBOLRATE_BYTE1, 0x50, + REG_21_SYMBOLRATE_BYTE2, 0x10, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x37, + 0x25, 0xbc, + 0x26, 0x00, + 0x27, 0x00, + 0x28, 0x00, + 0x29, 0x1e, + 0x2a, 0x14, + 0x2b, 0x1f, + 0x2c, 0x09, + 0x2d, 0x0a, + 0x2e, 0x00, + 0x2f, 0x00, + 0x30, 0x00, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x13, + 0xff, 0xff, +}; + +static struct stv0299_config opera1_stv0299_config = { + .demod_address = 0xd0>>1, + .min_delay_ms = 100, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .inittab = opera1_inittab, + .set_symbol_rate = opera1_stv0299_set_symbol_rate, +}; + +static int opera1_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config, + &d->dev->i2c_adap); + if ((d->fe_adap[0].fe) != NULL) { + d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage; + return 0; + } + info("not attached stv0299"); + return -EIO; +} + +static int opera1_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach( + dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1, + &adap->dev->i2c_adap, DVB_PLL_OPERA1 + ); + return 0; +} + +static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 val = onoff ? 0x01 : 0x00; + + if (dvb_usb_opera1_debug) + info("power %s", onoff ? "on" : "off"); + return opera1_xilinx_rw(d->udev, 0xb7, val, + &val, 1, OPERA_WRITE_MSG); +} + +static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + static u8 buf_start[2] = { 0xff, 0x03 }; + static u8 buf_stop[2] = { 0xff, 0x00 }; + struct i2c_msg start_tuner[] = { + {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2}, + }; + if (dvb_usb_opera1_debug) + info("streaming %s", onoff ? "on" : "off"); + i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1); + return 0; +} + +static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + u8 b_pid[3]; + struct i2c_msg msg[] = { + {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, + }; + if (dvb_usb_opera1_debug) + info("pidfilter index: %d pid: %d %s", index, pid, + onoff ? "on" : "off"); + b_pid[0] = (2 * index) + 4; + b_pid[1] = onoff ? (pid & 0xff) : (0x00); + b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00); + i2c_transfer(&adap->dev->i2c_adap, msg, 1); + return 0; +} + +static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) +{ + int u = 0x04; + u8 b_pid[3]; + struct i2c_msg msg[] = { + {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, + }; + if (dvb_usb_opera1_debug) + info("%s hw-pidfilter", onoff ? "enable" : "disable"); + for (; u < 0x7e; u += 2) { + b_pid[0] = u; + b_pid[1] = 0; + b_pid[2] = 0x80; + i2c_transfer(&adap->dev->i2c_adap, msg, 1); + } + return 0; +} + +static struct rc_map_table rc_map_opera1_table[] = { + {0x5fa0, KEY_1}, + {0x51af, KEY_2}, + {0x5da2, KEY_3}, + {0x41be, KEY_4}, + {0x0bf5, KEY_5}, + {0x43bd, KEY_6}, + {0x47b8, KEY_7}, + {0x49b6, KEY_8}, + {0x05fa, KEY_9}, + {0x45ba, KEY_0}, + {0x09f6, KEY_CHANNELUP}, /*chanup */ + {0x1be5, KEY_CHANNELDOWN}, /*chandown */ + {0x5da3, KEY_VOLUMEDOWN}, /*voldown */ + {0x5fa1, KEY_VOLUMEUP}, /*volup */ + {0x07f8, KEY_SPACE}, /*tab */ + {0x1fe1, KEY_OK}, /*play ok */ + {0x1be4, KEY_ZOOM}, /*zoom */ + {0x59a6, KEY_MUTE}, /*mute */ + {0x5ba5, KEY_RADIO}, /*tv/f */ + {0x19e7, KEY_RECORD}, /*rec */ + {0x01fe, KEY_STOP}, /*Stop */ + {0x03fd, KEY_PAUSE}, /*pause */ + {0x03fc, KEY_SCREEN}, /*<- -> */ + {0x07f9, KEY_CAMERA}, /*capture */ + {0x47b9, KEY_ESC}, /*exit */ + {0x43bc, KEY_POWER2}, /*power */ +}; + +static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) +{ + struct opera1_state *opst = dev->priv; + u8 rcbuffer[32]; + const u16 startmarker1 = 0x10ed; + const u16 startmarker2 = 0x11ec; + struct i2c_msg read_remote[] = { + {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32}, + }; + int i = 0; + u32 send_key = 0; + + if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) { + for (i = 0; i < 32; i++) { + if (rcbuffer[i]) + send_key |= 1; + if (i < 31) + send_key = send_key << 1; + } + if (send_key & 0x8000) + send_key = (send_key << 1) | (send_key >> 15 & 0x01); + + if (send_key == 0xffff && opst->last_key_pressed != 0) { + *state = REMOTE_KEY_REPEAT; + *event = opst->last_key_pressed; + return 0; + } + for (; send_key != 0;) { + if (send_key >> 16 == startmarker2) { + break; + } else if (send_key >> 16 == startmarker1) { + send_key = + (send_key & 0xfffeffff) | (startmarker1 << 16); + break; + } else + send_key >>= 1; + } + + if (send_key == 0) + return 0; + + send_key = (send_key & 0xffff) | 0x0100; + + for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) { + if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) { + *state = REMOTE_KEY_PRESSED; + *event = rc_map_opera1_table[i].keycode; + opst->last_key_pressed = + rc_map_opera1_table[i].keycode; + break; + } + opst->last_key_pressed = 0; + } + } else + *state = REMOTE_NO_KEY_PRESSED; + return 0; +} + +static struct usb_device_id opera1_table[] = { + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, + {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, opera1_table); + +static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + u8 command[] = { READ_MAC_ADDR }; + opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); + opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); + return 0; +} +static int opera1_xilinx_load_firmware(struct usb_device *dev, + const char *filename) +{ + const struct firmware *fw = NULL; + u8 *b, *p; + int ret = 0, i,fpgasize=40; + u8 testval; + info("start downloading fpga firmware %s",filename); + + if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems.", + filename); + return ret; + } else { + p = kmalloc(fw->size, GFP_KERNEL); + opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG); + if (p != NULL && testval != 0x67) { + + u8 reset = 0, fpga_command = 0; + memcpy(p, fw->data, fw->size); + /* clear fpga ? */ + opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, + OPERA_WRITE_MSG); + for (i = 0; i < fw->size;) { + if ( (fw->size - i) size-i; + } + b = (u8 *) p + i; + if (opera1_xilinx_rw + (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize, + OPERA_WRITE_MSG) != fpgasize + ) { + err("error while transferring firmware"); + ret = -EINVAL; + break; + } + i = i + fpgasize; + } + /* restart the CPU */ + if (ret || opera1_xilinx_rw + (dev, 0xa0, 0xe600, &reset, 1, + OPERA_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + } + } + kfree(p); + release_firmware(fw); + return ret; +} + +static struct dvb_usb_device_properties opera1_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-opera-01.fw", + .size_of_priv = sizeof(struct opera1_state), + + .power_ctrl = opera1_power_ctrl, + .i2c_algo = &opera1_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_opera1_table, + .rc_map_size = ARRAY_SIZE(rc_map_opera1_table), + .rc_interval = 200, + .rc_query = opera1_rc_query, + }, + .read_mac_address = opera1_read_mac_address, + .generic_bulk_ctrl_endpoint = 0x00, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = opera1_frontend_attach, + .streaming_ctrl = opera1_streaming_ctrl, + .tuner_attach = opera1_tuner_attach, + .caps = + DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter = opera1_pid_filter, + .pid_filter_ctrl = opera1_pid_filter_control, + .pid_filter_count = 252, + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .num_device_descs = 1, + .devices = { + {"Opera1 DVB-S USB2.0", + {&opera1_table[0], NULL}, + {&opera1_table[1], NULL}, + }, + } +}; + +static int opera1_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && + udev->descriptor.idVendor == USB_VID_OPERA1 && + opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0 + ) { + return -EINVAL; + } + + if (0 != dvb_usb_device_init(intf, &opera1_properties, + THIS_MODULE, NULL, adapter_nr)) + return -EINVAL; + return 0; +} + +static struct usb_driver opera1_driver = { + .name = "opera1", + .probe = opera1_probe, + .disconnect = dvb_usb_device_exit, + .id_table = opera1_table, +}; + +module_usb_driver(opera1_driver); + +MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org"); +MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de"); +MODULE_DESCRIPTION("Driver for Opera1 DVB-S device"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c new file mode 100644 index 00000000000..02e878577c3 --- /dev/null +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -0,0 +1,1063 @@ +/* + * PCTV 452e DVB driver + * + * Copyright (c) 2006-2008 Dominik Kuhlen + * + * TT connect S2-3650-CI Common Interface support, MAC readout + * Copyright (C) 2008 Michael H. Schimek + * + * 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. + */ + +/* dvb usb framework */ +#define DVB_USB_LOG_PREFIX "pctv452e" +#include "dvb-usb.h" + +/* Demodulator */ +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +/* Tuner */ +#include "stb6100.h" +#include "stb6100_cfg.h" +/* FE Power */ +#include "lnbp22.h" + +#include "dvb_ca_en50221.h" +#include "ttpci-eeprom.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define ISOC_INTERFACE_ALTERNATIVE 3 + +#define SYNC_BYTE_OUT 0xaa +#define SYNC_BYTE_IN 0x55 + +/* guessed: (copied from ttusb-budget) */ +#define PCTV_CMD_RESET 0x15 +/* command to poll IR receiver */ +#define PCTV_CMD_IR 0x1b +/* command to send I2C */ +#define PCTV_CMD_I2C 0x31 + +#define I2C_ADDR_STB0899 (0xd0 >> 1) +#define I2C_ADDR_STB6100 (0xc0 >> 1) +#define I2C_ADDR_LNBP22 (0x10 >> 1) +#define I2C_ADDR_24C16 (0xa0 >> 1) +#define I2C_ADDR_24C64 (0xa2 >> 1) + + +/* pctv452e sends us this amount of data for each issued usb-command */ +#define PCTV_ANSWER_LEN 64 +/* Wait up to 1000ms for device */ +#define PCTV_TIMEOUT 1000 + + +#define PCTV_LED_GPIO STB0899_GPIO01 +#define PCTV_LED_GREEN 0x82 +#define PCTV_LED_ORANGE 0x02 + +#define ci_dbg(format, arg...) \ +do { \ + if (0) \ + printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ + ": " format "\n" , ## arg); \ +} while (0) + +enum { + TT3650_CMD_CI_TEST = 0x40, + TT3650_CMD_CI_RD_CTRL, + TT3650_CMD_CI_WR_CTRL, + TT3650_CMD_CI_RD_ATTR, + TT3650_CMD_CI_WR_ATTR, + TT3650_CMD_CI_RESET, + TT3650_CMD_CI_SET_VIDEO_PORT +}; + + +static struct stb0899_postproc pctv45e_postproc[] = { + { PCTV_LED_GPIO, STB0899_GPIOPULLUP }, + { 0, 0 } +}; + +/* + * stores all private variables for communication with the PCTV452e DVB-S2 + */ +struct pctv452e_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; + + u8 c; /* transaction counter, wraps around... */ + u8 initialized; /* set to 1 if 0x15 has been sent */ + u16 last_rc_key; +}; + +static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, + unsigned int write_len, unsigned int read_len) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 buf[64]; + u8 id; + unsigned int rlen; + int ret; + + BUG_ON(NULL == data && 0 != (write_len | read_len)); + BUG_ON(write_len > 64 - 4); + BUG_ON(read_len > 64 - 4); + + id = state->c++; + + buf[0] = SYNC_BYTE_OUT; + buf[1] = id; + buf[2] = cmd; + buf[3] = write_len; + + memcpy(buf + 4, data, write_len); + + rlen = (read_len > 0) ? 64 : 0; + ret = dvb_usb_generic_rw(d, buf, 4 + write_len, + buf, rlen, /* delay_ms */ 0); + if (0 != ret) + goto failed; + + ret = -EIO; + if (SYNC_BYTE_IN != buf[0] || id != buf[1]) + goto failed; + + memcpy(data, buf + 4, read_len); + + return 0; + +failed: + err("CI error %d; %02X %02X %02X -> %*ph.", + ret, SYNC_BYTE_OUT, id, cmd, 3, buf); + + return ret; +} + +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, + u8 cmd, u8 *data, unsigned int write_len, + unsigned int read_len) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + int ret; + + mutex_lock(&state->ca_mutex); + ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + u8 buf[3]; + int ret; + + if (0 != slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); + + ci_dbg("%s %04x -> %d 0x%02x", + __func__, address, ret, buf[2]); + + if (ret < 0) + return ret; + + return buf[2]; +} + +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address, u8 value) +{ + u8 buf[3]; + + ci_dbg("%s %d 0x%04x 0x%02x", + __func__, slot, address, value); + + if (0 != slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + buf[2] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); +} + +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address) +{ + u8 buf[2]; + int ret; + + if (0 != slot) + return -EINVAL; + + buf[0] = address & 3; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); + + ci_dbg("%s 0x%02x -> %d 0x%02x", + __func__, address, ret, buf[1]); + + if (ret < 0) + return ret; + + return buf[1]; +} + +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address, + u8 value) +{ + u8 buf[2]; + + ci_dbg("%s %d 0x%02x 0x%02x", + __func__, slot, address, value); + + if (0 != slot) + return -EINVAL; + + buf[0] = address; + buf[1] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); +} + +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, + int slot, + int enable) +{ + u8 buf[1]; + int ret; + + ci_dbg("%s %d %d", __func__, slot, enable); + + if (0 != slot) + return -EINVAL; + + enable = !!enable; + buf[0] = enable; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + if (ret < 0) + return ret; + + if (enable != buf[0]) { + err("CI not %sabled.", enable ? "en" : "dis"); + return -EIO; + } + + return 0; +} + +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, /* enable */ 0); +} + +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, /* enable */ 1); +} + +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 buf[1]; + int ret; + + ci_dbg("%s %d", __func__, slot); + + if (0 != slot) + return -EINVAL; + + buf[0] = 0; + + mutex_lock(&state->ca_mutex); + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (0 != ret) + goto failed; + + msleep(500); + + buf[0] = 1; + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (0 != ret) + goto failed; + + msleep(500); + + buf[0] = 0; /* FTA */ + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + + failed: + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, + int slot, + int open) +{ + u8 buf[1]; + int ret; + + if (0 != slot) + return -EINVAL; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); + if (0 != ret) + return ret; + + if (1 == buf[0]) + return DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + + return 0; + +} + +static void tt3650_ci_uninit(struct dvb_usb_device *d) +{ + struct pctv452e_state *state; + + ci_dbg("%s", __func__); + + if (NULL == d) + return; + + state = (struct pctv452e_state *)d->priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + /* Error ignored. */ + tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0); + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + +static int tt3650_ci_init(struct dvb_usb_adapter *a) +{ + struct dvb_usb_device *d = a->dev; + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + int ret; + + ci_dbg("%s", __func__); + + mutex_init(&state->ca_mutex); + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; + state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; + state->ca.read_cam_control = tt3650_ci_read_cam_control; + state->ca.write_cam_control = tt3650_ci_write_cam_control; + state->ca.slot_reset = tt3650_ci_slot_reset; + state->ca.slot_shutdown = tt3650_ci_slot_shutdown; + state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; + state->ca.poll_slot_status = tt3650_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&a->dvb_adap, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (0 != ret) { + err("Cannot initialize CI: Error %d.", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + info("CI initialized."); + + return 0; +} + +#define CMD_BUFFER_SIZE 0x28 +static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, + const u8 *snd_buf, u8 snd_len, + u8 *rcv_buf, u8 rcv_len) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 buf[64]; + u8 id; + int ret; + + id = state->c++; + + ret = -EINVAL; + if (snd_len > 64 - 7 || rcv_len > 64 - 7) + goto failed; + + buf[0] = SYNC_BYTE_OUT; + buf[1] = id; + buf[2] = PCTV_CMD_I2C; + buf[3] = snd_len + 3; + buf[4] = addr << 1; + buf[5] = snd_len; + buf[6] = rcv_len; + + memcpy(buf + 7, snd_buf, snd_len); + + ret = dvb_usb_generic_rw(d, buf, 7 + snd_len, + buf, /* rcv_len */ 64, + /* delay_ms */ 0); + if (ret < 0) + goto failed; + + /* TT USB protocol error. */ + ret = -EIO; + if (SYNC_BYTE_IN != buf[0] || id != buf[1]) + goto failed; + + /* I2C device didn't respond as expected. */ + ret = -EREMOTEIO; + if (buf[5] < snd_len || buf[6] < rcv_len) + goto failed; + + memcpy(rcv_buf, buf + 7, rcv_len); + + return rcv_len; + +failed: + err("I2C error %d; %02X %02X %02X %02X %02X -> " + "%02X %02X %02X %02X %02X.", + ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len, + buf[0], buf[1], buf[4], buf[5], buf[6]); + + return ret; +} + +static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adapter); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; + int ret; + + if (msg[i].flags & I2C_M_RD) { + addr = msg[i].addr; + snd_buf = NULL; + snd_len = 0; + rcv_buf = msg[i].buf; + rcv_len = msg[i].len; + } else { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = NULL; + rcv_len = 0; + } + + ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, + rcv_len); + if (ret < rcv_len) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 }; + u8 rx[PCTV_ANSWER_LEN]; + int ret; + + info("%s: %d\n", __func__, i); + + if (!i) + return 0; + + if (state->initialized) + return 0; + + /* hmm where shoud this should go? */ + ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE); + if (ret != 0) + info("%s: Warning set interface returned: %d\n", + __func__, ret); + + /* this is a one-time initialization, dont know where to put */ + b0[1] = state->c++; + /* reset board */ + ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0); + if (ret) + return ret; + + b0[1] = state->c++; + b0[4] = 1; + /* reset board (again?) */ + ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0); + if (ret) + return ret; + + state->initialized = 1; + + return 0; +} + +static int pctv452e_rc_query(struct dvb_usb_device *d) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 b[CMD_BUFFER_SIZE]; + u8 rx[PCTV_ANSWER_LEN]; + int ret, i; + u8 id = state->c++; + + /* prepare command header */ + b[0] = SYNC_BYTE_OUT; + b[1] = id; + b[2] = PCTV_CMD_IR; + b[3] = 0; + + /* send ir request */ + ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0); + if (ret != 0) + return ret; + + if (debug > 3) { + info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx); + for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) + info(" %02x", rx[i+3]); + + info("\n"); + } + + if ((rx[3] == 9) && (rx[12] & 0x01)) { + /* got a "press" event */ + state->last_rc_key = (rx[7] << 8) | rx[6]; + if (debug > 2) + info("%s: cmd=0x%02x sys=0x%02x\n", + __func__, rx[6], rx[7]); + + rc_keydown(d->rc_dev, state->last_rc_key, 0); + } else if (state->last_rc_key) { + rc_keyup(d->rc_dev); + state->last_rc_key = 0; + } + + return 0; +} + +static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + const u8 mem_addr[] = { 0x1f, 0xcc }; + u8 encoded_mac[20]; + int ret; + + ret = -EAGAIN; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + goto failed; + + ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16, + mem_addr + 1, /* snd_len */ 1, + encoded_mac, /* rcv_len */ 20); + if (-EREMOTEIO == ret) + /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a + byte write if /WC is low. */ + ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64, + mem_addr, 2, + encoded_mac, 20); + + mutex_unlock(&d->i2c_mutex); + + if (20 != ret) + goto failed; + + ret = ttpci_eeprom_decode_mac(mac, encoded_mac); + if (0 != ret) + goto failed; + + return 0; + +failed: + memset(mac, 0, 6); + + return ret; +} + +static const struct stb0899_s1_reg pctv452e_init_dev[] = { + { STB0899_DISCNTRL1, 0x26 }, + { STB0899_DISCNTRL2, 0x80 }, + { STB0899_DISRX_ST0, 0x04 }, + { STB0899_DISRX_ST1, 0x20 }, + { STB0899_DISPARITY, 0x00 }, + { STB0899_DISFIFO, 0x00 }, + { STB0899_DISF22, 0x99 }, + { STB0899_DISF22RX, 0x85 }, /* 0xa8 */ + { STB0899_ACRPRESC, 0x11 }, + { STB0899_ACRDIV1, 0x0a }, + { STB0899_ACRDIV2, 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG, 0x00 }, + { STB0899_MODECFG, 0x00 }, /* Inversion */ + { STB0899_IRQMSK_3, 0xf3 }, + { STB0899_IRQMSK_2, 0xfc }, + { STB0899_IRQMSK_1, 0xff }, + { STB0899_IRQMSK_0, 0xff }, + { STB0899_I2CCFG, 0x88 }, + { STB0899_I2CRPT, 0x58 }, + { STB0899_GPIO00CFG, 0x82 }, + { STB0899_GPIO01CFG, 0x82 }, /* LED: 0x02 green, 0x82 orange */ + { STB0899_GPIO02CFG, 0x82 }, + { STB0899_GPIO03CFG, 0x82 }, + { STB0899_GPIO04CFG, 0x82 }, + { STB0899_GPIO05CFG, 0x82 }, + { STB0899_GPIO06CFG, 0x82 }, + { STB0899_GPIO07CFG, 0x82 }, + { STB0899_GPIO08CFG, 0x82 }, + { STB0899_GPIO09CFG, 0x82 }, + { STB0899_GPIO10CFG, 0x82 }, + { STB0899_GPIO11CFG, 0x82 }, + { STB0899_GPIO12CFG, 0x82 }, + { STB0899_GPIO13CFG, 0x82 }, + { STB0899_GPIO14CFG, 0x82 }, + { STB0899_GPIO15CFG, 0x82 }, + { STB0899_GPIO16CFG, 0x82 }, + { STB0899_GPIO17CFG, 0x82 }, + { STB0899_GPIO18CFG, 0x82 }, + { STB0899_GPIO19CFG, 0x82 }, + { STB0899_GPIO20CFG, 0x82 }, + { STB0899_SDATCFG, 0xb8 }, + { STB0899_SCLTCFG, 0xba }, + { STB0899_AGCRFCFG, 0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */ + { STB0899_GPIO22, 0x82 }, + { STB0899_GPIO21, 0x91 }, + { STB0899_DIRCLKCFG, 0x82 }, + { STB0899_CLKOUT27CFG, 0x7e }, + { STB0899_STDBYCFG, 0x82 }, + { STB0899_CS0CFG, 0x82 }, + { STB0899_CS1CFG, 0x82 }, + { STB0899_DISEQCOCFG, 0x20 }, + { STB0899_NCOARSE, 0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */ + { STB0899_SYNTCTRL, 0x00 }, /* 0x00 CLKI, 0x02 XTALI */ + { STB0899_FILTCTRL, 0x00 }, + { STB0899_SYSCTRL, 0x00 }, + { STB0899_STOPCLK1, 0x20 }, /* orig: 0x00 budget-ci: 0x20 */ + { STB0899_STOPCLK2, 0x00 }, + { STB0899_INTBUFCTRL, 0x0a }, + { STB0899_AGC2I1, 0x00 }, + { STB0899_AGC2I2, 0x00 }, + { STB0899_AGCIQIN, 0x00 }, + { STB0899_TSTRES, 0x40 }, /* rjkm */ + { 0xffff, 0xff }, +}; + +static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = { + { STB0899_DEMOD, 0x00 }, + { STB0899_RCOMPC, 0xc9 }, + { STB0899_AGC1CN, 0x01 }, + { STB0899_AGC1REF, 0x10 }, + { STB0899_RTC, 0x23 }, + { STB0899_TMGCFG, 0x4e }, + { STB0899_AGC2REF, 0x34 }, + { STB0899_TLSR, 0x84 }, + { STB0899_CFD, 0xf7 }, + { STB0899_ACLC, 0x87 }, + { STB0899_BCLC, 0x94 }, + { STB0899_EQON, 0x41 }, + { STB0899_LDT, 0xf1 }, + { STB0899_LDT2, 0xe3 }, + { STB0899_EQUALREF, 0xb4 }, + { STB0899_TMGRAMP, 0x10 }, + { STB0899_TMGTHD, 0x30 }, + { STB0899_IDCCOMP, 0xfd }, + { STB0899_QDCCOMP, 0xff }, + { STB0899_POWERI, 0x0c }, + { STB0899_POWERQ, 0x0f }, + { STB0899_RCOMP, 0x6c }, + { STB0899_AGCIQIN, 0x80 }, + { STB0899_AGC2I1, 0x06 }, + { STB0899_AGC2I2, 0x00 }, + { STB0899_TLIR, 0x30 }, + { STB0899_RTF, 0x7f }, + { STB0899_DSTATUS, 0x00 }, + { STB0899_LDI, 0xbc }, + { STB0899_CFRM, 0xea }, + { STB0899_CFRL, 0x31 }, + { STB0899_NIRM, 0x2b }, + { STB0899_NIRL, 0x80 }, + { STB0899_ISYMB, 0x1d }, + { STB0899_QSYMB, 0xa6 }, + { STB0899_SFRH, 0x2f }, + { STB0899_SFRM, 0x68 }, + { STB0899_SFRL, 0x40 }, + { STB0899_SFRUPH, 0x2f }, + { STB0899_SFRUPM, 0x68 }, + { STB0899_SFRUPL, 0x40 }, + { STB0899_EQUAI1, 0x02 }, + { STB0899_EQUAQ1, 0xff }, + { STB0899_EQUAI2, 0x04 }, + { STB0899_EQUAQ2, 0x05 }, + { STB0899_EQUAI3, 0x02 }, + { STB0899_EQUAQ3, 0xfd }, + { STB0899_EQUAI4, 0x03 }, + { STB0899_EQUAQ4, 0x07 }, + { STB0899_EQUAI5, 0x08 }, + { STB0899_EQUAQ5, 0xf5 }, + { STB0899_DSTATUS2, 0x00 }, + { STB0899_VSTATUS, 0x00 }, + { STB0899_VERROR, 0x86 }, + { STB0899_IQSWAP, 0x2a }, + { STB0899_ECNT1M, 0x00 }, + { STB0899_ECNT1L, 0x00 }, + { STB0899_ECNT2M, 0x00 }, + { STB0899_ECNT2L, 0x00 }, + { STB0899_ECNT3M, 0x0a }, + { STB0899_ECNT3L, 0xad }, + { STB0899_FECAUTO1, 0x06 }, + { STB0899_FECM, 0x01 }, + { STB0899_VTH12, 0xb0 }, + { STB0899_VTH23, 0x7a }, + { STB0899_VTH34, 0x58 }, + { STB0899_VTH56, 0x38 }, + { STB0899_VTH67, 0x34 }, + { STB0899_VTH78, 0x24 }, + { STB0899_PRVIT, 0xff }, + { STB0899_VITSYNC, 0x19 }, + { STB0899_RSULC, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC, 0x42 }, + { STB0899_RSLLC, 0x41 }, + { STB0899_TSLPL, 0x12 }, + { STB0899_TSCFGH, 0x0c }, + { STB0899_TSCFGM, 0x00 }, + { STB0899_TSCFGL, 0x00 }, + { STB0899_TSOUT, 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL, 0x00 }, + { STB0899_TSINHDELH, 0x02 }, + { STB0899_TSINHDELM, 0x00 }, + { STB0899_TSINHDELL, 0x00 }, + { STB0899_TSLLSTKM, 0x1b }, + { STB0899_TSLLSTKL, 0xb3 }, + { STB0899_TSULSTKM, 0x00 }, + { STB0899_TSULSTKL, 0x00 }, + { STB0899_PCKLENUL, 0xbc }, + { STB0899_PCKLENLL, 0xcc }, + { STB0899_RSPCKLEN, 0xbd }, + { STB0899_TSSTATUS, 0x90 }, + { STB0899_ERRCTRL1, 0xb6 }, + { STB0899_ERRCTRL2, 0x95 }, + { STB0899_ERRCTRL3, 0x8d }, + { STB0899_DMONMSK1, 0x27 }, + { STB0899_DMONMSK0, 0x03 }, + { STB0899_DEMAPVIT, 0x5c }, + { STB0899_PLPARM, 0x19 }, + { STB0899_PDELCTRL, 0x48 }, + { STB0899_PDELCTRL2, 0x00 }, + { STB0899_BBHCTRL1, 0x00 }, + { STB0899_BBHCTRL2, 0x00 }, + { STB0899_HYSTTHRESH, 0x77 }, + { STB0899_MATCSTM, 0x00 }, + { STB0899_MATCSTL, 0x00 }, + { STB0899_UPLCSTM, 0x00 }, + { STB0899_UPLCSTL, 0x00 }, + { STB0899_DFLCSTM, 0x00 }, + { STB0899_DFLCSTL, 0x00 }, + { STB0899_SYNCCST, 0x00 }, + { STB0899_SYNCDCSTM, 0x00 }, + { STB0899_SYNCDCSTL, 0x00 }, + { STB0899_ISI_ENTRY, 0x00 }, + { STB0899_ISI_BIT_EN, 0x00 }, + { STB0899_MATSTRM, 0xf0 }, + { STB0899_MATSTRL, 0x02 }, + { STB0899_UPLSTRM, 0x45 }, + { STB0899_UPLSTRL, 0x60 }, + { STB0899_DFLSTRM, 0xe3 }, + { STB0899_DFLSTRL, 0x00 }, + { STB0899_SYNCSTR, 0x47 }, + { STB0899_SYNCDSTRM, 0x05 }, + { STB0899_SYNCDSTRL, 0x18 }, + { STB0899_CFGPDELSTATUS1, 0x19 }, + { STB0899_CFGPDELSTATUS2, 0x2b }, + { STB0899_BBFERRORM, 0x00 }, + { STB0899_BBFERRORL, 0x01 }, + { STB0899_UPKTERRORM, 0x00 }, + { STB0899_UPKTERRORL, 0x00 }, + { 0xffff, 0xff }, +}; + +static struct stb0899_config stb0899_config = { + .init_dev = pctv452e_init_dev, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = pctv452e_init_s1_demod, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = I2C_ADDR_STB0899, /* I2C Address */ + .block_sync_mode = STB0899_SYNC_FORCED, /* ? */ + + .xtal_freq = 27000000, /* Assume Hz ? */ + .inversion = IQ_SWAP_ON, /* ? */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .ts_output_mode = 0, /* Use parallel mode */ + .clock_polarity = 0, + .data_clk_parity = 0, + .fec_mode = 0, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, + + /* helper for switching LED green/orange */ + .postproc = pctv45e_postproc +}; + +static struct stb6100_config stb6100_config = { + .tuner_address = I2C_ADDR_STB6100, + .refclock = 27000000 +}; + + +static struct i2c_algorithm pctv452e_i2c_algo = { + .master_xfer = pctv452e_i2c_xfer, + .functionality = pctv452e_i2c_func +}; + +static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) +{ + struct usb_device_id *id; + + a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config, + &a->dev->i2c_adap); + if (!a->fe_adap[0].fe) + return -ENODEV; + if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe, + &a->dev->i2c_adap)) == 0) + err("Cannot attach lnbp22\n"); + + id = a->dev->desc->warm_ids[0]; + if (USB_VID_TECHNOTREND == id->idVendor + && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) + /* Error ignored. */ + tt3650_ci_init(a); + + return 0; +} + +static int pctv452e_tuner_attach(struct dvb_usb_adapter *a) +{ + if (!a->fe_adap[0].fe) + return -ENODEV; + if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config, + &a->dev->i2c_adap) == 0) { + err("%s failed\n", __func__); + return -ENODEV; + } + + return 0; +} + +static struct usb_device_id pctv452e_usb_table[] = { + {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)}, + {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)}, + {USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)}, + {} +}; +MODULE_DEVICE_TABLE(usb, pctv452e_usb_table); + +static struct dvb_usb_device_properties pctv452e_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */ + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = sizeof(struct pctv452e_state), + + .power_ctrl = pctv452e_power_ctrl, + + .rc.core = { + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .allowed_protos = RC_TYPE_UNKNOWN, + .rc_query = pctv452e_rc_query, + .rc_interval = 100, + }, + + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + .frontend_attach = pctv452e_frontend_attach, + .tuner_attach = pctv452e_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 4, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1 + } + } + }, + } }, + } }, + + .i2c_algo = &pctv452e_i2c_algo, + + .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */ + + .num_device_descs = 1, + .devices = { + { .name = "PCTV HDTV USB", + .cold_ids = { NULL, NULL }, /* this is a warm only device */ + .warm_ids = { &pctv452e_usb_table[0], NULL } + }, + { 0 }, + } +}; + +static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */ + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = sizeof(struct pctv452e_state), + + .power_ctrl = pctv452e_power_ctrl, + .read_mac_address = pctv452e_read_mac_address, + + .rc.core = { + .rc_codes = RC_MAP_TT_1500, + .allowed_protos = RC_TYPE_UNKNOWN, + .rc_query = pctv452e_rc_query, + .rc_interval = 100, + }, + + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + .frontend_attach = pctv452e_frontend_attach, + .tuner_attach = pctv452e_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 7, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1 + } + } + }, + + } }, + } }, + + .i2c_algo = &pctv452e_i2c_algo, + + .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/ + + .num_device_descs = 2, + .devices = { + { .name = "Technotrend TT Connect S2-3600", + .cold_ids = { NULL, NULL }, /* this is a warm only device */ + .warm_ids = { &pctv452e_usb_table[1], NULL } + }, + { .name = "Technotrend TT Connect S2-3650-CI", + .cold_ids = { NULL, NULL }, + .warm_ids = { &pctv452e_usb_table[2], NULL } + }, + { 0 }, + } +}; + +static void pctv452e_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + tt3650_ci_uninit(d); + dvb_usb_device_exit(intf); +} + +static int pctv452e_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &pctv452e_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -ENODEV; +} + +static struct usb_driver pctv452e_usb_driver = { + .name = "pctv452e", + .probe = pctv452e_usb_probe, + .disconnect = pctv452e_usb_disconnect, + .id_table = pctv452e_usb_table, +}; + +module_usb_driver(pctv452e_usb_driver); + +MODULE_AUTHOR("Dominik Kuhlen "); +MODULE_AUTHOR("Andre Weidemann "); +MODULE_AUTHOR("Michael H. Schimek "); +MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c new file mode 100644 index 00000000000..acefaa89cc5 --- /dev/null +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -0,0 +1,789 @@ +/* + * Linux driver for Technisat DVB-S/S2 USB 2.0 device + * + * Copyright (C) 2010 Patrick Boettcher, + * Kernel Labs Inc. PO Box 745, St James, NY 11780 + * + * Development was sponsored by Technisat Digital UK Limited, whose + * registered office is Witan Gate House 500 - 600 Witan Gate West, + * Milton Keynes, MK9 1SH + * + * 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. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND + * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER + * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the + * GNU General Public License for more details. + */ + +#define DVB_USB_LOG_PREFIX "technisat-usb2" +#include "dvb-usb.h" + +#include "stv6110x.h" +#include "stv090x.h" + +/* module parameters */ +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \ + DVB_USB_DEBUG_STATUS); + +/* disables all LED control command and + * also does not start the signal polling thread */ +static int disable_led_control; +module_param(disable_led_control, int, 0444); +MODULE_PARM_DESC(disable_led_control, + "disable LED control of the device " + "(default: 0 - LED control is active)."); + +/* device private data */ +struct technisat_usb2_state { + struct dvb_usb_device *dev; + struct delayed_work green_led_work; + u8 power_state; + + u16 last_scan_code; +}; + +/* debug print helpers */ +#define deb_info(args...) dprintk(debug, 0x01, args) +#define deb_eeprom(args...) dprintk(debug, 0x02, args) +#define deb_i2c(args...) dprintk(debug, 0x04, args) +#define deb_rc(args...) dprintk(debug, 0x08, args) + +/* vendor requests */ +#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3 +#define SET_FRONT_END_RESET_VENDOR_REQUEST 0xB4 +#define GET_VERSION_INFO_VENDOR_REQUEST 0xB5 +#define SET_GREEN_LED_VENDOR_REQUEST 0xB6 +#define SET_RED_LED_VENDOR_REQUEST 0xB7 +#define GET_IR_DATA_VENDOR_REQUEST 0xB8 +#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST 0xB9 +#define SET_USB_REENUMERATION 0xBA + +/* i2c-access methods */ +#define I2C_SPEED_100KHZ_BIT 0x40 + +#define I2C_STATUS_NAK 7 +#define I2C_STATUS_OK 8 + +static int technisat_usb2_i2c_access(struct usb_device *udev, + u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +{ + u8 b[64]; + int ret, actual_length; + + deb_i2c("i2c-access: %02x, tx: ", device_addr); + debug_dump(tx, txlen, deb_i2c); + deb_i2c(" "); + + if (txlen > 62) { + err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)", + device_addr); + txlen = 62; + } + if (rxlen > 62) { + err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)", + device_addr); + txlen = 62; + } + + b[0] = I2C_SPEED_100KHZ_BIT; + b[1] = device_addr << 1; + + if (rx != NULL) { + b[0] |= rxlen; + b[1] |= 1; + } + + memcpy(&b[2], tx, txlen); + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x01), + b, 2 + txlen, + NULL, 1000); + + if (ret < 0) { + err("i2c-error: out failed %02x = %d", device_addr, ret); + return -ENODEV; + } + + ret = usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, 0x01), + b, 64, &actual_length, 1000); + if (ret < 0) { + err("i2c-error: in failed %02x = %d", device_addr, ret); + return -ENODEV; + } + + if (b[0] != I2C_STATUS_OK) { + err("i2c-error: %02x = %d", device_addr, b[0]); + /* handle tuner-i2c-nak */ + if (!(b[0] == I2C_STATUS_NAK && + device_addr == 0x60 + /* && device_is_technisat_usb2 */)) + return -ENODEV; + } + + deb_i2c("status: %d, ", b[0]); + + if (rx != NULL) { + memcpy(rx, &b[2], rxlen); + + deb_i2c("rx (%d): ", rxlen); + debug_dump(rx, rxlen, deb_i2c); + } + + deb_i2c("\n"); + + return 0; +} + +static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + int ret = 0, i; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i+1 < num && msg[i+1].flags & I2C_M_RD) { + ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr, + msg[i].buf, msg[i].len, + msg[i+1].buf, msg[i+1].len); + if (ret != 0) + break; + i++; + } else { + ret = technisat_usb2_i2c_access(d->udev, msg[i].addr, + msg[i].buf, msg[i].len, + NULL, 0); + if (ret != 0) + break; + } + } + + if (ret == 0) + ret = i; + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm technisat_usb2_i2c_algo = { + .master_xfer = technisat_usb2_i2c_xfer, + .functionality = technisat_usb2_i2c_func, +}; + +#if 0 +static void technisat_usb2_frontend_reset(struct usb_device *udev) +{ + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_FRONT_END_RESET_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 10, 0, + NULL, 0, 500); +} +#endif + +/* LED control */ +enum technisat_usb2_led_state { + LED_OFF, + LED_BLINK, + LED_ON, + LED_UNDEFINED +}; + +static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state) +{ + int ret; + + u8 led[8] = { + red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, + 0 + }; + + if (disable_led_control && state != LED_OFF) + return 0; + + switch (state) { + case LED_ON: + led[1] = 0x82; + break; + case LED_BLINK: + led[1] = 0x82; + if (red) { + led[2] = 0x02; + led[3] = 10; + led[4] = 10; + } else { + led[2] = 0xff; + led[3] = 50; + led[4] = 50; + } + led[5] = 1; + break; + + default: + case LED_OFF: + led[1] = 0x80; + break; + } + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + led, sizeof(led), 500); + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green) +{ + int ret; + u8 b = 0; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + SET_LED_TIMER_DIVIDER_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + (red << 8) | green, 0, + &b, 1, 500); + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static void technisat_usb2_green_led_control(struct work_struct *work) +{ + struct technisat_usb2_state *state = + container_of(work, struct technisat_usb2_state, green_led_work.work); + struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe; + + if (state->power_state == 0) + goto schedule; + + if (fe != NULL) { + enum fe_status status; + + if (fe->ops.read_status(fe, &status) != 0) + goto schedule; + + if (status & FE_HAS_LOCK) { + u32 ber; + + if (fe->ops.read_ber(fe, &ber) != 0) + goto schedule; + + if (ber > 1000) + technisat_usb2_set_led(state->dev, 0, LED_BLINK); + else + technisat_usb2_set_led(state->dev, 0, LED_ON); + } else + technisat_usb2_set_led(state->dev, 0, LED_OFF); + } + +schedule: + schedule_delayed_work(&state->green_led_work, + msecs_to_jiffies(500)); +} + +/* method to find out whether the firmware has to be downloaded or not */ +static int technisat_usb2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + int ret; + u8 version[3]; + + /* first select the interface */ + if (usb_set_interface(udev, 0, 1) != 0) + err("could not set alternate setting to 0"); + else + info("set alternate setting"); + + *cold = 0; /* by default do not download a firmware - just in case something is wrong */ + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + GET_VERSION_INFO_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_IN, + 0, 0, + version, sizeof(version), 500); + + if (ret < 0) + *cold = 1; + else { + info("firmware version: %d.%d", version[1], version[2]); + *cold = 0; + } + + return 0; +} + +/* power control */ +static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level) +{ + struct technisat_usb2_state *state = d->priv; + + state->power_state = level; + + if (disable_led_control) + return 0; + + /* green led is turned off in any case - will be turned on when tuning */ + technisat_usb2_set_led(d, 0, LED_OFF); + /* red led is turned on all the time */ + technisat_usb2_set_led(d, 1, LED_ON); + return 0; +} + +/* mac address reading - from the eeprom */ +#if 0 +static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d) +{ + u8 reg; + u8 b[16]; + int i, j; + + /* full EEPROM dump */ + for (j = 0; j < 256 * 4; j += 16) { + reg = j; + if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, ®, 1, b, 16) != 0) + break; + + deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg); + for (i = 0; i < 16; i++) + deb_eeprom("%02x ", b[i]); + deb_eeprom("\n"); + } +} +#endif + +static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length) +{ + u8 lrc = 0; + while (--length) + lrc ^= *b++; + return lrc; +} + +static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d, + u16 offset, u8 *b, u16 length, u8 tries) +{ + u8 bo = offset & 0xff; + struct i2c_msg msg[] = { + { + .addr = 0x50 | ((offset >> 8) & 0x3), + .buf = &bo, + .len = 1 + }, { + .addr = 0x50 | ((offset >> 8) & 0x3), + .flags = I2C_M_RD, + .buf = b, + .len = length + } + }; + + while (tries--) { + int status; + + if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) + break; + + status = + technisat_usb2_calc_lrc(b, length - 1) == b[length - 1]; + + if (status) + return 0; + } + + return -EREMOTEIO; +} + +#define EEPROM_MAC_START 0x3f8 +#define EEPROM_MAC_TOTAL 8 +static int technisat_usb2_read_mac_address(struct dvb_usb_device *d, + u8 mac[]) +{ + u8 buf[EEPROM_MAC_TOTAL]; + + if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START, + buf, EEPROM_MAC_TOTAL, 4) != 0) + return -ENODEV; + + memcpy(mac, buf, 6); + return 0; +} + +/* frontend attach */ +static int technisat_usb2_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + int i; + u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */ + + gpio[2] = 1; /* high - voltage ? */ + + switch (voltage) { + case SEC_VOLTAGE_13: + gpio[0] = 1; + break; + case SEC_VOLTAGE_18: + gpio[0] = 1; + gpio[1] = 1; + break; + default: + case SEC_VOLTAGE_OFF: + break; + } + + for (i = 0; i < 3; i++) + if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0) + return -EREMOTEIO; + return 0; +} + +static struct stv090x_config technisat_usb2_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 8000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts1_clk = 13400000, + .ts1_tei = 1, + + .repeater_level = STV090x_RPTLEVEL_64, + + .tuner_bbgain = 6, +}; + +static struct stv6110x_config technisat_usb2_stv6110x_config = { + .addr = 0x60, + .refclk = 16000000, + .clk_div = 2, +}; + +static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) +{ + struct usb_device *udev = a->dev->udev; + int ret; + + a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, + &a->dev->i2c_adap, STV090x_DEMODULATOR_0); + + if (a->fe_adap[0].fe) { + struct stv6110x_devctl *ctl; + + ctl = dvb_attach(stv6110x_attach, + a->fe_adap[0].fe, + &technisat_usb2_stv6110x_config, + &a->dev->i2c_adap); + + if (ctl) { + technisat_usb2_stv090x_config.tuner_init = ctl->tuner_init; + technisat_usb2_stv090x_config.tuner_sleep = ctl->tuner_sleep; + technisat_usb2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + technisat_usb2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + technisat_usb2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + technisat_usb2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + technisat_usb2_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (a->fe_adap[0].fe->ops.init) + a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe); + + if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + NULL, 0, 500); + mutex_unlock(&a->dev->i2c_mutex); + + if (ret != 0) + err("could not set IF_CLK to external"); + + a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage; + + /* if everything was successful assign a nice name to the frontend */ + strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name, + sizeof(a->fe_adap[0].fe->ops.info.name)); + } else { + dvb_frontend_detach(a->fe_adap[0].fe); + a->fe_adap[0].fe = NULL; + } + } + + technisat_usb2_set_led_timer(a->dev, 1, 1); + + return a->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +/* Remote control */ + +/* the device is giving providing raw IR-signals to the host mapping + * it only to one remote control is just the default implementation + */ +#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889 +#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US) + +#define FIRMWARE_CLOCK_TICK 83333 +#define FIRMWARE_CLOCK_DIVISOR 256 + +#define IR_PERCENT_TOLERANCE 15 + +#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) +#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR) + +#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) +#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR) + +#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) +#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) + +#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) +#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) + +static int technisat_usb2_get_ir(struct dvb_usb_device *d) +{ + u8 buf[62], *b; + int ret; + struct ir_raw_event ev; + + buf[0] = GET_IR_DATA_VENDOR_REQUEST; + buf[1] = 0x08; + buf[2] = 0x8f; + buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT; + buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GET_IR_DATA_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + buf, 5, 500); + if (ret < 0) + goto unlock; + + buf[1] = 0; + buf[2] = 0; + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + GET_IR_DATA_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_IN, + 0x8080, 0, + buf, sizeof(buf), 500); + +unlock: + mutex_unlock(&d->i2c_mutex); + + if (ret < 0) + return ret; + + if (ret == 1) + return 0; /* no key pressed */ + + /* decoding */ + b = buf+1; + +#if 0 + deb_rc("RC: %d ", ret); + debug_dump(b, ret, deb_rc); +#endif + + ev.pulse = 0; + while (1) { + ev.pulse = !ev.pulse; + ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000; + ir_raw_event_store(d->rc_dev, &ev); + + b++; + if (*b == 0xff) { + ev.pulse = 0; + ev.duration = 888888*2; + ir_raw_event_store(d->rc_dev, &ev); + break; + } + } + + ir_raw_event_handle(d->rc_dev); + + return 1; +} + +static int technisat_usb2_rc_query(struct dvb_usb_device *d) +{ + int ret = technisat_usb2_get_ir(d); + + if (ret < 0) + return ret; + + if (ret == 0) + return 0; + + if (!disable_led_control) + technisat_usb2_set_led(d, 1, LED_BLINK); + + return 0; +} + +/* DVB-USB and USB stuff follows */ +static struct usb_device_id technisat_usb2_id_table[] = { + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, + { 0 } /* Terminating entry */ +}; + +/* device description */ +static struct dvb_usb_device_properties technisat_usb2_devices = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .identify_state = technisat_usb2_identify_state, + .firmware = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw", + + .size_of_priv = sizeof(struct technisat_usb2_state), + + .i2c_algo = &technisat_usb2_i2c_algo, + + .power_ctrl = technisat_usb2_power_ctrl, + .read_mac_address = technisat_usb2_read_mac_address, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = technisat_usb2_frontend_attach, + + .stream = { + .type = USB_ISOC, + .count = 8, + .endpoint = 0x2, + .u = { + .isoc = { + .framesperurb = 32, + .framesize = 2048, + .interval = 3, + } + } + }, + }}, + .size_of_priv = 0, + }, + }, + + .num_device_descs = 1, + .devices = { + { "Technisat SkyStar USB HD (DVB-S/S2)", + { &technisat_usb2_id_table[0], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = 100, + .rc_codes = RC_MAP_TECHNISAT_USB2, + .module_name = "technisat-usb2", + .rc_query = technisat_usb2_rc_query, + .allowed_protos = RC_TYPE_ALL, + .driver_type = RC_DRIVER_IR_RAW, + } +}; + +static int technisat_usb2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *dev; + + if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE, + &dev, adapter_nr) != 0) + return -ENODEV; + + if (dev) { + struct technisat_usb2_state *state = dev->priv; + state->dev = dev; + + if (!disable_led_control) { + INIT_DELAYED_WORK(&state->green_led_work, + technisat_usb2_green_led_control); + schedule_delayed_work(&state->green_led_work, + msecs_to_jiffies(500)); + } + } + + return 0; +} + +static void technisat_usb2_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *dev = usb_get_intfdata(intf); + + /* work and stuff was only created when the device is is hot-state */ + if (dev != NULL) { + struct technisat_usb2_state *state = dev->priv; + if (state != NULL) + cancel_delayed_work_sync(&state->green_led_work); + } + + dvb_usb_device_exit(intf); +} + +static struct usb_driver technisat_usb2_driver = { + .name = "dvb_usb_technisat_usb2", + .probe = technisat_usb2_probe, + .disconnect = technisat_usb2_disconnect, + .id_table = technisat_usb2_id_table, +}; + +module_usb_driver(technisat_usb2_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c new file mode 100644 index 00000000000..e53a1061cb8 --- /dev/null +++ b/drivers/media/usb/dvb-usb/ttusb2.c @@ -0,0 +1,820 @@ +/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones + * (e.g. Pinnacle 400e DVB-S USB2.0). + * + * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. + * + * TDA8263 + TDA10086 + * + * I2C addresses: + * 0x08 - LNBP21PD - LNB power supply + * 0x0e - TDA10086 - Demodulator + * 0x50 - FX2 eeprom + * 0x60 - TDA8263 - Tuner + * 0x78 ??? + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * Copyright (C) 2005-6 Patrick Boettcher + * + * 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 + */ +#define DVB_USB_LOG_PREFIX "ttusb2" +#include "dvb-usb.h" + +#include "ttusb2.h" + +#include "tda826x.h" +#include "tda10086.h" +#include "tda1002x.h" +#include "tda10048.h" +#include "tda827x.h" +#include "lnbp21.h" +/* CA */ +#include "dvb_ca_en50221.h" + +/* debug */ +static int dvb_usb_ttusb2_debug; +#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) +module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); +static int dvb_usb_ttusb2_debug_ci; +module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644); +MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define ci_dbg(format, arg...) \ +do { \ + if (dvb_usb_ttusb2_debug_ci) \ + printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ + ": %s " format "\n" , __func__, ## arg); \ +} while (0) + +enum { + TT3650_CMD_CI_TEST = 0x40, + TT3650_CMD_CI_RD_CTRL, + TT3650_CMD_CI_WR_CTRL, + TT3650_CMD_CI_RD_ATTR, + TT3650_CMD_CI_WR_ATTR, + TT3650_CMD_CI_RESET, + TT3650_CMD_CI_SET_VIDEO_PORT +}; + +struct ttusb2_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; + u8 id; + u16 last_rc_key; +}; + +static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct ttusb2_state *st = d->priv; + u8 *s, *r = NULL; + int ret = 0; + + s = kzalloc(wlen+4, GFP_KERNEL); + if (!s) + return -ENOMEM; + + r = kzalloc(64, GFP_KERNEL); + if (!r) { + kfree(s); + return -ENOMEM; + } + + s[0] = 0xaa; + s[1] = ++st->id; + s[2] = cmd; + s[3] = wlen; + memcpy(&s[4],wbuf,wlen); + + ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); + + if (ret != 0 || + r[0] != 0x55 || + r[1] != s[1] || + r[2] != cmd || + (rlen > 0 && r[3] != rlen)) { + warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); + kfree(s); + kfree(r); + return -EIO; + } + + if (rlen > 0) + memcpy(rbuf, &r[4], rlen); + + kfree(s); + kfree(r); + + return 0; +} + +/* ci */ +static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) +{ + int ret; + u8 rx[60];/* (64 -4) */ + ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len); + if (!ret) + memcpy(data, rx, read_len); + return ret; +} + +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) +{ + struct dvb_usb_device *d = ca->data; + struct ttusb2_state *state = d->priv; + int ret; + + mutex_lock(&state->ca_mutex); + ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + u8 buf[3]; + int ret = 0; + + if (slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); + + ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]); + + if (ret < 0) + return ret; + + return buf[2]; +} + +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + u8 buf[3]; + + ci_dbg("%d 0x%04x 0x%02x", slot, address, value); + + if (slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + buf[2] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); +} + +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + u8 buf[2]; + int ret; + + if (slot) + return -EINVAL; + + buf[0] = address & 3; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); + + ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]); + + if (ret < 0) + return ret; + + return buf[1]; +} + +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + u8 buf[2]; + + ci_dbg("%d 0x%02x 0x%02x", slot, address, value); + + if (slot) + return -EINVAL; + + buf[0] = address; + buf[1] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); +} + +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable) +{ + u8 buf[1]; + int ret; + + ci_dbg("%d %d", slot, enable); + + if (slot) + return -EINVAL; + + buf[0] = enable; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + if (ret < 0) + return ret; + + if (enable != buf[0]) { + err("CI not %sabled.", enable ? "en" : "dis"); + return -EIO; + } + + return 0; +} + +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, 0); +} + +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, 1); +} + +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = ca->data; + struct ttusb2_state *state = d->priv; + u8 buf[1]; + int ret; + + ci_dbg("%d", slot); + + if (slot) + return -EINVAL; + + buf[0] = 0; + + mutex_lock(&state->ca_mutex); + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (ret) + goto failed; + + msleep(500); + + buf[0] = 1; + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (ret) + goto failed; + + msleep(500); + + buf[0] = 0; /* FTA */ + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + + msleep(1100); + + failed: + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + u8 buf[1]; + int ret; + + if (slot) + return -EINVAL; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); + if (ret) + return ret; + + if (1 == buf[0]) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + } + return 0; +} + +static void tt3650_ci_uninit(struct dvb_usb_device *d) +{ + struct ttusb2_state *state; + + ci_dbg(""); + + if (NULL == d) + return; + + state = d->priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + +static int tt3650_ci_init(struct dvb_usb_adapter *a) +{ + struct dvb_usb_device *d = a->dev; + struct ttusb2_state *state = d->priv; + int ret; + + ci_dbg(""); + + mutex_init(&state->ca_mutex); + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; + state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; + state->ca.read_cam_control = tt3650_ci_read_cam_control; + state->ca.write_cam_control = tt3650_ci_write_cam_control; + state->ca.slot_reset = tt3650_ci_slot_reset; + state->ca.slot_shutdown = tt3650_ci_slot_shutdown; + state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; + state->ca.poll_slot_status = tt3650_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&a->dvb_adap, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (ret) { + err("Cannot initialize CI: Error %d.", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + info("CI initialized."); + + return 0; +} + +static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + static u8 obuf[60], ibuf[60]; + int i, write_read, read; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + read = msg[i].flags & I2C_M_RD; + + obuf[0] = (msg[i].addr << 1) | (write_read | read); + if (read) + obuf[1] = 0; + else + obuf[1] = msg[i].len; + + /* read request */ + if (write_read) + obuf[2] = msg[i+1].len; + else if (read) + obuf[2] = msg[i].len; + else + obuf[2] = 0; + + memcpy(&obuf[3], msg[i].buf, msg[i].len); + + if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) { + err("i2c transfer failed."); + break; + } + + if (write_read) { + memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len); + i++; + } else if (read) + memcpy(msg[i].buf, &ibuf[3], msg[i].len); + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ttusb2_i2c_algo = { + .master_xfer = ttusb2_i2c_xfer, + .functionality = ttusb2_i2c_func, +}; + +/* command to poll IR receiver (copied from pctv452e.c) */ +#define CMD_GET_IR_CODE 0x1b + +/* IR */ +static int tt3650_rc_query(struct dvb_usb_device *d) +{ + int ret; + u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */ + struct ttusb2_state *st = d->priv; + ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx)); + if (ret != 0) + return ret; + + if (rx[8] & 0x01) { + /* got a "press" event */ + st->last_rc_key = (rx[3] << 8) | rx[2]; + deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]); + rc_keydown(d->rc_dev, st->last_rc_key, 0); + } else if (st->last_rc_key) { + rc_keyup(d->rc_dev); + st->last_rc_key = 0; + } + + return 0; +} + + +/* Callbacks for DVB USB */ +static int ttusb2_identify_state (struct usb_device *udev, struct + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; + return 0; +} + +static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = onoff; + ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); + return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); +} + + +static struct tda10086_config tda10086_config = { + .demod_address = 0x0e, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct tda10023_config tda10023_config = { + .demod_address = 0x0c, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; + +static struct tda10048_config tda10048_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_PARALLEL_OUTPUT, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_4000, + .dtv7_if_freq_khz = TDA10048_IF_4500, + .dtv8_if_freq_khz = TDA10048_IF_5000, + .clk_freq_khz = TDA10048_CLK_16000, + .no_firmware = 1, + .set_pll = true , + .pll_m = 5, + .pll_n = 3, + .pll_p = 0, +}; + +static struct tda827x_config tda827x_config = { + .config = 0, +}; + +static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev,0,3) < 0) + err("set interface to alts=3 failed"); + + if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { + deb_info("TDA10086 attach failed\n"); + return -ENODEV; + } + + return 0; +} + +static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable); +} + +static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 3) < 0) + err("set interface to alts=3 failed"); + + if (adap->fe_adap[0].fe == NULL) { + /* FE 0 DVB-C */ + adap->fe_adap[0].fe = dvb_attach(tda10023_attach, + &tda10023_config, &adap->dev->i2c_adap, 0x48); + + if (adap->fe_adap[0].fe == NULL) { + deb_info("TDA10023 attach failed\n"); + return -ENODEV; + } + tt3650_ci_init(adap); + } else { + adap->fe_adap[1].fe = dvb_attach(tda10048_attach, + &tda10048_config, &adap->dev->i2c_adap); + + if (adap->fe_adap[1].fe == NULL) { + deb_info("TDA10048 attach failed\n"); + return -ENODEV; + } + + /* tuner is behind TDA10023 I2C-gate */ + adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl; + + } + + return 0; +} + +static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + + /* MFE: select correct FE to attach tuner since that's called twice */ + if (adap->fe_adap[1].fe == NULL) + fe = adap->fe_adap[0].fe; + else + fe = adap->fe_adap[1].fe; + + /* attach tuner */ + if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) +{ + if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { + deb_info("TDA8263 attach failed\n"); + return -ENODEV; + } + + if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) { + deb_info("LNBP21 attach failed\n"); + return -ENODEV; + } + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ttusb2_properties; +static struct dvb_usb_device_properties ttusb2_properties_s2400; +static struct dvb_usb_device_properties ttusb2_properties_ct3650; + +static void ttusb2_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + tt3650_ci_uninit(d); + dvb_usb_device_exit(intf); +} + +static int ttusb2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &ttusb2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, + THIS_MODULE, NULL, adapter_nr)) + return 0; + return -ENODEV; +} + +static struct usb_device_id ttusb2_table [] = { + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, + { USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_S2400) }, + { USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_CT3650) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, ttusb2_table); + +static struct dvb_usb_device_properties ttusb2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-pctv-400e-01.fw", + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, + + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }}, + } + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 2, + .devices = { + { "Pinnacle 400e DVB-S USB2.0", + { &ttusb2_table[0], NULL }, + { NULL }, + }, + { "Pinnacle 450e DVB-S USB2.0", + { &ttusb2_table[1], NULL }, + { NULL }, + }, + } +}; + +static struct dvb_usb_device_properties ttusb2_properties_s2400 = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-tt-s2400-01.fw", + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }}, + } + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Technotrend TT-connect S-2400", + { &ttusb2_table[2], NULL }, + { NULL }, + }, + } +}; + +static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct ttusb2_state), + + .rc.core = { + .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ + .rc_codes = RC_MAP_TT_1500, + .rc_query = tt3650_rc_query, + .allowed_protos = RC_TYPE_UNKNOWN, + }, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 2, + .fe = {{ + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10023_attach, + .tuner_attach = ttusb2_tuner_tda827x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }, { + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10023_attach, + .tuner_attach = ttusb2_tuner_tda827x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }}, + }, + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Technotrend TT-connect CT-3650", + .warm_ids = { &ttusb2_table[3], NULL }, + }, + } +}; + +static struct usb_driver ttusb2_driver = { + .name = "dvb_usb_ttusb2", + .probe = ttusb2_probe, + .disconnect = ttusb2_usb_disconnect, + .id_table = ttusb2_table, +}; + +module_usb_driver(ttusb2_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/ttusb2.h b/drivers/media/usb/dvb-usb/ttusb2.h new file mode 100644 index 00000000000..52a63af4089 --- /dev/null +++ b/drivers/media/usb/dvb-usb/ttusb2.h @@ -0,0 +1,70 @@ +/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones + * (e.g. Pinnacle 400e DVB-S USB2.0). + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * Copyright (C) 2005-6 Patrick Boettcher + * + * 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_TTUSB2_H_ +#define _DVB_USB_TTUSB2_H_ + +/* TTUSB protocol + * + * always to messages (out/in) + * out message: + * 0xaa + * + * in message (complete block is always 0x40 bytes long) + * 0x55 + * + * id is incremented for each transaction + */ + +#define CMD_DSP_DOWNLOAD 0x13 +/* out data: [28] + * last block must be empty */ + +#define CMD_DSP_BOOT 0x14 +/* out data: nothing */ + +#define CMD_POWER 0x15 +/* out data: */ + +#define CMD_LNB 0x16 +/* out data: <18V=0,13V=1> */ + +#define CMD_GET_VERSION 0x17 +/* in data: [5] */ + +#define CMD_DISEQC 0x18 +/* out data: [cmdlen] */ + +#define CMD_PID_ENABLE 0x22 +/* out data: */ + +#define CMD_PID_DISABLE 0x23 +/* out data: */ + +#define CMD_FILTER_ENABLE 0x24 +/* out data: [12] [12] */ + +#define CMD_FILTER_DISABLE 0x25 +/* out data: */ + +#define CMD_GET_DSP_VERSION 0x26 +/* in data: [28] */ + +#define CMD_I2C_XFER 0x31 +/* out data: [sndlen] + * in data: [rcvlen] */ + +#define CMD_I2C_BITRATE 0x32 +/* out data: */ + +#endif diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c new file mode 100644 index 00000000000..9b042292e78 --- /dev/null +++ b/drivers/media/usb/dvb-usb/umt-010.c @@ -0,0 +1,151 @@ +/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0 + * DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +#include "mt352.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int umt_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 }; + + static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff }; + static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff }; + static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 }; + static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 }; + static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f }; + + static u8 mt352_acq_ctl[] = { 0x53, 0x50 }; + static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio)); + + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + + mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1)); + mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2)); + mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3)); + mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4)); + mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5)); + + mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl)); + mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1)); + + return 0; +} + +static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct mt352_config umt_config; + + memset(&umt_config,0,sizeof(struct mt352_config)); + umt_config.demod_init = umt_mt352_demod_init; + umt_config.demod_address = 0xf; + + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); + + return 0; +} + +static int umt_tuner_attach (struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034); + return 0; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties umt_properties; + +static int umt_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &umt_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + return -EINVAL; +} + +/* do not change the order of the ID table */ +static struct usb_device_id umt_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, umt_table); + +static struct dvb_usb_device_properties umt_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-umt-010-02.fw", + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .frontend_attach = umt_mt352_frontend_attach, + .tuner_attach = umt_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = MAX_NO_URBS_FOR_DATA_STREAM, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb_power_ctrl, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Hanftek UMT-010 DVB-T USB2.0", + { &umt_table[0], NULL }, + { &umt_table[1], NULL }, + }, + } +}; + +static struct usb_driver umt_driver = { + .name = "dvb_usb_umt_010", + .probe = umt_probe, + .disconnect = dvb_usb_device_exit, + .id_table = umt_table, +}; + +module_usb_driver(umt_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/usb-urb.c b/drivers/media/usb/dvb-usb/usb-urb.c new file mode 100644 index 00000000000..d62ee0f5a16 --- /dev/null +++ b/drivers/media/usb/dvb-usb/usb-urb.c @@ -0,0 +1,254 @@ +/* usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * BULK and ISOC USB data transfers in a generic way. + * Can be used for DVB-only and also, that's the plan, for + * Hybrid USB devices (analog and DVB). + */ +#include "dvb-usb-common.h" + +/* URB stuff for streaming */ +static void usb_urb_complete(struct urb *urb) +{ + struct usb_data_stream *stream = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; + + deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status,urb->actual_length,urb->transfer_buffer_length, + urb->number_of_packets,urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + deb_ts("urb completition error %d.\n", urb->status); + break; + } + + b = (u8 *) urb->transfer_buffer; + switch (ptype) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + + if (urb->iso_frame_desc[i].status != 0) + deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); + + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + debug_dump(b,20,deb_uxfer); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + err("unknown endpoint type in completition handler."); + return; + } + usb_submit_urb(urb,GFP_ATOMIC); +} + +int usb_urb_kill(struct usb_data_stream *stream) +{ + int i; + for (i = 0; i < stream->urbs_submitted; i++) { + deb_ts("killing URB no. %d.\n",i); + + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + return 0; +} + +int usb_urb_submit(struct usb_data_stream *stream) +{ + int i,ret; + for (i = 0; i < stream->urbs_initialized; i++) { + deb_ts("submitting URB no. %d\n",i); + if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { + err("could not submit URB no. %d - get them all back",i); + usb_urb_kill(stream); + return ret; + } + stream->urbs_submitted++; + } + return 0; +} + +static int usb_free_stream_buffers(struct usb_data_stream *stream) +{ + if (stream->state & USB_STATE_URB_BUF) { + while (stream->buf_num) { + stream->buf_num--; + deb_mem("freeing buffer %d\n",stream->buf_num); + usb_free_coherent(stream->udev, stream->buf_size, + stream->buf_list[stream->buf_num], + stream->dma_addr[stream->buf_num]); + } + } + + stream->state &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) +{ + stream->buf_num = 0; + stream->buf_size = size; + + deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + + for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { + deb_mem("allocating buffer %d\n",stream->buf_num); + if (( stream->buf_list[stream->buf_num] = + usb_alloc_coherent(stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]) ) == NULL) { + deb_mem("not enough memory for urb-buffer allocation.\n"); + usb_free_stream_buffers(stream); + return -ENOMEM; + } + deb_mem("buffer %d: %p (dma: %Lu)\n", + stream->buf_num, +stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num],0,size); + stream->state |= USB_STATE_URB_BUF; + } + deb_mem("allocation successful\n"); + + return 0; +} + +static int usb_bulk_urb_init(struct usb_data_stream *stream) +{ + int i, j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.bulk.buffersize)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!.\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb( stream->urb_list[i], stream->udev, + usb_rcvbulkpipe(stream->udev,stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_isoc_urb_init(struct usb_data_stream *stream) +{ + int i,j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + + stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->buf_size; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) +{ + if (stream == NULL || props == NULL) + return -EINVAL; + + memcpy(&stream->props, props, sizeof(*props)); + + usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); + + if (stream->complete == NULL) { + err("there is no data callback - this doesn't make sense."); + return -EINVAL; + } + + switch (stream->props.type) { + case USB_BULK: + return usb_bulk_urb_init(stream); + case USB_ISOC: + return usb_isoc_urb_init(stream); + default: + err("unknown URB-type for data transfer."); + return -EINVAL; + } +} + +int usb_urb_exit(struct usb_data_stream *stream) +{ + int i; + + usb_urb_kill(stream); + + for (i = 0; i < stream->urbs_initialized; i++) { + if (stream->urb_list[i] != NULL) { + deb_mem("freeing URB no. %d.\n",i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + usb_free_stream_buffers(stream); + return 0; +} diff --git a/drivers/media/usb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c new file mode 100644 index 00000000000..5eab468dd90 --- /dev/null +++ b/drivers/media/usb/dvb-usb/vp702x-fe.c @@ -0,0 +1,379 @@ +/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 + * DVB-S receiver. + * + * Copyright (C) 2005 Ralph Metzler + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * This file can be removed soon, after the DST-driver is rewritten to provice + * the frontend-controlling separately. + * + * 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 "vp702x.h" + +struct vp702x_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; + + struct dvb_frontend_ops ops; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone_mode; + + u8 lnb_buf[8]; + + u8 lock; + u8 sig; + u8 snr; + + unsigned long next_status_check; + unsigned long status_check_interval; +}; + +static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) +{ + struct vp702x_device_state *dst = st->d->priv; + u8 *buf; + + if (time_after(jiffies, st->next_status_check)) { + mutex_lock(&dst->buf_mutex); + buf = dst->buf; + + vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10); + st->lock = buf[4]; + + vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1); + st->snr = buf[0]; + + vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1); + st->sig = buf[0]; + + mutex_unlock(&dst->buf_mutex); + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static u8 vp702x_chksum(u8 *buf,int f, int count) +{ + u8 s = 0; + int i; + for (i = f; i < f+count; i++) + s += buf[i]; + return ~s+1; +} + +static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + deb_fe("%s\n",__func__); + + if (st->lock == 0) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 250; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *unc = 0; + return 0; +} + +static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + *strength = (st->sig << 8) | st->sig; + return 0; +} + +static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + u8 _snr; + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + _snr = (st->snr & 0x1f) * 0xff / 0x1f; + *snr = (_snr << 8) | _snr; + return 0; +} + +static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + deb_fe("%s\n",__func__); + tune->min_delay_ms = 2000; + return 0; +} + +static int vp702x_fe_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + u32 freq = fep->frequency/1000; + /*CalFrequency*/ +/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ + u64 sr; + u8 *cmd; + + mutex_lock(&dst->buf_mutex); + + cmd = dst->buf; + memset(cmd, 0, 10); + + cmd[0] = (freq >> 8) & 0x7f; + cmd[1] = freq & 0xff; + cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ + + sr = (u64) (fep->symbol_rate/1000) << 20; + do_div(sr,88000); + cmd[3] = (sr >> 12) & 0xff; + cmd[4] = (sr >> 4) & 0xff; + cmd[5] = (sr << 4) & 0xf0; + + deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", + fep->frequency, freq, freq, fep->symbol_rate, + (unsigned long) sr, (unsigned long) sr); + +/* if (fep->inversion == INVERSION_ON) + cmd[6] |= 0x80; */ + + if (st->voltage == SEC_VOLTAGE_18) + cmd[6] |= 0x40; + +/* if (fep->symbol_rate > 8000000) + cmd[6] |= 0x20; + + if (fep->frequency < 1531000) + cmd[6] |= 0x04; + + if (st->tone_mode == SEC_TONE_ON) + cmd[6] |= 0x01;*/ + + cmd[7] = vp702x_chksum(cmd,0,7); + + st->status_check_interval = 250; + st->next_status_check = jiffies; + + vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); + + if (cmd[2] == 0 && cmd[3] == 0) + deb_fe("tuning failed.\n"); + else + deb_fe("tuning succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + +static int vp702x_fe_init(struct dvb_frontend *fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + deb_fe("%s\n",__func__); + vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); + return 0; +} + +static int vp702x_fe_sleep(struct dvb_frontend *fe) +{ + deb_fe("%s\n",__func__); + return 0; +} + +static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + u8 *cmd; + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + + deb_fe("%s\n",__func__); + + if (m->msg_len > 4) + return -EINVAL; + + mutex_lock(&dst->buf_mutex); + + cmd = dst->buf; + cmd[1] = SET_DISEQC_CMD; + cmd[2] = m->msg_len; + memcpy(&cmd[3], m->msg, m->msg_len); + cmd[7] = vp702x_chksum(cmd, 0, 7); + + vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); + + if (cmd[2] == 0 && cmd[3] == 0) + deb_fe("diseqc cmd failed.\n"); + else + deb_fe("diseqc cmd succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + +static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + deb_fe("%s\n",__func__); + return 0; +} + +static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + u8 *buf; + + deb_fe("%s\n",__func__); + + st->tone_mode = tone; + + if (tone == SEC_TONE_ON) + st->lnb_buf[2] = 0x02; + else + st->lnb_buf[2] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); + + mutex_lock(&dst->buf_mutex); + + buf = dst->buf; + memcpy(buf, st->lnb_buf, 8); + + vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); + if (buf[2] == 0 && buf[3] == 0) + deb_fe("set_tone cmd failed.\n"); + else + deb_fe("set_tone cmd succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + +static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t + voltage) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + u8 *buf; + deb_fe("%s\n",__func__); + + st->voltage = voltage; + + if (voltage != SEC_VOLTAGE_OFF) + st->lnb_buf[4] = 0x01; + else + st->lnb_buf[4] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); + + mutex_lock(&dst->buf_mutex); + + buf = dst->buf; + memcpy(buf, st->lnb_buf, 8); + + vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); + if (buf[2] == 0 && buf[3] == 0) + deb_fe("set_voltage cmd failed.\n"); + else + deb_fe("set_voltage cmd succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + return 0; +} + +static void vp702x_fe_release(struct dvb_frontend* fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + kfree(st); +} + +static struct dvb_frontend_ops vp702x_fe_ops; + +struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) +{ + struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + + memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + s->lnb_buf[1] = SET_LNB_POWER; + s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ + + return &s->fe; +error: + return NULL; +} + + +static struct dvb_frontend_ops vp702x_fe_ops = { + .delsys = { SYS_DVBS }, + .info = { + .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + .release = vp702x_fe_release, + + .init = vp702x_fe_init, + .sleep = vp702x_fe_sleep, + + .set_frontend = vp702x_fe_set_frontend, + .get_tune_settings = vp702x_fe_get_tune_settings, + + .read_status = vp702x_fe_read_status, + .read_ber = vp702x_fe_read_ber, + .read_signal_strength = vp702x_fe_read_signal_strength, + .read_snr = vp702x_fe_read_snr, + .read_ucblocks = vp702x_fe_read_unc_blocks, + + .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, + .diseqc_send_burst = vp702x_fe_send_diseqc_burst, + .set_tone = vp702x_fe_set_tone, + .set_voltage = vp702x_fe_set_voltage, +}; diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c new file mode 100644 index 00000000000..07c673a6e76 --- /dev/null +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -0,0 +1,444 @@ +/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S + * receiver. + * + * Copyright (C) 2005 Ralph Metzler + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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 "vp702x.h" +#include + +/* debug */ +int dvb_usb_vp702x_debug; +module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct vp702x_adapter_state { + int pid_filter_count; + int pid_filter_can_bypass; + u8 pid_filter_state; +}; + +static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req, + u16 value, u16 index, u8 *b, int blen) +{ + int ret; + + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, b, blen, + 2000); + + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else + ret = 0; + + + deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + return ret; +} + +int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + mutex_lock(&d->usb_mutex); + ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen); + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if ((ret = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000)) != blen) { + warn("usb out operation failed. (%d)",ret); + return -EIO; + } else + return 0; +} + +int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + mutex_lock(&d->usb_mutex); + ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen); + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec) +{ + int ret; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen); + msleep(msec); + ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen); + + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, + int olen, u8 *i, int ilen, int msec) +{ + struct vp702x_device_state *st = d->priv; + int ret = 0; + u8 *buf; + int buflen = max(olen + 2, ilen + 1); + + ret = mutex_lock_interruptible(&st->buf_mutex); + if (ret < 0) + return ret; + + if (buflen > st->buf_len) { + buf = kmalloc(buflen, GFP_KERNEL); + if (!buf) { + mutex_unlock(&st->buf_mutex); + return -ENOMEM; + } + info("successfully reallocated a bigger buffer"); + kfree(st->buf); + st->buf = buf; + st->buf_len = buflen; + } else { + buf = st->buf; + } + + buf[0] = 0x00; + buf[1] = cmd; + memcpy(&buf[2], o, olen); + + ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec); + + if (ret == 0) + memcpy(i, &buf[1], ilen); + mutex_unlock(&st->buf_mutex); + + return ret; +} + +static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass) +{ + int ret; + struct vp702x_device_state *st = adap->dev->priv; + u8 *buf; + + mutex_lock(&st->buf_mutex); + + buf = st->buf; + memset(buf, 0, 16); + + ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, + 0, buf, 16); + mutex_unlock(&st->buf_mutex); + return ret; +} + +static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state) +{ + int ret; + struct vp702x_device_state *st = adap->dev->priv; + u8 *buf; + + mutex_lock(&st->buf_mutex); + + buf = st->buf; + memset(buf, 0, 16); + ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, + 0, buf, 16); + + mutex_unlock(&st->buf_mutex); + + return ret; +} + +static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff) +{ + struct vp702x_adapter_state *st = adap->priv; + struct vp702x_device_state *dst = adap->dev->priv; + u8 *buf; + + if (onoff) + st->pid_filter_state |= (1 << id); + else { + st->pid_filter_state &= ~(1 << id); + pid = 0xffff; + } + + id = 0x10 + id*2; + + vp702x_set_pld_state(adap, st->pid_filter_state); + + mutex_lock(&dst->buf_mutex); + + buf = dst->buf; + memset(buf, 0, 16); + vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16); + vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + + +static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap) +{ + struct vp702x_adapter_state *st = adap->priv; + struct vp702x_device_state *dst = adap->dev->priv; + int i; + u8 *b; + + st->pid_filter_count = 8; + st->pid_filter_can_bypass = 1; + st->pid_filter_state = 0x00; + + vp702x_set_pld_mode(adap, 1); /* bypass */ + + for (i = 0; i < st->pid_filter_count; i++) + vp702x_set_pid(adap, 0xffff, i, 1); + + mutex_lock(&dst->buf_mutex); + b = dst->buf; + memset(b, 0, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10); + mutex_unlock(&dst->buf_mutex); + /*vp702x_set_pld_mode(d, 0); // filter */ + + return 0; +} + +static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + return 0; +} + +/* keys for the enclosed remote control */ +static struct rc_map_table rc_map_vp702x_table[] = { + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, +}; + +/* remote control stuff (does not work with my box) */ +static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 *key; + int i; + +/* remove the following return to enabled remote querying */ + return 0; + + key = kmalloc(10, GFP_KERNEL); + if (!key) + return -ENOMEM; + + vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10); + + deb_rc("remote query key: %x %d\n",key[1],key[1]); + + if (key[1] == 0x44) { + *state = REMOTE_NO_KEY_PRESSED; + kfree(key); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++) + if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) { + *state = REMOTE_KEY_PRESSED; + *event = rc_map_vp702x_table[i].keycode; + break; + } + kfree(key); + return 0; +} + + +static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) +{ + u8 i, *buf; + struct vp702x_device_state *st = d->priv; + + mutex_lock(&st->buf_mutex); + buf = st->buf; + for (i = 6; i < 12; i++) + vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1); + + memcpy(mac, buf, 6); + mutex_unlock(&st->buf_mutex); + return 0; +} + +static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[10] = { 0 }; + + vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); + + if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, + buf, 10, 10)) + return -EIO; + + buf[9] = '\0'; + info("system string: %s",&buf[1]); + + vp702x_init_pid_filter(adap); + + adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev); + vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); + + return 0; +} + +static struct dvb_usb_device_properties vp702x_properties; + +static int vp702x_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct vp702x_device_state *st; + int ret; + + ret = dvb_usb_device_init(intf, &vp702x_properties, + THIS_MODULE, &d, adapter_nr); + if (ret) + goto out; + + st = d->priv; + st->buf_len = 16; + st->buf = kmalloc(st->buf_len, GFP_KERNEL); + if (!st->buf) { + ret = -ENOMEM; + dvb_usb_device_exit(intf); + goto out; + } + mutex_init(&st->buf_mutex); + +out: + return ret; + +} + +static void vp702x_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct vp702x_device_state *st = d->priv; + mutex_lock(&st->buf_mutex); + kfree(st->buf); + mutex_unlock(&st->buf_mutex); + dvb_usb_device_exit(intf); +} + +static struct usb_device_id vp702x_usb_table [] = { + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, +// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, +// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, vp702x_usb_table); + +static struct dvb_usb_device_properties vp702x_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-vp702x-02.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct vp702x_device_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, + + .streaming_ctrl = vp702x_streaming_ctrl, + .frontend_attach = vp702x_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + .size_of_priv = sizeof(struct vp702x_adapter_state), + } + }, + .read_mac_address = vp702x_read_mac_addr, + + .rc.legacy = { + .rc_map_table = rc_map_vp702x_table, + .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table), + .rc_interval = 400, + .rc_query = vp702x_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", + .cold_ids = { &vp702x_usb_table[0], NULL }, + .warm_ids = { NULL }, + }, +/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", + .cold_ids = { &vp702x_usb_table[2], NULL }, + .warm_ids = { &vp702x_usb_table[3], NULL }, + }, +*/ { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vp702x_usb_driver = { + .name = "dvb_usb_vp702x", + .probe = vp702x_usb_probe, + .disconnect = vp702x_usb_disconnect, + .id_table = vp702x_usb_table, +}; + +module_usb_driver(vp702x_usb_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/vp702x.h b/drivers/media/usb/dvb-usb/vp702x.h new file mode 100644 index 00000000000..20b90055e7a --- /dev/null +++ b/drivers/media/usb/dvb-usb/vp702x.h @@ -0,0 +1,113 @@ +#ifndef _DVB_USB_VP7021_H_ +#define _DVB_USB_VP7021_H_ + +#define DVB_USB_LOG_PREFIX "vp702x" +#include "dvb-usb.h" + +extern int dvb_usb_vp702x_debug; +#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args) + +/* commands are read and written with USB control messages */ + +/* consecutive read/write operation */ +#define REQUEST_OUT 0xB2 +#define REQUEST_IN 0xB3 + +/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0 + * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer + * the returning buffer looks as follows + * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */ + +#define GET_TUNER_STATUS 0x05 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */ + +#define GET_SYSTEM_STRING 0x06 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */ + +#define SET_DISEQC_CMD 0x08 +/* additional out buffer: + * 0 1 2 3 4 + * len X1 X2 X3 X4 + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */ + +#define SET_LNB_POWER 0x09 +/* additional out buffer: + * 0 1 2 + * 0x00 0xff 1 = on, 0 = off + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */ + +#define GET_MAC_ADDRESS 0x0A +/* #define GET_MAC_ADDRESS 0x0B */ +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */ + +#define SET_PID_FILTER 0x11 +/* additional in buffer: + * 0 1 ... 14 15 16 + * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ + +/* request: 0xB2; i: 0; v: 0; + * b[0] != 0 -> tune and lock a channel + * 0 1 2 3 4 5 6 7 + * freq0 freq1 divstep srate0 srate1 srate2 flag chksum + */ + +/* one direction requests */ +#define READ_REMOTE_REQ 0xB4 +/* IN i: 0; v: 0; b[0] == request, b[1] == key */ + +#define READ_PID_NUMBER_REQ 0xB5 +/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */ + +#define WRITE_EEPROM_REQ 0xB6 +/* OUT i: offset; v: value to write; no extra buffer */ + +#define READ_EEPROM_REQ 0xB7 +/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ + +#define READ_STATUS 0xB8 +/* IN i: 0; v: 0; bufferlen 10 */ + +#define READ_TUNER_REG_REQ 0xB9 +/* IN i: 0; v: register; b[0] = value */ + +#define READ_FX2_REG_REQ 0xBA +/* IN i: offset; v: 0; b[0] = value */ + +#define WRITE_FX2_REG_REQ 0xBB +/* OUT i: offset; v: value to write; 1 byte extra buffer */ + +#define SET_TUNER_POWER_REQ 0xBC +/* IN i: 0 = power off, 1 = power on */ + +#define WRITE_TUNER_REG_REQ 0xBD +/* IN i: register, v: value to write, no extra buffer */ + +#define RESET_TUNER 0xBE +/* IN i: 0, v: 0, no extra buffer */ + +struct vp702x_device_state { + struct mutex buf_mutex; + int buf_len; + u8 *buf; +}; + + +extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); + +extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); +extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); + +#endif diff --git a/drivers/media/usb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c new file mode 100644 index 00000000000..b8825b18c00 --- /dev/null +++ b/drivers/media/usb/dvb-usb/vp7045-fe.c @@ -0,0 +1,190 @@ +/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0 + * DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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 "vp7045.h" + +/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT + * + * Programming is hidden inside the firmware, so set_frontend is very easy. + * Even though there is a Firmware command that one can use to access the demod + * via its registers. This is used for status information. + */ + +struct vp7045_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; +}; + +static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u8 s0 = vp7045_read_reg(state->d,0x00), + s1 = vp7045_read_reg(state->d,0x01), + s3 = vp7045_read_reg(state->d,0x03); + + *status = 0; + if (s0 & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (s0 & (1 << 1)) + *status |= FE_HAS_VITERBI; + if (s0 & (1 << 5)) + *status |= FE_HAS_LOCK; + if (s1 & (1 << 1)) + *status |= FE_HAS_SYNC; + if (s3 & (1 << 6)) + *status |= FE_HAS_SIGNAL; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + *ber = (vp7045_read_reg(state->d, 0x0D) << 16) | + (vp7045_read_reg(state->d, 0x0E) << 8) | + vp7045_read_reg(state->d, 0x0F); + return 0; +} + +static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + *unc = (vp7045_read_reg(state->d, 0x10) << 8) | + vp7045_read_reg(state->d, 0x11); + return 0; +} + +static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) | + vp7045_read_reg(state->d, 0x15); + + *strength = ~signal; + return 0; +} + +static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u8 _snr = vp7045_read_reg(state->d, 0x09); + *snr = (_snr << 8) | _snr; + return 0; +} + +static int vp7045_fe_init(struct dvb_frontend* fe) +{ + return 0; +} + +static int vp7045_fe_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int vp7045_fe_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct vp7045_fe_state *state = fe->demodulator_priv; + u8 buf[5]; + u32 freq = fep->frequency / 1000; + + buf[0] = (freq >> 16) & 0xff; + buf[1] = (freq >> 8) & 0xff; + buf[2] = freq & 0xff; + buf[3] = 0; + + switch (fep->bandwidth_hz) { + case 8000000: + buf[4] = 8; + break; + case 7000000: + buf[4] = 7; + break; + case 6000000: + buf[4] = 6; + break; + default: + return -EINVAL; + } + + vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200); + return 0; +} + +static void vp7045_fe_release(struct dvb_frontend* fe) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops vp7045_fe_ops; + +struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) +{ + struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + return &s->fe; +error: + return NULL; +} + + +static struct dvb_frontend_ops vp7045_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Twinhan VP7045/46 USB DVB-T", + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 1000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = vp7045_fe_release, + + .init = vp7045_fe_init, + .sleep = vp7045_fe_sleep, + + .set_frontend = vp7045_fe_set_frontend, + .get_tune_settings = vp7045_fe_get_tune_settings, + + .read_status = vp7045_fe_read_status, + .read_ber = vp7045_fe_read_ber, + .read_signal_strength = vp7045_fe_read_signal_strength, + .read_snr = vp7045_fe_read_snr, + .read_ucblocks = vp7045_fe_read_unc_blocks, +}; diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c new file mode 100644 index 00000000000..d750724132e --- /dev/null +++ b/drivers/media/usb/dvb-usb/vp7045.c @@ -0,0 +1,302 @@ +/* DVB USB compliant Linux driver for the + * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver + * - DigitalNow TinyUSB2 DVB-t receiver + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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 "vp7045.h" + +/* debug */ +static int dvb_usb_vp7045_debug; +module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) + +int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) +{ + int ret = 0; + u8 *buf = d->priv; + + buf[0] = cmd; + + if (outlen > 19) + outlen = 19; + + if (inlen > 11) + inlen = 11; + + ret = mutex_lock_interruptible(&d->usb_mutex); + if (ret) + return ret; + + if (out != NULL && outlen > 0) + memcpy(&buf[1], out, outlen); + + deb_xfer("out buffer: "); + debug_dump(buf, outlen+1, deb_xfer); + + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, + buf, 20, 2000) != 20) { + err("USB control message 'out' went wrong."); + ret = -EIO; + goto unlock; + } + + msleep(msec); + + if (usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + buf, 12, 2000) != 12) { + err("USB control message 'in' went wrong."); + ret = -EIO; + goto unlock; + } + + deb_xfer("in buffer: "); + debug_dump(buf, 12, deb_xfer); + + if (in != NULL && inlen > 0) + memcpy(in, &buf[1], inlen); + +unlock: + mutex_unlock(&d->usb_mutex); + + return ret; +} + +u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg) +{ + u8 obuf[2] = { 0 },v; + obuf[1] = reg; + + vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30); + + return v; +} + +static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 v = onoff; + return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150); +} + +/* remote control stuff */ + +/* The keymapping struct. Somehow this should be loaded to the driver, but + * currently it is hardcoded. */ +static struct rc_map_table rc_map_vp7045_table[] = { + { 0x0016, KEY_POWER }, + { 0x0010, KEY_MUTE }, + { 0x0003, KEY_1 }, + { 0x0001, KEY_2 }, + { 0x0006, KEY_3 }, + { 0x0009, KEY_4 }, + { 0x001d, KEY_5 }, + { 0x001f, KEY_6 }, + { 0x000d, KEY_7 }, + { 0x0019, KEY_8 }, + { 0x001b, KEY_9 }, + { 0x0015, KEY_0 }, + { 0x0005, KEY_CHANNELUP }, + { 0x0002, KEY_CHANNELDOWN }, + { 0x001e, KEY_VOLUMEUP }, + { 0x000a, KEY_VOLUMEDOWN }, + { 0x0011, KEY_RECORD }, + { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x0014, KEY_PLAY }, + { 0x001a, KEY_STOP }, + { 0x0040, KEY_REWIND }, + { 0x0012, KEY_FASTFORWARD }, + { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x004c, KEY_PAUSE }, + { 0x004d, KEY_SCREEN }, /* Full screen mode. */ + { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + { 0x000c, KEY_CANCEL }, /* Cancel */ + { 0x001c, KEY_EPG }, /* EPG */ + { 0x0000, KEY_TAB }, /* Tab */ + { 0x0048, KEY_INFO }, /* Preview */ + { 0x0004, KEY_LIST }, /* RecordList */ + { 0x000f, KEY_TEXT }, /* Teletext */ + { 0x0041, KEY_PREVIOUSSONG }, + { 0x0042, KEY_NEXTSONG }, + { 0x004b, KEY_UP }, + { 0x0051, KEY_DOWN }, + { 0x004e, KEY_LEFT }, + { 0x0052, KEY_RIGHT }, + { 0x004f, KEY_ENTER }, + { 0x0013, KEY_CANCEL }, + { 0x004a, KEY_CLEAR }, + { 0x0054, KEY_PRINT }, /* Capture */ + { 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */ + { 0x0008, KEY_VIDEO }, /* A/V */ + { 0x0007, KEY_SLEEP }, /* Hibernate */ + { 0x0045, KEY_ZOOM }, /* Zoom+ */ + { 0x0018, KEY_RED}, + { 0x0053, KEY_GREEN}, + { 0x005e, KEY_YELLOW}, + { 0x005f, KEY_BLUE} +}; + +static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key; + int i; + vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20); + + deb_rc("remote query key: %x %d\n",key,key); + + if (key == 0x44) { + *state = REMOTE_NO_KEY_PRESSED; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++) + if (rc5_data(&rc_map_vp7045_table[i]) == key) { + *state = REMOTE_KEY_PRESSED; + *event = rc_map_vp7045_table[i].keycode; + break; + } + return 0; +} + +static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset) +{ + int i = 0; + u8 v,br[2]; + for (i=0; i < len; i++) { + v = offset + i; + vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5); + buf[i] = br[1]; + } + deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i); + debug_dump(buf,i,deb_info); + return 0; +} + +static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) +{ + return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); +} + +static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[255] = { 0 }; + + vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0); + buf[10] = '\0'; + deb_info("firmware says: %s ",buf); + + vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0); + buf[10] = '\0'; + deb_info("%s ",buf); + + vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0); + buf[10] = '\0'; + deb_info("v%s\n",buf); + +/* Dump the EEPROM */ +/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ + + adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev); + + return 0; +} + +static struct dvb_usb_device_properties vp7045_properties; + +static int vp7045_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &vp7045_properties, + THIS_MODULE, NULL, adapter_nr); +} + +static struct usb_device_id vp7045_usb_table [] = { + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, vp7045_usb_table); + +static struct dvb_usb_device_properties vp7045_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-vp7045-01.fw", + .size_of_priv = 20, + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = vp7045_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }}, + } + }, + .power_ctrl = vp7045_power_ctrl, + .read_mac_address = vp7045_read_mac_addr, + + .rc.legacy = { + .rc_interval = 400, + .rc_map_table = rc_map_vp7045_table, + .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table), + .rc_query = vp7045_rc_query, + }, + + .num_device_descs = 2, + .devices = { + { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", + .cold_ids = { &vp7045_usb_table[0], NULL }, + .warm_ids = { &vp7045_usb_table[1], NULL }, + }, + { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", + .cold_ids = { &vp7045_usb_table[2], NULL }, + .warm_ids = { &vp7045_usb_table[3], NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vp7045_usb_driver = { + .name = "dvb_usb_vp7045", + .probe = vp7045_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = vp7045_usb_table, +}; + +module_usb_driver(vp7045_usb_driver); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/vp7045.h b/drivers/media/usb/dvb-usb/vp7045.h new file mode 100644 index 00000000000..cf5ec46f8bb --- /dev/null +++ b/drivers/media/usb/dvb-usb/vp7045.h @@ -0,0 +1,70 @@ +/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII + * USB2.0 DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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_VP7045_H_ +#define _DVB_USB_VP7045_H_ + +#define DVB_USB_LOG_PREFIX "vp7045" +#include "dvb-usb.h" + +/* vp7045 commands */ + +/* Twinhan Vendor requests */ +#define TH_COMMAND_IN 0xC0 +#define TH_COMMAND_OUT 0xC1 + +/* command bytes */ +#define TUNER_REG_READ 0x03 +#define TUNER_REG_WRITE 0x04 + +#define RC_VAL_READ 0x05 + #define RC_NO_KEY 0x44 + +#define SET_TUNER_POWER 0x06 +#define CHECK_TUNER_POWER 0x12 + #define Tuner_Power_ON 1 + #define Tuner_Power_OFF 0 + +#define GET_USB_SPEED 0x07 + +#define LOCK_TUNER_COMMAND 0x09 + +#define TUNER_SIGNAL_READ 0x0A + +/* FX2 eeprom */ +#define SET_EE_VALUE 0x10 +#define GET_EE_VALUE 0x11 + #define FX2_ID_ADDR 0x00 + #define VID_MSB_ADDR 0x02 + #define VID_LSB_ADDR 0x01 + #define PID_MSB_ADDR 0x04 + #define PID_LSB_ADDR 0x03 + #define MAC_0_ADDR 0x07 + #define MAC_1_ADDR 0x08 + #define MAC_2_ADDR 0x09 + #define MAC_3_ADDR 0x0a + #define MAC_4_ADDR 0x0b + #define MAC_5_ADDR 0x0c + +#define RESET_FX2 0x13 + +#define FW_VERSION_READ 0x0B +#define VENDOR_STRING_READ 0x0C +#define PRODUCT_STRING_READ 0x0D +#define FW_BCD_VERSION_READ 0x14 + +extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d); +extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec); +extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg); + +#endif diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig new file mode 100644 index 00000000000..bc6456eb2c4 --- /dev/null +++ b/drivers/media/usb/siano/Kconfig @@ -0,0 +1,34 @@ +# +# Siano Mobile Silicon Digital TV device configuration +# + +config SMS_SIANO_MDTV + tristate "Siano SMS1xxx based MDTV receiver" + depends on DVB_CORE && RC_CORE && HAS_DMA + ---help--- + Choose Y or M here if you have MDTV receiver with a Siano chipset. + + To compile this driver as a module, choose M here + (The module will be called smsmdtv). + + Further documentation on this driver can be found on the WWW + at http://www.siano-ms.com/ + +if SMS_SIANO_MDTV +menu "Siano module components" + +# Hardware interfaces support + +config SMS_USB_DRV + tristate "USB interface support" + depends on DVB_CORE && USB + ---help--- + Choose if you would like to have Siano's support for USB interface + +config SMS_SDIO_DRV + tristate "SDIO interface support" + depends on DVB_CORE && MMC + ---help--- + Choose if you would like to have Siano's support for SDIO interface +endmenu +endif # SMS_SIANO_MDTV diff --git a/drivers/media/usb/siano/Makefile b/drivers/media/usb/siano/Makefile new file mode 100644 index 00000000000..14756bdb6ea --- /dev/null +++ b/drivers/media/usb/siano/Makefile @@ -0,0 +1,11 @@ + +smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o + +obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o +obj-$(CONFIG_SMS_USB_DRV) += smsusb.o +obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o + +ccflags-y += -Idrivers/media/dvb-core + +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) + diff --git a/drivers/media/usb/siano/sms-cards.c b/drivers/media/usb/siano/sms-cards.c new file mode 100644 index 00000000000..680c781c8dd --- /dev/null +++ b/drivers/media/usb/siano/sms-cards.c @@ -0,0 +1,311 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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 "sms-cards.h" +#include "smsir.h" +#include + +static int sms_dbg; +module_param_named(cards_dbg, sms_dbg, int, 0644); +MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); + +static struct sms_board sms_boards[] = { + [SMS_BOARD_UNKNOWN] = { + .name = "Unknown board", + }, + [SMS1XXX_BOARD_SIANO_STELLAR] = { + .name = "Siano Stellar Digital Receiver", + .type = SMS_STELLAR, + }, + [SMS1XXX_BOARD_SIANO_NOVA_A] = { + .name = "Siano Nova A Digital Receiver", + .type = SMS_NOVA_A0, + }, + [SMS1XXX_BOARD_SIANO_NOVA_B] = { + .name = "Siano Nova B Digital Receiver", + .type = SMS_NOVA_B0, + }, + [SMS1XXX_BOARD_SIANO_VEGA] = { + .name = "Siano Vega Digital Receiver", + .type = SMS_VEGA, + }, + [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { + .name = "Hauppauge Catamount", + .type = SMS_STELLAR, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { + .name = "Hauppauge Okemo-A", + .type = SMS_NOVA_A0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { + .name = "Hauppauge Okemo-B", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { + .name = "Hauppauge WinTV MiniStick", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .rc_codes = RC_MAP_HAUPPAUGE, + .board_cfg.leds_power = 26, + .board_cfg.led0 = 27, + .board_cfg.led1 = 28, + .board_cfg.ir = 9, + .led_power = 26, + .led_lo = 27, + .led_hi = 28, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 29, + .board_cfg.foreign_lna0_ctrl = 29, + .rf_switch = 17, + .board_cfg.rf_switch_uhf = 17, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = -1, + }, + [SMS1XXX_BOARD_SIANO_NICE] = { + /* 11 */ + .name = "Siano Nice Digital Receiver", + .type = SMS_NOVA_B0, + }, + [SMS1XXX_BOARD_SIANO_VENICE] = { + /* 12 */ + .name = "Siano Venice Digital Receiver", + .type = SMS_VEGA, + }, +}; + +struct sms_board *sms_get_board(unsigned id) +{ + BUG_ON(id >= ARRAY_SIZE(sms_boards)); + + return &sms_boards[id]; +} +EXPORT_SYMBOL_GPL(sms_get_board); +static inline void sms_gpio_assign_11xx_default_led_config( + struct smscore_gpio_config *pGpioConfig) { + pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; + pGpioConfig->InputCharacteristics = + SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; + pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; + pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; + pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; +} + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent) { + struct smscore_gpio_config MyGpioConfig; + + sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); + + switch (gevent) { + case BOARD_EVENT_POWER_INIT: /* including hotplug */ + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_POWER_SUSPEND: + break; /* BOARD_EVENT_POWER_SUSPEND */ + + case BOARD_EVENT_POWER_RESUME: + break; /* BOARD_EVENT_POWER_RESUME */ + + case BOARD_EVENT_BIND: + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_SCAN_PROG: + break; /* BOARD_EVENT_SCAN_PROG */ + case BOARD_EVENT_SCAN_COMP: + break; /* BOARD_EVENT_SCAN_COMP */ + case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: + break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ + case BOARD_EVENT_FE_LOCK: + break; /* BOARD_EVENT_FE_LOCK */ + case BOARD_EVENT_FE_UNLOCK: + break; /* BOARD_EVENT_FE_UNLOCK */ + case BOARD_EVENT_DEMOD_LOCK: + break; /* BOARD_EVENT_DEMOD_LOCK */ + case BOARD_EVENT_DEMOD_UNLOCK: + break; /* BOARD_EVENT_DEMOD_UNLOCK */ + case BOARD_EVENT_RECEPTION_MAX_4: + break; /* BOARD_EVENT_RECEPTION_MAX_4 */ + case BOARD_EVENT_RECEPTION_3: + break; /* BOARD_EVENT_RECEPTION_3 */ + case BOARD_EVENT_RECEPTION_2: + break; /* BOARD_EVENT_RECEPTION_2 */ + case BOARD_EVENT_RECEPTION_1: + break; /* BOARD_EVENT_RECEPTION_1 */ + case BOARD_EVENT_RECEPTION_LOST_0: + break; /* BOARD_EVENT_RECEPTION_LOST_0 */ + case BOARD_EVENT_MULTIPLEX_OK: + break; /* BOARD_EVENT_MULTIPLEX_OK */ + case BOARD_EVENT_MULTIPLEX_ERRORS: + break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ + + default: + sms_err("Unknown SMS board event"); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_event); + +static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) +{ + int lvl, ret; + u32 gpio; + struct smscore_config_gpio gpioconfig = { + .direction = SMS_GPIO_DIRECTION_OUTPUT, + .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, + .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, + .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, + .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, + }; + + if (pin == 0) + return -EINVAL; + + if (pin < 0) { + /* inverted gpio */ + gpio = pin * -1; + lvl = enable ? 0 : 1; + } else { + gpio = pin; + lvl = enable ? 1 : 0; + } + + ret = smscore_configure_gpio(coredev, gpio, &gpioconfig); + if (ret < 0) + return ret; + + return smscore_set_gpio(coredev, gpio, lvl); +} + +int sms_board_setup(struct smscore_device_t *coredev) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* turn off all LEDs */ + sms_set_gpio(coredev, board->led_power, 0); + sms_set_gpio(coredev, board->led_hi, 0); + sms_set_gpio(coredev, board->led_lo, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* turn off LNA */ + sms_set_gpio(coredev, board->lna_ctrl, 0); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_setup); + +int sms_board_power(struct smscore_device_t *coredev, int onoff) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* power LED */ + sms_set_gpio(coredev, + board->led_power, onoff ? 1 : 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* LNA */ + if (!onoff) + sms_set_gpio(coredev, board->lna_ctrl, 0); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_power); + +int sms_board_led_feedback(struct smscore_device_t *coredev, int led) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + /* dont touch GPIO if LEDs are already set */ + if (smscore_led_state(coredev, -1) == led) + return 0; + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + sms_set_gpio(coredev, + board->led_lo, (led & SMS_LED_LO) ? 1 : 0); + sms_set_gpio(coredev, + board->led_hi, (led & SMS_LED_HI) ? 1 : 0); + + smscore_led_state(coredev, led); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_led_feedback); + +int sms_board_lna_control(struct smscore_device_t *coredev, int onoff) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled"); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + sms_set_gpio(coredev, + board->rf_switch, onoff ? 1 : 0); + return sms_set_gpio(coredev, + board->lna_ctrl, onoff ? 1 : 0); + } + return -EINVAL; +} +EXPORT_SYMBOL_GPL(sms_board_lna_control); + +int sms_board_load_modules(int id) +{ + switch (id) { + case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT: + case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A: + case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B: + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + request_module("smsdvb"); + break; + default: + /* do nothing */ + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_load_modules); diff --git a/drivers/media/usb/siano/sms-cards.h b/drivers/media/usb/siano/sms-cards.h new file mode 100644 index 00000000000..d8cdf756f7c --- /dev/null +++ b/drivers/media/usb/siano/sms-cards.h @@ -0,0 +1,123 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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 __SMS_CARDS_H__ +#define __SMS_CARDS_H__ + +#include +#include "smscoreapi.h" +#include "smsir.h" + +#define SMS_BOARD_UNKNOWN 0 +#define SMS1XXX_BOARD_SIANO_STELLAR 1 +#define SMS1XXX_BOARD_SIANO_NOVA_A 2 +#define SMS1XXX_BOARD_SIANO_NOVA_B 3 +#define SMS1XXX_BOARD_SIANO_VEGA 4 +#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 +#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 +#define SMS1XXX_BOARD_SIANO_NICE 11 +#define SMS1XXX_BOARD_SIANO_VENICE 12 + +struct sms_board_gpio_cfg { + int lna_vhf_exist; + int lna_vhf_ctrl; + int lna_uhf_exist; + int lna_uhf_ctrl; + int lna_uhf_d_ctrl; + int lna_sband_exist; + int lna_sband_ctrl; + int lna_sband_d_ctrl; + int foreign_lna0_ctrl; + int foreign_lna1_ctrl; + int foreign_lna2_ctrl; + int rf_switch_vhf; + int rf_switch_uhf; + int rf_switch_sband; + int leds_power; + int led0; + int led1; + int led2; + int led3; + int led4; + int ir; + int eeprom_wp; + int mrc_sense; + int mrc_pdn_resetn; + int mrc_gp0; /* mrcs spi int */ + int mrc_gp1; + int mrc_gp2; + int mrc_gp3; + int mrc_gp4; + int host_spi_gsp_ts_int; +}; + +struct sms_board { + enum sms_device_type_st type; + char *name, *fw[DEVICE_MODE_MAX]; + struct sms_board_gpio_cfg board_cfg; + char *rc_codes; /* Name of IR codes table */ + + /* gpios */ + int led_power, led_hi, led_lo, lna_ctrl, rf_switch; +}; + +struct sms_board *sms_get_board(unsigned id); + +extern struct smscore_device_t *coredev; + +enum SMS_BOARD_EVENTS { + BOARD_EVENT_POWER_INIT, + BOARD_EVENT_POWER_SUSPEND, + BOARD_EVENT_POWER_RESUME, + BOARD_EVENT_BIND, + BOARD_EVENT_SCAN_PROG, + BOARD_EVENT_SCAN_COMP, + BOARD_EVENT_EMERGENCY_WARNING_SIGNAL, + BOARD_EVENT_FE_LOCK, + BOARD_EVENT_FE_UNLOCK, + BOARD_EVENT_DEMOD_LOCK, + BOARD_EVENT_DEMOD_UNLOCK, + BOARD_EVENT_RECEPTION_MAX_4, + BOARD_EVENT_RECEPTION_3, + BOARD_EVENT_RECEPTION_2, + BOARD_EVENT_RECEPTION_1, + BOARD_EVENT_RECEPTION_LOST_0, + BOARD_EVENT_MULTIPLEX_OK, + BOARD_EVENT_MULTIPLEX_ERRORS +}; + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent); + +int sms_board_setup(struct smscore_device_t *coredev); + +#define SMS_LED_OFF 0 +#define SMS_LED_LO 1 +#define SMS_LED_HI 2 +int sms_board_led_feedback(struct smscore_device_t *coredev, int led); +int sms_board_power(struct smscore_device_t *coredev, int onoff); +int sms_board_lna_control(struct smscore_device_t *coredev, int onoff); + +extern int sms_board_load_modules(int id); + +#endif /* __SMS_CARDS_H__ */ diff --git a/drivers/media/usb/siano/smscoreapi.c b/drivers/media/usb/siano/smscoreapi.c new file mode 100644 index 00000000000..9cc55546cc3 --- /dev/null +++ b/drivers/media/usb/siano/smscoreapi.c @@ -0,0 +1,1637 @@ +/* + * Siano core API module + * + * This file contains implementation for the interface to sms core component + * + * author: Uri Shkolnik + * + * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" +#include "smsir.h" +#include "smsendian.h" + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +struct smscore_device_notifyee_t { + struct list_head entry; + hotplug_t hotplug; +}; + +struct smscore_idlist_t { + struct list_head entry; + int id; + int data_type; +}; + +struct smscore_client_t { + struct list_head entry; + struct smscore_device_t *coredev; + void *context; + struct list_head idlist; + onresponse_t onresponse_handler; + onremove_t onremove_handler; +}; + +void smscore_set_board_id(struct smscore_device_t *core, int id) +{ + core->board_id = id; +} + +int smscore_led_state(struct smscore_device_t *core, int led) +{ + if (led >= 0) + core->led_state = led; + return core->led_state; +} +EXPORT_SYMBOL_GPL(smscore_set_board_id); + +int smscore_get_board_id(struct smscore_device_t *core) +{ + return core->board_id; +} +EXPORT_SYMBOL_GPL(smscore_get_board_id); + +struct smscore_registry_entry_t { + struct list_head entry; + char devpath[32]; + int mode; + enum sms_device_type_st type; +}; + +static struct list_head g_smscore_notifyees; +static struct list_head g_smscore_devices; +static struct mutex g_smscore_deviceslock; + +static struct list_head g_smscore_registry; +static struct mutex g_smscore_registrylock; + +static int default_mode = 4; + +module_param(default_mode, int, 0644); +MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); + +static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) +{ + struct smscore_registry_entry_t *entry; + struct list_head *next; + + kmutex_lock(&g_smscore_registrylock); + for (next = g_smscore_registry.next; + next != &g_smscore_registry; + next = next->next) { + entry = (struct smscore_registry_entry_t *) next; + if (!strcmp(entry->devpath, devpath)) { + kmutex_unlock(&g_smscore_registrylock); + return entry; + } + } + entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL); + if (entry) { + entry->mode = default_mode; + strcpy(entry->devpath, devpath); + list_add(&entry->entry, &g_smscore_registry); + } else + sms_err("failed to create smscore_registry."); + kmutex_unlock(&g_smscore_registrylock); + return entry; +} + +int smscore_registry_getmode(char *devpath) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + return entry->mode; + else + sms_err("No registry found."); + + return default_mode; +} +EXPORT_SYMBOL_GPL(smscore_registry_getmode); + +static enum sms_device_type_st smscore_registry_gettype(char *devpath) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + return entry->type; + else + sms_err("No registry found."); + + return -1; +} + +void smscore_registry_setmode(char *devpath, int mode) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + entry->mode = mode; + else + sms_err("No registry found."); +} + +static void smscore_registry_settype(char *devpath, + enum sms_device_type_st type) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + entry->type = type; + else + sms_err("No registry found."); +} + + +static void list_add_locked(struct list_head *new, struct list_head *head, + spinlock_t *lock) +{ + unsigned long flags; + + spin_lock_irqsave(lock, flags); + + list_add(new, head); + + spin_unlock_irqrestore(lock, flags); +} + +/** + * register a client callback that called when device plugged in/unplugged + * NOTE: if devices exist callback is called immediately for each device + * + * @param hotplug callback + * + * @return 0 on success, <0 on error. + */ +int smscore_register_hotplug(hotplug_t hotplug) +{ + struct smscore_device_notifyee_t *notifyee; + struct list_head *next, *first; + int rc = 0; + + kmutex_lock(&g_smscore_deviceslock); + + notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), + GFP_KERNEL); + if (notifyee) { + /* now notify callback about existing devices */ + first = &g_smscore_devices; + for (next = first->next; + next != first && !rc; + next = next->next) { + struct smscore_device_t *coredev = + (struct smscore_device_t *) next; + rc = hotplug(coredev, coredev->device, 1); + } + + if (rc >= 0) { + notifyee->hotplug = hotplug; + list_add(¬ifyee->entry, &g_smscore_notifyees); + } else + kfree(notifyee); + } else + rc = -ENOMEM; + + kmutex_unlock(&g_smscore_deviceslock); + + return rc; +} +EXPORT_SYMBOL_GPL(smscore_register_hotplug); + +/** + * unregister a client callback that called when device plugged in/unplugged + * + * @param hotplug callback + * + */ +void smscore_unregister_hotplug(hotplug_t hotplug) +{ + struct list_head *next, *first; + + kmutex_lock(&g_smscore_deviceslock); + + first = &g_smscore_notifyees; + + for (next = first->next; next != first;) { + struct smscore_device_notifyee_t *notifyee = + (struct smscore_device_notifyee_t *) next; + next = next->next; + + if (notifyee->hotplug == hotplug) { + list_del(¬ifyee->entry); + kfree(notifyee); + } + } + + kmutex_unlock(&g_smscore_deviceslock); +} +EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); + +static void smscore_notify_clients(struct smscore_device_t *coredev) +{ + struct smscore_client_t *client; + + /* the client must call smscore_unregister_client from remove handler */ + while (!list_empty(&coredev->clients)) { + client = (struct smscore_client_t *) coredev->clients.next; + client->onremove_handler(client->context); + } +} + +static int smscore_notify_callbacks(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct smscore_device_notifyee_t *elem; + int rc = 0; + + /* note: must be called under g_deviceslock */ + + list_for_each_entry(elem, &g_smscore_notifyees, entry) { + rc = elem->hotplug(coredev, device, arrival); + if (rc < 0) + break; + } + + return rc; +} + +static struct +smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, + dma_addr_t common_buffer_phys) +{ + struct smscore_buffer_t *cb = + kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + if (!cb) { + sms_info("kmalloc(...) failed"); + return NULL; + } + + cb->p = buffer; + cb->offset_in_common = buffer - (u8 *) common_buffer; + cb->phys = common_buffer_phys + cb->offset_in_common; + + return cb; +} + +/** + * creates coredev object for a device, prepares buffers, + * creates buffer mappings, notifies registered hotplugs about new device. + * + * @param params device pointer to struct with device specific parameters + * and handlers + * @param coredev pointer to a value that receives created coredev object + * + * @return 0 on success, <0 on error. + */ +int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev) +{ + struct smscore_device_t *dev; + u8 *buffer; + + dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); + if (!dev) { + sms_info("kzalloc(...) failed"); + return -ENOMEM; + } + + /* init list entry so it could be safe in smscore_unregister_device */ + INIT_LIST_HEAD(&dev->entry); + + /* init queues */ + INIT_LIST_HEAD(&dev->clients); + INIT_LIST_HEAD(&dev->buffers); + + /* init locks */ + spin_lock_init(&dev->clientslock); + spin_lock_init(&dev->bufferslock); + + /* init completion events */ + init_completion(&dev->version_ex_done); + init_completion(&dev->data_download_done); + init_completion(&dev->trigger_done); + init_completion(&dev->init_device_done); + init_completion(&dev->reload_start_done); + init_completion(&dev->resume_done); + init_completion(&dev->gpio_configuration_done); + init_completion(&dev->gpio_set_level_done); + init_completion(&dev->gpio_get_level_done); + init_completion(&dev->ir_init_done); + + /* Buffer management */ + init_waitqueue_head(&dev->buffer_mng_waitq); + + /* alloc common buffer */ + dev->common_buffer_size = params->buffer_size * params->num_buffers; + dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, + &dev->common_buffer_phys, + GFP_KERNEL | GFP_DMA); + if (!dev->common_buffer) { + smscore_unregister_device(dev); + return -ENOMEM; + } + + /* prepare dma buffers */ + for (buffer = dev->common_buffer; + dev->num_buffers < params->num_buffers; + dev->num_buffers++, buffer += params->buffer_size) { + struct smscore_buffer_t *cb = + smscore_createbuffer(buffer, dev->common_buffer, + dev->common_buffer_phys); + if (!cb) { + smscore_unregister_device(dev); + return -ENOMEM; + } + + smscore_putbuffer(dev, cb); + } + + sms_info("allocated %d buffers", dev->num_buffers); + + dev->mode = DEVICE_MODE_NONE; + dev->context = params->context; + dev->device = params->device; + dev->setmode_handler = params->setmode_handler; + dev->detectmode_handler = params->detectmode_handler; + dev->sendrequest_handler = params->sendrequest_handler; + dev->preload_handler = params->preload_handler; + dev->postload_handler = params->postload_handler; + + dev->device_flags = params->flags; + strcpy(dev->devpath, params->devpath); + + smscore_registry_settype(dev->devpath, params->device_type); + + /* add device to devices list */ + kmutex_lock(&g_smscore_deviceslock); + list_add(&dev->entry, &g_smscore_devices); + kmutex_unlock(&g_smscore_deviceslock); + + *coredev = dev; + + sms_info("device %p created", dev); + + return 0; +} +EXPORT_SYMBOL_GPL(smscore_register_device); + + +static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, + void *buffer, size_t size, struct completion *completion) { + int rc = coredev->sendrequest_handler(coredev->context, buffer, size); + if (rc < 0) { + sms_info("sendrequest returned error %d", rc); + return rc; + } + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? + 0 : -ETIME; +} + +/** + * Starts & enables IR operations + * + * @return 0 on success, < 0 on error. + */ +static int smscore_init_ir(struct smscore_device_t *coredev) +{ + int ir_io; + int rc; + void *buffer; + + coredev->ir.dev = NULL; + ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; + if (ir_io) {/* only if IR port exist we use IR sub-module */ + sms_info("IR loading"); + rc = sms_ir_init(coredev); + + if (rc != 0) + sms_err("Error initialization DTV IR sub-module"); + else { + buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST2 *msg = + (struct SmsMsgData_ST2 *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, + MSG_SMS_START_IR_REQ, + sizeof(struct SmsMsgData_ST2)); + msg->msgData[0] = coredev->ir.controller; + msg->msgData[1] = coredev->ir.timeout; + + smsendian_handle_tx_message( + (struct SmsMsgHdr_ST2 *)msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader. msgLength, + &coredev->ir_init_done); + + kfree(buffer); + } else + sms_err + ("Sending IR initialization message failed"); + } + } else + sms_info("IR port has not been detected"); + + return 0; +} + +/** + * sets initial device mode and notifies client hotplugs that device is ready + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +int smscore_start_device(struct smscore_device_t *coredev) +{ + int rc = smscore_set_device_mode( + coredev, smscore_registry_getmode(coredev->devpath)); + if (rc < 0) { + sms_info("set device mode faile , rc %d", rc); + return rc; + } + + kmutex_lock(&g_smscore_deviceslock); + + rc = smscore_notify_callbacks(coredev, coredev->device, 1); + smscore_init_ir(coredev); + + sms_info("device %p started, rc %d", coredev, rc); + + kmutex_unlock(&g_smscore_deviceslock); + + return rc; +} +EXPORT_SYMBOL_GPL(smscore_start_device); + + +static int smscore_load_firmware_family2(struct smscore_device_t *coredev, + void *buffer, size_t size) +{ + struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; + struct SmsMsgHdr_ST *msg; + u32 mem_address; + u8 *payload = firmware->Payload; + int rc = 0; + firmware->StartAddress = le32_to_cpu(firmware->StartAddress); + firmware->Length = le32_to_cpu(firmware->Length); + + mem_address = firmware->StartAddress; + + sms_info("loading FW to addr 0x%x size %d", + mem_address, firmware->Length); + if (coredev->preload_handler) { + rc = coredev->preload_handler(coredev->context); + if (rc < 0) + return rc; + } + + /* PAGE_SIZE buffer shall be enough and dma aligned */ + msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); + if (!msg) + return -ENOMEM; + + if (coredev->mode != DEVICE_MODE_NONE) { + sms_debug("sending reload command."); + SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, + sizeof(struct SmsMsgHdr_ST)); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->msgLength, + &coredev->reload_start_done); + mem_address = *(u32 *) &payload[20]; + } + + while (size && rc >= 0) { + struct SmsDataDownload_ST *DataMsg = + (struct SmsDataDownload_ST *) msg; + int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); + + SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, + (u16)(sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) + payload_size)); + + DataMsg->MemAddr = mem_address; + memcpy(DataMsg->Payload, payload, payload_size); + + if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && + (coredev->mode == DEVICE_MODE_NONE)) + rc = coredev->sendrequest_handler( + coredev->context, DataMsg, + DataMsg->xMsgHeader.msgLength); + else + rc = smscore_sendrequest_and_wait( + coredev, DataMsg, + DataMsg->xMsgHeader.msgLength, + &coredev->data_download_done); + + payload += payload_size; + size -= payload_size; + mem_address += payload_size; + } + + if (rc >= 0) { + if (coredev->mode == DEVICE_MODE_NONE) { + struct SmsMsgData_ST *TriggerMsg = + (struct SmsMsgData_ST *) msg; + + SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, + sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) * 5); + + TriggerMsg->msgData[0] = firmware->StartAddress; + /* Entry point */ + TriggerMsg->msgData[1] = 5; /* Priority */ + TriggerMsg->msgData[2] = 0x200; /* Stack size */ + TriggerMsg->msgData[3] = 0; /* Parameter */ + TriggerMsg->msgData[4] = 4; /* Task ID */ + + if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { + rc = coredev->sendrequest_handler( + coredev->context, TriggerMsg, + TriggerMsg->xMsgHeader.msgLength); + msleep(100); + } else + rc = smscore_sendrequest_and_wait( + coredev, TriggerMsg, + TriggerMsg->xMsgHeader.msgLength, + &coredev->trigger_done); + } else { + SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct SmsMsgHdr_ST)); + + rc = coredev->sendrequest_handler(coredev->context, + msg, msg->msgLength); + } + msleep(500); + } + + sms_debug("rc=%d, postload=%p ", rc, + coredev->postload_handler); + + kfree(msg); + + return ((rc >= 0) && coredev->postload_handler) ? + coredev->postload_handler(coredev->context) : + rc; +} + +/** + * loads specified firmware into a buffer and calls device loadfirmware_handler + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param filename null-terminated string specifies firmware file name + * @param loadfirmware_handler device handler that loads firmware + * + * @return 0 on success, <0 on error. + */ +static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler) +{ + int rc = -ENOENT; + const struct firmware *fw; + u8 *fw_buffer; + + if (loadfirmware_handler == NULL && !(coredev->device_flags & + SMS_DEVICE_FAMILY2)) + return -EINVAL; + + rc = request_firmware(&fw, filename, coredev->device); + if (rc < 0) { + sms_info("failed to open \"%s\"", filename); + return rc; + } + sms_info("read FW %s, size=%zd", filename, fw->size); + fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), + GFP_KERNEL | GFP_DMA); + if (fw_buffer) { + memcpy(fw_buffer, fw->data, fw->size); + + rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? + smscore_load_firmware_family2(coredev, + fw_buffer, + fw->size) : + loadfirmware_handler(coredev->context, + fw_buffer, fw->size); + + kfree(fw_buffer); + } else { + sms_info("failed to allocate firmware buffer"); + rc = -ENOMEM; + } + + release_firmware(fw); + + return rc; +} + +/** + * notifies all clients registered with the device, notifies hotplugs, + * frees all buffers and coredev object + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +void smscore_unregister_device(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb; + int num_buffers = 0; + int retry = 0; + + kmutex_lock(&g_smscore_deviceslock); + + /* Release input device (IR) resources */ + sms_ir_exit(coredev); + + smscore_notify_clients(coredev); + smscore_notify_callbacks(coredev, NULL, 0); + + /* at this point all buffers should be back + * onresponse must no longer be called */ + + while (1) { + while (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); + kfree(cb); + num_buffers++; + } + if (num_buffers == coredev->num_buffers) + break; + if (++retry > 10) { + sms_info("exiting although " + "not all buffers released."); + break; + } + + sms_info("waiting for %d buffer(s)", + coredev->num_buffers - num_buffers); + msleep(100); + } + + sms_info("freed %d buffers", num_buffers); + + if (coredev->common_buffer) + dma_free_coherent(NULL, coredev->common_buffer_size, + coredev->common_buffer, coredev->common_buffer_phys); + + if (coredev->fw_buf != NULL) + kfree(coredev->fw_buf); + + list_del(&coredev->entry); + kfree(coredev); + + kmutex_unlock(&g_smscore_deviceslock); + + sms_info("device %p destroyed", coredev); +} +EXPORT_SYMBOL_GPL(smscore_unregister_device); + +static int smscore_detect_mode(struct smscore_device_t *coredev) +{ + void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + struct SmsMsgHdr_ST *msg = + (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); + int rc; + + if (!buffer) + return -ENOMEM; + + SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, + sizeof(struct SmsMsgHdr_ST)); + + rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, + &coredev->version_ex_done); + if (rc == -ETIME) { + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); + + if (wait_for_completion_timeout(&coredev->resume_done, + msecs_to_jiffies(5000))) { + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->msgLength, + &coredev->version_ex_done); + if (rc < 0) + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " + "second try, rc %d", rc); + } else + rc = -ETIME; + } + + kfree(buffer); + + return rc; +} + +static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { + /*Stellar NOVA A0 Nova B0 VEGA*/ + /*DVBT*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*DVBH*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*TDMB*/ + {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, + /*DABIP*/ + {"none", "none", "none", "none"}, + /*BDA*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*ISDBT*/ + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, + /*ISDBTBDA*/ + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, + /*CMMB*/ + {"none", "none", "none", "cmmb_vega_12mhz.inp"} +}; + +static inline char *sms_get_fw_name(struct smscore_device_t *coredev, + int mode, enum sms_device_type_st type) +{ + char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; + return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; +} + +/** + * calls device handler to change mode of operation + * NOTE: stellar/usb may disconnect when changing mode + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * + * @return 0 on success, <0 on error. + */ +int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) +{ + void *buffer; + int rc = 0; + enum sms_device_type_st type; + + sms_debug("set device mode to %d", mode); + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { + sms_err("invalid mode specified %d", mode); + return -EINVAL; + } + + smscore_registry_setmode(coredev->devpath, mode); + + if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { + rc = smscore_detect_mode(coredev); + if (rc < 0) { + sms_err("mode detect failed %d", rc); + return rc; + } + } + + if (coredev->mode == mode) { + sms_info("device mode %d already set", mode); + return 0; + } + + if (!(coredev->modes_supported & (1 << mode))) { + char *fw_filename; + + type = smscore_registry_gettype(coredev->devpath); + fw_filename = sms_get_fw_name(coredev, mode, type); + + rc = smscore_load_firmware_from_file(coredev, + fw_filename, NULL); + if (rc < 0) { + sms_warn("error %d loading firmware: %s, " + "trying again with default firmware", + rc, fw_filename); + + /* try again with the default firmware */ + fw_filename = smscore_fw_lkup[mode][type]; + rc = smscore_load_firmware_from_file(coredev, + fw_filename, NULL); + + if (rc < 0) { + sms_warn("error %d loading " + "firmware: %s", rc, + fw_filename); + return rc; + } + } + sms_log("firmware download success: %s", fw_filename); + } else + sms_info("mode %d supported by running " + "firmware", mode); + + buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST *msg = + (struct SmsMsgData_ST *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct SmsMsgData_ST)); + msg->msgData[0] = mode; + + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->xMsgHeader.msgLength, + &coredev->init_device_done); + + kfree(buffer); + } else { + sms_err("Could not allocate buffer for " + "init device message."); + rc = -ENOMEM; + } + } else { + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid mode specified %d", mode); + return -EINVAL; + } + + smscore_registry_setmode(coredev->devpath, mode); + + if (coredev->detectmode_handler) + coredev->detectmode_handler(coredev->context, + &coredev->mode); + + if (coredev->mode != mode && coredev->setmode_handler) + rc = coredev->setmode_handler(coredev->context, mode); + } + + if (rc >= 0) { + coredev->mode = mode; + coredev->device_flags &= ~SMS_DEVICE_NOT_READY; + } + + if (rc < 0) + sms_err("return error code %d.", rc); + return rc; +} + +/** + * calls device handler to get current mode of operation + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return current mode + */ +int smscore_get_device_mode(struct smscore_device_t *coredev) +{ + return coredev->mode; +} +EXPORT_SYMBOL_GPL(smscore_get_device_mode); + +/** + * find client by response id & type within the clients list. + * return client handle or NULL. + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param data_type client data type (SMS_DONT_CARE for all types) + * @param id client id (SMS_DONT_CARE for all id) + * + */ +static struct +smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, + int data_type, int id) +{ + struct list_head *first; + struct smscore_client_t *client; + unsigned long flags; + struct list_head *firstid; + struct smscore_idlist_t *client_id; + + spin_lock_irqsave(&coredev->clientslock, flags); + first = &coredev->clients; + list_for_each_entry(client, first, entry) { + firstid = &client->idlist; + list_for_each_entry(client_id, firstid, entry) { + if ((client_id->id == id) && + (client_id->data_type == data_type || + (client_id->data_type == 0))) + goto found; + } + } + client = NULL; +found: + spin_unlock_irqrestore(&coredev->clientslock, flags); + return client; +} + +/** + * find client by response id/type, call clients onresponse handler + * return buffer to pool on error + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param cb pointer to response buffer descriptor + * + */ +void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p + + cb->offset); + struct smscore_client_t *client; + int rc = -EBUSY; + static unsigned long last_sample_time; /* = 0; */ + static int data_total; /* = 0; */ + unsigned long time_now = jiffies_to_msecs(jiffies); + + if (!last_sample_time) + last_sample_time = time_now; + + if (time_now - last_sample_time > 10000) { + sms_debug("\ndata rate %d bytes/secs", + (int)((data_total * 1000) / + (time_now - last_sample_time))); + + last_sample_time = time_now; + data_total = 0; + } + + data_total += cb->size; + /* Do we need to re-route? */ + if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || + (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { + if (coredev->mode == DEVICE_MODE_DVBT_BDA) + phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; + } + + + client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + + /* If no client registered for type & id, + * check for control client where type is not registered */ + if (client) + rc = client->onresponse_handler(client->context, cb); + + if (rc < 0) { + switch (phdr->msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) phdr; + sms_debug("MSG_SMS_GET_VERSION_EX_RES " + "id %d prots 0x%x ver %d.%d", + ver->FirmwareId, ver->SupportedProtocols, + ver->RomVersionMajor, ver->RomVersionMinor); + + coredev->mode = ver->FirmwareId == 255 ? + DEVICE_MODE_NONE : ver->FirmwareId; + coredev->modes_supported = ver->SupportedProtocols; + + complete(&coredev->version_ex_done); + break; + } + case MSG_SMS_INIT_DEVICE_RES: + sms_debug("MSG_SMS_INIT_DEVICE_RES"); + complete(&coredev->init_device_done); + break; + case MSG_SW_RELOAD_START_RES: + sms_debug("MSG_SW_RELOAD_START_RES"); + complete(&coredev->reload_start_done); + break; + case MSG_SMS_DATA_DOWNLOAD_RES: + complete(&coredev->data_download_done); + break; + case MSG_SW_RELOAD_EXEC_RES: + sms_debug("MSG_SW_RELOAD_EXEC_RES"); + break; + case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: + sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); + complete(&coredev->trigger_done); + break; + case MSG_SMS_SLEEP_RESUME_COMP_IND: + complete(&coredev->resume_done); + break; + case MSG_SMS_GPIO_CONFIG_EX_RES: + sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); + complete(&coredev->gpio_configuration_done); + break; + case MSG_SMS_GPIO_SET_LEVEL_RES: + sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); + complete(&coredev->gpio_set_level_done); + break; + case MSG_SMS_GPIO_GET_LEVEL_RES: + { + u32 *msgdata = (u32 *) phdr; + coredev->gpio_get_res = msgdata[1]; + sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", + coredev->gpio_get_res); + complete(&coredev->gpio_get_level_done); + break; + } + case MSG_SMS_START_IR_RES: + complete(&coredev->ir_init_done); + break; + case MSG_SMS_IR_SAMPLES_IND: + sms_ir_event(coredev, + (const char *) + ((char *)phdr + + sizeof(struct SmsMsgHdr_ST)), + (int)phdr->msgLength + - sizeof(struct SmsMsgHdr_ST)); + break; + + default: + break; + } + smscore_putbuffer(coredev, cb); + } +} +EXPORT_SYMBOL_GPL(smscore_onresponse); + +/** + * return pointer to next free buffer descriptor from core pool + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return pointer to descriptor on success, NULL on error. + */ + +struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb = NULL; + unsigned long flags; + + spin_lock_irqsave(&coredev->bufferslock, flags); + if (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); + } + spin_unlock_irqrestore(&coredev->bufferslock, flags); + return cb; +} + +struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb = NULL; + + wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev))); + + return cb; +} +EXPORT_SYMBOL_GPL(smscore_getbuffer); + +/** + * return buffer descriptor to a pool + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param cb pointer buffer descriptor + * + */ +void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb) { + wake_up_interruptible(&coredev->buffer_mng_waitq); + list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); +} +EXPORT_SYMBOL_GPL(smscore_putbuffer); + +static int smscore_validate_client(struct smscore_device_t *coredev, + struct smscore_client_t *client, + int data_type, int id) +{ + struct smscore_idlist_t *listentry; + struct smscore_client_t *registered_client; + + if (!client) { + sms_err("bad parameter."); + return -EINVAL; + } + registered_client = smscore_find_client(coredev, data_type, id); + if (registered_client == client) + return 0; + + if (registered_client) { + sms_err("The msg ID already registered to another client."); + return -EEXIST; + } + listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); + if (!listentry) { + sms_err("Can't allocate memory for client id."); + return -ENOMEM; + } + listentry->id = id; + listentry->data_type = data_type; + list_add_locked(&listentry->entry, &client->idlist, + &coredev->clientslock); + return 0; +} + +/** + * creates smsclient object, check that id is taken by another client + * + * @param coredev pointer to a coredev object from clients hotplug + * @param initial_id all messages with this id would be sent to this client + * @param data_type all messages of this type would be sent to this client + * @param onresponse_handler client handler that is called to + * process incoming messages + * @param onremove_handler client handler that is called when device is removed + * @param context client-specific context + * @param client pointer to a value that receives created smsclient object + * + * @return 0 on success, <0 on error. + */ +int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client) +{ + struct smscore_client_t *newclient; + /* check that no other channel with same parameters exists */ + if (smscore_find_client(coredev, params->data_type, + params->initial_id)) { + sms_err("Client already exist."); + return -EEXIST; + } + + newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); + if (!newclient) { + sms_err("Failed to allocate memory for client."); + return -ENOMEM; + } + + INIT_LIST_HEAD(&newclient->idlist); + newclient->coredev = coredev; + newclient->onresponse_handler = params->onresponse_handler; + newclient->onremove_handler = params->onremove_handler; + newclient->context = params->context; + list_add_locked(&newclient->entry, &coredev->clients, + &coredev->clientslock); + smscore_validate_client(coredev, newclient, params->data_type, + params->initial_id); + *client = newclient; + sms_debug("%p %d %d", params->context, params->data_type, + params->initial_id); + + return 0; +} +EXPORT_SYMBOL_GPL(smscore_register_client); + +/** + * frees smsclient object and all subclients associated with it + * + * @param client pointer to smsclient object returned by + * smscore_register_client + * + */ +void smscore_unregister_client(struct smscore_client_t *client) +{ + struct smscore_device_t *coredev = client->coredev; + unsigned long flags; + + spin_lock_irqsave(&coredev->clientslock, flags); + + + while (!list_empty(&client->idlist)) { + struct smscore_idlist_t *identry = + (struct smscore_idlist_t *) client->idlist.next; + list_del(&identry->entry); + kfree(identry); + } + + sms_info("%p", client->context); + + list_del(&client->entry); + kfree(client); + + spin_unlock_irqrestore(&coredev->clientslock, flags); +} +EXPORT_SYMBOL_GPL(smscore_unregister_client); + +/** + * verifies that source id is not taken by another client, + * calls device handler to send requests to the device + * + * @param client pointer to smsclient object returned by + * smscore_register_client + * @param buffer pointer to a request buffer + * @param size size (in bytes) of request buffer + * + * @return 0 on success, <0 on error. + */ +int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size) +{ + struct smscore_device_t *coredev; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; + int rc; + + if (client == NULL) { + sms_err("Got NULL client"); + return -EINVAL; + } + + coredev = client->coredev; + + /* check that no other channel with same id exists */ + if (coredev == NULL) { + sms_err("Got NULL coredev"); + return -EINVAL; + } + + rc = smscore_validate_client(client->coredev, client, 0, + phdr->msgSrcId); + if (rc < 0) + return rc; + + return coredev->sendrequest_handler(coredev->context, buffer, size); +} +EXPORT_SYMBOL_GPL(smsclient_sendrequest); + + +/* old GPIO managements implementation */ +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_config_gpio *pinconfig) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[6]; + } msg; + + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = pinconfig->pullupdown; + + /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ + msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; + + switch (pinconfig->outputdriving) { + case SMS_GPIO_OUTPUTDRIVING_16mA: + msg.data[3] = 7; /* Nova - 16mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_12mA: + msg.data[3] = 5; /* Nova - 11mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_8mA: + msg.data[3] = 3; /* Nova - 7mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_4mA: + default: + msg.data[3] = 2; /* Nova - 4mA */ + break; + } + + msg.data[4] = pinconfig->direction; + msg.data[5] = 0; + } else /* TODO: SMS_DEVICE_FAMILY1 */ + return -EINVAL; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[3]; + } msg; + + if (pin > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = level ? 1 : 0; + msg.data[2] = 0; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + +/* new GPIO management implementation */ +static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, + u32 *pGroupNum, u32 *pGroupCfg) { + + *pGroupCfg = 1; + + if (PinNum <= 1) { + *pTranslatedPinNum = 0; + *pGroupNum = 9; + *pGroupCfg = 2; + } else if (PinNum >= 2 && PinNum <= 6) { + *pTranslatedPinNum = 2; + *pGroupNum = 0; + *pGroupCfg = 2; + } else if (PinNum >= 7 && PinNum <= 11) { + *pTranslatedPinNum = 7; + *pGroupNum = 1; + } else if (PinNum >= 12 && PinNum <= 15) { + *pTranslatedPinNum = 12; + *pGroupNum = 2; + *pGroupCfg = 3; + } else if (PinNum == 16) { + *pTranslatedPinNum = 16; + *pGroupNum = 23; + } else if (PinNum >= 17 && PinNum <= 24) { + *pTranslatedPinNum = 17; + *pGroupNum = 3; + } else if (PinNum == 25) { + *pTranslatedPinNum = 25; + *pGroupNum = 6; + } else if (PinNum >= 26 && PinNum <= 28) { + *pTranslatedPinNum = 26; + *pGroupNum = 4; + } else if (PinNum == 29) { + *pTranslatedPinNum = 29; + *pGroupNum = 5; + *pGroupCfg = 2; + } else if (PinNum == 30) { + *pTranslatedPinNum = 30; + *pGroupNum = 8; + } else if (PinNum == 31) { + *pTranslatedPinNum = 31; + *pGroupNum = 17; + } else + return -1; + + *pGroupCfg <<= 24; + + return 0; +} + +int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig) { + + u32 totalLen; + u32 TranslatedPinNum = 0; + u32 GroupNum = 0; + u32 ElectricChar; + u32 groupCfg; + void *buffer; + int rc; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[6]; + } *pMsg; + + + if (PinNum > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + if (pGpioConfig == NULL) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + + if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; + if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, + &groupCfg) != 0) { + rc = -EINVAL; + goto free; + } + + pMsg->msgData[1] = TranslatedPinNum; + pMsg->msgData[2] = GroupNum; + ElectricChar = (pGpioConfig->PullUpDown) + | (pGpioConfig->InputCharacteristics << 2) + | (pGpioConfig->OutputSlewRate << 3) + | (pGpioConfig->OutputDriving << 4); + pMsg->msgData[3] = ElectricChar; + pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[5] = groupCfg; + } else { + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + pMsg->msgData[1] = pGpioConfig->PullUpDown; + pMsg->msgData[2] = pGpioConfig->OutputSlewRate; + pMsg->msgData[3] = pGpioConfig->OutputDriving; + pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[5] = 0; + } + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_configuration_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_configure timeout"); + else + sms_err("smscore_gpio_configure error"); + } +free: + kfree(buffer); + + return rc; +} + +int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel) { + + u32 totalLen; + int rc; + void *buffer; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[3]; /* keep it 3 ! */ + } *pMsg; + + if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER)) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + + (3 * sizeof(u32)); /* keep it 3 ! */ + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + pMsg->msgData[1] = NewLevel; + + /* Send message to SMS */ + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_set_level_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_set_level timeout"); + else + sms_err("smscore_gpio_set_level error"); + } + kfree(buffer); + + return rc; +} + +int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level) { + + u32 totalLen; + int rc; + void *buffer; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[2]; + } *pMsg; + + + if (PinNum > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + pMsg->msgData[1] = 0; + + /* Send message to SMS */ + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_get_level_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_get_level timeout"); + else + sms_err("smscore_gpio_get_level error"); + } + kfree(buffer); + + /* Its a race between other gpio_get_level() and the copy of the single + * global 'coredev->gpio_get_res' to the function's variable 'level' + */ + *level = coredev->gpio_get_res; + + return rc; +} + +static int __init smscore_module_init(void) +{ + int rc = 0; + + INIT_LIST_HEAD(&g_smscore_notifyees); + INIT_LIST_HEAD(&g_smscore_devices); + kmutex_init(&g_smscore_deviceslock); + + INIT_LIST_HEAD(&g_smscore_registry); + kmutex_init(&g_smscore_registrylock); + + return rc; +} + +static void __exit smscore_module_exit(void) +{ + kmutex_lock(&g_smscore_deviceslock); + while (!list_empty(&g_smscore_notifyees)) { + struct smscore_device_notifyee_t *notifyee = + (struct smscore_device_notifyee_t *) + g_smscore_notifyees.next; + + list_del(¬ifyee->entry); + kfree(notifyee); + } + kmutex_unlock(&g_smscore_deviceslock); + + kmutex_lock(&g_smscore_registrylock); + while (!list_empty(&g_smscore_registry)) { + struct smscore_registry_entry_t *entry = + (struct smscore_registry_entry_t *) + g_smscore_registry.next; + + list_del(&entry->entry); + kfree(entry); + } + kmutex_unlock(&g_smscore_registrylock); + + sms_debug(""); +} + +module_init(smscore_module_init); +module_exit(smscore_module_exit); + +MODULE_DESCRIPTION("Siano MDTV Core module"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/siano/smscoreapi.h b/drivers/media/usb/siano/smscoreapi.h new file mode 100644 index 00000000000..c592ae09039 --- /dev/null +++ b/drivers/media/usb/siano/smscoreapi.h @@ -0,0 +1,775 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat + +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, see . + +****************************************************************/ + +#ifndef __SMS_CORE_API_H__ +#define __SMS_CORE_API_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "smsir.h" + +#define kmutex_init(_p_) mutex_init(_p_) +#define kmutex_lock(_p_) mutex_lock(_p_) +#define kmutex_trylock(_p_) mutex_trylock(_p_) +#define kmutex_unlock(_p_) mutex_unlock(_p_) + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) +#define SMS_ALLOC_ALIGNMENT 128 +#define SMS_DMA_ALIGNMENT 16 +#define SMS_ALIGN_ADDRESS(addr) \ + ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) + +#define SMS_DEVICE_FAMILY2 1 +#define SMS_ROM_NO_RESPONSE 2 +#define SMS_DEVICE_NOT_READY 0x8000000 + +enum sms_device_type_st { + SMS_STELLAR = 0, + SMS_NOVA_A0, + SMS_NOVA_B0, + SMS_VEGA, + SMS_NUM_OF_DEVICE_TYPES +}; + +struct smscore_device_t; +struct smscore_client_t; +struct smscore_buffer_t; + +typedef int (*hotplug_t)(struct smscore_device_t *coredev, + struct device *device, int arrival); + +typedef int (*setmode_t)(void *context, int mode); +typedef void (*detectmode_t)(void *context, int *mode); +typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); +typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); +typedef int (*preload_t)(void *context); +typedef int (*postload_t)(void *context); + +typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); +typedef void (*onremove_t)(void *context); + +struct smscore_buffer_t { + /* public members, once passed to clients can be changed freely */ + struct list_head entry; + int size; + int offset; + + /* private members, read-only for clients */ + void *p; + dma_addr_t phys; + unsigned long offset_in_common; +}; + +struct smsdevice_params_t { + struct device *device; + + int buffer_size; + int num_buffers; + + char devpath[32]; + unsigned long flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + void *context; + enum sms_device_type_st device_type; +}; + +struct smsclient_params_t { + int initial_id; + int data_type; + onresponse_t onresponse_handler; + onremove_t onremove_handler; + void *context; +}; + +struct smscore_device_t { + struct list_head entry; + + struct list_head clients; + struct list_head subclients; + spinlock_t clientslock; + + struct list_head buffers; + spinlock_t bufferslock; + int num_buffers; + + void *common_buffer; + int common_buffer_size; + dma_addr_t common_buffer_phys; + + void *context; + struct device *device; + + char devpath[32]; + unsigned long device_flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + int mode, modes_supported; + + /* host <--> device messages */ + struct completion version_ex_done, data_download_done, trigger_done; + struct completion init_device_done, reload_start_done, resume_done; + struct completion gpio_configuration_done, gpio_set_level_done; + struct completion gpio_get_level_done, ir_init_done; + + /* Buffer management */ + wait_queue_head_t buffer_mng_waitq; + + /* GPIO */ + int gpio_get_res; + + /* Target hardware board */ + int board_id; + + /* Firmware */ + u8 *fw_buf; + u32 fw_buf_size; + + /* Infrared (IR) */ + struct ir_t ir; + + int led_state; +}; + +/* GPIO definitions for antenna frequency domain control (SMS8021) */ +#define SMS_ANTENNA_GPIO_0 1 +#define SMS_ANTENNA_GPIO_1 0 + +#define BW_8_MHZ 0 +#define BW_7_MHZ 1 +#define BW_6_MHZ 2 +#define BW_5_MHZ 3 +#define BW_ISDBT_1SEG 4 +#define BW_ISDBT_3SEG 5 + +#define MSG_HDR_FLAG_SPLIT_MSG 4 + +#define MAX_GPIO_PIN_NUMBER 31 + +#define HIF_TASK 11 +#define SMS_HOST_LIB 150 +#define DVBT_BDA_CONTROL_MSG_ID 201 + +#define SMS_MAX_PAYLOAD_SIZE 240 +#define SMS_TUNE_TIMEOUT 500 + +#define MSG_SMS_GPIO_CONFIG_REQ 507 +#define MSG_SMS_GPIO_CONFIG_RES 508 +#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 +#define MSG_SMS_GPIO_SET_LEVEL_RES 510 +#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 +#define MSG_SMS_GPIO_GET_LEVEL_RES 512 +#define MSG_SMS_RF_TUNE_REQ 561 +#define MSG_SMS_RF_TUNE_RES 562 +#define MSG_SMS_INIT_DEVICE_REQ 578 +#define MSG_SMS_INIT_DEVICE_RES 579 +#define MSG_SMS_ADD_PID_FILTER_REQ 601 +#define MSG_SMS_ADD_PID_FILTER_RES 602 +#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 +#define MSG_SMS_REMOVE_PID_FILTER_RES 604 +#define MSG_SMS_DAB_CHANNEL 607 +#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 +#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 +#define MSG_SMS_GET_STATISTICS_RES 616 +#define MSG_SMS_GET_STATISTICS_REQ 615 +#define MSG_SMS_HO_PER_SLICES_IND 630 +#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 +#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 +#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 +#define MSG_SMS_DATA_DOWNLOAD_REQ 660 +#define MSG_SMS_DATA_DOWNLOAD_RES 661 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 +#define MSG_SMS_GET_VERSION_EX_REQ 668 +#define MSG_SMS_GET_VERSION_EX_RES 669 +#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 +#define MSG_SMS_I2C_SET_FREQ_REQ 685 +#define MSG_SMS_GENERIC_I2C_REQ 687 +#define MSG_SMS_GENERIC_I2C_RES 688 +#define MSG_SMS_DVBT_BDA_DATA 693 +#define MSG_SW_RELOAD_REQ 697 +#define MSG_SMS_DATA_MSG 699 +#define MSG_SW_RELOAD_START_REQ 702 +#define MSG_SW_RELOAD_START_RES 703 +#define MSG_SW_RELOAD_EXEC_REQ 704 +#define MSG_SW_RELOAD_EXEC_RES 705 +#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 +#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 +#define MSG_SMS_GPIO_CONFIG_EX_RES 713 +#define MSG_SMS_ISDBT_TUNE_REQ 776 +#define MSG_SMS_ISDBT_TUNE_RES 777 +#define MSG_SMS_TRANSMISSION_IND 782 +#define MSG_SMS_START_IR_REQ 800 +#define MSG_SMS_START_IR_RES 801 +#define MSG_SMS_IR_SAMPLES_IND 802 +#define MSG_SMS_SIGNAL_DETECTED_IND 827 +#define MSG_SMS_NO_SIGNAL_IND 828 + +#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ + (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ + (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ +} while (0) + +#define SMS_INIT_MSG(ptr, type, len) \ + SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) + +enum SMS_DVB3_EVENTS { + DVB3_EVENT_INIT = 0, + DVB3_EVENT_SLEEP, + DVB3_EVENT_HOTPLUG, + DVB3_EVENT_FE_LOCK, + DVB3_EVENT_FE_UNLOCK, + DVB3_EVENT_UNC_OK, + DVB3_EVENT_UNC_ERR +}; + +enum SMS_DEVICE_MODE { + DEVICE_MODE_NONE = -1, + DEVICE_MODE_DVBT = 0, + DEVICE_MODE_DVBH, + DEVICE_MODE_DAB_TDMB, + DEVICE_MODE_DAB_TDMB_DABIP, + DEVICE_MODE_DVBT_BDA, + DEVICE_MODE_ISDBT, + DEVICE_MODE_ISDBT_BDA, + DEVICE_MODE_CMMB, + DEVICE_MODE_RAW_TUNER, + DEVICE_MODE_MAX, +}; + +struct SmsMsgHdr_ST { + u16 msgType; + u8 msgSrcId; + u8 msgDstId; + u16 msgLength; /* Length of entire message, including header */ + u16 msgFlags; +}; + +struct SmsMsgData_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[1]; +}; + +struct SmsMsgData_ST2 { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[2]; +}; + +struct SmsDataDownload_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 MemAddr; + u8 Payload[SMS_MAX_PAYLOAD_SIZE]; +}; + +struct SmsVersionRes_ST { + struct SmsMsgHdr_ST xMsgHeader; + + u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ + u8 Step; /* 0 - Step A */ + u8 MetalFix; /* 0 - Metal 0 */ + + /* FirmwareId 0xFF if ROM, otherwise the + * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ + u8 FirmwareId; + /* SupportedProtocols Bitwise OR combination of + * supported protocols */ + u8 SupportedProtocols; + + u8 VersionMajor; + u8 VersionMinor; + u8 VersionPatch; + u8 VersionFieldPatch; + + u8 RomVersionMajor; + u8 RomVersionMinor; + u8 RomVersionPatch; + u8 RomVersionFieldPatch; + + u8 TextLabel[34]; +}; + +struct SmsFirmware_ST { + u32 CheckSum; + u32 Length; + u32 StartAddress; + u8 Payload[1]; +}; + +/* Statistics information returned as response for + * SmsHostApiGetStatistics_Req */ +struct SMSHOSTLIB_STATISTICS_ST { + u32 Reserved; /* Reserved */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ + u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + for DVB-T/H FFT mode carriers in Kilos */ + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, + valid only for DVB-T/H */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + valid only for DVB-T/H */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, + valid only for DVB-T/H */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ + + /* Burst parameters, valid only for DVB-H */ + u32 BurstSize; /* Current burst size in bytes, + valid only for DVB-H */ + u32 BurstDuration; /* Current burst duration in mSec, + valid only for DVB-H */ + u32 BurstCycleTime; /* Current burst cycle time in mSec, + valid only for DVB-H */ + u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, + as calculated by demodulator, valid only for DVB-H */ + u32 NumOfRows; /* Number of rows in MPE table, + valid only for DVB-H */ + u32 NumOfPaddCols; /* Number of padding columns in MPE table, + valid only for DVB-H */ + u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, + valid only for DVB-H */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + errors after MPE RS decoding */ + u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors + after MPE RS decoding */ + u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were + corrected by MPE RS decoding */ + /* Common params */ + u32 BERErrorCount; /* Number of errornous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + + /* Interface information */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + + /* DAB/T-DMB */ + u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + + u32 NumMPEReceived; /* DVB-H, Num MPE section received */ + + u32 ReservedFields[10]; /* Reserved */ +}; + +struct SmsMsgStatisticsInfo_ST { + u32 RequestResult; + + struct SMSHOSTLIB_STATISTICS_ST Stat; + + /* Split the calc of the SNR in DAB */ + u32 Signal; /* dB */ + u32 Noise; /* dB */ + +}; + +struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { + /* Per-layer information */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + * 255 means layer does not exist */ + u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, + * 255 means layer does not exist */ + u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ + u32 BERErrorCount; /* Post Viterbi Error Bits Count */ + u32 BERBitCount; /* Post Viterbi Total Bits Count */ + u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ + u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ + u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 TILdepthI; /* Time interleaver depth I parameter, + * 255 means layer does not exist */ + u32 NumberOfSegments; /* Number of segments in layer A, + * 255 means layer does not exist */ + u32 TMCCErrors; /* TMCC errors */ +}; + +struct SMSHOSTLIB_STATISTICS_ISDBT_ST { + u32 StatisticsType; /* Enumerator identifying the type of the + * structure. Values are the same as + * SMSHOSTLIB_DEVICE_MODES_E + * + * This field MUST always be first in any + * statistics structure */ + + u32 FullSize; /* Total size of the structure returned by the modem. + * If the size requested by the host is smaller than + * FullSize, the struct will be truncated */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in Hz */ + + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* ISDB-T transmission mode */ + u32 ModemState; /* 0 - Acquisition, 1 - Locked */ + u32 GuardInterval; /* Guard Interval, 1 divided by value */ + u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ + u32 NumOfLayers; /* Number of ISDB-T layers in the network */ + + /* Per-layer information */ + /* Layers A, B and C */ + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; + /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ + + /* Interface information */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ +}; + +struct PID_STATISTICS_DATA_S { + struct PID_BURST_S { + u32 size; + u32 padding_cols; + u32 punct_cols; + u32 duration; + u32 cycle; + u32 calc_cycle; + } burst; + + u32 tot_tbl_cnt; + u32 invalid_tbl_cnt; + u32 tot_cor_tbl; +}; + +struct PID_DATA_S { + u32 pid; + u32 num_rows; + struct PID_STATISTICS_DATA_S pid_statistics; +}; + +#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) +#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) +#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ + if (_stat.TransmissionMode == 0) \ + _stat.TransmissionMode = 2; \ + else if (_stat.TransmissionMode == 1) \ + _stat.TransmissionMode = 8; \ + else \ + _stat.TransmissionMode = 4; + +struct TRANSMISSION_STATISTICS_S { + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* FFT mode carriers in Kilos */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET */ + + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ +}; + +struct RECEPTION_STATISTICS_S { + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + + s32 MRC_SNR; /* dB */ + s32 MRC_RSSI; /* dBm */ + s32 MRC_InBandPwr; /* In band power in dBM */ +}; + + +/* Statistics information returned as response for + * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +struct SMSHOSTLIB_STATISTICS_DVB_S { + /* Reception */ + struct RECEPTION_STATISTICS_S ReceptionData; + + /* Transmission parameters */ + struct TRANSMISSION_STATISTICS_S TransmissionData; + + /* Burst parameters, valid only for DVB-H */ +#define SRVM_MAX_PID_FILTERS 8 + struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; +}; + +struct SRVM_SIGNAL_STATUS_S { + u32 result; + u32 snr; + u32 tsPackets; + u32 etsPackets; + u32 constellation; + u32 hpCode; + u32 tpsSrvIndLP; + u32 tpsSrvIndHP; + u32 cellId; + u32 reason; + + s32 inBandPower; + u32 requestId; +}; + +struct SMSHOSTLIB_I2C_REQ_ST { + u32 DeviceAddress; /* I2c device address */ + u32 WriteCount; /* number of bytes to write */ + u32 ReadCount; /* number of bytes to read */ + u8 Data[1]; +}; + +struct SMSHOSTLIB_I2C_RES_ST { + u32 Status; /* non-zero value in case of failure */ + u32 ReadCount; /* number of bytes read */ + u8 Data[1]; +}; + + +struct smscore_config_gpio { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 direction; + +#define SMS_GPIO_PULLUPDOWN_NONE 0 +#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 +#define SMS_GPIO_PULLUPDOWN_PULLUP 2 +#define SMS_GPIO_PULLUPDOWN_KEEPER 3 + u8 pullupdown; + +#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 + u8 inputcharacteristics; + +#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 +#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 + u8 outputslewrate; + +#define SMS_GPIO_OUTPUTDRIVING_4mA 0 +#define SMS_GPIO_OUTPUTDRIVING_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_12mA 2 +#define SMS_GPIO_OUTPUTDRIVING_16mA 3 + u8 outputdriving; +}; + +struct smscore_gpio_config { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 Direction; + +#define SMS_GPIO_PULL_UP_DOWN_NONE 0 +#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 +#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 +#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 + u8 PullUpDown; + +#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 + u8 InputCharacteristics; + +#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ + + +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ + u8 OutputSlewRate; + +#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ + +#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ + u8 OutputDriving; +}; + +extern void smscore_registry_setmode(char *devpath, int mode); +extern int smscore_registry_getmode(char *devpath); + +extern int smscore_register_hotplug(hotplug_t hotplug); +extern void smscore_unregister_hotplug(hotplug_t hotplug); + +extern int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev); +extern void smscore_unregister_device(struct smscore_device_t *coredev); + +extern int smscore_start_device(struct smscore_device_t *coredev); +extern int smscore_load_firmware(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler); + +extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); +extern int smscore_get_device_mode(struct smscore_device_t *coredev); + +extern int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client); +extern void smscore_unregister_client(struct smscore_client_t *client); + +extern int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size); +extern void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); +extern int smscore_map_common_buffer(struct smscore_device_t *coredev, + struct vm_area_struct *vma); +extern int smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode, char *filename); +extern int smscore_send_fw_file(struct smscore_device_t *coredev, + u8 *ufwbuf, int size); + +extern +struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); +extern void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +/* old GPIO management */ +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_config_gpio *pinconfig); +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); + +/* new GPIO management */ +extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig); +extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel); +extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level); + +void smscore_set_board_id(struct smscore_device_t *core, int id); +int smscore_get_board_id(struct smscore_device_t *core); + +int smscore_led_state(struct smscore_device_t *core, int led); + + +/* ------------------------------------------------------------------------ */ + +#define DBG_INFO 1 +#define DBG_ADV 2 + +#define sms_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define dprintk(kern, lvl, fmt, arg...) do {\ + if (sms_dbg & lvl) \ + sms_printk(kern, fmt, ##arg); } while (0) + +#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) +#define sms_err(fmt, arg...) \ + sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) +#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) +#define sms_info(fmt, arg...) \ + dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) +#define sms_debug(fmt, arg...) \ + dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) + + +#endif /* __SMS_CORE_API_H__ */ diff --git a/drivers/media/usb/siano/smsdvb.c b/drivers/media/usb/siano/smsdvb.c new file mode 100644 index 00000000000..aa77e54a8fa --- /dev/null +++ b/drivers/media/usb/siano/smsdvb.c @@ -0,0 +1,1078 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +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, see . + +****************************************************************/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "smscoreapi.h" +#include "smsendian.h" +#include "sms-cards.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct smsdvb_client_t { + struct list_head entry; + + struct smscore_device_t *coredev; + struct smscore_client_t *smsclient; + + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend frontend; + + fe_status_t fe_status; + + struct completion tune_done; + + struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; + int event_fe_state; + int event_unc_state; +}; + +static struct list_head g_smsdvb_clients; +static struct mutex g_smsdvb_clientslock; + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +/* Events that may come from DVB v3 adapter */ +static void sms_board_dvb3_event(struct smsdvb_client_t *client, + enum SMS_DVB3_EVENTS event) { + + struct smscore_device_t *coredev = client->coredev; + switch (event) { + case DVB3_EVENT_INIT: + sms_debug("DVB3_EVENT_INIT"); + sms_board_event(coredev, BOARD_EVENT_BIND); + break; + case DVB3_EVENT_SLEEP: + sms_debug("DVB3_EVENT_SLEEP"); + sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); + break; + case DVB3_EVENT_HOTPLUG: + sms_debug("DVB3_EVENT_HOTPLUG"); + sms_board_event(coredev, BOARD_EVENT_POWER_INIT); + break; + case DVB3_EVENT_FE_LOCK: + if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { + client->event_fe_state = DVB3_EVENT_FE_LOCK; + sms_debug("DVB3_EVENT_FE_LOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_LOCK); + } + break; + case DVB3_EVENT_FE_UNLOCK: + if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { + client->event_fe_state = DVB3_EVENT_FE_UNLOCK; + sms_debug("DVB3_EVENT_FE_UNLOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); + } + break; + case DVB3_EVENT_UNC_OK: + if (client->event_unc_state != DVB3_EVENT_UNC_OK) { + client->event_unc_state = DVB3_EVENT_UNC_OK; + sms_debug("DVB3_EVENT_UNC_OK"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); + } + break; + case DVB3_EVENT_UNC_ERR: + if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { + client->event_unc_state = DVB3_EVENT_UNC_ERR; + sms_debug("DVB3_EVENT_UNC_ERR"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); + } + break; + + default: + sms_err("Unknown dvb3 api event"); + break; + } +} + + +static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData, + struct SMSHOSTLIB_STATISTICS_ST *p) +{ + if (sms_dbg & 2) { + printk(KERN_DEBUG "Reserved = %d", p->Reserved); + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "BER = %d", p->BER); + printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); + printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); + printk(KERN_DEBUG "MFER = %d", p->MFER); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); + printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); + printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); + printk(KERN_DEBUG "Constellation = %d", p->Constellation); + printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); + printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); + printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); + printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); + printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); + printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); + printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); + printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); + printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); + printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); + printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); + printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); + printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); + printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); + printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + printk(KERN_DEBUG "PreBER = %d", p->PreBER); + printk(KERN_DEBUG "CellId = %d", p->CellId); + printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); + printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); + printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); + } + + pReceptionData->IsDemodLocked = p->IsDemodLocked; + + pReceptionData->SNR = p->SNR; + pReceptionData->BER = p->BER; + pReceptionData->BERErrorCount = p->BERErrorCount; + pReceptionData->InBandPwr = p->InBandPwr; + pReceptionData->ErrorTSPackets = p->ErrorTSPackets; +}; + + +static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData, + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) +{ + int i; + + if (sms_dbg & 2) { + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "SystemType = %d", p->SystemType); + printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); + printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); + printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); + printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); + printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); + printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); + printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); + printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); + printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); + printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); + printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); + printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); + printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); + printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + } + } + + pReceptionData->IsDemodLocked = p->IsDemodLocked; + + pReceptionData->SNR = p->SNR; + pReceptionData->InBandPwr = p->InBandPwr; + + pReceptionData->ErrorTSPackets = 0; + pReceptionData->BER = 0; + pReceptionData->BERErrorCount = 0; + for (i = 0; i < 3; i++) { + pReceptionData->BER += p->LayerInfo[i].BER; + pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount; + pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets; + } +} + +static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) +{ + struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + + cb->offset); + u32 *pMsgData = (u32 *) phdr + 1; + /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ + bool is_status_update = false; + + smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); + + switch (phdr->msgType) { + case MSG_SMS_DVBT_BDA_DATA: + dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), + cb->size - sizeof(struct SmsMsgHdr_ST)); + break; + + case MSG_SMS_RF_TUNE_RES: + case MSG_SMS_ISDBT_TUNE_RES: + complete(&client->tune_done); + break; + + case MSG_SMS_SIGNAL_DETECTED_IND: + sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; + is_status_update = true; + break; + + case MSG_SMS_NO_SIGNAL_IND: + sms_info("MSG_SMS_NO_SIGNAL_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; + is_status_update = true; + break; + + case MSG_SMS_TRANSMISSION_IND: { + sms_info("MSG_SMS_TRANSMISSION_IND"); + + pMsgData++; + memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, + sizeof(struct TRANSMISSION_STATISTICS_S)); + + /* Mo need to correct guard interval + * (as opposed to old statistics message). + */ + CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); + CORRECT_STAT_TRANSMISSON_MODE( + client->sms_stat_dvb.TransmissionData); + is_status_update = true; + break; + } + case MSG_SMS_HO_PER_SLICES_IND: { + struct RECEPTION_STATISTICS_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + struct SRVM_SIGNAL_STATUS_S SignalStatusData; + + /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ + pMsgData++; + SignalStatusData.result = pMsgData[0]; + SignalStatusData.snr = pMsgData[1]; + SignalStatusData.inBandPower = (s32) pMsgData[2]; + SignalStatusData.tsPackets = pMsgData[3]; + SignalStatusData.etsPackets = pMsgData[4]; + SignalStatusData.constellation = pMsgData[5]; + SignalStatusData.hpCode = pMsgData[6]; + SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; + SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; + SignalStatusData.cellId = pMsgData[9] & 0xFFFF; + SignalStatusData.reason = pMsgData[10]; + SignalStatusData.requestId = pMsgData[11]; + pReceptionData->IsRfLocked = pMsgData[16]; + pReceptionData->IsDemodLocked = pMsgData[17]; + pReceptionData->ModemState = pMsgData[12]; + pReceptionData->SNR = pMsgData[1]; + pReceptionData->BER = pMsgData[13]; + pReceptionData->RSSI = pMsgData[14]; + CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); + + pReceptionData->InBandPwr = (s32) pMsgData[2]; + pReceptionData->CarrierOffset = (s32) pMsgData[15]; + pReceptionData->TotalTSPackets = pMsgData[3]; + pReceptionData->ErrorTSPackets = pMsgData[4]; + + /* TS PER */ + if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) + > 0) { + pReceptionData->TS_PER = (SignalStatusData.etsPackets + * 100) / (SignalStatusData.tsPackets + + SignalStatusData.etsPackets); + } else { + pReceptionData->TS_PER = 0; + } + + pReceptionData->BERBitCount = pMsgData[18]; + pReceptionData->BERErrorCount = pMsgData[19]; + + pReceptionData->MRC_SNR = pMsgData[20]; + pReceptionData->MRC_InBandPwr = pMsgData[21]; + pReceptionData->MRC_RSSI = pMsgData[22]; + + is_status_update = true; + break; + } + case MSG_SMS_GET_STATISTICS_RES: { + union { + struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; + struct SmsMsgStatisticsInfo_ST dvb; + } *p = (void *) (phdr + 1); + struct RECEPTION_STATISTICS_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + + sms_info("MSG_SMS_GET_STATISTICS_RES"); + + is_status_update = true; + + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt); + break; + default: + smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat); + } + if (!pReceptionData->IsDemodLocked) { + pReceptionData->SNR = 0; + pReceptionData->BER = 0; + pReceptionData->BERErrorCount = 0; + pReceptionData->InBandPwr = 0; + pReceptionData->ErrorTSPackets = 0; + } + + complete(&client->tune_done); + break; + } + default: + sms_info("Unhandled message %d", phdr->msgType); + + } + smscore_putbuffer(client->coredev, cb); + + if (is_status_update) { + if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER + | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); + if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets + == 0) + sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); + else + sms_board_dvb3_event(client, + DVB3_EVENT_UNC_ERR); + + } else { + if (client->sms_stat_dvb.ReceptionData.IsRfLocked) + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + client->fe_status = 0; + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); + } + } + + return 0; +} + +static void smsdvb_unregister_client(struct smsdvb_client_t *client) +{ + /* must be called under clientslock */ + + list_del(&client->entry); + + smscore_unregister_client(client->smsclient); + dvb_unregister_frontend(&client->frontend); + dvb_dmxdev_release(&client->dmxdev); + dvb_dmx_release(&client->demux); + dvb_unregister_adapter(&client->adapter); + kfree(client); +} + +static void smsdvb_onremove(void *context) +{ + kmutex_lock(&g_smsdvb_clientslock); + + smsdvb_unregister_client((struct smsdvb_client_t *) context); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +static int smsdvb_start_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("add pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("remove pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, + void *buffer, size_t size, + struct completion *completion) +{ + int rc; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); + rc = smsclient_sendrequest(client->smsclient, buffer, size); + if (rc < 0) + return rc; + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(2000)) ? + 0 : -ETIME; +} + +static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) +{ + int rc; + struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, + DVBT_BDA_CONTROL_MSG_ID, + HIF_TASK, + sizeof(struct SmsMsgHdr_ST), 0 }; + + rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + return rc; +} + +static inline int led_feedback(struct smsdvb_client_t *client) +{ + if (client->fe_status & FE_HAS_LOCK) + return sms_board_led_feedback(client->coredev, + (client->sms_stat_dvb.ReceptionData.BER + == 0) ? SMS_LED_HI : SMS_LED_LO); + else + return sms_board_led_feedback(client->coredev, SMS_LED_OFF); +} + +static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *stat = client->fe_status; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ber = client->sms_stat_dvb.ReceptionData.BER; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + int rc; + + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) + *strength = 0; + else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) + *strength = 100; + else + *strength = + (client->sms_stat_dvb.ReceptionData.InBandPwr + + 95) * 3 / 2; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *snr = client->sms_stat_dvb.ReceptionData.SNR; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; + + led_feedback(client); + + return rc; +} + +static int smsdvb_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + sms_debug(""); + + tune->min_delay_ms = 400; + tune->step_size = 250000; + tune->max_drift = 0; + return 0; +} + +static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[3]; + } Msg; + + int ret; + + client->fe_status = FE_HAS_SIGNAL; + client->event_fe_state = -1; + client->event_unc_state = -1; + fe->dtv_property_cache.delivery_system = SYS_DVBT; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + Msg.Data[0] = c->frequency; + Msg.Data[2] = 12000000; + + sms_info("%s: freq %d band %d", __func__, c->frequency, + c->bandwidth_hz); + + switch (c->bandwidth_hz / 1000000) { + case 8: + Msg.Data[1] = BW_8_MHZ; + break; + case 7: + Msg.Data[1] = BW_7_MHZ; + break; + case 6: + Msg.Data[1] = BW_6_MHZ; + break; + case 0: + return -EOPNOTSUPP; + default: + return -EINVAL; + } + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } + + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[4]; + } Msg; + + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + + if (c->isdbt_sb_segment_idx == -1) + c->isdbt_sb_segment_idx = 0; + + switch (c->isdbt_sb_segment_count) { + case 3: + Msg.Data[1] = BW_ISDBT_3SEG; + break; + case 1: + Msg.Data[1] = BW_ISDBT_1SEG; + break; + case 0: /* AUTO */ + switch (c->bandwidth_hz / 1000000) { + case 8: + case 7: + c->isdbt_sb_segment_count = 3; + Msg.Data[1] = BW_ISDBT_3SEG; + break; + case 6: + c->isdbt_sb_segment_count = 1; + Msg.Data[1] = BW_ISDBT_1SEG; + break; + default: /* Assumes 6 MHZ bw */ + c->isdbt_sb_segment_count = 1; + c->bandwidth_hz = 6000; + Msg.Data[1] = BW_ISDBT_1SEG; + break; + } + break; + default: + sms_info("Segment count %d not supported", c->isdbt_sb_segment_count); + return -EINVAL; + } + + Msg.Data[0] = c->frequency; + Msg.Data[2] = 12000000; + Msg.Data[3] = c->isdbt_sb_segment_idx; + + sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, + c->frequency, c->isdbt_sb_segment_count, + c->isdbt_sb_segment_idx); + + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_set_frontend(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + return smsdvb_dvbt_set_frontend(fe); + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + return smsdvb_isdbt_set_frontend(fe); + default: + return -EINVAL; + } +} + +static int smsdvb_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + struct TRANSMISSION_STATISTICS_S *td = + &client->sms_stat_dvb.TransmissionData; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + fep->frequency = td->Frequency; + + switch (td->Bandwidth) { + case 6: + fep->bandwidth_hz = 6000000; + break; + case 7: + fep->bandwidth_hz = 7000000; + break; + case 8: + fep->bandwidth_hz = 8000000; + break; + } + + switch (td->TransmissionMode) { + case 2: + fep->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 8: + fep->transmission_mode = TRANSMISSION_MODE_8K; + } + + switch (td->GuardInterval) { + case 0: + fep->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + fep->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + fep->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + fep->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch (td->CodeRate) { + case 0: + fep->code_rate_HP = FEC_1_2; + break; + case 1: + fep->code_rate_HP = FEC_2_3; + break; + case 2: + fep->code_rate_HP = FEC_3_4; + break; + case 3: + fep->code_rate_HP = FEC_5_6; + break; + case 4: + fep->code_rate_HP = FEC_7_8; + break; + } + + switch (td->LPCodeRate) { + case 0: + fep->code_rate_LP = FEC_1_2; + break; + case 1: + fep->code_rate_LP = FEC_2_3; + break; + case 2: + fep->code_rate_LP = FEC_3_4; + break; + case 3: + fep->code_rate_LP = FEC_5_6; + break; + case 4: + fep->code_rate_LP = FEC_7_8; + break; + } + + switch (td->Constellation) { + case 0: + fep->modulation = QPSK; + break; + case 1: + fep->modulation = QAM_16; + break; + case 2: + fep->modulation = QAM_64; + break; + } + + switch (td->Hierarchy) { + case 0: + fep->hierarchy = HIERARCHY_NONE; + break; + case 1: + fep->hierarchy = HIERARCHY_1; + break; + case 2: + fep->hierarchy = HIERARCHY_2; + break; + case 3: + fep->hierarchy = HIERARCHY_4; + break; + } + + fep->inversion = INVERSION_AUTO; + break; + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + fep->frequency = td->Frequency; + fep->bandwidth_hz = 6000000; + /* todo: retrive the other parameters */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smsdvb_init(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_power(client->coredev, 1); + + sms_board_dvb3_event(client, DVB3_EVENT_INIT); + return 0; +} + +static int smsdvb_sleep(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + sms_board_power(client->coredev, 0); + + sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); + + return 0; +} + +static void smsdvb_release(struct dvb_frontend *fe) +{ + /* do nothing */ +} + +static struct dvb_frontend_ops smsdvb_fe_ops = { + .info = { + .name = "Siano Mobile Digital MDTV Receiver", + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = smsdvb_release, + + .set_frontend = smsdvb_set_frontend, + .get_frontend = smsdvb_get_frontend, + .get_tune_settings = smsdvb_get_tune_settings, + + .read_status = smsdvb_read_status, + .read_ber = smsdvb_read_ber, + .read_signal_strength = smsdvb_read_signal_strength, + .read_snr = smsdvb_read_snr, + .read_ucblocks = smsdvb_read_ucblocks, + + .init = smsdvb_init, + .sleep = smsdvb_sleep, +}; + +static int smsdvb_hotplug(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct smsclient_params_t params; + struct smsdvb_client_t *client; + int rc; + + /* device removal handled by onremove callback */ + if (!arrival) + return 0; + client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); + if (!client) { + sms_err("kmalloc() failed"); + return -ENOMEM; + } + + /* register dvb adapter */ + rc = dvb_register_adapter(&client->adapter, + sms_get_board( + smscore_get_board_id(coredev))->name, + THIS_MODULE, device, adapter_nr); + if (rc < 0) { + sms_err("dvb_register_adapter() failed %d", rc); + goto adapter_error; + } + + /* init dvb demux */ + client->demux.dmx.capabilities = DMX_TS_FILTERING; + client->demux.filternum = 32; /* todo: nova ??? */ + client->demux.feednum = 32; + client->demux.start_feed = smsdvb_start_feed; + client->demux.stop_feed = smsdvb_stop_feed; + + rc = dvb_dmx_init(&client->demux); + if (rc < 0) { + sms_err("dvb_dmx_init failed %d", rc); + goto dvbdmx_error; + } + + /* init dmxdev */ + client->dmxdev.filternum = 32; + client->dmxdev.demux = &client->demux.dmx; + client->dmxdev.capabilities = 0; + + rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); + if (rc < 0) { + sms_err("dvb_dmxdev_init failed %d", rc); + goto dmxdev_error; + } + + /* init and register frontend */ + memcpy(&client->frontend.ops, &smsdvb_fe_ops, + sizeof(struct dvb_frontend_ops)); + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + client->frontend.ops.delsys[0] = SYS_DVBT; + break; + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + client->frontend.ops.delsys[0] = SYS_ISDBT; + break; + } + + rc = dvb_register_frontend(&client->adapter, &client->frontend); + if (rc < 0) { + sms_err("frontend registration failed %d", rc); + goto frontend_error; + } + + params.initial_id = 1; + params.data_type = MSG_SMS_DVBT_BDA_DATA; + params.onresponse_handler = smsdvb_onresponse; + params.onremove_handler = smsdvb_onremove; + params.context = client; + + rc = smscore_register_client(coredev, ¶ms, &client->smsclient); + if (rc < 0) { + sms_err("smscore_register_client() failed %d", rc); + goto client_error; + } + + client->coredev = coredev; + + init_completion(&client->tune_done); + + kmutex_lock(&g_smsdvb_clientslock); + + list_add(&client->entry, &g_smsdvb_clients); + + kmutex_unlock(&g_smsdvb_clientslock); + + client->event_fe_state = -1; + client->event_unc_state = -1; + sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); + + sms_info("success"); + sms_board_setup(coredev); + + return 0; + +client_error: + dvb_unregister_frontend(&client->frontend); + +frontend_error: + dvb_dmxdev_release(&client->dmxdev); + +dmxdev_error: + dvb_dmx_release(&client->demux); + +dvbdmx_error: + dvb_unregister_adapter(&client->adapter); + +adapter_error: + kfree(client); + return rc; +} + +static int __init smsdvb_module_init(void) +{ + int rc; + + INIT_LIST_HEAD(&g_smsdvb_clients); + kmutex_init(&g_smsdvb_clientslock); + + rc = smscore_register_hotplug(smsdvb_hotplug); + + sms_debug(""); + + return rc; +} + +static void __exit smsdvb_module_exit(void) +{ + smscore_unregister_hotplug(smsdvb_hotplug); + + kmutex_lock(&g_smsdvb_clientslock); + + while (!list_empty(&g_smsdvb_clients)) + smsdvb_unregister_client( + (struct smsdvb_client_t *) g_smsdvb_clients.next); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +module_init(smsdvb_module_init); +module_exit(smsdvb_module_exit); + +MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/siano/smsendian.c b/drivers/media/usb/siano/smsendian.c new file mode 100644 index 00000000000..e2657c2f010 --- /dev/null +++ b/drivers/media/usb/siano/smsendian.c @@ -0,0 +1,103 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + 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, see . + + ****************************************************************/ + +#include +#include + +#include "smsendian.h" +#include "smscoreapi.h" + +void smsendian_handle_tx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_DATA_DOWNLOAD_REQ: + { + msg->msgData[0] = le32_to_cpu(msg->msgData[0]); + break; + } + + default: + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); + +void smsendian_handle_rx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) msg; + ver->ChipModel = le16_to_cpu(ver->ChipModel); + break; + } + + case MSG_SMS_DVBT_BDA_DATA: + case MSG_SMS_DAB_CHANNEL: + case MSG_SMS_DATA_MSG: + { + break; + } + + default: + { + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } + } +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); + +void smsendian_handle_message_header(void *msg) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; + + phdr->msgType = le16_to_cpu(phdr->msgType); + phdr->msgLength = le16_to_cpu(phdr->msgLength); + phdr->msgFlags = le16_to_cpu(phdr->msgFlags); +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/usb/siano/smsendian.h b/drivers/media/usb/siano/smsendian.h new file mode 100644 index 00000000000..1624d6fd367 --- /dev/null +++ b/drivers/media/usb/siano/smsendian.h @@ -0,0 +1,32 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + +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, see . + +****************************************************************/ + +#ifndef __SMS_ENDIAN_H__ +#define __SMS_ENDIAN_H__ + +#include + +extern void smsendian_handle_tx_message(void *buffer); +extern void smsendian_handle_rx_message(void *buffer); +extern void smsendian_handle_message_header(void *msg); + +#endif /* __SMS_ENDIAN_H__ */ + diff --git a/drivers/media/usb/siano/smsir.c b/drivers/media/usb/siano/smsir.c new file mode 100644 index 00000000000..37bc5c4b8ad --- /dev/null +++ b/drivers/media/usb/siano/smsir.c @@ -0,0 +1,114 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + Copyright (c) 2010 - Mauro Carvalho Chehab + - Ported the driver to use rc-core + - IR raw event decoding is now done at rc-core + - Code almost re-written + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (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, see . + + ****************************************************************/ + + +#include +#include + +#include "smscoreapi.h" +#include "smsir.h" +#include "sms-cards.h" + +#define MODULE_NAME "smsmdtv" + +void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) +{ + int i; + const s32 *samples = (const void *)buf; + + for (i = 0; i < len >> 2; i++) { + DEFINE_IR_RAW_EVENT(ev); + + ev.duration = abs(samples[i]) * 1000; /* Convert to ns */ + ev.pulse = (samples[i] > 0) ? false : true; + + ir_raw_event_store(coredev->ir.dev, &ev); + } + ir_raw_event_handle(coredev->ir.dev); +} + +int sms_ir_init(struct smscore_device_t *coredev) +{ + int err; + int board_id = smscore_get_board_id(coredev); + struct rc_dev *dev; + + sms_log("Allocating rc device"); + dev = rc_allocate_device(); + if (!dev) { + sms_err("Not enough memory"); + return -ENOMEM; + } + + coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ + coredev->ir.timeout = IR_DEFAULT_TIMEOUT; + sms_log("IR port %d, timeout %d ms", + coredev->ir.controller, coredev->ir.timeout); + + snprintf(coredev->ir.name, sizeof(coredev->ir.name), + "SMS IR (%s)", sms_get_board(board_id)->name); + + strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); + strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); + + dev->input_name = coredev->ir.name; + dev->input_phys = coredev->ir.phys; + dev->dev.parent = coredev->device; + +#if 0 + /* TODO: properly initialize the parameters bellow */ + dev->input_id.bustype = BUS_USB; + dev->input_id.version = 1; + dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); +#endif + + dev->priv = coredev; + dev->driver_type = RC_DRIVER_IR_RAW; + dev->allowed_protos = RC_TYPE_ALL; + dev->map_name = sms_get_board(board_id)->rc_codes; + dev->driver_name = MODULE_NAME; + + sms_log("Input device (IR) %s is set for key events", dev->input_name); + + err = rc_register_device(dev); + if (err < 0) { + sms_err("Failed to register device"); + rc_free_device(dev); + return err; + } + + coredev->ir.dev = dev; + return 0; +} + +void sms_ir_exit(struct smscore_device_t *coredev) +{ + if (coredev->ir.dev) + rc_unregister_device(coredev->ir.dev); + + sms_log(""); +} diff --git a/drivers/media/usb/siano/smsir.h b/drivers/media/usb/siano/smsir.h new file mode 100644 index 00000000000..ae92b3a8587 --- /dev/null +++ b/drivers/media/usb/siano/smsir.h @@ -0,0 +1,55 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + + Copyright (c) 2010 - Mauro Carvalho Chehab + - Ported the driver to use rc-core + - IR raw event decoding is now done at rc-core + - Code almost re-written + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(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, see . + +****************************************************************/ + +#ifndef __SMS_IR_H__ +#define __SMS_IR_H__ + +#include +#include + +#define IR_DEFAULT_TIMEOUT 100 + +struct smscore_device_t; + +struct ir_t { + struct rc_dev *dev; + char name[40]; + char phys[32]; + + char *rc_codes; + u64 protocol; + + u32 timeout; + u32 controller; +}; + +int sms_ir_init(struct smscore_device_t *coredev); +void sms_ir_exit(struct smscore_device_t *coredev); +void sms_ir_event(struct smscore_device_t *coredev, + const char *buf, int len); + +#endif /* __SMS_IR_H__ */ + diff --git a/drivers/media/usb/siano/smssdio.c b/drivers/media/usb/siano/smssdio.c new file mode 100644 index 00000000000..d6f3f100699 --- /dev/null +++ b/drivers/media/usb/siano/smssdio.c @@ -0,0 +1,365 @@ +/* + * smssdio.c - Siano 1xxx SDIO interface driver + * + * Copyright 2008 Pierre Ossman + * + * Based on code by Siano Mobile Silicon, Inc., + * Copyright (C) 2006-2008, Uri Shkolnik + * + * 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 hardware is a bit odd in that all transfers should be done + * to/from the SMSSDIO_DATA register, yet the "increase address" bit + * always needs to be set. + * + * Also, buffers from the card are always aligned to 128 byte + * boundaries. + */ + +/* + * General cleanup notes: + * + * - only typedefs should be name *_t + * + * - use ERR_PTR and friends for smscore_register_device() + * + * - smscore_getbuffer should zero fields + * + * Fix stop command + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" + +/* Registers */ + +#define SMSSDIO_DATA 0x00 +#define SMSSDIO_INT 0x04 +#define SMSSDIO_BLOCK_SIZE 128 + +static const struct sdio_device_id smssdio_ids[] __devinitconst = { + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), + .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), + .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0), + .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0), + .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), + .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, smssdio_ids); + +struct smssdio_device { + struct sdio_func *func; + + struct smscore_device_t *coredev; + + struct smscore_buffer_t *split_cb; +}; + +/*******************************************************************/ +/* Siano core callbacks */ +/*******************************************************************/ + +static int smssdio_sendrequest(void *context, void *buffer, size_t size) +{ + int ret = 0; + struct smssdio_device *smsdev; + + smsdev = context; + + sdio_claim_host(smsdev->func); + + while (size >= smsdev->func->cur_blksize) { + ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, + buffer, smsdev->func->cur_blksize); + if (ret) + goto out; + + buffer += smsdev->func->cur_blksize; + size -= smsdev->func->cur_blksize; + } + + if (size) { + ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, + buffer, size); + } + +out: + sdio_release_host(smsdev->func); + + return ret; +} + +/*******************************************************************/ +/* SDIO callbacks */ +/*******************************************************************/ + +static void smssdio_interrupt(struct sdio_func *func) +{ + int ret; + + struct smssdio_device *smsdev; + struct smscore_buffer_t *cb; + struct SmsMsgHdr_ST *hdr; + size_t size; + + smsdev = sdio_get_drvdata(func); + + /* + * The interrupt register has no defined meaning. It is just + * a way of turning of the level triggered interrupt. + */ + (void)sdio_readb(func, SMSSDIO_INT, &ret); + if (ret) { + sms_err("Unable to read interrupt register!\n"); + return; + } + + if (smsdev->split_cb == NULL) { + cb = smscore_getbuffer(smsdev->coredev); + if (!cb) { + sms_err("Unable to allocate data buffer!\n"); + return; + } + + ret = sdio_memcpy_fromio(smsdev->func, + cb->p, + SMSSDIO_DATA, + SMSSDIO_BLOCK_SIZE); + if (ret) { + sms_err("Error %d reading initial block!\n", ret); + return; + } + + hdr = cb->p; + + if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { + smsdev->split_cb = cb; + return; + } + + if (hdr->msgLength > smsdev->func->cur_blksize) + size = hdr->msgLength - smsdev->func->cur_blksize; + else + size = 0; + } else { + cb = smsdev->split_cb; + hdr = cb->p; + + size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); + + smsdev->split_cb = NULL; + } + + if (size) { + void *buffer; + + buffer = cb->p + (hdr->msgLength - size); + size = ALIGN(size, SMSSDIO_BLOCK_SIZE); + + BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); + + /* + * First attempt to transfer all of it in one go... + */ + ret = sdio_memcpy_fromio(smsdev->func, + buffer, + SMSSDIO_DATA, + size); + if (ret && ret != -EINVAL) { + smscore_putbuffer(smsdev->coredev, cb); + sms_err("Error %d reading data from card!\n", ret); + return; + } + + /* + * ..then fall back to one block at a time if that is + * not possible... + * + * (we have to do this manually because of the + * problem with the "increase address" bit) + */ + if (ret == -EINVAL) { + while (size) { + ret = sdio_memcpy_fromio(smsdev->func, + buffer, SMSSDIO_DATA, + smsdev->func->cur_blksize); + if (ret) { + smscore_putbuffer(smsdev->coredev, cb); + sms_err("Error %d reading " + "data from card!\n", ret); + return; + } + + buffer += smsdev->func->cur_blksize; + if (size > smsdev->func->cur_blksize) + size -= smsdev->func->cur_blksize; + else + size = 0; + } + } + } + + cb->size = hdr->msgLength; + cb->offset = 0; + + smscore_onresponse(smsdev->coredev, cb); +} + +static int __devinit smssdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret; + + int board_id; + struct smssdio_device *smsdev; + struct smsdevice_params_t params; + + board_id = id->driver_data; + + smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL); + if (!smsdev) + return -ENOMEM; + + smsdev->func = func; + + memset(¶ms, 0, sizeof(struct smsdevice_params_t)); + + params.device = &func->dev; + params.buffer_size = 0x5000; /* ?? */ + params.num_buffers = 22; /* ?? */ + params.context = smsdev; + + snprintf(params.devpath, sizeof(params.devpath), + "sdio\\%s", sdio_func_id(func)); + + params.sendrequest_handler = smssdio_sendrequest; + + params.device_type = sms_get_board(board_id)->type; + + if (params.device_type != SMS_STELLAR) + params.flags |= SMS_DEVICE_FAMILY2; + else { + /* + * FIXME: Stellar needs special handling... + */ + ret = -ENODEV; + goto free; + } + + ret = smscore_register_device(¶ms, &smsdev->coredev); + if (ret < 0) + goto free; + + smscore_set_board_id(smsdev->coredev, board_id); + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) + goto release; + + ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE); + if (ret) + goto disable; + + ret = sdio_claim_irq(func, smssdio_interrupt); + if (ret) + goto disable; + + sdio_set_drvdata(func, smsdev); + + sdio_release_host(func); + + ret = smscore_start_device(smsdev->coredev); + if (ret < 0) + goto reclaim; + + return 0; + +reclaim: + sdio_claim_host(func); + sdio_release_irq(func); +disable: + sdio_disable_func(func); +release: + sdio_release_host(func); + smscore_unregister_device(smsdev->coredev); +free: + kfree(smsdev); + + return ret; +} + +static void smssdio_remove(struct sdio_func *func) +{ + struct smssdio_device *smsdev; + + smsdev = sdio_get_drvdata(func); + + /* FIXME: racy! */ + if (smsdev->split_cb) + smscore_putbuffer(smsdev->coredev, smsdev->split_cb); + + smscore_unregister_device(smsdev->coredev); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + kfree(smsdev); +} + +static struct sdio_driver smssdio_driver = { + .name = "smssdio", + .id_table = smssdio_ids, + .probe = smssdio_probe, + .remove = smssdio_remove, +}; + +/*******************************************************************/ +/* Module functions */ +/*******************************************************************/ + +static int __init smssdio_module_init(void) +{ + int ret = 0; + + printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n"); + printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n"); + + ret = sdio_register_driver(&smssdio_driver); + + return ret; +} + +static void __exit smssdio_module_exit(void) +{ + sdio_unregister_driver(&smssdio_driver); +} + +module_init(smssdio_module_init); +module_exit(smssdio_module_exit); + +MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver"); +MODULE_AUTHOR("Pierre Ossman"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c new file mode 100644 index 00000000000..664e460f247 --- /dev/null +++ b/drivers/media/usb/siano/smsusb.c @@ -0,0 +1,568 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat + +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, see . + +****************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" +#include "smsendian.h" + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +#define USB1_BUFFER_SIZE 0x1000 +#define USB2_BUFFER_SIZE 0x4000 + +#define MAX_BUFFERS 50 +#define MAX_URBS 10 + +struct smsusb_device_t; + +struct smsusb_urb_t { + struct smscore_buffer_t *cb; + struct smsusb_device_t *dev; + + struct urb urb; +}; + +struct smsusb_device_t { + struct usb_device *udev; + struct smscore_device_t *coredev; + + struct smsusb_urb_t surbs[MAX_URBS]; + + int response_alignment; + int buffer_size; +}; + +static int smsusb_submit_urb(struct smsusb_device_t *dev, + struct smsusb_urb_t *surb); + +static void smsusb_onresponse(struct urb *urb) +{ + struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; + struct smsusb_device_t *dev = surb->dev; + + if (urb->status == -ESHUTDOWN) { + sms_err("error, urb status %d (-ESHUTDOWN), %d bytes", + urb->status, urb->actual_length); + return; + } + + if ((urb->actual_length > 0) && (urb->status == 0)) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; + + smsendian_handle_message_header(phdr); + if (urb->actual_length >= phdr->msgLength) { + surb->cb->size = phdr->msgLength; + + if (dev->response_alignment && + (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) { + + surb->cb->offset = + dev->response_alignment + + ((phdr->msgFlags >> 8) & 3); + + /* sanity check */ + if (((int) phdr->msgLength + + surb->cb->offset) > urb->actual_length) { + sms_err("invalid response " + "msglen %d offset %d " + "size %d", + phdr->msgLength, + surb->cb->offset, + urb->actual_length); + goto exit_and_resubmit; + } + + /* move buffer pointer and + * copy header to its new location */ + memcpy((char *) phdr + surb->cb->offset, + phdr, sizeof(struct SmsMsgHdr_ST)); + } else + surb->cb->offset = 0; + + smscore_onresponse(dev->coredev, surb->cb); + surb->cb = NULL; + } else { + sms_err("invalid response " + "msglen %d actual %d", + phdr->msgLength, urb->actual_length); + } + } else + sms_err("error, urb status %d, %d bytes", + urb->status, urb->actual_length); + + +exit_and_resubmit: + smsusb_submit_urb(dev, surb); +} + +static int smsusb_submit_urb(struct smsusb_device_t *dev, + struct smsusb_urb_t *surb) +{ + if (!surb->cb) { + surb->cb = smscore_getbuffer(dev->coredev); + if (!surb->cb) { + sms_err("smscore_getbuffer(...) returned NULL"); + return -ENOMEM; + } + } + + usb_fill_bulk_urb( + &surb->urb, + dev->udev, + usb_rcvbulkpipe(dev->udev, 0x81), + surb->cb->p, + dev->buffer_size, + smsusb_onresponse, + surb + ); + surb->urb.transfer_dma = surb->cb->phys; + surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + return usb_submit_urb(&surb->urb, GFP_ATOMIC); +} + +static void smsusb_stop_streaming(struct smsusb_device_t *dev) +{ + int i; + + for (i = 0; i < MAX_URBS; i++) { + usb_kill_urb(&dev->surbs[i].urb); + + if (dev->surbs[i].cb) { + smscore_putbuffer(dev->coredev, dev->surbs[i].cb); + dev->surbs[i].cb = NULL; + } + } +} + +static int smsusb_start_streaming(struct smsusb_device_t *dev) +{ + int i, rc; + + for (i = 0; i < MAX_URBS; i++) { + rc = smsusb_submit_urb(dev, &dev->surbs[i]); + if (rc < 0) { + sms_err("smsusb_submit_urb(...) failed"); + smsusb_stop_streaming(dev); + break; + } + } + + return rc; +} + +static int smsusb_sendrequest(void *context, void *buffer, size_t size) +{ + struct smsusb_device_t *dev = (struct smsusb_device_t *) context; + int dummy; + + smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); + return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), + buffer, size, &dummy, 1000); +} + +static char *smsusb1_fw_lkup[] = { + "dvbt_stellar_usb.inp", + "dvbh_stellar_usb.inp", + "tdmb_stellar_usb.inp", + "none", + "dvbt_bda_stellar_usb.inp", +}; + +static inline char *sms_get_fw_name(int mode, int board_id) +{ + char **fw = sms_get_board(board_id)->fw; + return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode]; +} + +static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) +{ + const struct firmware *fw; + u8 *fw_buffer; + int rc, dummy; + char *fw_filename; + + if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid firmware id specified %d", id); + return -EINVAL; + } + + fw_filename = sms_get_fw_name(id, board_id); + + rc = request_firmware(&fw, fw_filename, &udev->dev); + if (rc < 0) { + sms_warn("failed to open \"%s\" mode %d, " + "trying again with default firmware", fw_filename, id); + + fw_filename = smsusb1_fw_lkup[id]; + rc = request_firmware(&fw, fw_filename, &udev->dev); + if (rc < 0) { + sms_warn("failed to open \"%s\" mode %d", + fw_filename, id); + + return rc; + } + } + + fw_buffer = kmalloc(fw->size, GFP_KERNEL); + if (fw_buffer) { + memcpy(fw_buffer, fw->data, fw->size); + + rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), + fw_buffer, fw->size, &dummy, 1000); + + sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc); + + kfree(fw_buffer); + } else { + sms_err("failed to allocate firmware buffer"); + rc = -ENOMEM; + } + sms_info("read FW %s, size=%zd", fw_filename, fw->size); + + release_firmware(fw); + + return rc; +} + +static void smsusb1_detectmode(void *context, int *mode) +{ + char *product_string = + ((struct smsusb_device_t *) context)->udev->product; + + *mode = DEVICE_MODE_NONE; + + if (!product_string) { + product_string = "none"; + sms_err("product string not found"); + } else if (strstr(product_string, "DVBH")) + *mode = 1; + else if (strstr(product_string, "BDA")) + *mode = 4; + else if (strstr(product_string, "DVBT")) + *mode = 0; + else if (strstr(product_string, "TDMB")) + *mode = 2; + + sms_info("%d \"%s\"", *mode, product_string); +} + +static int smsusb1_setmode(void *context, int mode) +{ + struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, + sizeof(struct SmsMsgHdr_ST), 0 }; + + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid firmware id specified %d", mode); + return -EINVAL; + } + + return smsusb_sendrequest(context, &Msg, sizeof(Msg)); +} + +static void smsusb_term_device(struct usb_interface *intf) +{ + struct smsusb_device_t *dev = usb_get_intfdata(intf); + + if (dev) { + smsusb_stop_streaming(dev); + + /* unregister from smscore */ + if (dev->coredev) + smscore_unregister_device(dev->coredev); + + sms_info("device %p destroyed", dev); + kfree(dev); + } + + usb_set_intfdata(intf, NULL); +} + +static int smsusb_init_device(struct usb_interface *intf, int board_id) +{ + struct smsdevice_params_t params; + struct smsusb_device_t *dev; + int i, rc; + + /* create device object */ + dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); + if (!dev) { + sms_err("kzalloc(sizeof(struct smsusb_device_t) failed"); + return -ENOMEM; + } + + memset(¶ms, 0, sizeof(params)); + usb_set_intfdata(intf, dev); + dev->udev = interface_to_usbdev(intf); + + params.device_type = sms_get_board(board_id)->type; + + switch (params.device_type) { + case SMS_STELLAR: + dev->buffer_size = USB1_BUFFER_SIZE; + + params.setmode_handler = smsusb1_setmode; + params.detectmode_handler = smsusb1_detectmode; + break; + default: + sms_err("Unspecified sms device type!"); + /* fall-thru */ + case SMS_NOVA_A0: + case SMS_NOVA_B0: + case SMS_VEGA: + dev->buffer_size = USB2_BUFFER_SIZE; + dev->response_alignment = + le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - + sizeof(struct SmsMsgHdr_ST); + + params.flags |= SMS_DEVICE_FAMILY2; + break; + } + + params.device = &dev->udev->dev; + params.buffer_size = dev->buffer_size; + params.num_buffers = MAX_BUFFERS; + params.sendrequest_handler = smsusb_sendrequest; + params.context = dev; + usb_make_path(dev->udev, params.devpath, sizeof(params.devpath)); + + /* register in smscore */ + rc = smscore_register_device(¶ms, &dev->coredev); + if (rc < 0) { + sms_err("smscore_register_device(...) failed, rc %d", rc); + smsusb_term_device(intf); + return rc; + } + + smscore_set_board_id(dev->coredev, board_id); + + /* initialize urbs */ + for (i = 0; i < MAX_URBS; i++) { + dev->surbs[i].dev = dev; + usb_init_urb(&dev->surbs[i].urb); + } + + sms_info("smsusb_start_streaming(...)."); + rc = smsusb_start_streaming(dev); + if (rc < 0) { + sms_err("smsusb_start_streaming(...) failed"); + smsusb_term_device(intf); + return rc; + } + + rc = smscore_start_device(dev->coredev); + if (rc < 0) { + sms_err("smscore_start_device(...) failed"); + smsusb_term_device(intf); + return rc; + } + + sms_info("device %p created", dev); + + return rc; +} + +static int __devinit smsusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + char devpath[32]; + int i, rc; + + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + + if (intf->num_altsetting > 0) { + rc = usb_set_interface( + udev, intf->cur_altsetting->desc.bInterfaceNumber, 0); + if (rc < 0) { + sms_err("usb_set_interface failed, rc %d", rc); + return rc; + } + } + + sms_info("smsusb_probe %d", + intf->cur_altsetting->desc.bInterfaceNumber); + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + sms_info("endpoint %d %02x %02x %d", i, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, + intf->cur_altsetting->endpoint[i].desc.bmAttributes, + intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + + if ((udev->actconfig->desc.bNumInterfaces == 2) && + (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { + sms_err("rom interface 0 is not used"); + return -ENODEV; + } + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + snprintf(devpath, sizeof(devpath), "usb\\%d-%s", + udev->bus->busnum, udev->devpath); + sms_info("stellar device was found."); + return smsusb1_load_firmware( + udev, smscore_registry_getmode(devpath), + id->driver_info); + } + + rc = smsusb_init_device(intf, id->driver_info); + sms_info("rc %d", rc); + sms_board_load_modules(id->driver_info); + return rc; +} + +static void smsusb_disconnect(struct usb_interface *intf) +{ + smsusb_term_device(intf); +} + +static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct smsusb_device_t *dev = usb_get_intfdata(intf); + printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event); + smsusb_stop_streaming(dev); + return 0; +} + +static int smsusb_resume(struct usb_interface *intf) +{ + int rc, i; + struct smsusb_device_t *dev = usb_get_intfdata(intf); + struct usb_device *udev = interface_to_usbdev(intf); + + printk(KERN_INFO "%s: Entering.\n", __func__); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, + intf->cur_altsetting->endpoint[i].desc.bmAttributes, + intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + + if (intf->num_altsetting > 0) { + rc = usb_set_interface(udev, + intf->cur_altsetting->desc. + bInterfaceNumber, 0); + if (rc < 0) { + printk(KERN_INFO "%s usb_set_interface failed, " + "rc %d\n", __func__, rc); + return rc; + } + } + + smsusb_start_streaming(dev); + return 0; +} + +static const struct usb_device_id smsusb_id_table[] __devinitconst = { + { USB_DEVICE(0x187f, 0x0010), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0100), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0200), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, + { USB_DEVICE(0x187f, 0x0201), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B }, + { USB_DEVICE(0x187f, 0x0300), + .driver_info = SMS1XXX_BOARD_SIANO_VEGA }, + { USB_DEVICE(0x2040, 0x1700), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT }, + { USB_DEVICE(0x2040, 0x1800), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, + { USB_DEVICE(0x2040, 0x1801), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, + { USB_DEVICE(0x2040, 0x2000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2009), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 }, + { USB_DEVICE(0x2040, 0x200a), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2011), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2019), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x5500), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5510), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5520), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5530), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5580), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5590), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x187f, 0x0202), + .driver_info = SMS1XXX_BOARD_SIANO_NICE }, + { USB_DEVICE(0x187f, 0x0301), + .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, + { USB_DEVICE(0x2040, 0xb900), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb910), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb980), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb990), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc080), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc090), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc0a0), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xf5a0), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { } /* Terminating entry */ + }; + +MODULE_DEVICE_TABLE(usb, smsusb_id_table); + +static struct usb_driver smsusb_driver = { + .name = "smsusb", + .probe = smsusb_probe, + .disconnect = smsusb_disconnect, + .id_table = smsusb_id_table, + + .suspend = smsusb_suspend, + .resume = smsusb_resume, +}; + +module_usb_driver(smsusb_driver); + +MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); +MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/ttusb-budget/Kconfig b/drivers/media/usb/ttusb-budget/Kconfig new file mode 100644 index 00000000000..2663ae39b88 --- /dev/null +++ b/drivers/media/usb/ttusb-budget/Kconfig @@ -0,0 +1,18 @@ +config DVB_TTUSB_BUDGET + tristate "Technotrend/Hauppauge Nova-USB devices" + depends on DVB_CORE && USB && I2C && PCI + select DVB_CX22700 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_VES1820 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + help + Support for external USB adapters designed by Technotrend and + produced by Hauppauge, shipped under the brand name 'Nova-USB'. + + These devices don't have a MPEG decoder built in, so you need + an external software decoder to watch TV. + + Say Y if you own such a device and want to use it. diff --git a/drivers/media/usb/ttusb-budget/Makefile b/drivers/media/usb/ttusb-budget/Makefile new file mode 100644 index 00000000000..f47bbf62dcd --- /dev/null +++ b/drivers/media/usb/ttusb-budget/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c new file mode 100644 index 00000000000..5b682cc4c81 --- /dev/null +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -0,0 +1,1816 @@ +/* + * TTUSB DVB driver + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "ves1820.h" +#include "cx22700.h" +#include "tda1004x.h" +#include "stv0299.h" +#include "tda8083.h" +#include "stv0297.h" +#include "lnbp21.h" + +#include +#include +#include + +/* + TTUSB_HWSECTIONS: + the DSP supports filtering in hardware, however, since the "muxstream" + is a bit braindead (no matching channel masks or no matching filter mask), + we won't support this - yet. it doesn't event support negative filters, + so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just + parse TS data. USB bandwidth will be a problem when having large + datastreams, especially for dvb-net, but hey, that's not my problem. + + TTUSB_DISEQC, TTUSB_TONE: + let the STC do the diseqc/tone stuff. this isn't supported at least with + my TTUSB, so let it undef'd unless you want to implement another + frontend. never tested. + + debug: + define it to > 3 for really hardcore debugging. you probably don't want + this unless the device doesn't load at all. > 2 for bandwidth statistics. +*/ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0) + +#define ISO_BUF_COUNT 4 +#define FRAMES_PER_ISO_BUF 4 +#define ISO_FRAME_SIZE 912 +#define TTUSB_MAXCHANNEL 32 +#ifdef TTUSB_HWSECTIONS +#define TTUSB_MAXFILTER 16 /* ??? */ +#endif + +#define TTUSB_REV_2_2 0x22 +#define TTUSB_BUDGET_NAME "ttusb_stc_fw" + +/** + * since we're casting (struct ttusb*) <-> (struct dvb_demux*) around + * the dvb_demux field must be the first in struct!! + */ +struct ttusb { + struct dvb_demux dvb_demux; + struct dmxdev dmxdev; + struct dvb_net dvbnet; + + /* and one for USB access. */ + struct mutex semi2c; + struct mutex semusb; + + struct dvb_adapter adapter; + struct usb_device *dev; + + struct i2c_adapter i2c_adap; + + int disconnecting; + int iso_streaming; + + unsigned int bulk_out_pipe; + unsigned int bulk_in_pipe; + unsigned int isoc_in_pipe; + + void *iso_buffer; + dma_addr_t iso_dma_handle; + + struct urb *iso_urb[ISO_BUF_COUNT]; + + int running_feed_count; + int last_channel; + int last_filter; + + u8 c; /* transaction counter, wraps around... */ + fe_sec_tone_mode_t tone; + fe_sec_voltage_t voltage; + + int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack + u8 mux_npacks; + u8 muxpack[256 + 8]; + int muxpack_ptr, muxpack_len; + + int insync; + + int cc; /* MuxCounter - will increment on EVERY MUX PACKET */ + /* (including stuffing. yes. really.) */ + + u8 last_result[32]; + + int revision; + + struct dvb_frontend* fe; +}; + +/* ugly workaround ... don't know why it's necessary to read */ +/* all result codes. */ + +static int ttusb_cmd(struct ttusb *ttusb, + const u8 * data, int len, int needresult) +{ + int actual_len; + int err; + int i; + + if (debug >= 3) { + printk(KERN_DEBUG ">"); + for (i = 0; i < len; ++i) + printk(KERN_CONT " %02x", data[i]); + printk(KERN_CONT "\n"); + } + + if (mutex_lock_interruptible(&ttusb->semusb) < 0) + return -EAGAIN; + + err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe, + (u8 *) data, len, &actual_len, 1000); + if (err != 0) { + dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n", + __func__, err); + mutex_unlock(&ttusb->semusb); + return err; + } + if (actual_len != len) { + dprintk("%s: only wrote %d of %d bytes\n", __func__, + actual_len, len); + mutex_unlock(&ttusb->semusb); + return -1; + } + + err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe, + ttusb->last_result, 32, &actual_len, 1000); + + if (err != 0) { + printk("%s: failed, receive error %d\n", __func__, + err); + mutex_unlock(&ttusb->semusb); + return err; + } + + if (debug >= 3) { + actual_len = ttusb->last_result[3] + 4; + printk(KERN_DEBUG "<"); + for (i = 0; i < actual_len; ++i) + printk(KERN_CONT " %02x", ttusb->last_result[i]); + printk(KERN_CONT "\n"); + } + + if (!needresult) + mutex_unlock(&ttusb->semusb); + return 0; +} + +static int ttusb_result(struct ttusb *ttusb, u8 * data, int len) +{ + memcpy(data, ttusb->last_result, len); + mutex_unlock(&ttusb->semusb); + return 0; +} + +static int ttusb_i2c_msg(struct ttusb *ttusb, + u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf, + u8 rcv_len) +{ + u8 b[0x28]; + u8 id = ++ttusb->c; + int i, err; + + if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7) + return -EINVAL; + + b[0] = 0xaa; + b[1] = id; + b[2] = 0x31; + b[3] = snd_len + 3; + b[4] = addr << 1; + b[5] = snd_len; + b[6] = rcv_len; + + for (i = 0; i < snd_len; i++) + b[7 + i] = snd_buf[i]; + + err = ttusb_cmd(ttusb, b, snd_len + 7, 1); + + if (err) + return -EREMOTEIO; + + err = ttusb_result(ttusb, b, 0x20); + + /* check if the i2c transaction was successful */ + if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO; + + if (rcv_len > 0) { + + if (err || b[0] != 0x55 || b[1] != id) { + dprintk + ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ", + __func__, err, id); + return -EREMOTEIO; + } + + for (i = 0; i < rcv_len; i++) + rcv_buf[i] = b[7 + i]; + } + + return rcv_len; +} + +static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) +{ + struct ttusb *ttusb = i2c_get_adapdata(adapter); + int i = 0; + int inc; + + if (mutex_lock_interruptible(&ttusb->semi2c) < 0) + return -EAGAIN; + + while (i < num) { + u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; + int err; + + if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = msg[i + 1].buf; + rcv_len = msg[i + 1].len; + inc = 2; + } else { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = NULL; + rcv_len = 0; + inc = 1; + } + + err = ttusb_i2c_msg(ttusb, addr, + snd_buf, snd_len, rcv_buf, rcv_len); + + if (err < rcv_len) { + dprintk("%s: i == %i\n", __func__, i); + break; + } + + i += inc; + } + + mutex_unlock(&ttusb->semi2c); + return i; +} + +static int ttusb_boot_dsp(struct ttusb *ttusb) +{ + const struct firmware *fw; + int i, err; + u8 b[40]; + + err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin", + &ttusb->dev->dev); + if (err) { + printk(KERN_ERR "ttusb-budget: failed to request firmware\n"); + return err; + } + + /* BootBlock */ + b[0] = 0xaa; + b[2] = 0x13; + b[3] = 28; + + /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ + /* 32 is max packet size, no messages should be splitted. */ + for (i = 0; i < fw->size; i += 28) { + memcpy(&b[4], &fw->data[i], 28); + + b[1] = ++ttusb->c; + + err = ttusb_cmd(ttusb, b, 32, 0); + if (err) + goto done; + } + + /* last block ... */ + b[1] = ++ttusb->c; + b[2] = 0x13; + b[3] = 0; + + err = ttusb_cmd(ttusb, b, 4, 0); + if (err) + goto done; + + /* BootEnd */ + b[1] = ++ttusb->c; + b[2] = 0x14; + b[3] = 0; + + err = ttusb_cmd(ttusb, b, 4, 0); + + done: + release_firmware(fw); + if (err) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } + + return err; +} + +static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type, + int pid) +{ + int err; + /* SetChannel */ + u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type, + (pid >> 8) & 0xff, pid & 0xff + }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +static int ttusb_del_channel(struct ttusb *ttusb, int channel_id) +{ + int err; + /* DelChannel */ + u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +#ifdef TTUSB_HWSECTIONS +static int ttusb_set_filter(struct ttusb *ttusb, int filter_id, + int associated_chan, u8 filter[8], u8 mask[8]) +{ + int err; + /* SetFilter */ + u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan, + filter[0], filter[1], filter[2], filter[3], + filter[4], filter[5], filter[6], filter[7], + filter[8], filter[9], filter[10], filter[11], + mask[0], mask[1], mask[2], mask[3], + mask[4], mask[5], mask[6], mask[7], + mask[8], mask[9], mask[10], mask[11] + }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +static int ttusb_del_filter(struct ttusb *ttusb, int filter_id) +{ + int err; + /* DelFilter */ + u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} +#endif + +static int ttusb_init_controller(struct ttusb *ttusb) +{ + u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 }; + u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 }; + u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 }; + /* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */ + u8 b3[] = + { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e }; + u8 b4[] = + { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e }; + + u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 }; + u8 get_dsp_version[0x20] = + { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 }; + int err; + + /* reset board */ + if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0))) + return err; + + /* reset board (again?) */ + if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0))) + return err; + + ttusb_boot_dsp(ttusb); + + /* set i2c bit rate */ + if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0))) + return err; + + if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1))) + return err; + + err = ttusb_result(ttusb, b4, sizeof(b4)); + + if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1))) + return err; + + if ((err = ttusb_result(ttusb, get_version, sizeof(get_version)))) + return err; + + dprintk("%s: stc-version: %c%c%c%c%c\n", __func__, + get_version[4], get_version[5], get_version[6], + get_version[7], get_version[8]); + + if (memcmp(get_version + 4, "V 0.0", 5) && + memcmp(get_version + 4, "V 1.1", 5) && + memcmp(get_version + 4, "V 2.1", 5) && + memcmp(get_version + 4, "V 2.2", 5)) { + printk + ("%s: unknown STC version %c%c%c%c%c, please report!\n", + __func__, get_version[4], get_version[5], + get_version[6], get_version[7], get_version[8]); + } + + ttusb->revision = ((get_version[6] - '0') << 4) | + (get_version[8] - '0'); + + err = + ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1); + if (err) + return err; + + err = + ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version)); + if (err) + return err; + printk("%s: dsp-version: %c%c%c\n", __func__, + get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]); + return 0; +} + +#ifdef TTUSB_DISEQC +static int ttusb_send_diseqc(struct dvb_frontend* fe, + const struct dvb_diseqc_master_cmd *cmd) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; + + int err; + + b[3] = 4 + 2 + cmd->msg_len; + b[4] = 0xFF; /* send diseqc master, not burst */ + b[5] = cmd->msg_len; + + memcpy(b + 5, cmd->msg, cmd->msg_len); + + /* Diseqc */ + if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } + + return err; +} +#endif + +static int ttusb_update_lnb(struct ttusb *ttusb) +{ + u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, + ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1, + ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1 + }; + int err; + + /* SetLNB */ + if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } + + return err; +} + +static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + ttusb->voltage = voltage; + return ttusb_update_lnb(ttusb); +} + +#ifdef TTUSB_TONE +static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + ttusb->tone = tone; + return ttusb_update_lnb(ttusb); +} +#endif + + +#if 0 +static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) +{ + u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq }; + int err, actual_len; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + if (err) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } +} +#endif + +/*****************************************************************************/ + +#ifdef TTUSB_HWSECTIONS +static void ttusb_handle_ts_data(struct ttusb_channel *channel, + const u8 * data, int len); +static void ttusb_handle_sec_data(struct ttusb_channel *channel, + const u8 * data, int len); +#endif + +static int numpkt, numts, numstuff, numsec, numinvalid; +static unsigned long lastj; + +static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, + int len) +{ + u16 csum = 0, cc; + int i; + for (i = 0; i < len; i += 2) + csum ^= le16_to_cpup((__le16 *) (muxpack + i)); + if (csum) { + printk("%s: muxpack with incorrect checksum, ignoring\n", + __func__); + numinvalid++; + return; + } + + cc = (muxpack[len - 4] << 8) | muxpack[len - 3]; + cc &= 0x7FFF; + if ((cc != ttusb->cc) && (ttusb->cc != -1)) + printk("%s: cc discontinuity (%d frames missing)\n", + __func__, (cc - ttusb->cc) & 0x7FFF); + ttusb->cc = (cc + 1) & 0x7FFF; + if (muxpack[0] & 0x80) { +#ifdef TTUSB_HWSECTIONS + /* section data */ + int pusi = muxpack[0] & 0x40; + int channel = muxpack[0] & 0x1F; + int payload = muxpack[1]; + const u8 *data = muxpack + 2; + /* check offset flag */ + if (muxpack[0] & 0x20) + data++; + + ttusb_handle_sec_data(ttusb->channel + channel, data, + payload); + data += payload; + + if ((!!(ttusb->muxpack[0] & 0x20)) ^ + !!(ttusb->muxpack[1] & 1)) + data++; +#warning TODO: pusi + printk("cc: %04x\n", (data[0] << 8) | data[1]); +#endif + numsec++; + } else if (muxpack[0] == 0x47) { +#ifdef TTUSB_HWSECTIONS + /* we have TS data here! */ + int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2]; + int channel; + for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) + if (ttusb->channel[channel].active + && (pid == ttusb->channel[channel].pid)) + ttusb_handle_ts_data(ttusb->channel + + channel, muxpack, + 188); +#endif + numts++; + dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1); + } else if (muxpack[0] != 0) { + numinvalid++; + printk("illegal muxpack type %02x\n", muxpack[0]); + } else + numstuff++; +} + +static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) +{ + int maxwork = 1024; + while (len) { + if (!(maxwork--)) { + printk("%s: too much work\n", __func__); + break; + } + + switch (ttusb->mux_state) { + case 0: + case 1: + case 2: + len--; + if (*data++ == 0xAA) + ++ttusb->mux_state; + else { + ttusb->mux_state = 0; + if (ttusb->insync) { + dprintk("%s: %02x\n", + __func__, data[-1]); + printk(KERN_INFO "%s: lost sync.\n", + __func__); + ttusb->insync = 0; + } + } + break; + case 3: + ttusb->insync = 1; + len--; + ttusb->mux_npacks = *data++; + ++ttusb->mux_state; + ttusb->muxpack_ptr = 0; + /* maximum bytes, until we know the length */ + ttusb->muxpack_len = 2; + break; + case 4: + { + int avail; + avail = len; + if (avail > + (ttusb->muxpack_len - + ttusb->muxpack_ptr)) + avail = + ttusb->muxpack_len - + ttusb->muxpack_ptr; + memcpy(ttusb->muxpack + ttusb->muxpack_ptr, + data, avail); + ttusb->muxpack_ptr += avail; + BUG_ON(ttusb->muxpack_ptr > 264); + data += avail; + len -= avail; + /* determine length */ + if (ttusb->muxpack_ptr == 2) { + if (ttusb->muxpack[0] & 0x80) { + ttusb->muxpack_len = + ttusb->muxpack[1] + 2; + if (ttusb-> + muxpack[0] & 0x20) + ttusb-> + muxpack_len++; + if ((!! + (ttusb-> + muxpack[0] & 0x20)) ^ + !!(ttusb-> + muxpack[1] & 1)) + ttusb-> + muxpack_len++; + ttusb->muxpack_len += 4; + } else if (ttusb->muxpack[0] == + 0x47) + ttusb->muxpack_len = + 188 + 4; + else if (ttusb->muxpack[0] == 0x00) + ttusb->muxpack_len = + ttusb->muxpack[1] + 2 + + 4; + else { + dprintk + ("%s: invalid state: first byte is %x\n", + __func__, + ttusb->muxpack[0]); + ttusb->mux_state = 0; + } + } + + /** + * if length is valid and we reached the end: + * goto next muxpack + */ + if ((ttusb->muxpack_ptr >= 2) && + (ttusb->muxpack_ptr == + ttusb->muxpack_len)) { + ttusb_process_muxpack(ttusb, + ttusb-> + muxpack, + ttusb-> + muxpack_ptr); + ttusb->muxpack_ptr = 0; + /* maximum bytes, until we know the length */ + ttusb->muxpack_len = 2; + + /** + * no muxpacks left? + * return to search-sync state + */ + if (!ttusb->mux_npacks--) { + ttusb->mux_state = 0; + break; + } + } + break; + } + default: + BUG(); + break; + } + } +} + +static void ttusb_iso_irq(struct urb *urb) +{ + struct ttusb *ttusb = urb->context; + struct usb_iso_packet_descriptor *d; + u8 *data; + int len, i; + + if (!ttusb->iso_streaming) + return; + +#if 0 + printk("%s: status %d, errcount == %d, length == %i\n", + __func__, + urb->status, urb->error_count, urb->actual_length); +#endif + + if (!urb->status) { + for (i = 0; i < urb->number_of_packets; ++i) { + numpkt++; + if (time_after_eq(jiffies, lastj + HZ)) { + dprintk("frames/s: %lu (ts: %d, stuff %d, " + "sec: %d, invalid: %d, all: %d)\n", + numpkt * HZ / (jiffies - lastj), + numts, numstuff, numsec, numinvalid, + numts + numstuff + numsec + numinvalid); + numts = numstuff = numsec = numinvalid = 0; + lastj = jiffies; + numpkt = 0; + } + d = &urb->iso_frame_desc[i]; + data = urb->transfer_buffer + d->offset; + len = d->actual_length; + d->actual_length = 0; + d->status = 0; + ttusb_process_frame(ttusb, data, len); + } + } + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void ttusb_free_iso_urbs(struct ttusb *ttusb) +{ + int i; + + for (i = 0; i < ISO_BUF_COUNT; i++) + if (ttusb->iso_urb[i]) + usb_free_urb(ttusb->iso_urb[i]); + + pci_free_consistent(NULL, + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT, ttusb->iso_buffer, + ttusb->iso_dma_handle); +} + +static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) +{ + int i; + + ttusb->iso_buffer = pci_alloc_consistent(NULL, + ISO_FRAME_SIZE * + FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT, + &ttusb->iso_dma_handle); + + if (!ttusb->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + + memset(ttusb->iso_buffer, 0, + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + struct urb *urb; + + if (! + (urb = + usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { + ttusb_free_iso_urbs(ttusb); + return -ENOMEM; + } + + ttusb->iso_urb[i] = urb; + } + + return 0; +} + +static void ttusb_stop_iso_xfer(struct ttusb *ttusb) +{ + int i; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_kill_urb(ttusb->iso_urb[i]); + + ttusb->iso_streaming = 0; +} + +static int ttusb_start_iso_xfer(struct ttusb *ttusb) +{ + int i, j, err, buffer_offset = 0; + + if (ttusb->iso_streaming) { + printk("%s: iso xfer already running!\n", __func__); + return 0; + } + + ttusb->cc = -1; + ttusb->insync = 0; + ttusb->mux_state = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) { + int frame_offset = 0; + struct urb *urb = ttusb->iso_urb[i]; + + urb->dev = ttusb->dev; + urb->context = ttusb; + urb->complete = ttusb_iso_irq; + urb->pipe = ttusb->isoc_in_pipe; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = FRAMES_PER_ISO_BUF; + urb->transfer_buffer_length = + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + urb->transfer_buffer = ttusb->iso_buffer + buffer_offset; + buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + + for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; + frame_offset += ISO_FRAME_SIZE; + } + } + + for (i = 0; i < ISO_BUF_COUNT; i++) { + if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) { + ttusb_stop_iso_xfer(ttusb); + printk + ("%s: failed urb submission (%i: err = %i)!\n", + __func__, i, err); + return err; + } + } + + ttusb->iso_streaming = 1; + + return 0; +} + +#ifdef TTUSB_HWSECTIONS +static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, + int len) +{ + dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0); +} + +static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, + int len) +{ +// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; +#error TODO: handle ugly stuff +// dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0); +} +#endif + +static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; + int feed_type = 1; + + dprintk("ttusb_start_feed\n"); + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + break; + case DMX_TYPE_SEC: + break; + default: + return -EINVAL; + } + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + break; + default: + return -EINVAL; + } + } + +#ifdef TTUSB_HWSECTIONS +#error TODO: allocate filters + if (dvbdmxfeed->type == DMX_TYPE_TS) { + feed_type = 1; + } else if (dvbdmxfeed->type == DMX_TYPE_SEC) { + feed_type = 2; + } +#endif + + ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid); + + if (0 == ttusb->running_feed_count++) + ttusb_start_iso_xfer(ttusb); + + return 0; +} + +static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; + + ttusb_del_channel(ttusb, dvbdmxfeed->index); + + if (--ttusb->running_feed_count == 0) + ttusb_stop_iso_xfer(ttusb); + + return 0; +} + +static int ttusb_setup_interfaces(struct ttusb *ttusb) +{ + usb_set_interface(ttusb->dev, 1, 1); + + ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); + ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1); + ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2); + + return 0; +} + +#if 0 +static u8 stc_firmware[8192]; + +static int stc_open(struct inode *inode, struct file *file) +{ + struct ttusb *ttusb = file->private_data; + int addr; + + for (addr = 0; addr < 8192; addr += 16) { + u8 snd_buf[2] = { addr >> 8, addr & 0xFF }; + ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr, + 16); + } + + return 0; +} + +static ssize_t stc_read(struct file *file, char *buf, size_t count, + loff_t *offset) +{ + return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192); +} + +static int stc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations stc_fops = { + .owner = THIS_MODULE, + .read = stc_read, + .open = stc_open, + .release = stc_release, +}; +#endif + +static u32 functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + + + +static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 data[4]; + struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; + u32 div; + + div = (p->frequency + 36166667) / 166667; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | 0x85; + data[3] = p->frequency < 592000000 ? 0x40 : 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct cx22700_config alps_tdmb7_config = { + .demod_address = 0x43, +}; + + + + + +static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; + + // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); + } + + return 0; +} + +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = p->frequency + 36130000; + if (tuner_frequency < 87000000) return -EINVAL; + else if (tuner_frequency < 130000000) cp = 3; + else if (tuner_frequency < 160000000) cp = 5; + else if (tuner_frequency < 200000000) cp = 6; + else if (tuner_frequency < 290000000) cp = 3; + else if (tuner_frequency < 420000000) cp = 5; + else if (tuner_frequency < 480000000) cp = 6; + else if (tuner_frequency < 620000000) cp = 3; + else if (tuner_frequency < 830000000) cp = 5; + else if (tuner_frequency < 895000000) cp = 7; + else return -EINVAL; + + // determine band + if (p->frequency < 49000000) + return -EINVAL; + else if (p->frequency < 159000000) + band = 1; + else if (p->frequency < 444000000) + band = 2; + else if (p->frequency < 861000000) + band = 4; + else return -EINVAL; + + // setup PLL filter + switch (p->bandwidth_hz) { + case 6000000: + tda1004x_writereg(fe, 0x0C, 0); + filter = 0; + break; + + case 7000000: + tda1004x_writereg(fe, 0x0C, 0); + filter = 0; + break; + + case 8000000: + tda1004x_writereg(fe, 0x0C, 0xFF); + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + return request_firmware(fw, name, &ttusb->dev->dev); +} + +static struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .request_firmware = philips_tdm1316l_request_firmware, +}; + +static u8 alps_bsbe1_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, + 0xff, 0xff +}; + +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; + +static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((p->frequency < 950000) || (p->frequency > 2150000)) + return -EINVAL; + + div = (p->frequency + (125 - 1)) / 125; /* round correctly */ + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0xC4; + + if (p->frequency > 1530000) + buf[3] = 0xC0; + + /* BSBE1 wants XCE bit set */ + if (ttusb->revision == TTUSB_REV_2_2) + buf[3] |= 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static struct stv0299_config alps_stv0299_config = { + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_stv0299_set_symbol_rate, +}; + +static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + div = p->frequency / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + buf[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static struct tda8083_config ttusb_novas_grundig_29504_491_config = { + + .demod_address = 0x68, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusb* ttusb = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (p->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + +static u8 read_pwm(struct ttusb* ttusb) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + + +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; + u8 tuner_buf[5]; + struct i2c_msg tuner_msg = {.addr = 0x60, + .flags = 0, + .buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = p->frequency; + if (tuner_frequency < 87000000) {return -EINVAL;} + else if (tuner_frequency < 130000000) {cp = 3; band = 1;} + else if (tuner_frequency < 160000000) {cp = 5; band = 1;} + else if (tuner_frequency < 200000000) {cp = 6; band = 1;} + else if (tuner_frequency < 290000000) {cp = 3; band = 2;} + else if (tuner_frequency < 420000000) {cp = 5; band = 2;} + else if (tuner_frequency < 480000000) {cp = 6; band = 2;} + else if (tuner_frequency < 620000000) {cp = 3; band = 4;} + else if (tuner_frequency < 830000000) {cp = 5; band = 4;} + else if (tuner_frequency < 895000000) {cp = 7; band = 4;} + else {return -EINVAL;} + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz + tuner_frequency = ((p->frequency + 36125000) / 62500); + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n"); + return -EIO; + } + + msleep(50); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n"); + return -EIO; + } + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x21, + 0x80, 0x20, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0xff, + 0x4b, 0x7f, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x00, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x4b, + 0xc1, 0x00, + 0xc2, 0x00, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0x55, 0x00, + 0x56, 0x40, + 0x57, 0x08, + 0x58, 0x3d, + 0x88, 0x10, + 0xa0, 0x00, + 0xa0, 0x00, + 0xa0, 0x00, + 0xa0, 0x04, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, +}; + +static void frontend_init(struct ttusb* ttusb) +{ + switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) { + case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059)) + // try the stv0299 based first + ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params; + + if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1 + alps_stv0299_config.inittab = alps_bsbe1_inittab; + dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0); + } else { // ALPS BSRU6 + ttusb->fe->ops.set_voltage = ttusb_set_voltage; + } + break; + } + + // Grundig 29504-491 + ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params; + ttusb->fe->ops.set_voltage = ttusb_set_voltage; + break; + } + break; + + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + break; + } + + ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) + // try the ALPS TDMB7 first + ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params; + break; + } + + // Philips td1316 + ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; + break; + } + break; + } + + if (ttusb->fe == NULL) { + printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", + le16_to_cpu(ttusb->dev->descriptor.idVendor), + le16_to_cpu(ttusb->dev->descriptor.idProduct)); + } else { + if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) { + printk("dvb-ttusb-budget: Frontend registration failed!\n"); + dvb_frontend_detach(ttusb->fe); + ttusb->fe = NULL; + } + } +} + + + +static struct i2c_algorithm ttusb_dec_algo = { + .master_xfer = master_xfer, + .functionality = functionality, +}; + +static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev; + struct ttusb *ttusb; + int result; + + dprintk("%s: TTUSB DVB connected\n", __func__); + + udev = interface_to_usbdev(intf); + + if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV; + + if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL))) + return -ENOMEM; + + ttusb->dev = udev; + ttusb->c = 0; + ttusb->mux_state = 0; + mutex_init(&ttusb->semi2c); + + mutex_lock(&ttusb->semi2c); + + mutex_init(&ttusb->semusb); + + ttusb_setup_interfaces(ttusb); + + result = ttusb_alloc_iso_urbs(ttusb); + if (result < 0) { + dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__); + mutex_unlock(&ttusb->semi2c); + kfree(ttusb); + return result; + } + + if (ttusb_init_controller(ttusb)) + printk("ttusb_init_controller: error\n"); + + mutex_unlock(&ttusb->semi2c); + + result = dvb_register_adapter(&ttusb->adapter, + "Technotrend/Hauppauge Nova-USB", + THIS_MODULE, &udev->dev, adapter_nr); + if (result < 0) { + ttusb_free_iso_urbs(ttusb); + kfree(ttusb); + return result; + } + ttusb->adapter.priv = ttusb; + + /* i2c */ + memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); + strcpy(ttusb->i2c_adap.name, "TTUSB DEC"); + + i2c_set_adapdata(&ttusb->i2c_adap, ttusb); + + ttusb->i2c_adap.algo = &ttusb_dec_algo; + ttusb->i2c_adap.algo_data = NULL; + ttusb->i2c_adap.dev.parent = &udev->dev; + + result = i2c_add_adapter(&ttusb->i2c_adap); + if (result) + goto err_unregister_adapter; + + memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); + + ttusb->dvb_demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING; + ttusb->dvb_demux.priv = NULL; +#ifdef TTUSB_HWSECTIONS + ttusb->dvb_demux.filternum = TTUSB_MAXFILTER; +#else + ttusb->dvb_demux.filternum = 32; +#endif + ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; + ttusb->dvb_demux.start_feed = ttusb_start_feed; + ttusb->dvb_demux.stop_feed = ttusb_stop_feed; + ttusb->dvb_demux.write_to_decoder = NULL; + + result = dvb_dmx_init(&ttusb->dvb_demux); + if (result < 0) { + printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); + result = -ENODEV; + goto err_i2c_del_adapter; + } +//FIXME dmxdev (nur WAS?) + ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; + ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; + ttusb->dmxdev.capabilities = 0; + + result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter); + if (result < 0) { + printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", + result); + result = -ENODEV; + goto err_release_dmx; + } + + if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { + printk("ttusb_dvb: dvb_net_init failed!\n"); + result = -ENODEV; + goto err_release_dmxdev; + } + + usb_set_intfdata(intf, (void *) ttusb); + + frontend_init(ttusb); + + return 0; + +err_release_dmxdev: + dvb_dmxdev_release(&ttusb->dmxdev); +err_release_dmx: + dvb_dmx_release(&ttusb->dvb_demux); +err_i2c_del_adapter: + i2c_del_adapter(&ttusb->i2c_adap); +err_unregister_adapter: + dvb_unregister_adapter (&ttusb->adapter); + return result; +} + +static void ttusb_disconnect(struct usb_interface *intf) +{ + struct ttusb *ttusb = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + ttusb->disconnecting = 1; + + ttusb_stop_iso_xfer(ttusb); + + ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx); + dvb_net_release(&ttusb->dvbnet); + dvb_dmxdev_release(&ttusb->dmxdev); + dvb_dmx_release(&ttusb->dvb_demux); + if (ttusb->fe != NULL) { + dvb_unregister_frontend(ttusb->fe); + dvb_frontend_detach(ttusb->fe); + } + i2c_del_adapter(&ttusb->i2c_adap); + dvb_unregister_adapter(&ttusb->adapter); + + ttusb_free_iso_urbs(ttusb); + + kfree(ttusb); + + dprintk("%s: TTUSB DVB disconnected\n", __func__); +} + +static struct usb_device_id ttusb_table[] = { + {USB_DEVICE(0xb48, 0x1003)}, + {USB_DEVICE(0xb48, 0x1004)}, + {USB_DEVICE(0xb48, 0x1005)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, ttusb_table); + +static struct usb_driver ttusb_driver = { + .name = "ttusb", + .probe = ttusb_probe, + .disconnect = ttusb_disconnect, + .id_table = ttusb_table, +}; + +module_usb_driver(ttusb_driver); + +MODULE_AUTHOR("Holger Waechtler "); +MODULE_DESCRIPTION("TTUSB DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("ttusb-budget/dspbootcode.bin"); diff --git a/drivers/media/usb/ttusb-dec/Kconfig b/drivers/media/usb/ttusb-dec/Kconfig new file mode 100644 index 00000000000..290254ab06d --- /dev/null +++ b/drivers/media/usb/ttusb-dec/Kconfig @@ -0,0 +1,21 @@ +config DVB_TTUSB_DEC + tristate "Technotrend/Hauppauge USB DEC devices" + depends on DVB_CORE && USB && INPUT && PCI + select CRC32 + help + Support for external USB adapters designed by Technotrend and + produced by Hauppauge, shipped under the brand name 'DEC2000-t' + and 'DEC3000-s'. + + Even if these devices have a MPEG decoder built in, they transmit + only compressed MPEG data over the USB bus, so you need + an external software decoder to watch TV on your computer. + + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware dec2000t", + "/Documentation/dvb/get_dvb_firmware dec2540t", + "/Documentation/dvb/get_dvb_firmware dec3000s", + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + + Say Y if you own such a device and want to use it. diff --git a/drivers/media/usb/ttusb-dec/Makefile b/drivers/media/usb/ttusb-dec/Makefile new file mode 100644 index 00000000000..5352740d235 --- /dev/null +++ b/drivers/media/usb/ttusb-dec/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o + +ccflags-y += -Idrivers/media/dvb-core/ diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c new file mode 100644 index 00000000000..504c8123033 --- /dev/null +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -0,0 +1,1764 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003-2004 Alex Woods + * IR support by Peter Beutner + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "ttusbdecfe.h" + +static int debug; +static int output_pva; +static int enable_rc; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +module_param(output_pva, int, 0444); +MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)"); +module_param(enable_rc, int, 0644); +MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk if (debug) printk + +#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" + +#define COMMAND_PIPE 0x03 +#define RESULT_PIPE 0x04 +#define IN_PIPE 0x08 +#define OUT_PIPE 0x07 +#define IRQ_PIPE 0x0A + +#define COMMAND_PACKET_SIZE 0x3c +#define ARM_PACKET_SIZE 0x1000 +#define IRQ_PACKET_SIZE 0x8 + +#define ISO_BUF_COUNT 0x04 +#define FRAMES_PER_ISO_BUF 0x04 +#define ISO_FRAME_SIZE 0x0380 + +#define MAX_PVA_LENGTH 6144 + +enum ttusb_dec_model { + TTUSB_DEC2000T, + TTUSB_DEC2540T, + TTUSB_DEC3000S +}; + +enum ttusb_dec_packet_type { + TTUSB_DEC_PACKET_PVA, + TTUSB_DEC_PACKET_SECTION, + TTUSB_DEC_PACKET_EMPTY +}; + +enum ttusb_dec_interface { + TTUSB_DEC_INTERFACE_INITIAL, + TTUSB_DEC_INTERFACE_IN, + TTUSB_DEC_INTERFACE_OUT +}; + +struct ttusb_dec { + enum ttusb_dec_model model; + char *model_name; + char *firmware_name; + int can_playback; + + /* DVB bits */ + struct dvb_adapter adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvb_net; + struct dvb_frontend* fe; + + u16 pid[DMX_PES_OTHER]; + + /* USB bits */ + struct usb_device *udev; + u8 trans_count; + unsigned int command_pipe; + unsigned int result_pipe; + unsigned int in_pipe; + unsigned int out_pipe; + unsigned int irq_pipe; + enum ttusb_dec_interface interface; + struct mutex usb_mutex; + + void *irq_buffer; + struct urb *irq_urb; + dma_addr_t irq_dma_handle; + void *iso_buffer; + dma_addr_t iso_dma_handle; + struct urb *iso_urb[ISO_BUF_COUNT]; + int iso_stream_count; + struct mutex iso_mutex; + + u8 packet[MAX_PVA_LENGTH + 4]; + enum ttusb_dec_packet_type packet_type; + int packet_state; + int packet_length; + int packet_payload_length; + u16 next_packet_id; + + int pva_stream_count; + int filter_stream_count; + + struct dvb_filter_pes2ts a_pes2ts; + struct dvb_filter_pes2ts v_pes2ts; + + u8 v_pes[16 + MAX_PVA_LENGTH]; + int v_pes_length; + int v_pes_postbytes; + + struct list_head urb_frame_list; + struct tasklet_struct urb_tasklet; + spinlock_t urb_frame_list_lock; + + struct dvb_demux_filter *audio_filter; + struct dvb_demux_filter *video_filter; + struct list_head filter_info_list; + spinlock_t filter_info_list_lock; + + struct input_dev *rc_input_dev; + char rc_phys[64]; + + int active; /* Loaded successfully */ +}; + +struct urb_frame { + u8 data[ISO_FRAME_SIZE]; + int length; + struct list_head urb_frame_list; +}; + +struct filter_info { + u8 stream_id; + struct dvb_demux_filter *filter; + struct list_head filter_info_list; +}; + +static u16 rc_keys[] = { + KEY_POWER, + KEY_MUTE, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_CHANNELUP, + KEY_VOLUMEDOWN, + KEY_OK, + KEY_VOLUMEUP, + KEY_CHANNELDOWN, + KEY_PREVIOUS, + KEY_ESC, + KEY_RED, + KEY_GREEN, + KEY_YELLOW, + KEY_BLUE, + KEY_OPTION, + KEY_M, + KEY_RADIO +}; + +static void ttusb_dec_set_model(struct ttusb_dec *dec, + enum ttusb_dec_model model); + +static void ttusb_dec_handle_irq( struct urb *urb) +{ + struct ttusb_dec * dec = urb->context; + char *buffer = dec->irq_buffer; + int retval; + + switch(urb->status) { + case 0: /*success*/ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ETIME: + /* this urb is dead, cleanup */ + dprintk("%s:urb shutting down with status: %d\n", + __func__, urb->status); + return; + default: + dprintk("%s:nonzero status received: %d\n", + __func__,urb->status); + goto exit; + } + + if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) { + /* IR - Event */ + /* this is an fact a bit too simple implementation; + * the box also reports a keyrepeat signal + * (with buffer[3] == 0x40) in an intervall of ~100ms. + * But to handle this correctly we had to imlemenent some + * kind of timer which signals a 'key up' event if no + * keyrepeat signal is received for lets say 200ms. + * this should/could be added later ... + * for now lets report each signal as a key down and up*/ + dprintk("%s:rc signal:%d\n", __func__, buffer[4]); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); + input_sync(dec->rc_input_dev); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); + input_sync(dec->rc_input_dev); + } + +exit: retval = usb_submit_urb(urb, GFP_ATOMIC); + if(retval) + printk("%s - usb_commit_urb failed with result: %d\n", + __func__, retval); +} + +static u16 crc16(u16 crc, const u8 *buf, size_t len) +{ + u16 tmp; + + while (len--) { + crc ^= *buf++; + crc ^= (u8)crc >> 4; + tmp = (u8)crc; + crc ^= (tmp ^ (tmp << 1)) << 4; + } + return crc; +} + +static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + int result, actual_len, i; + u8 *b; + + dprintk("%s\n", __func__); + + b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); + if (!b) + return -ENOMEM; + + if ((result = mutex_lock_interruptible(&dec->usb_mutex))) { + kfree(b); + printk("%s: Failed to lock usb mutex.\n", __func__); + return result; + } + + b[0] = 0xaa; + b[1] = ++dec->trans_count; + b[2] = command; + b[3] = param_length; + + if (params) + memcpy(&b[4], params, param_length); + + if (debug) { + printk("%s: command: ", __func__); + for (i = 0; i < param_length + 4; i++) + printk("0x%02X ", b[i]); + printk("\n"); + } + + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + COMMAND_PACKET_SIZE + 4, &actual_len, 1000); + + if (result) { + printk("%s: command bulk message failed: error %d\n", + __func__, result); + mutex_unlock(&dec->usb_mutex); + kfree(b); + return result; + } + + result = usb_bulk_msg(dec->udev, dec->result_pipe, b, + COMMAND_PACKET_SIZE + 4, &actual_len, 1000); + + if (result) { + printk("%s: result bulk message failed: error %d\n", + __func__, result); + mutex_unlock(&dec->usb_mutex); + kfree(b); + return result; + } else { + if (debug) { + printk("%s: result: ", __func__); + for (i = 0; i < actual_len; i++) + printk("0x%02X ", b[i]); + printk("\n"); + } + + if (result_length) + *result_length = b[3]; + if (cmd_result && b[3] > 0) + memcpy(cmd_result, &b[4], b[3]); + + mutex_unlock(&dec->usb_mutex); + + kfree(b); + return 0; + } +} + +static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, + unsigned int *model, unsigned int *version) +{ + u8 c[COMMAND_PACKET_SIZE]; + int c_length; + int result; + __be32 tmp; + + dprintk("%s\n", __func__); + + result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); + if (result) + return result; + + if (c_length >= 0x0c) { + if (mode != NULL) { + memcpy(&tmp, c, 4); + *mode = ntohl(tmp); + } + if (model != NULL) { + memcpy(&tmp, &c[4], 4); + *model = ntohl(tmp); + } + if (version != NULL) { + memcpy(&tmp, &c[8], 4); + *version = ntohl(tmp); + } + return 0; + } else { + return -1; + } +} + +static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) +{ + struct ttusb_dec *dec = priv; + + dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, + &dec->audio_filter->feed->feed.ts, + DMX_OK); + + return 0; +} + +static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) +{ + struct ttusb_dec *dec = priv; + + dec->video_filter->feed->cb.ts(data, 188, NULL, 0, + &dec->video_filter->feed->feed.ts, + DMX_OK); + + return 0; +} + +static void ttusb_dec_set_pids(struct ttusb_dec *dec) +{ + u8 b[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; + + __be16 pcr = htons(dec->pid[DMX_PES_PCR]); + __be16 audio = htons(dec->pid[DMX_PES_AUDIO]); + __be16 video = htons(dec->pid[DMX_PES_VIDEO]); + + dprintk("%s\n", __func__); + + memcpy(&b[0], &pcr, 2); + memcpy(&b[2], &audio, 2); + memcpy(&b[4], &video, 2); + + ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); + + dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], + ttusb_dec_audio_pes2ts_cb, dec); + dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], + ttusb_dec_video_pes2ts_cb, dec); + dec->v_pes_length = 0; + dec->v_pes_postbytes = 0; +} + +static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) +{ + if (length < 8) { + printk("%s: packet too short - discarding\n", __func__); + return; + } + + if (length > 8 + MAX_PVA_LENGTH) { + printk("%s: packet too long - discarding\n", __func__); + return; + } + + switch (pva[2]) { + + case 0x01: { /* VideoStream */ + int prebytes = pva[5] & 0x03; + int postbytes = (pva[5] & 0x0c) >> 2; + __be16 v_pes_payload_length; + + if (output_pva) { + dec->video_filter->feed->cb.ts(pva, length, NULL, 0, + &dec->video_filter->feed->feed.ts, DMX_OK); + return; + } + + if (dec->v_pes_postbytes > 0 && + dec->v_pes_postbytes == prebytes) { + memcpy(&dec->v_pes[dec->v_pes_length], + &pva[12], prebytes); + + dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, + dec->v_pes_length + prebytes, 1); + } + + if (pva[5] & 0x10) { + dec->v_pes[7] = 0x80; + dec->v_pes[8] = 0x05; + + dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5); + dec->v_pes[10] = ((pva[8] & 0x3f) << 2) | + ((pva[9] & 0xc0) >> 6); + dec->v_pes[11] = 0x01 | + ((pva[9] & 0x3f) << 2) | + ((pva[10] & 0x80) >> 6); + dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | + ((pva[11] & 0xc0) >> 7); + dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1); + + memcpy(&dec->v_pes[14], &pva[12 + prebytes], + length - 12 - prebytes); + dec->v_pes_length = 14 + length - 12 - prebytes; + } else { + dec->v_pes[7] = 0x00; + dec->v_pes[8] = 0x00; + + memcpy(&dec->v_pes[9], &pva[8], length - 8); + dec->v_pes_length = 9 + length - 8; + } + + dec->v_pes_postbytes = postbytes; + + if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && + dec->v_pes[10 + dec->v_pes[8]] == 0x00 && + dec->v_pes[11 + dec->v_pes[8]] == 0x01) + dec->v_pes[6] = 0x84; + else + dec->v_pes[6] = 0x80; + + v_pes_payload_length = htons(dec->v_pes_length - 6 + + postbytes); + memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); + + if (postbytes == 0) + dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, + dec->v_pes_length, 1); + + break; + } + + case 0x02: /* MainAudioStream */ + if (output_pva) { + dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, + &dec->audio_filter->feed->feed.ts, DMX_OK); + return; + } + + dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8, + pva[5] & 0x10); + break; + + default: + printk("%s: unknown PVA type: %02x.\n", __func__, + pva[2]); + break; + } +} + +static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, + int length) +{ + struct list_head *item; + struct filter_info *finfo; + struct dvb_demux_filter *filter = NULL; + unsigned long flags; + u8 sid; + + sid = packet[1]; + spin_lock_irqsave(&dec->filter_info_list_lock, flags); + for (item = dec->filter_info_list.next; item != &dec->filter_info_list; + item = item->next) { + finfo = list_entry(item, struct filter_info, filter_info_list); + if (finfo->stream_id == sid) { + filter = finfo->filter; + break; + } + } + spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); + + if (filter) + filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, + &filter->filter, DMX_OK); +} + +static void ttusb_dec_process_packet(struct ttusb_dec *dec) +{ + int i; + u16 csum = 0; + u16 packet_id; + + if (dec->packet_length % 2) { + printk("%s: odd sized packet - discarding\n", __func__); + return; + } + + for (i = 0; i < dec->packet_length; i += 2) + csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]); + + if (csum) { + printk("%s: checksum failed - discarding\n", __func__); + return; + } + + packet_id = dec->packet[dec->packet_length - 4] << 8; + packet_id += dec->packet[dec->packet_length - 3]; + + if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { + printk("%s: warning: lost packets between %u and %u\n", + __func__, dec->next_packet_id - 1, packet_id); + } + + if (packet_id == 0xffff) + dec->next_packet_id = 0x8000; + else + dec->next_packet_id = packet_id + 1; + + switch (dec->packet_type) { + case TTUSB_DEC_PACKET_PVA: + if (dec->pva_stream_count) + ttusb_dec_process_pva(dec, dec->packet, + dec->packet_payload_length); + break; + + case TTUSB_DEC_PACKET_SECTION: + if (dec->filter_stream_count) + ttusb_dec_process_filter(dec, dec->packet, + dec->packet_payload_length); + break; + + case TTUSB_DEC_PACKET_EMPTY: + break; + } +} + +static void swap_bytes(u8 *b, int length) +{ + u8 c; + + length -= length % 2; + for (; length; b += 2, length -= 2) { + c = *b; + *b = *(b + 1); + *(b + 1) = c; + } +} + +static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, + int length) +{ + swap_bytes(b, length); + + while (length) { + switch (dec->packet_state) { + + case 0: + case 1: + case 2: + if (*b++ == 0xaa) + dec->packet_state++; + else + dec->packet_state = 0; + + length--; + break; + + case 3: + if (*b == 0x00) { + dec->packet_state++; + dec->packet_length = 0; + } else if (*b != 0xaa) { + dec->packet_state = 0; + } + + b++; + length--; + break; + + case 4: + dec->packet[dec->packet_length++] = *b++; + + if (dec->packet_length == 2) { + if (dec->packet[0] == 'A' && + dec->packet[1] == 'V') { + dec->packet_type = + TTUSB_DEC_PACKET_PVA; + dec->packet_state++; + } else if (dec->packet[0] == 'S') { + dec->packet_type = + TTUSB_DEC_PACKET_SECTION; + dec->packet_state++; + } else if (dec->packet[0] == 0x00) { + dec->packet_type = + TTUSB_DEC_PACKET_EMPTY; + dec->packet_payload_length = 2; + dec->packet_state = 7; + } else { + printk("%s: unknown packet type: " + "%02x%02x\n", __func__, + dec->packet[0], dec->packet[1]); + dec->packet_state = 0; + } + } + + length--; + break; + + case 5: + dec->packet[dec->packet_length++] = *b++; + + if (dec->packet_type == TTUSB_DEC_PACKET_PVA && + dec->packet_length == 8) { + dec->packet_state++; + dec->packet_payload_length = 8 + + (dec->packet[6] << 8) + + dec->packet[7]; + } else if (dec->packet_type == + TTUSB_DEC_PACKET_SECTION && + dec->packet_length == 5) { + dec->packet_state++; + dec->packet_payload_length = 5 + + ((dec->packet[3] & 0x0f) << 8) + + dec->packet[4]; + } + + length--; + break; + + case 6: { + int remainder = dec->packet_payload_length - + dec->packet_length; + + if (length >= remainder) { + memcpy(dec->packet + dec->packet_length, + b, remainder); + dec->packet_length += remainder; + b += remainder; + length -= remainder; + dec->packet_state++; + } else { + memcpy(&dec->packet[dec->packet_length], + b, length); + dec->packet_length += length; + length = 0; + } + + break; + } + + case 7: { + int tail = 4; + + dec->packet[dec->packet_length++] = *b++; + + if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && + dec->packet_payload_length % 2) + tail++; + + if (dec->packet_length == + dec->packet_payload_length + tail) { + ttusb_dec_process_packet(dec); + dec->packet_state = 0; + } + + length--; + break; + } + + default: + printk("%s: illegal packet state encountered.\n", + __func__); + dec->packet_state = 0; + } + } +} + +static void ttusb_dec_process_urb_frame_list(unsigned long data) +{ + struct ttusb_dec *dec = (struct ttusb_dec *)data; + struct list_head *item; + struct urb_frame *frame; + unsigned long flags; + + while (1) { + spin_lock_irqsave(&dec->urb_frame_list_lock, flags); + if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { + frame = list_entry(item, struct urb_frame, + urb_frame_list); + list_del(&frame->urb_frame_list); + } else { + spin_unlock_irqrestore(&dec->urb_frame_list_lock, + flags); + return; + } + spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); + + ttusb_dec_process_urb_frame(dec, frame->data, frame->length); + kfree(frame); + } +} + +static void ttusb_dec_process_urb(struct urb *urb) +{ + struct ttusb_dec *dec = urb->context; + + if (!urb->status) { + int i; + + for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { + struct usb_iso_packet_descriptor *d; + u8 *b; + int length; + struct urb_frame *frame; + + d = &urb->iso_frame_desc[i]; + b = urb->transfer_buffer + d->offset; + length = d->actual_length; + + if ((frame = kmalloc(sizeof(struct urb_frame), + GFP_ATOMIC))) { + unsigned long flags; + + memcpy(frame->data, b, length); + frame->length = length; + + spin_lock_irqsave(&dec->urb_frame_list_lock, + flags); + list_add_tail(&frame->urb_frame_list, + &dec->urb_frame_list); + spin_unlock_irqrestore(&dec->urb_frame_list_lock, + flags); + + tasklet_schedule(&dec->urb_tasklet); + } + } + } else { + /* -ENOENT is expected when unlinking urbs */ + if (urb->status != -ENOENT) + dprintk("%s: urb error: %d\n", __func__, + urb->status); + } + + if (dec->iso_stream_count) + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) +{ + int i, j, buffer_offset = 0; + + dprintk("%s\n", __func__); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + int frame_offset = 0; + struct urb *urb = dec->iso_urb[i]; + + urb->dev = dec->udev; + urb->context = dec; + urb->complete = ttusb_dec_process_urb; + urb->pipe = dec->in_pipe; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = FRAMES_PER_ISO_BUF; + urb->transfer_buffer_length = ISO_FRAME_SIZE * + FRAMES_PER_ISO_BUF; + urb->transfer_buffer = dec->iso_buffer + buffer_offset; + buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + + for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; + frame_offset += ISO_FRAME_SIZE; + } + } +} + +static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + if (mutex_lock_interruptible(&dec->iso_mutex)) + return; + + dec->iso_stream_count--; + + if (!dec->iso_stream_count) { + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_kill_urb(dec->iso_urb[i]); + } + + mutex_unlock(&dec->iso_mutex); +} + +/* Setting the interface of the DEC tends to take down the USB communications + * for a short period, so it's important not to call this function just before + * trying to talk to it. + */ +static int ttusb_dec_set_interface(struct ttusb_dec *dec, + enum ttusb_dec_interface interface) +{ + int result = 0; + u8 b[] = { 0x05 }; + + if (interface != dec->interface) { + switch (interface) { + case TTUSB_DEC_INTERFACE_INITIAL: + result = usb_set_interface(dec->udev, 0, 0); + break; + case TTUSB_DEC_INTERFACE_IN: + result = ttusb_dec_send_command(dec, 0x80, sizeof(b), + b, NULL, NULL); + if (result) + return result; + result = usb_set_interface(dec->udev, 0, 8); + break; + case TTUSB_DEC_INTERFACE_OUT: + result = usb_set_interface(dec->udev, 0, 1); + break; + } + + if (result) + return result; + + dec->interface = interface; + } + + return 0; +} + +static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) +{ + int i, result; + + dprintk("%s\n", __func__); + + if (mutex_lock_interruptible(&dec->iso_mutex)) + return -EAGAIN; + + if (!dec->iso_stream_count) { + ttusb_dec_setup_urbs(dec); + + dec->packet_state = 0; + dec->v_pes_postbytes = 0; + dec->next_packet_id = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) { + if ((result = usb_submit_urb(dec->iso_urb[i], + GFP_ATOMIC))) { + printk("%s: failed urb submission %d: " + "error %d\n", __func__, i, result); + + while (i) { + usb_kill_urb(dec->iso_urb[i - 1]); + i--; + } + + mutex_unlock(&dec->iso_mutex); + return result; + } + } + } + + dec->iso_stream_count++; + + mutex_unlock(&dec->iso_mutex); + + return 0; +} + +static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ttusb_dec *dec = dvbdmx->priv; + u8 b0[] = { 0x05 }; + int result = 0; + + dprintk("%s\n", __func__); + + dprintk(" ts_type:"); + + if (dvbdmxfeed->ts_type & TS_DECODER) + dprintk(" TS_DECODER"); + + if (dvbdmxfeed->ts_type & TS_PACKET) + dprintk(" TS_PACKET"); + + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + dprintk(" TS_PAYLOAD_ONLY"); + + dprintk("\n"); + + switch (dvbdmxfeed->pes_type) { + + case DMX_TS_PES_VIDEO: + dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); + dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; + dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; + dec->video_filter = dvbdmxfeed->filter; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_AUDIO: + dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); + dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; + dec->audio_filter = dvbdmxfeed->filter; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_TELETEXT: + dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; + dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); + return -ENOSYS; + + case DMX_TS_PES_PCR: + dprintk(" pes_type: DMX_TS_PES_PCR\n"); + dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_OTHER: + dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + return -ENOSYS; + + default: + dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); + return -EINVAL; + + } + + result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); + if (result) + return result; + + dec->pva_stream_count++; + return ttusb_dec_start_iso_xfer(dec); +} + +static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + u8 b0[] = { 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 }; + __be16 pid; + u8 c[COMMAND_PACKET_SIZE]; + int c_length; + int result; + struct filter_info *finfo; + unsigned long flags; + u8 x = 1; + + dprintk("%s\n", __func__); + + pid = htons(dvbdmxfeed->pid); + memcpy(&b0[0], &pid, 2); + memcpy(&b0[4], &x, 1); + memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); + + result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, + &c_length, c); + + if (!result) { + if (c_length == 2) { + if (!(finfo = kmalloc(sizeof(struct filter_info), + GFP_ATOMIC))) + return -ENOMEM; + + finfo->stream_id = c[1]; + finfo->filter = dvbdmxfeed->filter; + + spin_lock_irqsave(&dec->filter_info_list_lock, flags); + list_add_tail(&finfo->filter_info_list, + &dec->filter_info_list); + spin_unlock_irqrestore(&dec->filter_info_list_lock, + flags); + + dvbdmxfeed->priv = finfo; + + dec->filter_stream_count++; + return ttusb_dec_start_iso_xfer(dec); + } + + return -EAGAIN; + } else + return result; +} + +static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + dprintk("%s\n", __func__); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); + + switch (dvbdmxfeed->type) { + + case DMX_TYPE_TS: + return ttusb_dec_start_ts_feed(dvbdmxfeed); + break; + + case DMX_TYPE_SEC: + return ttusb_dec_start_sec_feed(dvbdmxfeed); + break; + + default: + dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); + return -EINVAL; + + } +} + +static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + u8 b0[] = { 0x00 }; + + ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); + + dec->pva_stream_count--; + + ttusb_dec_stop_iso_xfer(dec); + + return 0; +} + +static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + u8 b0[] = { 0x00, 0x00 }; + struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; + unsigned long flags; + + b0[1] = finfo->stream_id; + spin_lock_irqsave(&dec->filter_info_list_lock, flags); + list_del(&finfo->filter_info_list); + spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); + kfree(finfo); + ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); + + dec->filter_stream_count--; + + ttusb_dec_stop_iso_xfer(dec); + + return 0; +} + +static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + dprintk("%s\n", __func__); + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + return ttusb_dec_stop_ts_feed(dvbdmxfeed); + break; + + case DMX_TYPE_SEC: + return ttusb_dec_stop_sec_feed(dvbdmxfeed); + break; + } + + return 0; +} + +static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_free_urb(dec->iso_urb[i]); + + pci_free_consistent(NULL, + ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT), + dec->iso_buffer, dec->iso_dma_handle); +} + +static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + dec->iso_buffer = pci_alloc_consistent(NULL, + ISO_FRAME_SIZE * + (FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT), + &dec->iso_dma_handle); + + if (!dec->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + + memset(dec->iso_buffer, 0, + ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + struct urb *urb; + + if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { + ttusb_dec_free_iso_urbs(dec); + return -ENOMEM; + } + + dec->iso_urb[i] = urb; + } + + ttusb_dec_setup_urbs(dec); + + return 0; +} + +static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) +{ + spin_lock_init(&dec->urb_frame_list_lock); + INIT_LIST_HEAD(&dec->urb_frame_list); + tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list, + (unsigned long)dec); +} + +static int ttusb_init_rc( struct ttusb_dec *dec) +{ + struct input_dev *input_dev; + u8 b[] = { 0x00, 0x01 }; + int i; + int err; + + usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); + strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "ttusb_dec remote control"; + input_dev->phys = dec->rc_phys; + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->keycodesize = sizeof(u16); + input_dev->keycodemax = 0x1a; + input_dev->keycode = rc_keys; + + for (i = 0; i < ARRAY_SIZE(rc_keys); i++) + set_bit(rc_keys[i], input_dev->keybit); + + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + + dec->rc_input_dev = input_dev; + if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) + printk("%s: usb_submit_urb failed\n",__func__); + /* enable irq pipe */ + ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); + + return 0; +} + +static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) +{ + dprintk("%s\n", __func__); + + dec->v_pes[0] = 0x00; + dec->v_pes[1] = 0x00; + dec->v_pes[2] = 0x01; + dec->v_pes[3] = 0xe0; +} + +static int ttusb_dec_init_usb(struct ttusb_dec *dec) +{ + dprintk("%s\n", __func__); + + mutex_init(&dec->usb_mutex); + mutex_init(&dec->iso_mutex); + + dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); + dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); + dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); + dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); + dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); + + if(enable_rc) { + dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if(!dec->irq_urb) { + return -ENOMEM; + } + dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, + GFP_ATOMIC, &dec->irq_dma_handle); + if(!dec->irq_buffer) { + usb_free_urb(dec->irq_urb); + return -ENOMEM; + } + usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, + dec->irq_buffer, IRQ_PACKET_SIZE, + ttusb_dec_handle_irq, dec, 1); + dec->irq_urb->transfer_dma = dec->irq_dma_handle; + dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + } + + return ttusb_dec_alloc_iso_urbs(dec); +} + +static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) +{ + int i, j, actual_len, result, size, trans_count; + u8 b0[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x61, 0x00 }; + u8 b1[] = { 0x61 }; + u8 *b; + char idstring[21]; + const u8 *firmware = NULL; + size_t firmware_size = 0; + u16 firmware_csum = 0; + __be16 firmware_csum_ns; + __be32 firmware_size_nl; + u32 crc32_csum, crc32_check; + __be32 tmp; + const struct firmware *fw_entry = NULL; + + dprintk("%s\n", __func__); + + if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { + printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", + __func__, dec->firmware_name); + return 1; + } + + firmware = fw_entry->data; + firmware_size = fw_entry->size; + + if (firmware_size < 60) { + printk("%s: firmware size too small for DSP code (%zu < 60).\n", + __func__, firmware_size); + release_firmware(fw_entry); + return -1; + } + + /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored + at offset 56 of file, so use it to check if the firmware file is + valid. */ + crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; + memcpy(&tmp, &firmware[56], 4); + crc32_check = ntohl(tmp); + if (crc32_csum != crc32_check) { + printk("%s: crc32 check of DSP code failed (calculated " + "0x%08x != 0x%08x in file), file invalid.\n", + __func__, crc32_csum, crc32_check); + release_firmware(fw_entry); + return -1; + } + memcpy(idstring, &firmware[36], 20); + idstring[20] = '\0'; + printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); + + firmware_size_nl = htonl(firmware_size); + memcpy(b0, &firmware_size_nl, 4); + firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; + firmware_csum_ns = htons(firmware_csum); + memcpy(&b0[6], &firmware_csum_ns, 2); + + result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); + + if (result) { + release_firmware(fw_entry); + return result; + } + + trans_count = 0; + j = 0; + + b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); + if (b == NULL) { + release_firmware(fw_entry); + return -ENOMEM; + } + + for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { + size = firmware_size - i; + if (size > COMMAND_PACKET_SIZE) + size = COMMAND_PACKET_SIZE; + + b[j + 0] = 0xaa; + b[j + 1] = trans_count++; + b[j + 2] = 0xf0; + b[j + 3] = size; + memcpy(&b[j + 4], &firmware[i], size); + + j += COMMAND_PACKET_SIZE + 4; + + if (j >= ARM_PACKET_SIZE) { + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + ARM_PACKET_SIZE, &actual_len, + 100); + j = 0; + } else if (size < COMMAND_PACKET_SIZE) { + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + j - COMMAND_PACKET_SIZE + size, + &actual_len, 100); + } + } + + result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); + + release_firmware(fw_entry); + kfree(b); + + return result; +} + +static int ttusb_dec_init_stb(struct ttusb_dec *dec) +{ + int result; + unsigned int mode = 0, model = 0, version = 0; + + dprintk("%s\n", __func__); + + result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); + + if (!result) { + if (!mode) { + if (version == 0xABCDEFAB) + printk(KERN_INFO "ttusb_dec: no version " + "info in Firmware\n"); + else + printk(KERN_INFO "ttusb_dec: Firmware " + "%x.%02x%c%c\n", + version >> 24, (version >> 16) & 0xff, + (version >> 8) & 0xff, version & 0xff); + + result = ttusb_dec_boot_dsp(dec); + if (result) + return result; + else + return 1; + } else { + /* We can't trust the USB IDs that some firmwares + give the box */ + switch (model) { + case 0x00070001: + case 0x00070008: + case 0x0007000c: + ttusb_dec_set_model(dec, TTUSB_DEC3000S); + break; + case 0x00070009: + case 0x00070013: + ttusb_dec_set_model(dec, TTUSB_DEC2000T); + break; + case 0x00070011: + ttusb_dec_set_model(dec, TTUSB_DEC2540T); + break; + default: + printk(KERN_ERR "%s: unknown model returned " + "by firmware (%08x) - please report\n", + __func__, model); + return -1; + break; + } + + if (version >= 0x01770000) + dec->can_playback = 1; + + return 0; + } + } + else + return result; +} + +static int ttusb_dec_init_dvb(struct ttusb_dec *dec) +{ + int result; + + dprintk("%s\n", __func__); + + if ((result = dvb_register_adapter(&dec->adapter, + dec->model_name, THIS_MODULE, + &dec->udev->dev, + adapter_nr)) < 0) { + printk("%s: dvb_register_adapter failed: error %d\n", + __func__, result); + + return result; + } + + dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + + dec->demux.priv = (void *)dec; + dec->demux.filternum = 31; + dec->demux.feednum = 31; + dec->demux.start_feed = ttusb_dec_start_feed; + dec->demux.stop_feed = ttusb_dec_stop_feed; + dec->demux.write_to_decoder = NULL; + + if ((result = dvb_dmx_init(&dec->demux)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + dec->dmxdev.filternum = 32; + dec->dmxdev.demux = &dec->demux.dmx; + dec->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { + printk("%s: dvb_dmxdev_init failed: error %d\n", + __func__, result); + + dvb_dmx_release(&dec->demux); + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + dec->frontend.source = DMX_FRONTEND_0; + + if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, + &dec->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, + &dec->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); + + return 0; +} + +static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) +{ + dprintk("%s\n", __func__); + + dvb_net_release(&dec->dvb_net); + dec->demux.dmx.close(&dec->demux.dmx); + dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + if (dec->fe) { + dvb_unregister_frontend(dec->fe); + if (dec->fe->ops.release) + dec->fe->ops.release(dec->fe); + } + dvb_unregister_adapter(&dec->adapter); +} + +static void ttusb_dec_exit_rc(struct ttusb_dec *dec) +{ + + dprintk("%s\n", __func__); + /* we have to check whether the irq URB is already submitted. + * As the irq is submitted after the interface is changed, + * this is the best method i figured out. + * Any others?*/ + if (dec->interface == TTUSB_DEC_INTERFACE_IN) + usb_kill_urb(dec->irq_urb); + + usb_free_urb(dec->irq_urb); + + usb_free_coherent(dec->udev,IRQ_PACKET_SIZE, + dec->irq_buffer, dec->irq_dma_handle); + + if (dec->rc_input_dev) { + input_unregister_device(dec->rc_input_dev); + dec->rc_input_dev = NULL; + } +} + + +static void ttusb_dec_exit_usb(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + dec->iso_stream_count = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_kill_urb(dec->iso_urb[i]); + + ttusb_dec_free_iso_urbs(dec); +} + +static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) +{ + struct list_head *item; + struct urb_frame *frame; + + tasklet_kill(&dec->urb_tasklet); + + while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { + frame = list_entry(item, struct urb_frame, urb_frame_list); + list_del(&frame->urb_frame_list); + kfree(frame); + } +} + +static void ttusb_dec_init_filters(struct ttusb_dec *dec) +{ + INIT_LIST_HEAD(&dec->filter_info_list); + spin_lock_init(&dec->filter_info_list_lock); +} + +static void ttusb_dec_exit_filters(struct ttusb_dec *dec) +{ + struct list_head *item; + struct filter_info *finfo; + + while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { + finfo = list_entry(item, struct filter_info, filter_info_list); + list_del(&finfo->filter_info_list); + kfree(finfo); + } +} + +static int fe_send_command(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + struct ttusb_dec* dec = fe->dvb->priv; + return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); +} + +static struct ttusbdecfe_config fe_config = { + .send_command = fe_send_command +}; + +static int ttusb_dec_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct ttusb_dec *dec; + + dprintk("%s\n", __func__); + + udev = interface_to_usbdev(intf); + + if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { + printk("%s: couldn't allocate memory.\n", __func__); + return -ENOMEM; + } + + usb_set_intfdata(intf, (void *)dec); + + switch (id->idProduct) { + case 0x1006: + ttusb_dec_set_model(dec, TTUSB_DEC3000S); + break; + + case 0x1008: + ttusb_dec_set_model(dec, TTUSB_DEC2000T); + break; + + case 0x1009: + ttusb_dec_set_model(dec, TTUSB_DEC2540T); + break; + } + + dec->udev = udev; + + if (ttusb_dec_init_usb(dec)) + return 0; + if (ttusb_dec_init_stb(dec)) { + ttusb_dec_exit_usb(dec); + return 0; + } + ttusb_dec_init_dvb(dec); + + dec->adapter.priv = dec; + switch (id->idProduct) { + case 0x1006: + dec->fe = ttusbdecfe_dvbs_attach(&fe_config); + break; + + case 0x1008: + case 0x1009: + dec->fe = ttusbdecfe_dvbt_attach(&fe_config); + break; + } + + if (dec->fe == NULL) { + printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", + le16_to_cpu(dec->udev->descriptor.idVendor), + le16_to_cpu(dec->udev->descriptor.idProduct)); + } else { + if (dvb_register_frontend(&dec->adapter, dec->fe)) { + printk("budget-ci: Frontend registration failed!\n"); + if (dec->fe->ops.release) + dec->fe->ops.release(dec->fe); + dec->fe = NULL; + } + } + + ttusb_dec_init_v_pes(dec); + ttusb_dec_init_filters(dec); + ttusb_dec_init_tasklet(dec); + + dec->active = 1; + + ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); + + if (enable_rc) + ttusb_init_rc(dec); + + return 0; +} + +static void ttusb_dec_disconnect(struct usb_interface *intf) +{ + struct ttusb_dec *dec = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + dprintk("%s\n", __func__); + + if (dec->active) { + ttusb_dec_exit_tasklet(dec); + ttusb_dec_exit_filters(dec); + if(enable_rc) + ttusb_dec_exit_rc(dec); + ttusb_dec_exit_usb(dec); + ttusb_dec_exit_dvb(dec); + } + + kfree(dec); +} + +static void ttusb_dec_set_model(struct ttusb_dec *dec, + enum ttusb_dec_model model) +{ + dec->model = model; + + switch (model) { + case TTUSB_DEC2000T: + dec->model_name = "DEC2000-t"; + dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; + break; + + case TTUSB_DEC2540T: + dec->model_name = "DEC2540-t"; + dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; + break; + + case TTUSB_DEC3000S: + dec->model_name = "DEC3000-s"; + dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; + break; + } +} + +static struct usb_device_id ttusb_dec_table[] = { + {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ + /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ + {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ + {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ + {} +}; + +static struct usb_driver ttusb_dec_driver = { + .name = "ttusb-dec", + .probe = ttusb_dec_probe, + .disconnect = ttusb_dec_disconnect, + .id_table = ttusb_dec_table, +}; + +module_usb_driver(ttusb_dec_driver); + +MODULE_AUTHOR("Alex Woods "); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, ttusb_dec_table); diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c new file mode 100644 index 00000000000..5c45c9d0712 --- /dev/null +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -0,0 +1,298 @@ +/* + * TTUSB DEC Frontend Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * 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 "dvb_frontend.h" +#include "ttusbdecfe.h" + + +#define LOF_HI 10600000 +#define LOF_LO 9750000 + +struct ttusbdecfe_state { + + /* configuration settings */ + const struct ttusbdecfe_config* config; + + struct dvb_frontend frontend; + + u8 hi_band; + u8 voltage; +}; + + +static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; +} + + +static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct ttusbdecfe_state* state = fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + u8 result[4]; + int len, ret; + + *status=0; + + ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); + if(ret) + return ret; + + if(len != 4) { + printk(KERN_ERR "%s: unexpected reply\n", __func__); + return -EIO; + } + + switch(result[3]) { + case 1: /* not tuned yet */ + case 2: /* no signal/no lock*/ + break; + case 3: /* signal found and locked*/ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + break; + case 4: + *status = FE_TIMEDOUT; + break; + default: + pr_info("%s: returned unknown value: %d\n", + __func__, result[3]); + return -EIO; + } + + return 0; +} + +static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff }; + + __be32 freq = htonl(p->frequency / 1000); + memcpy(&b[4], &freq, sizeof (u32)); + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 1500; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + u8 b[] = { 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + __be32 freq; + __be32 sym_rate; + __be32 band; + __be32 lnb_voltage; + + freq = htonl(p->frequency + + (state->hi_band ? LOF_HI : LOF_LO)); + memcpy(&b[4], &freq, sizeof(u32)); + sym_rate = htonl(p->symbol_rate); + memcpy(&b[12], &sym_rate, sizeof(u32)); + band = htonl(state->hi_band ? LOF_HI : LOF_LO); + memcpy(&b[24], &band, sizeof(u32)); + lnb_voltage = htonl(state->voltage); + memcpy(&b[28], &lnb_voltage, sizeof(u32)); + + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + + memcpy(&b[4], cmd->msg, cmd->msg_len); + + state->config->send_command(fe, 0x72, + sizeof(b) - (6 - cmd->msg_len), b, + NULL, NULL); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + state->hi_band = (SEC_TONE_ON == tone); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + state->voltage = 13; + break; + case SEC_VOLTAGE_18: + state->voltage = 18; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void ttusbdecfe_release(struct dvb_frontend* fe) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; + +struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + /* setup the state */ + state->config = config; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; + +struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + /* setup the state */ + state->config = config; + state->voltage = 0; + state->hi_band = 0; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_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 = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbt_set_frontend, + + .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, + + .read_status = ttusbdecfe_dvbt_read_status, +}; + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { + .delsys = { SYS_DVBS }, + .info = { + .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, + .symbol_rate_min = 1000000, /* guessed */ + .symbol_rate_max = 45000000, /* guessed */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbs_set_frontend, + + .read_status = ttusbdecfe_dvbs_read_status, + + .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, + .set_voltage = ttusbdecfe_dvbs_set_voltage, + .set_tone = ttusbdecfe_dvbs_set_tone, +}; + +MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); +MODULE_AUTHOR("Alex Woods/Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ttusbdecfe_dvbt_attach); +EXPORT_SYMBOL(ttusbdecfe_dvbs_attach); diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.h b/drivers/media/usb/ttusb-dec/ttusbdecfe.h new file mode 100644 index 00000000000..15ccc3d1a20 --- /dev/null +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.h @@ -0,0 +1,38 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * 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 TTUSBDECFE_H +#define TTUSBDECFE_H + +#include + +struct ttusbdecfe_config +{ + int (*send_command)(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]); +}; + +extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config); + +extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config); + +#endif // TTUSBDECFE_H diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile index 3ba13f9aaf7..9f2d4a9df3f 100644 --- a/drivers/media/video/cx231xx/Makefile +++ b/drivers/media/video/cx231xx/Makefile @@ -12,4 +12,4 @@ ccflags-y += -Idrivers/media/video ccflags-y += -Idrivers/media/common/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/dvb/dvb-usb +ccflags-y += -Idrivers/media/usb/dvb-usb diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile index f654ddcb2c6..3fdbef5306a 100644 --- a/drivers/staging/media/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile @@ -24,7 +24,7 @@ s2250-y := s2250-board.o #ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3 # S2250 needs cypress ezusb loader from dvb-usb -ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/dvb/dvb-usb +ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/usb/dvb-usb ccflags-y += -Idrivers/media/dvb-frontends ccflags-y += -Idrivers/media/dvb-core -- cgit v1.2.3-70-g09d2 From 25aee3debe0464f6c680173041fa3de30ec9ff54 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Jun 2012 16:35:57 -0300 Subject: [media] Rename media/dvb as media/pci The remaining dvb drivers are pci, so rename them to match the bus. Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/dvb/kdapi.xml | 2 +- drivers/media/Kconfig | 2 +- drivers/media/Makefile | 2 +- drivers/media/dvb/Kconfig | 50 - drivers/media/dvb/Makefile | 13 - drivers/media/dvb/b2c2/Kconfig | 45 - drivers/media/dvb/b2c2/Makefile | 16 - drivers/media/dvb/b2c2/flexcop-common.h | 185 -- drivers/media/dvb/b2c2/flexcop-dma.c | 172 -- drivers/media/dvb/b2c2/flexcop-eeprom.c | 147 -- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 678 ------ drivers/media/dvb/b2c2/flexcop-hw-filter.c | 232 -- drivers/media/dvb/b2c2/flexcop-i2c.c | 288 --- drivers/media/dvb/b2c2/flexcop-misc.c | 86 - drivers/media/dvb/b2c2/flexcop-pci.c | 450 ---- drivers/media/dvb/b2c2/flexcop-reg.h | 166 -- drivers/media/dvb/b2c2/flexcop-sram.c | 363 --- drivers/media/dvb/b2c2/flexcop-usb.c | 587 ----- drivers/media/dvb/b2c2/flexcop-usb.h | 111 - drivers/media/dvb/b2c2/flexcop.c | 324 --- drivers/media/dvb/b2c2/flexcop.h | 29 - drivers/media/dvb/b2c2/flexcop_ibi_value_be.h | 455 ---- drivers/media/dvb/b2c2/flexcop_ibi_value_le.h | 455 ---- drivers/media/dvb/bt8xx/Kconfig | 22 - drivers/media/dvb/bt8xx/Makefile | 6 - drivers/media/dvb/bt8xx/bt878.c | 609 ----- drivers/media/dvb/bt8xx/bt878.h | 159 -- drivers/media/dvb/bt8xx/dst.c | 1873 ---------------- drivers/media/dvb/bt8xx/dst_ca.c | 726 ------ drivers/media/dvb/bt8xx/dst_ca.h | 58 - drivers/media/dvb/bt8xx/dst_common.h | 182 -- drivers/media/dvb/bt8xx/dst_priv.h | 35 - drivers/media/dvb/bt8xx/dvb-bt8xx.c | 975 -------- drivers/media/dvb/bt8xx/dvb-bt8xx.h | 63 - drivers/media/dvb/ddbridge/Kconfig | 18 - drivers/media/dvb/ddbridge/Makefile | 14 - drivers/media/dvb/ddbridge/ddbridge-core.c | 1723 --------------- drivers/media/dvb/ddbridge/ddbridge-regs.h | 151 -- drivers/media/dvb/ddbridge/ddbridge.h | 185 -- drivers/media/dvb/dm1105/Kconfig | 20 - drivers/media/dvb/dm1105/Makefile | 3 - drivers/media/dvb/dm1105/dm1105.c | 1248 ----------- drivers/media/dvb/mantis/Kconfig | 38 - drivers/media/dvb/mantis/Makefile | 28 - drivers/media/dvb/mantis/hopper_cards.c | 277 --- drivers/media/dvb/mantis/hopper_vp3028.c | 88 - drivers/media/dvb/mantis/hopper_vp3028.h | 30 - drivers/media/dvb/mantis/mantis_ca.c | 209 -- drivers/media/dvb/mantis/mantis_ca.h | 27 - drivers/media/dvb/mantis/mantis_cards.c | 307 --- drivers/media/dvb/mantis/mantis_common.h | 179 -- drivers/media/dvb/mantis/mantis_core.c | 235 -- drivers/media/dvb/mantis/mantis_core.h | 57 - drivers/media/dvb/mantis/mantis_dma.c | 230 -- drivers/media/dvb/mantis/mantis_dma.h | 30 - drivers/media/dvb/mantis/mantis_dvb.c | 301 --- drivers/media/dvb/mantis/mantis_dvb.h | 35 - drivers/media/dvb/mantis/mantis_evm.c | 117 - drivers/media/dvb/mantis/mantis_hif.c | 239 -- drivers/media/dvb/mantis/mantis_hif.h | 29 - drivers/media/dvb/mantis/mantis_i2c.c | 266 --- drivers/media/dvb/mantis/mantis_i2c.h | 30 - drivers/media/dvb/mantis/mantis_input.c | 159 -- drivers/media/dvb/mantis/mantis_ioc.c | 124 -- drivers/media/dvb/mantis/mantis_ioc.h | 51 - drivers/media/dvb/mantis/mantis_link.h | 83 - drivers/media/dvb/mantis/mantis_pci.c | 170 -- drivers/media/dvb/mantis/mantis_pci.h | 27 - drivers/media/dvb/mantis/mantis_pcmcia.c | 121 - drivers/media/dvb/mantis/mantis_reg.h | 197 -- drivers/media/dvb/mantis/mantis_uart.c | 188 -- drivers/media/dvb/mantis/mantis_uart.h | 58 - drivers/media/dvb/mantis/mantis_vp1033.c | 212 -- drivers/media/dvb/mantis/mantis_vp1033.h | 30 - drivers/media/dvb/mantis/mantis_vp1034.c | 120 - drivers/media/dvb/mantis/mantis_vp1034.h | 33 - drivers/media/dvb/mantis/mantis_vp1041.c | 357 --- drivers/media/dvb/mantis/mantis_vp1041.h | 33 - drivers/media/dvb/mantis/mantis_vp2033.c | 188 -- drivers/media/dvb/mantis/mantis_vp2033.h | 30 - drivers/media/dvb/mantis/mantis_vp2040.c | 187 -- drivers/media/dvb/mantis/mantis_vp2040.h | 32 - drivers/media/dvb/mantis/mantis_vp3028.c | 38 - drivers/media/dvb/mantis/mantis_vp3028.h | 33 - drivers/media/dvb/mantis/mantis_vp3030.c | 105 - drivers/media/dvb/mantis/mantis_vp3030.h | 30 - drivers/media/dvb/ngene/Kconfig | 13 - drivers/media/dvb/ngene/Makefile | 14 - drivers/media/dvb/ngene/ngene-cards.c | 823 ------- drivers/media/dvb/ngene/ngene-core.c | 1707 -------------- drivers/media/dvb/ngene/ngene-dvb.c | 261 --- drivers/media/dvb/ngene/ngene-i2c.c | 176 -- drivers/media/dvb/ngene/ngene.h | 921 -------- drivers/media/dvb/pluto2/Kconfig | 15 - drivers/media/dvb/pluto2/Makefile | 3 - drivers/media/dvb/pluto2/pluto2.c | 815 ------- drivers/media/dvb/pt1/Kconfig | 12 - drivers/media/dvb/pt1/Makefile | 5 - drivers/media/dvb/pt1/pt1.c | 1246 ----------- drivers/media/dvb/pt1/va1j5jf8007s.c | 735 ------- drivers/media/dvb/pt1/va1j5jf8007s.h | 46 - drivers/media/dvb/pt1/va1j5jf8007t.c | 536 ----- drivers/media/dvb/pt1/va1j5jf8007t.h | 46 - drivers/media/dvb/ttpci/Kconfig | 159 -- drivers/media/dvb/ttpci/Makefile | 21 - drivers/media/dvb/ttpci/av7110.c | 2939 ------------------------- drivers/media/dvb/ttpci/av7110.h | 314 --- drivers/media/dvb/ttpci/av7110_av.c | 1626 -------------- drivers/media/dvb/ttpci/av7110_av.h | 30 - drivers/media/dvb/ttpci/av7110_ca.c | 387 ---- drivers/media/dvb/ttpci/av7110_ca.h | 14 - drivers/media/dvb/ttpci/av7110_hw.c | 1208 ---------- drivers/media/dvb/ttpci/av7110_hw.h | 495 ----- drivers/media/dvb/ttpci/av7110_ipack.c | 403 ---- drivers/media/dvb/ttpci/av7110_ipack.h | 12 - drivers/media/dvb/ttpci/av7110_ir.c | 415 ---- drivers/media/dvb/ttpci/av7110_v4l.c | 966 -------- drivers/media/dvb/ttpci/budget-av.c | 1640 -------------- drivers/media/dvb/ttpci/budget-ci.c | 1591 ------------- drivers/media/dvb/ttpci/budget-core.c | 602 ----- drivers/media/dvb/ttpci/budget-patch.c | 680 ------ drivers/media/dvb/ttpci/budget.c | 871 -------- drivers/media/dvb/ttpci/budget.h | 124 -- drivers/media/dvb/ttpci/ttpci-eeprom.c | 176 -- drivers/media/dvb/ttpci/ttpci-eeprom.h | 34 - drivers/media/pci/Kconfig | 50 + drivers/media/pci/Makefile | 13 + drivers/media/pci/b2c2/Kconfig | 45 + drivers/media/pci/b2c2/Makefile | 16 + drivers/media/pci/b2c2/flexcop-common.h | 185 ++ drivers/media/pci/b2c2/flexcop-dma.c | 172 ++ drivers/media/pci/b2c2/flexcop-eeprom.c | 147 ++ drivers/media/pci/b2c2/flexcop-fe-tuner.c | 678 ++++++ drivers/media/pci/b2c2/flexcop-hw-filter.c | 232 ++ drivers/media/pci/b2c2/flexcop-i2c.c | 288 +++ drivers/media/pci/b2c2/flexcop-misc.c | 86 + drivers/media/pci/b2c2/flexcop-pci.c | 450 ++++ drivers/media/pci/b2c2/flexcop-reg.h | 166 ++ drivers/media/pci/b2c2/flexcop-sram.c | 363 +++ drivers/media/pci/b2c2/flexcop-usb.c | 587 +++++ drivers/media/pci/b2c2/flexcop-usb.h | 111 + drivers/media/pci/b2c2/flexcop.c | 324 +++ drivers/media/pci/b2c2/flexcop.h | 29 + drivers/media/pci/b2c2/flexcop_ibi_value_be.h | 455 ++++ drivers/media/pci/b2c2/flexcop_ibi_value_le.h | 455 ++++ drivers/media/pci/bt8xx/Kconfig | 22 + drivers/media/pci/bt8xx/Makefile | 6 + drivers/media/pci/bt8xx/bt878.c | 609 +++++ drivers/media/pci/bt8xx/bt878.h | 159 ++ drivers/media/pci/bt8xx/dst.c | 1873 ++++++++++++++++ drivers/media/pci/bt8xx/dst_ca.c | 726 ++++++ drivers/media/pci/bt8xx/dst_ca.h | 58 + drivers/media/pci/bt8xx/dst_common.h | 182 ++ drivers/media/pci/bt8xx/dst_priv.h | 35 + drivers/media/pci/bt8xx/dvb-bt8xx.c | 975 ++++++++ drivers/media/pci/bt8xx/dvb-bt8xx.h | 63 + drivers/media/pci/ddbridge/Kconfig | 18 + drivers/media/pci/ddbridge/Makefile | 14 + drivers/media/pci/ddbridge/ddbridge-core.c | 1723 +++++++++++++++ drivers/media/pci/ddbridge/ddbridge-regs.h | 151 ++ drivers/media/pci/ddbridge/ddbridge.h | 185 ++ drivers/media/pci/dm1105/Kconfig | 20 + drivers/media/pci/dm1105/Makefile | 3 + drivers/media/pci/dm1105/dm1105.c | 1248 +++++++++++ drivers/media/pci/mantis/Kconfig | 38 + drivers/media/pci/mantis/Makefile | 28 + drivers/media/pci/mantis/hopper_cards.c | 277 +++ drivers/media/pci/mantis/hopper_vp3028.c | 88 + drivers/media/pci/mantis/hopper_vp3028.h | 30 + drivers/media/pci/mantis/mantis_ca.c | 209 ++ drivers/media/pci/mantis/mantis_ca.h | 27 + drivers/media/pci/mantis/mantis_cards.c | 307 +++ drivers/media/pci/mantis/mantis_common.h | 179 ++ drivers/media/pci/mantis/mantis_core.c | 235 ++ drivers/media/pci/mantis/mantis_core.h | 57 + drivers/media/pci/mantis/mantis_dma.c | 230 ++ drivers/media/pci/mantis/mantis_dma.h | 30 + drivers/media/pci/mantis/mantis_dvb.c | 301 +++ drivers/media/pci/mantis/mantis_dvb.h | 35 + drivers/media/pci/mantis/mantis_evm.c | 117 + drivers/media/pci/mantis/mantis_hif.c | 239 ++ drivers/media/pci/mantis/mantis_hif.h | 29 + drivers/media/pci/mantis/mantis_i2c.c | 266 +++ drivers/media/pci/mantis/mantis_i2c.h | 30 + drivers/media/pci/mantis/mantis_input.c | 159 ++ drivers/media/pci/mantis/mantis_ioc.c | 124 ++ drivers/media/pci/mantis/mantis_ioc.h | 51 + drivers/media/pci/mantis/mantis_link.h | 83 + drivers/media/pci/mantis/mantis_pci.c | 170 ++ drivers/media/pci/mantis/mantis_pci.h | 27 + drivers/media/pci/mantis/mantis_pcmcia.c | 121 + drivers/media/pci/mantis/mantis_reg.h | 197 ++ drivers/media/pci/mantis/mantis_uart.c | 188 ++ drivers/media/pci/mantis/mantis_uart.h | 58 + drivers/media/pci/mantis/mantis_vp1033.c | 212 ++ drivers/media/pci/mantis/mantis_vp1033.h | 30 + drivers/media/pci/mantis/mantis_vp1034.c | 120 + drivers/media/pci/mantis/mantis_vp1034.h | 33 + drivers/media/pci/mantis/mantis_vp1041.c | 357 +++ drivers/media/pci/mantis/mantis_vp1041.h | 33 + drivers/media/pci/mantis/mantis_vp2033.c | 188 ++ drivers/media/pci/mantis/mantis_vp2033.h | 30 + drivers/media/pci/mantis/mantis_vp2040.c | 187 ++ drivers/media/pci/mantis/mantis_vp2040.h | 32 + drivers/media/pci/mantis/mantis_vp3028.c | 38 + drivers/media/pci/mantis/mantis_vp3028.h | 33 + drivers/media/pci/mantis/mantis_vp3030.c | 105 + drivers/media/pci/mantis/mantis_vp3030.h | 30 + drivers/media/pci/ngene/Kconfig | 13 + drivers/media/pci/ngene/Makefile | 14 + drivers/media/pci/ngene/ngene-cards.c | 823 +++++++ drivers/media/pci/ngene/ngene-core.c | 1707 ++++++++++++++ drivers/media/pci/ngene/ngene-dvb.c | 261 +++ drivers/media/pci/ngene/ngene-i2c.c | 176 ++ drivers/media/pci/ngene/ngene.h | 921 ++++++++ drivers/media/pci/pluto2/Kconfig | 15 + drivers/media/pci/pluto2/Makefile | 3 + drivers/media/pci/pluto2/pluto2.c | 815 +++++++ drivers/media/pci/pt1/Kconfig | 12 + drivers/media/pci/pt1/Makefile | 5 + drivers/media/pci/pt1/pt1.c | 1246 +++++++++++ drivers/media/pci/pt1/va1j5jf8007s.c | 735 +++++++ drivers/media/pci/pt1/va1j5jf8007s.h | 46 + drivers/media/pci/pt1/va1j5jf8007t.c | 536 +++++ drivers/media/pci/pt1/va1j5jf8007t.h | 46 + drivers/media/pci/ttpci/Kconfig | 159 ++ drivers/media/pci/ttpci/Makefile | 21 + drivers/media/pci/ttpci/av7110.c | 2939 +++++++++++++++++++++++++ drivers/media/pci/ttpci/av7110.h | 314 +++ drivers/media/pci/ttpci/av7110_av.c | 1626 ++++++++++++++ drivers/media/pci/ttpci/av7110_av.h | 30 + drivers/media/pci/ttpci/av7110_ca.c | 387 ++++ drivers/media/pci/ttpci/av7110_ca.h | 14 + drivers/media/pci/ttpci/av7110_hw.c | 1208 ++++++++++ drivers/media/pci/ttpci/av7110_hw.h | 495 +++++ drivers/media/pci/ttpci/av7110_ipack.c | 403 ++++ drivers/media/pci/ttpci/av7110_ipack.h | 12 + drivers/media/pci/ttpci/av7110_ir.c | 415 ++++ drivers/media/pci/ttpci/av7110_v4l.c | 966 ++++++++ drivers/media/pci/ttpci/budget-av.c | 1640 ++++++++++++++ drivers/media/pci/ttpci/budget-ci.c | 1591 +++++++++++++ drivers/media/pci/ttpci/budget-core.c | 602 +++++ drivers/media/pci/ttpci/budget-patch.c | 680 ++++++ drivers/media/pci/ttpci/budget.c | 871 ++++++++ drivers/media/pci/ttpci/budget.h | 124 ++ drivers/media/pci/ttpci/ttpci-eeprom.c | 176 ++ drivers/media/pci/ttpci/ttpci-eeprom.h | 34 + drivers/media/usb/dvb-usb/Makefile | 2 +- 248 files changed, 40365 insertions(+), 40365 deletions(-) delete mode 100644 drivers/media/dvb/Kconfig delete mode 100644 drivers/media/dvb/Makefile delete mode 100644 drivers/media/dvb/b2c2/Kconfig delete mode 100644 drivers/media/dvb/b2c2/Makefile delete mode 100644 drivers/media/dvb/b2c2/flexcop-common.h delete mode 100644 drivers/media/dvb/b2c2/flexcop-dma.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-eeprom.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-fe-tuner.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-hw-filter.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-i2c.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-misc.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-pci.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-reg.h delete mode 100644 drivers/media/dvb/b2c2/flexcop-sram.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-usb.c delete mode 100644 drivers/media/dvb/b2c2/flexcop-usb.h delete mode 100644 drivers/media/dvb/b2c2/flexcop.c delete mode 100644 drivers/media/dvb/b2c2/flexcop.h delete mode 100644 drivers/media/dvb/b2c2/flexcop_ibi_value_be.h delete mode 100644 drivers/media/dvb/b2c2/flexcop_ibi_value_le.h delete mode 100644 drivers/media/dvb/bt8xx/Kconfig delete mode 100644 drivers/media/dvb/bt8xx/Makefile delete mode 100644 drivers/media/dvb/bt8xx/bt878.c delete mode 100644 drivers/media/dvb/bt8xx/bt878.h delete mode 100644 drivers/media/dvb/bt8xx/dst.c delete mode 100644 drivers/media/dvb/bt8xx/dst_ca.c delete mode 100644 drivers/media/dvb/bt8xx/dst_ca.h delete mode 100644 drivers/media/dvb/bt8xx/dst_common.h delete mode 100644 drivers/media/dvb/bt8xx/dst_priv.h delete mode 100644 drivers/media/dvb/bt8xx/dvb-bt8xx.c delete mode 100644 drivers/media/dvb/bt8xx/dvb-bt8xx.h delete mode 100644 drivers/media/dvb/ddbridge/Kconfig delete mode 100644 drivers/media/dvb/ddbridge/Makefile delete mode 100644 drivers/media/dvb/ddbridge/ddbridge-core.c delete mode 100644 drivers/media/dvb/ddbridge/ddbridge-regs.h delete mode 100644 drivers/media/dvb/ddbridge/ddbridge.h delete mode 100644 drivers/media/dvb/dm1105/Kconfig delete mode 100644 drivers/media/dvb/dm1105/Makefile delete mode 100644 drivers/media/dvb/dm1105/dm1105.c delete mode 100644 drivers/media/dvb/mantis/Kconfig delete mode 100644 drivers/media/dvb/mantis/Makefile delete mode 100644 drivers/media/dvb/mantis/hopper_cards.c delete mode 100644 drivers/media/dvb/mantis/hopper_vp3028.c delete mode 100644 drivers/media/dvb/mantis/hopper_vp3028.h delete mode 100644 drivers/media/dvb/mantis/mantis_ca.c delete mode 100644 drivers/media/dvb/mantis/mantis_ca.h delete mode 100644 drivers/media/dvb/mantis/mantis_cards.c delete mode 100644 drivers/media/dvb/mantis/mantis_common.h delete mode 100644 drivers/media/dvb/mantis/mantis_core.c delete mode 100644 drivers/media/dvb/mantis/mantis_core.h delete mode 100644 drivers/media/dvb/mantis/mantis_dma.c delete mode 100644 drivers/media/dvb/mantis/mantis_dma.h delete mode 100644 drivers/media/dvb/mantis/mantis_dvb.c delete mode 100644 drivers/media/dvb/mantis/mantis_dvb.h delete mode 100644 drivers/media/dvb/mantis/mantis_evm.c delete mode 100644 drivers/media/dvb/mantis/mantis_hif.c delete mode 100644 drivers/media/dvb/mantis/mantis_hif.h delete mode 100644 drivers/media/dvb/mantis/mantis_i2c.c delete mode 100644 drivers/media/dvb/mantis/mantis_i2c.h delete mode 100644 drivers/media/dvb/mantis/mantis_input.c delete mode 100644 drivers/media/dvb/mantis/mantis_ioc.c delete mode 100644 drivers/media/dvb/mantis/mantis_ioc.h delete mode 100644 drivers/media/dvb/mantis/mantis_link.h delete mode 100644 drivers/media/dvb/mantis/mantis_pci.c delete mode 100644 drivers/media/dvb/mantis/mantis_pci.h delete mode 100644 drivers/media/dvb/mantis/mantis_pcmcia.c delete mode 100644 drivers/media/dvb/mantis/mantis_reg.h delete mode 100644 drivers/media/dvb/mantis/mantis_uart.c delete mode 100644 drivers/media/dvb/mantis/mantis_uart.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp1033.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp1033.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp1034.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp1034.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp1041.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp1041.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp2033.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp2033.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp2040.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp2040.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp3028.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp3028.h delete mode 100644 drivers/media/dvb/mantis/mantis_vp3030.c delete mode 100644 drivers/media/dvb/mantis/mantis_vp3030.h delete mode 100644 drivers/media/dvb/ngene/Kconfig delete mode 100644 drivers/media/dvb/ngene/Makefile delete mode 100644 drivers/media/dvb/ngene/ngene-cards.c delete mode 100644 drivers/media/dvb/ngene/ngene-core.c delete mode 100644 drivers/media/dvb/ngene/ngene-dvb.c delete mode 100644 drivers/media/dvb/ngene/ngene-i2c.c delete mode 100644 drivers/media/dvb/ngene/ngene.h delete mode 100644 drivers/media/dvb/pluto2/Kconfig delete mode 100644 drivers/media/dvb/pluto2/Makefile delete mode 100644 drivers/media/dvb/pluto2/pluto2.c delete mode 100644 drivers/media/dvb/pt1/Kconfig delete mode 100644 drivers/media/dvb/pt1/Makefile delete mode 100644 drivers/media/dvb/pt1/pt1.c delete mode 100644 drivers/media/dvb/pt1/va1j5jf8007s.c delete mode 100644 drivers/media/dvb/pt1/va1j5jf8007s.h delete mode 100644 drivers/media/dvb/pt1/va1j5jf8007t.c delete mode 100644 drivers/media/dvb/pt1/va1j5jf8007t.h delete mode 100644 drivers/media/dvb/ttpci/Kconfig delete mode 100644 drivers/media/dvb/ttpci/Makefile delete mode 100644 drivers/media/dvb/ttpci/av7110.c delete mode 100644 drivers/media/dvb/ttpci/av7110.h delete mode 100644 drivers/media/dvb/ttpci/av7110_av.c delete mode 100644 drivers/media/dvb/ttpci/av7110_av.h delete mode 100644 drivers/media/dvb/ttpci/av7110_ca.c delete mode 100644 drivers/media/dvb/ttpci/av7110_ca.h delete mode 100644 drivers/media/dvb/ttpci/av7110_hw.c delete mode 100644 drivers/media/dvb/ttpci/av7110_hw.h delete mode 100644 drivers/media/dvb/ttpci/av7110_ipack.c delete mode 100644 drivers/media/dvb/ttpci/av7110_ipack.h delete mode 100644 drivers/media/dvb/ttpci/av7110_ir.c delete mode 100644 drivers/media/dvb/ttpci/av7110_v4l.c delete mode 100644 drivers/media/dvb/ttpci/budget-av.c delete mode 100644 drivers/media/dvb/ttpci/budget-ci.c delete mode 100644 drivers/media/dvb/ttpci/budget-core.c delete mode 100644 drivers/media/dvb/ttpci/budget-patch.c delete mode 100644 drivers/media/dvb/ttpci/budget.c delete mode 100644 drivers/media/dvb/ttpci/budget.h delete mode 100644 drivers/media/dvb/ttpci/ttpci-eeprom.c delete mode 100644 drivers/media/dvb/ttpci/ttpci-eeprom.h create mode 100644 drivers/media/pci/Kconfig create mode 100644 drivers/media/pci/Makefile create mode 100644 drivers/media/pci/b2c2/Kconfig create mode 100644 drivers/media/pci/b2c2/Makefile create mode 100644 drivers/media/pci/b2c2/flexcop-common.h create mode 100644 drivers/media/pci/b2c2/flexcop-dma.c create mode 100644 drivers/media/pci/b2c2/flexcop-eeprom.c create mode 100644 drivers/media/pci/b2c2/flexcop-fe-tuner.c create mode 100644 drivers/media/pci/b2c2/flexcop-hw-filter.c create mode 100644 drivers/media/pci/b2c2/flexcop-i2c.c create mode 100644 drivers/media/pci/b2c2/flexcop-misc.c create mode 100644 drivers/media/pci/b2c2/flexcop-pci.c create mode 100644 drivers/media/pci/b2c2/flexcop-reg.h create mode 100644 drivers/media/pci/b2c2/flexcop-sram.c create mode 100644 drivers/media/pci/b2c2/flexcop-usb.c create mode 100644 drivers/media/pci/b2c2/flexcop-usb.h create mode 100644 drivers/media/pci/b2c2/flexcop.c create mode 100644 drivers/media/pci/b2c2/flexcop.h create mode 100644 drivers/media/pci/b2c2/flexcop_ibi_value_be.h create mode 100644 drivers/media/pci/b2c2/flexcop_ibi_value_le.h create mode 100644 drivers/media/pci/bt8xx/Kconfig create mode 100644 drivers/media/pci/bt8xx/Makefile create mode 100644 drivers/media/pci/bt8xx/bt878.c create mode 100644 drivers/media/pci/bt8xx/bt878.h create mode 100644 drivers/media/pci/bt8xx/dst.c create mode 100644 drivers/media/pci/bt8xx/dst_ca.c create mode 100644 drivers/media/pci/bt8xx/dst_ca.h create mode 100644 drivers/media/pci/bt8xx/dst_common.h create mode 100644 drivers/media/pci/bt8xx/dst_priv.h create mode 100644 drivers/media/pci/bt8xx/dvb-bt8xx.c create mode 100644 drivers/media/pci/bt8xx/dvb-bt8xx.h create mode 100644 drivers/media/pci/ddbridge/Kconfig create mode 100644 drivers/media/pci/ddbridge/Makefile create mode 100644 drivers/media/pci/ddbridge/ddbridge-core.c create mode 100644 drivers/media/pci/ddbridge/ddbridge-regs.h create mode 100644 drivers/media/pci/ddbridge/ddbridge.h create mode 100644 drivers/media/pci/dm1105/Kconfig create mode 100644 drivers/media/pci/dm1105/Makefile create mode 100644 drivers/media/pci/dm1105/dm1105.c create mode 100644 drivers/media/pci/mantis/Kconfig create mode 100644 drivers/media/pci/mantis/Makefile create mode 100644 drivers/media/pci/mantis/hopper_cards.c create mode 100644 drivers/media/pci/mantis/hopper_vp3028.c create mode 100644 drivers/media/pci/mantis/hopper_vp3028.h create mode 100644 drivers/media/pci/mantis/mantis_ca.c create mode 100644 drivers/media/pci/mantis/mantis_ca.h create mode 100644 drivers/media/pci/mantis/mantis_cards.c create mode 100644 drivers/media/pci/mantis/mantis_common.h create mode 100644 drivers/media/pci/mantis/mantis_core.c create mode 100644 drivers/media/pci/mantis/mantis_core.h create mode 100644 drivers/media/pci/mantis/mantis_dma.c create mode 100644 drivers/media/pci/mantis/mantis_dma.h create mode 100644 drivers/media/pci/mantis/mantis_dvb.c create mode 100644 drivers/media/pci/mantis/mantis_dvb.h create mode 100644 drivers/media/pci/mantis/mantis_evm.c create mode 100644 drivers/media/pci/mantis/mantis_hif.c create mode 100644 drivers/media/pci/mantis/mantis_hif.h create mode 100644 drivers/media/pci/mantis/mantis_i2c.c create mode 100644 drivers/media/pci/mantis/mantis_i2c.h create mode 100644 drivers/media/pci/mantis/mantis_input.c create mode 100644 drivers/media/pci/mantis/mantis_ioc.c create mode 100644 drivers/media/pci/mantis/mantis_ioc.h create mode 100644 drivers/media/pci/mantis/mantis_link.h create mode 100644 drivers/media/pci/mantis/mantis_pci.c create mode 100644 drivers/media/pci/mantis/mantis_pci.h create mode 100644 drivers/media/pci/mantis/mantis_pcmcia.c create mode 100644 drivers/media/pci/mantis/mantis_reg.h create mode 100644 drivers/media/pci/mantis/mantis_uart.c create mode 100644 drivers/media/pci/mantis/mantis_uart.h create mode 100644 drivers/media/pci/mantis/mantis_vp1033.c create mode 100644 drivers/media/pci/mantis/mantis_vp1033.h create mode 100644 drivers/media/pci/mantis/mantis_vp1034.c create mode 100644 drivers/media/pci/mantis/mantis_vp1034.h create mode 100644 drivers/media/pci/mantis/mantis_vp1041.c create mode 100644 drivers/media/pci/mantis/mantis_vp1041.h create mode 100644 drivers/media/pci/mantis/mantis_vp2033.c create mode 100644 drivers/media/pci/mantis/mantis_vp2033.h create mode 100644 drivers/media/pci/mantis/mantis_vp2040.c create mode 100644 drivers/media/pci/mantis/mantis_vp2040.h create mode 100644 drivers/media/pci/mantis/mantis_vp3028.c create mode 100644 drivers/media/pci/mantis/mantis_vp3028.h create mode 100644 drivers/media/pci/mantis/mantis_vp3030.c create mode 100644 drivers/media/pci/mantis/mantis_vp3030.h create mode 100644 drivers/media/pci/ngene/Kconfig create mode 100644 drivers/media/pci/ngene/Makefile create mode 100644 drivers/media/pci/ngene/ngene-cards.c create mode 100644 drivers/media/pci/ngene/ngene-core.c create mode 100644 drivers/media/pci/ngene/ngene-dvb.c create mode 100644 drivers/media/pci/ngene/ngene-i2c.c create mode 100644 drivers/media/pci/ngene/ngene.h create mode 100644 drivers/media/pci/pluto2/Kconfig create mode 100644 drivers/media/pci/pluto2/Makefile create mode 100644 drivers/media/pci/pluto2/pluto2.c create mode 100644 drivers/media/pci/pt1/Kconfig create mode 100644 drivers/media/pci/pt1/Makefile create mode 100644 drivers/media/pci/pt1/pt1.c create mode 100644 drivers/media/pci/pt1/va1j5jf8007s.c create mode 100644 drivers/media/pci/pt1/va1j5jf8007s.h create mode 100644 drivers/media/pci/pt1/va1j5jf8007t.c create mode 100644 drivers/media/pci/pt1/va1j5jf8007t.h create mode 100644 drivers/media/pci/ttpci/Kconfig create mode 100644 drivers/media/pci/ttpci/Makefile create mode 100644 drivers/media/pci/ttpci/av7110.c create mode 100644 drivers/media/pci/ttpci/av7110.h create mode 100644 drivers/media/pci/ttpci/av7110_av.c create mode 100644 drivers/media/pci/ttpci/av7110_av.h create mode 100644 drivers/media/pci/ttpci/av7110_ca.c create mode 100644 drivers/media/pci/ttpci/av7110_ca.h create mode 100644 drivers/media/pci/ttpci/av7110_hw.c create mode 100644 drivers/media/pci/ttpci/av7110_hw.h create mode 100644 drivers/media/pci/ttpci/av7110_ipack.c create mode 100644 drivers/media/pci/ttpci/av7110_ipack.h create mode 100644 drivers/media/pci/ttpci/av7110_ir.c create mode 100644 drivers/media/pci/ttpci/av7110_v4l.c create mode 100644 drivers/media/pci/ttpci/budget-av.c create mode 100644 drivers/media/pci/ttpci/budget-ci.c create mode 100644 drivers/media/pci/ttpci/budget-core.c create mode 100644 drivers/media/pci/ttpci/budget-patch.c create mode 100644 drivers/media/pci/ttpci/budget.c create mode 100644 drivers/media/pci/ttpci/budget.h create mode 100644 drivers/media/pci/ttpci/ttpci-eeprom.c create mode 100644 drivers/media/pci/ttpci/ttpci-eeprom.h (limited to 'Documentation') diff --git a/Documentation/DocBook/media/dvb/kdapi.xml b/Documentation/DocBook/media/dvb/kdapi.xml index 6c67481eaa4..6c11ec52cbe 100644 --- a/Documentation/DocBook/media/dvb/kdapi.xml +++ b/Documentation/DocBook/media/dvb/kdapi.xml @@ -2,7 +2,7 @@ The kernel demux API defines a driver-internal interface for registering low-level, hardware specific driver to a hardware independent demux layer. It is only of interest for DVB device driver writers. The header file for this API is named demux.h and located in -drivers/media/dvb/dvb-core. +drivers/media/dvb-core. Maintainer note: This section must be reviewed. It is probably out of date. diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 26da8b8721d..81c8662a1a7 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -162,7 +162,7 @@ source "drivers/media/radio/Kconfig" # source "drivers/media/dvb-core/Kconfig" -source "drivers/media/dvb/Kconfig" +source "drivers/media/pci/Kconfig" source "drivers/media/usb/Kconfig" comment "Supported FireWire (IEEE 1394) Adapters" diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 46a8dc3337b..90ec998a8e6 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -11,5 +11,5 @@ endif obj-y += v4l2-core/ common/ rc/ video/ obj-$(CONFIG_VIDEO_DEV) += radio/ -obj-$(CONFIG_DVB_CORE) += dvb-core/ dvb/ dvb-frontends/ usb/ +obj-$(CONFIG_DVB_CORE) += dvb-core/ pci/ dvb-frontends/ usb/ obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig deleted file mode 100644 index e2565a45de9..00000000000 --- a/drivers/media/dvb/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# -# DVB device configuration -# - -menuconfig DVB_CAPTURE_DRIVERS - bool "DVB/ATSC adapters" - depends on DVB_CORE - default y - ---help--- - Say Y to select Digital TV adapters - -if DVB_CAPTURE_DRIVERS && DVB_CORE - -comment "Supported SAA7146 based PCI Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/ttpci/Kconfig" - -comment "Supported FlexCopII (B2C2) Adapters" - depends on DVB_CORE && (PCI || USB) && I2C -source "drivers/media/dvb/b2c2/Kconfig" - -comment "Supported BT878 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/bt8xx/Kconfig" - -comment "Supported Pluto2 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/pluto2/Kconfig" - -comment "Supported SDMC DM1105 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/dm1105/Kconfig" - -comment "Supported Earthsoft PT1 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/pt1/Kconfig" - -comment "Supported Mantis Adapters" - depends on DVB_CORE && PCI && I2C - source "drivers/media/dvb/mantis/Kconfig" - -comment "Supported nGene Adapters" - depends on DVB_CORE && PCI && I2C - source "drivers/media/dvb/ngene/Kconfig" - -comment "Supported ddbridge ('Octopus') Adapters" - depends on DVB_CORE && PCI && I2C - source "drivers/media/dvb/ddbridge/Kconfig" - -endif # DVB_CAPTURE_DRIVERS diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile deleted file mode 100644 index c5fa43a275a..00000000000 --- a/drivers/media/dvb/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# Makefile for the kernel multimedia device drivers. -# - -obj-y := ttpci/ \ - b2c2/ \ - bt8xx/ \ - pluto2/ \ - dm1105/ \ - pt1/ \ - mantis/ \ - ngene/ \ - ddbridge/ diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig deleted file mode 100644 index 9e578140074..00000000000 --- a/drivers/media/dvb/b2c2/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config DVB_B2C2_FLEXCOP - tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" - depends on DVB_CORE && I2C - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_BCM3510 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_S5H1420 if !DVB_FE_CUSTOMISE - select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_CX24123 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE - help - Support for the digital TV receiver chip made by B2C2 Inc. included in - Technisats PCI cards and USB boxes. - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_PCI - tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" - depends on DVB_B2C2_FLEXCOP && PCI && I2C - help - Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_USB - tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" - depends on DVB_B2C2_FLEXCOP && USB && I2C - help - Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_DEBUG - bool "Enable debug for the B2C2 FlexCop drivers" - depends on DVB_B2C2_FLEXCOP - help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile deleted file mode 100644 index 7a1f5ce6d32..00000000000 --- a/drivers/media/dvb/b2c2/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \ - flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o - -ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),) -b2c2-flexcop-objs += flexcop-dma.o -endif - -b2c2-flexcop-pci-objs = flexcop-pci.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o - -b2c2-flexcop-usb-objs = flexcop-usb.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h deleted file mode 100644 index 437912e4982..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-common.h - common header file for device-specific source files - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_COMMON_H__ -#define __FLEXCOP_COMMON_H__ - -#include -#include -#include - -#include "flexcop-reg.h" - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_filter.h" -#include "dvb_net.h" -#include "dvb_frontend.h" - -#define FC_MAX_FEED 256 - -#ifndef FC_LOG_PREFIX -#warning please define a log prefix for your file, using a default one -#define FC_LOG_PREFIX "b2c2-undef" -#endif - -/* Steal from usb.h */ -#undef err -#define err(format, arg...) \ - printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) \ - printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) \ - printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg) - -struct flexcop_dma { - struct pci_dev *pdev; - - u8 *cpu_addr0; - dma_addr_t dma_addr0; - u8 *cpu_addr1; - dma_addr_t dma_addr1; - u32 size; /* size of each address in bytes */ -}; - -struct flexcop_i2c_adapter { - struct flexcop_device *fc; - struct i2c_adapter i2c_adap; - - u8 no_base_addr; - flexcop_i2c_port_t port; -}; - -/* Control structure for data definitions that are common to - * the B2C2-based PCI and USB devices. - */ -struct flexcop_device { - /* general */ - struct device *dev; /* for firmware_class */ - -#define FC_STATE_DVB_INIT 0x01 -#define FC_STATE_I2C_INIT 0x02 -#define FC_STATE_FE_INIT 0x04 - int init_state; - - /* device information */ - int has_32_hw_pid_filter; - flexcop_revision_t rev; - flexcop_device_type_t dev_type; - flexcop_bus_t bus_type; - - /* dvb stuff */ - struct dvb_adapter dvb_adapter; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - int (*fe_sleep) (struct dvb_frontend *); - - struct flexcop_i2c_adapter fc_i2c_adap[3]; - struct mutex i2c_mutex; - struct module *owner; - - /* options and status */ - int extra_feedcount; - int feedcount; - int pid_filtering; - int fullts_streaming_state; - - /* bus specific callbacks */ - flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *, - flexcop_ibi_register); - int (*write_ibi_reg) (struct flexcop_device *, - flexcop_ibi_register, flexcop_ibi_value); - int (*i2c_request) (struct flexcop_i2c_adapter *, - flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); - int (*stream_control) (struct flexcop_device *, int); - int (*get_mac_addr) (struct flexcop_device *fc, int extended); - void *bus_specific; -}; - -/* exported prototypes */ - -/* from flexcop.c */ -void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len); -void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no); - -struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len); -void flexcop_device_kfree(struct flexcop_device *); - -int flexcop_device_initialize(struct flexcop_device *); -void flexcop_device_exit(struct flexcop_device *fc); -void flexcop_reset_block_300(struct flexcop_device *fc); - -/* from flexcop-dma.c */ -int flexcop_dma_allocate(struct pci_dev *pdev, - struct flexcop_dma *dma, u32 size); -void flexcop_dma_free(struct flexcop_dma *dma); - -int flexcop_dma_control_timer_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, int onoff); -int flexcop_dma_control_size_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, int onoff); -int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, - flexcop_dma_index_t dma_idx); -int flexcop_dma_xfer_control(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, - int onoff); -int flexcop_dma_config_timer(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, u8 cycles); - -/* from flexcop-eeprom.c */ -/* the PCI part uses this call to get the MAC address, the USB part has its own */ -int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); - -/* from flexcop-i2c.c */ -/* the PCI part uses this a i2c_request callback, whereas the usb part has its own - * one. We have it in flexcop-i2c.c, because it is going via the actual - * I2C-channel of the flexcop. - */ -int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t, - u8 chipaddr, u8 addr, u8 *buf, u16 len); - -/* from flexcop-sram.c */ -int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, - flexcop_sram_dest_target_t target); -void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s); -void flexcop_sram_ctrl(struct flexcop_device *fc, - int usb_wan, int sramdma, int maximumfill); - -/* global prototypes for the flexcop-chip */ -/* from flexcop-fe-tuner.c */ -int flexcop_frontend_init(struct flexcop_device *fc); -void flexcop_frontend_exit(struct flexcop_device *fc); - -/* from flexcop-i2c.c */ -int flexcop_i2c_init(struct flexcop_device *fc); -void flexcop_i2c_exit(struct flexcop_device *fc); - -/* from flexcop-sram.c */ -int flexcop_sram_init(struct flexcop_device *fc); - -/* from flexcop-misc.c */ -void flexcop_determine_revision(struct flexcop_device *fc); -void flexcop_device_name(struct flexcop_device *fc, - const char *prefix, const char *suffix); -void flexcop_dump_reg(struct flexcop_device *fc, - flexcop_ibi_register reg, int num); - -/* from flexcop-hw-filter.c */ -int flexcop_pid_feed_control(struct flexcop_device *fc, - struct dvb_demux_feed *dvbdmxfeed, int onoff); -void flexcop_hw_filter_init(struct flexcop_device *fc); - -void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff); - -void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]); -void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff); - -#endif diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c deleted file mode 100644 index 2881e0d956a..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-dma.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-dma.c - configuring and controlling the DMA of the FlexCop - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -int flexcop_dma_allocate(struct pci_dev *pdev, - struct flexcop_dma *dma, u32 size) -{ - u8 *tcpu; - dma_addr_t tdma = 0; - - if (size % 2) { - err("dma buffersize has to be even."); - return -EINVAL; - } - - if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { - dma->pdev = pdev; - dma->cpu_addr0 = tcpu; - dma->dma_addr0 = tdma; - dma->cpu_addr1 = tcpu + size/2; - dma->dma_addr1 = tdma + size/2; - dma->size = size/2; - return 0; - } - return -ENOMEM; -} -EXPORT_SYMBOL(flexcop_dma_allocate); - -void flexcop_dma_free(struct flexcop_dma *dma) -{ - pci_free_consistent(dma->pdev, dma->size*2, - dma->cpu_addr0, dma->dma_addr0); - memset(dma,0,sizeof(struct flexcop_dma)); -} -EXPORT_SYMBOL(flexcop_dma_free); - -int flexcop_dma_config(struct flexcop_device *fc, - struct flexcop_dma *dma, - flexcop_dma_index_t dma_idx) -{ - flexcop_ibi_value v0x0,v0x4,v0xc; - v0x0.raw = v0x4.raw = v0xc.raw = 0; - - v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; - v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; - v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; - - if ((dma_idx & FC_DMA_1) == dma_idx) { - fc->write_ibi_reg(fc,dma1_000,v0x0); - fc->write_ibi_reg(fc,dma1_004,v0x4); - fc->write_ibi_reg(fc,dma1_00c,v0xc); - } else if ((dma_idx & FC_DMA_2) == dma_idx) { - fc->write_ibi_reg(fc,dma2_010,v0x0); - fc->write_ibi_reg(fc,dma2_014,v0x4); - fc->write_ibi_reg(fc,dma2_01c,v0xc); - } else { - err("either DMA1 or DMA2 can be configured within one " - "flexcop_dma_config call."); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(flexcop_dma_config); - -/* start the DMA transfers, but not the DMA IRQs */ -int flexcop_dma_xfer_control(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, - flexcop_dma_addr_index_t index, - int onoff) -{ - flexcop_ibi_value v0x0,v0xc; - flexcop_ibi_register r0x0,r0xc; - - if ((dma_idx & FC_DMA_1) == dma_idx) { - r0x0 = dma1_000; - r0xc = dma1_00c; - } else if ((dma_idx & FC_DMA_2) == dma_idx) { - r0x0 = dma2_010; - r0xc = dma2_01c; - } else { - err("either transfer DMA1 or DMA2 can be started within one " - "flexcop_dma_xfer_control call."); - return -EINVAL; - } - - v0x0 = fc->read_ibi_reg(fc,r0x0); - v0xc = fc->read_ibi_reg(fc,r0xc); - - deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); - deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); - - if (index & FC_DMA_SUBADDR_0) - v0x0.dma_0x0.dma_0start = onoff; - - if (index & FC_DMA_SUBADDR_1) - v0xc.dma_0xc.dma_1start = onoff; - - fc->write_ibi_reg(fc,r0x0,v0x0); - fc->write_ibi_reg(fc,r0xc,v0xc); - - deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); - deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_xfer_control); - -static int flexcop_dma_remap(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, - int onoff) -{ - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - deb_info("%s\n",__func__); - v.dma_0xc.remap_enable = onoff; - fc->write_ibi_reg(fc,r,v); - return 0; -} - -int flexcop_dma_control_size_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, - int onoff) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); - - if (no & FC_DMA_1) - v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; - - if (no & FC_DMA_2) - v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; - - fc->write_ibi_reg(fc,ctrl_208,v); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_control_size_irq); - -int flexcop_dma_control_timer_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, - int onoff) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); - - if (no & FC_DMA_1) - v.ctrl_208.DMA1_Timer_Enable_sig = onoff; - - if (no & FC_DMA_2) - v.ctrl_208.DMA2_Timer_Enable_sig = onoff; - - fc->write_ibi_reg(fc,ctrl_208,v); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_control_timer_irq); - -/* 1 cycles = 1.97 msec */ -int flexcop_dma_config_timer(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, u8 cycles) -{ - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - - flexcop_dma_remap(fc,dma_idx,0); - - deb_info("%s\n",__func__); - v.dma_0x4_write.dmatimer = cycles; - fc->write_ibi_reg(fc,r,v); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_config_timer); - diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c deleted file mode 100644 index a25373a9bd8..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-eeprom.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading) - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -#if 0 -/*EEPROM (Skystar2 has one "24LC08B" chip on board) */ -static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) -{ - return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); -} - -static int eeprom_lrc_write(struct adapter *adapter, u32 addr, - u32 len, u8 *wbuf, u8 *rbuf, int retries) -{ -int i; - -for (i = 0; i < retries; i++) { - if (eeprom_write(adapter, addr, wbuf, len) == len) { - if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) - return 1; - } - } - return 0; -} - -/* These functions could be used to unlock SkyStar2 cards. */ - -static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 rbuf[20]; - u8 wbuf[20]; - - if (len != 16) - return 0; - - memcpy(wbuf, key, len); - wbuf[16] = 0; - wbuf[17] = 0; - wbuf[18] = 0; - wbuf[19] = calc_lrc(wbuf, 19); - return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); -} - -static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 buf[20]; - - if (len != 16) - return 0; - - if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) - return 0; - - memcpy(key, buf, len); - return 1; -} - -static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) -{ - u8 tmp[8]; - - if (type != 0) { - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[5]; - tmp[4] = mac[6]; - tmp[5] = mac[7]; - } else { - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[3]; - tmp[4] = mac[4]; - tmp[5] = mac[5]; - } - - tmp[6] = 0; - tmp[7] = calc_lrc(tmp, 7); - - if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) - return 1; - return 0; -} - -static int flexcop_eeprom_read(struct flexcop_device *fc, - u16 addr, u8 *buf, u16 len) -{ - return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); -} - -#endif - -static u8 calc_lrc(u8 *buf, int len) -{ - int i; - u8 sum = 0; - for (i = 0; i < len; i++) - sum = sum ^ buf[i]; - return sum; -} - -static int flexcop_eeprom_request(struct flexcop_device *fc, - flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) -{ - int i,ret = 0; - u8 chipaddr = 0x50 | ((addr >> 8) & 3); - for (i = 0; i < retries; i++) { - ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr, - addr & 0xff, buf, len); - if (ret == 0) - break; - } - return ret; -} - -static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, - u8 *buf, u16 len, int retries) -{ - int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries); - if (ret == 0) - if (calc_lrc(buf, len - 1) != buf[len - 1]) - ret = -EINVAL; - return ret; -} - -/* JJ's comment about extended == 1: it is not presently used anywhere but was - * added to the low-level functions for possible support of EUI64 */ -int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) -{ - u8 buf[8]; - int ret = 0; - - if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { - if (extended != 0) { - err("TODO: extended (EUI64) MAC addresses aren't " - "completely supported yet"); - ret = -EINVAL; - } else - memcpy(fc->dvb_adapter.proposed_mac,buf,6); - } - return ret; -} -EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c deleted file mode 100644 index 850a6c60675..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling - * see flexcop.c for copyright information - */ -#include -#include "flexcop.h" -#include "mt312.h" -#include "stv0299.h" -#include "s5h1420.h" -#include "itd1000.h" -#include "cx24113.h" -#include "cx24123.h" -#include "isl6421.h" -#include "mt352.h" -#include "bcm3510.h" -#include "nxt200x.h" -#include "dvb-pll.h" -#include "lgdt330x.h" -#include "tuner-simple.h" -#include "stv0297.h" - - -/* Can we use the specified front-end? Remember that if we are compiled - * into the kernel we can't call code that's in modules. */ -#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \ - (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE))) - -/* lnb control */ -#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299) -static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct flexcop_device *fc = fe->dvb->priv; - flexcop_ibi_value v; - deb_tuner("polarity/voltage = %u\n", voltage); - - v = fc->read_ibi_reg(fc, misc_204); - switch (voltage) { - case SEC_VOLTAGE_OFF: - v.misc_204.ACPI1_sig = 1; - break; - case SEC_VOLTAGE_13: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 0; - break; - case SEC_VOLTAGE_18: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 1; - break; - default: - err("unknown SEC_VOLTAGE value"); - return -EINVAL; - } - return fc->write_ibi_reg(fc, misc_204, v); -} -#endif - -#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312) -static int flexcop_sleep(struct dvb_frontend* fe) -{ - struct flexcop_device *fc = fe->dvb->priv; - if (fc->fe_sleep) - return fc->fe_sleep(fe); - return 0; -} -#endif - -/* SkyStar2 DVB-S rev 2.3 */ -#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL) -static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ -/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ - struct flexcop_device *fc = fe->dvb->priv; - flexcop_ibi_value v; - u16 ax; - v.raw = 0; - deb_tuner("tone = %u\n",tone); - - switch (tone) { - case SEC_TONE_ON: - ax = 0x01ff; - break; - case SEC_TONE_OFF: - ax = 0; - break; - default: - err("unknown SEC_TONE value"); - return -EINVAL; - } - - v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ - v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; - v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; - return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); -} - -static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) -{ - flexcop_set_tone(fe, SEC_TONE_ON); - udelay(data ? 500 : 1000); - flexcop_set_tone(fe, SEC_TONE_OFF); - udelay(data ? 1000 : 500); -} - -static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) -{ - int i, par = 1, d; - for (i = 7; i >= 0; i--) { - d = (data >> i) & 1; - par ^= d; - flexcop_diseqc_send_bit(fe, d); - } - flexcop_diseqc_send_bit(fe, par); -} - -static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, - int len, u8 *msg, unsigned long burst) -{ - int i; - - flexcop_set_tone(fe, SEC_TONE_OFF); - mdelay(16); - - for (i = 0; i < len; i++) - flexcop_diseqc_send_byte(fe,msg[i]); - mdelay(16); - - if (burst != -1) { - if (burst) - flexcop_diseqc_send_byte(fe, 0xff); - else { - flexcop_set_tone(fe, SEC_TONE_ON); - mdelay(12); - udelay(500); - flexcop_set_tone(fe, SEC_TONE_OFF); - } - msleep(20); - } - return 0; -} - -static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); -} - -static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) -{ - return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); -} - -static struct mt312_config skystar23_samsung_tbdu18132_config = { - .demod_address = 0x0e, -}; - -static int skystar2_rev23_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - struct dvb_frontend_ops *ops; - - fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); - if (!fc->fe) - return 0; - - if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, - DVB_PLL_SAMSUNG_TBDU18132)) - return 0; - - ops = &fc->fe->ops; - ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - ops->diseqc_send_burst = flexcop_diseqc_send_burst; - ops->set_tone = flexcop_set_tone; - ops->set_voltage = flexcop_set_voltage; - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - return 1; -} -#else -#define skystar2_rev23_attach NULL -#endif - -/* SkyStar2 DVB-S rev 2.6 */ -#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL) -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; bclk = 0x51; - } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, ratio & 0xf0); - return 0; -} - -static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, -}; - -static struct stv0299_config samsung_tbmu24112_config = { - .demod_address = 0x68, - .inittab = samsung_tbmu24112_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, -}; - -static int skystar2_rev26_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); - if (!fc->fe) - return 0; - - if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, - DVB_PLL_SAMSUNG_TBMU24112)) - return 0; - - fc->fe->ops.set_voltage = flexcop_set_voltage; - fc->fe_sleep = fc->fe->ops.sleep; - fc->fe->ops.sleep = flexcop_sleep; - return 1; - -} -#else -#define skystar2_rev26_attach NULL -#endif - -/* SkyStar2 DVB-S rev 2.7 */ -#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000) -static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .repeated_start_workaround = 1, - .serial_mpeg = 1, -}; - -static struct itd1000_config skystar2_rev2_7_itd1000_config = { - .i2c_address = 0x61, -}; - -static int skystar2_rev27_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - flexcop_ibi_value r108; - struct i2c_adapter *i2c_tuner; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[0].no_base_addr = 1; - fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, - i2c); - if (!fc->fe) - goto fail; - - i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); - if (!i2c_tuner) - goto fail; - - fc->fe_sleep = fc->fe->ops.sleep; - fc->fe->ops.sleep = flexcop_sleep; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[2].no_base_addr = 1; - if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 1, 1)) { - err("ISL6421 could NOT be attached"); - goto fail_isl; - } - info("ISL6421 successfully attached"); - - /* the ITD1000 requires a lower i2c clock - is it a problem ? */ - r108.raw = 0x00000506; - fc->write_ibi_reg(fc, tw_sm_c_108, r108); - if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner, - &skystar2_rev2_7_itd1000_config)) { - err("ITD1000 could NOT be attached"); - /* Should i2c clock be restored? */ - goto fail_isl; - } - info("ITD1000 successfully attached"); - - return 1; - -fail_isl: - fc->fc_i2c_adap[2].no_base_addr = 0; -fail: - /* for the next devices we need it again */ - fc->fc_i2c_adap[0].no_base_addr = 0; - return 0; -} -#else -#define skystar2_rev27_attach NULL -#endif - -/* SkyStar2 rev 2.8 */ -#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113) -static struct cx24123_config skystar2_rev2_8_cx24123_config = { - .demod_address = 0x55, - .dont_use_pll = 1, - .agc_callback = cx24113_agc_callback, -}; - -static const struct cx24113_config skystar2_rev2_8_cx24113_config = { - .i2c_addr = 0x54, - .xtal_khz = 10111, -}; - -static int skystar2_rev28_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - struct i2c_adapter *i2c_tuner; - - fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config, - i2c); - if (!fc->fe) - return 0; - - i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); - if (!i2c_tuner) - return 0; - - if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config, - i2c_tuner)) { - err("CX24113 could NOT be attached"); - return 0; - } - info("CX24113 successfully attached"); - - fc->fc_i2c_adap[2].no_base_addr = 1; - if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 0, 0)) { - err("ISL6421 could NOT be attached"); - fc->fc_i2c_adap[2].no_base_addr = 0; - return 0; - } - info("ISL6421 successfully attached"); - /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an - * IR-receiver (PIC16F818) - but the card has no input for that ??? */ - return 1; -} -#else -#define skystar2_rev28_attach NULL -#endif - -/* AirStar DVB-T */ -#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL) -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) -{ - static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; - static u8 mt352_reset[] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - return 0; -} - -static struct mt352_config samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, -}; - -static int airstar_dvbt_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); - if (!fc->fe) - return 0; - - return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, - DVB_PLL_SAMSUNG_TDTC9251DH0); -} -#else -#define airstar_dvbt_attach NULL -#endif - -/* AirStar ATSC 1st generation */ -#if FE_SUPPORTED(BCM3510) -static int flexcop_fe_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char* name) -{ - struct flexcop_device *fc = fe->dvb->priv; - return request_firmware(fw, name, fc->dev); -} - -static struct bcm3510_config air2pc_atsc_first_gen_config = { - .demod_address = 0x0f, - .request_firmware = flexcop_fe_request_firmware, -}; - -static int airstar_atsc1_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); - return fc->fe != NULL; -} -#else -#define airstar_atsc1_attach NULL -#endif - -/* AirStar ATSC 2nd generation */ -#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) -static struct nxt200x_config samsung_tbmv_config = { - .demod_address = 0x0a, -}; - -static int airstar_atsc2_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); - if (!fc->fe) - return 0; - - return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, - DVB_PLL_SAMSUNG_TBMV); -} -#else -#define airstar_atsc2_attach NULL -#endif - -/* AirStar ATSC 3rd generation */ -#if FE_SUPPORTED(LGDT330X) -static struct lgdt330x_config air2pc_atsc_hd5000_config = { - .demod_address = 0x59, - .demod_chip = LGDT3303, - .serial_mpeg = 0x04, - .clock_polarity_flip = 1, -}; - -static int airstar_atsc3_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); - if (!fc->fe) - return 0; - - return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, - TUNER_LG_TDVS_H06XF); -} -#else -#define airstar_atsc3_attach NULL -#endif - -/* CableStar2 DVB-C */ -#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL) -static u8 alps_tdee4_stv0297_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x48, - 0x01, 0x58, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x30, 0xff, - 0x31, 0x9d, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x29, - 0x35, 0x55, - 0x36, 0x80, - 0x37, 0x6e, - 0x38, 0x9c, - 0x40, 0x1a, - 0x41, 0xfe, - 0x42, 0x33, - 0x43, 0x00, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x51, - 0x4b, 0xf8, - 0x52, 0x30, - 0x53, 0x06, - 0x59, 0x06, - 0x5a, 0x5e, - 0x5b, 0x04, - 0x61, 0x49, - 0x62, 0x0a, - 0x70, 0xff, - 0x71, 0x04, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x20, - 0x81, 0x00, - 0x82, 0x30, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x22, - 0x86, 0x08, - 0x87, 0x1b, - 0x88, 0x00, - 0x89, 0x00, - 0x90, 0x00, - 0x91, 0x04, - 0xa0, 0x86, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x5b, - 0xc1, 0x10, - 0xc2, 0x12, - 0xd0, 0x02, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x02, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x01, - 0xff, 0xff, -}; - -static struct stv0297_config alps_tdee4_stv0297_config = { - .demod_address = 0x1c, - .inittab = alps_tdee4_stv0297_inittab, -}; - -static int cablestar2_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fc_i2c_adap[0].no_base_addr = 1; - fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); - if (!fc->fe) - goto fail; - - /* This tuner doesn't use the stv0297's I2C gate, but instead the - * tuner is connected to a different flexcop I2C adapter. */ - if (fc->fe->ops.i2c_gate_ctrl) - fc->fe->ops.i2c_gate_ctrl(fc->fe, 0); - fc->fe->ops.i2c_gate_ctrl = NULL; - - if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, - &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4)) - goto fail; - - return 1; - -fail: - /* Reset for next frontend to try */ - fc->fc_i2c_adap[0].no_base_addr = 0; - return 0; -} -#else -#define cablestar2_attach NULL -#endif - -static struct { - flexcop_device_type_t type; - int (*attach)(struct flexcop_device *, struct i2c_adapter *); -} flexcop_frontends[] = { - { FC_SKY_REV27, skystar2_rev27_attach }, - { FC_SKY_REV28, skystar2_rev28_attach }, - { FC_SKY_REV26, skystar2_rev26_attach }, - { FC_AIR_DVBT, airstar_dvbt_attach }, - { FC_AIR_ATSC2, airstar_atsc2_attach }, - { FC_AIR_ATSC3, airstar_atsc3_attach }, - { FC_AIR_ATSC1, airstar_atsc1_attach }, - { FC_CABLE, cablestar2_attach }, - { FC_SKY_REV23, skystar2_rev23_attach }, -}; - -/* try to figure out the frontend */ -int flexcop_frontend_init(struct flexcop_device *fc) -{ - int i; - for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { - if (!flexcop_frontends[i].attach) - continue; - /* type needs to be set before, because of some workarounds - * done based on the probed card type */ - fc->dev_type = flexcop_frontends[i].type; - if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap)) - goto fe_found; - /* Clean up partially attached frontend */ - if (fc->fe) { - dvb_frontend_detach(fc->fe); - fc->fe = NULL; - } - } - fc->dev_type = FC_UNK; - err("no frontend driver found for this B2C2/FlexCop adapter"); - return -ENODEV; - -fe_found: - info("found '%s' .", fc->fe->ops.info.name); - if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { - err("frontend registration failed!"); - dvb_frontend_detach(fc->fe); - fc->fe = NULL; - return -EINVAL; - } - fc->init_state |= FC_STATE_FE_INIT; - return 0; -} - -void flexcop_frontend_exit(struct flexcop_device *fc) -{ - if (fc->init_state & FC_STATE_FE_INIT) { - dvb_unregister_frontend(fc->fe); - dvb_frontend_detach(fc->fe); - } - fc->init_state &= ~FC_STATE_FE_INIT; -} diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c deleted file mode 100644 index 77e45475f4c..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-hw-filter.c - pid and mac address filtering and control functions - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff); - deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off"); -} - -void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff); -} - -static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff); -} - -void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) -{ - flexcop_ibi_value v418, v41c; - v41c = fc->read_ibi_reg(fc, mac_address_41c); - - v418.mac_address_418.MAC1 = mac[0]; - v418.mac_address_418.MAC2 = mac[1]; - v418.mac_address_418.MAC3 = mac[2]; - v418.mac_address_418.MAC6 = mac[3]; - v41c.mac_address_41c.MAC7 = mac[4]; - v41c.mac_address_41c.MAC8 = mac[5]; - - fc->write_ibi_reg(fc, mac_address_418, v418); - fc->write_ibi_reg(fc, mac_address_41c, v41c); -} - -void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff); -} - -static void flexcop_pid_group_filter(struct flexcop_device *fc, - u16 pid, u16 mask) -{ - /* index_reg_310.extra_index_reg need to 0 or 7 to work */ - flexcop_ibi_value v30c; - v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; - v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; - fc->write_ibi_reg(fc, pid_filter_30c, v30c); -} - -static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff); -} - -/* this fancy define reduces the code size of the quite similar PID controlling of - * the first 6 PIDs - */ - -#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ - flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ -v208 = fc->read_ibi_reg(fc, ctrl_208); \ -vpid.vregname.field = onoff ? pid : 0x1fff; \ -vpid.vregname.trans_field = transval; \ -v208.ctrl_208.enablefield = onoff; \ -fc->write_ibi_reg(fc, vregname, vpid); \ -fc->write_ibi_reg(fc, ctrl_208, v208); - -static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig, - Stream1_trans, 0); -} - -static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig, - Stream2_trans, 0); -} - -static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0); -} - -static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0); -} - -static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0); -} - -static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0); -} - -static void flexcop_pid_control(struct flexcop_device *fc, - int index, u16 pid, int onoff) -{ - if (pid == 0x2000) - return; - - deb_ts("setting pid: %5d %04x at index %d '%s'\n", - pid, pid, index, onoff ? "on" : "off"); - - /* We could use bit magic here to reduce source code size. - * I decided against it, but to use the real register names */ - switch (index) { - case 0: - flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff); - break; - case 1: - flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff); - break; - case 2: - flexcop_pid_PCR_PID_ctrl(fc, pid, onoff); - break; - case 3: - flexcop_pid_PMT_PID_ctrl(fc, pid, onoff); - break; - case 4: - flexcop_pid_EMM_PID_ctrl(fc, pid, onoff); - break; - case 5: - flexcop_pid_ECM_PID_ctrl(fc, pid, onoff); - break; - default: - if (fc->has_32_hw_pid_filter && index < 38) { - flexcop_ibi_value vpid, vid; - - /* set the index */ - vid = fc->read_ibi_reg(fc, index_reg_310); - vid.index_reg_310.index_reg = index - 6; - fc->write_ibi_reg(fc, index_reg_310, vid); - - vpid = fc->read_ibi_reg(fc, pid_n_reg_314); - vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; - vpid.pid_n_reg_314.PID_enable_bit = onoff; - fc->write_ibi_reg(fc, pid_n_reg_314, vpid); - } - break; - } -} - -static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff) -{ - if (fc->fullts_streaming_state != onoff) { - deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); - flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); - flexcop_pid_group_filter_ctrl(fc, onoff); - fc->fullts_streaming_state = onoff; - } - return 0; -} - -int flexcop_pid_feed_control(struct flexcop_device *fc, - struct dvb_demux_feed *dvbdmxfeed, int onoff) -{ - int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; - - fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ - if (dvbdmxfeed->index >= max_pid_filter) - fc->extra_feedcount += onoff ? 1 : -1; - - /* toggle complete-TS-streaming when: - * - pid_filtering is not enabled and it is the first or last feed requested - * - pid_filtering is enabled, - * - but the number of requested feeds is exceeded - * - or the requested pid is 0x2000 */ - - if (!fc->pid_filtering && fc->feedcount == onoff) - flexcop_toggle_fullts_streaming(fc, onoff); - - if (fc->pid_filtering) { - flexcop_pid_control \ - (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); - - if (fc->extra_feedcount > 0) - flexcop_toggle_fullts_streaming(fc, 1); - else if (dvbdmxfeed->pid == 0x2000) - flexcop_toggle_fullts_streaming(fc, onoff); - else - flexcop_toggle_fullts_streaming(fc, 0); - } - - /* if it was the first or last feed request change the stream-status */ - if (fc->feedcount == onoff) { - flexcop_rcv_data_ctrl(fc, onoff); - if (fc->stream_control) /* device specific stream control */ - fc->stream_control(fc, onoff); - - /* feeding stopped -> reset the flexcop filter*/ - if (onoff == 0) { - flexcop_reset_block_300(fc); - flexcop_hw_filter_init(fc); - } - } - return 0; -} -EXPORT_SYMBOL(flexcop_pid_feed_control); - -void flexcop_hw_filter_init(struct flexcop_device *fc) -{ - int i; - flexcop_ibi_value v; - for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) - flexcop_pid_control(fc, i, 0x1fff, 0); - - flexcop_pid_group_filter(fc, 0, 0x1fe0); - flexcop_pid_group_filter_ctrl(fc, 0); - - v = fc->read_ibi_reg(fc, pid_filter_308); - v.pid_filter_308.EMM_filter_4 = 1; - v.pid_filter_308.EMM_filter_6 = 0; - fc->write_ibi_reg(fc, pid_filter_308, v); - - flexcop_null_filter_ctrl(fc, 1); -} diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c deleted file mode 100644 index 965d5eb3375..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -#define FC_MAX_I2C_RETRIES 100000 - -static int flexcop_i2c_operation(struct flexcop_device *fc, - flexcop_ibi_value *r100) -{ - int i; - flexcop_ibi_value r; - - r100->tw_sm_c_100.working_start = 1; - deb_i2c("r100 before: %08x\n",r100->raw); - - fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); - fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */ - - for (i = 0; i < FC_MAX_I2C_RETRIES; i++) { - r = fc->read_ibi_reg(fc, tw_sm_c_100); - - if (!r.tw_sm_c_100.no_base_addr_ack_error) { - if (r.tw_sm_c_100.st_done) { - *r100 = r; - deb_i2c("i2c success\n"); - return 0; - } - } else { - deb_i2c("suffering from an i2c ack_error\n"); - return -EREMOTEIO; - } - } - deb_i2c("tried %d times i2c operation, " - "never finished or too many ack errors.\n", i); - return -EREMOTEIO; -} - -static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, - flexcop_ibi_value r100, u8 *buf) -{ - flexcop_ibi_value r104; - int len = r100.tw_sm_c_100.total_bytes, - /* remember total_bytes is buflen-1 */ - ret; - - /* work-around to have CableStar2 and SkyStar2 rev 2.7 work - * correctly: - * - * the ITD1000 is behind an i2c-gate which closes automatically - * after an i2c-transaction the STV0297 needs 2 consecutive reads - * one with no_base_addr = 0 and one with 1 - * - * those two work-arounds are conflictin: we check for the card - * type, it is set when probing the ITD1000 */ - if (i2c->fc->dev_type == FC_SKY_REV27) - r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; - - ret = flexcop_i2c_operation(i2c->fc, &r100); - if (ret != 0) { - deb_i2c("Retrying operation\n"); - r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; - ret = flexcop_i2c_operation(i2c->fc, &r100); - } - if (ret != 0) { - deb_i2c("read failed. %d\n", ret); - return ret; - } - - buf[0] = r100.tw_sm_c_100.data1_reg; - - if (len > 0) { - r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104); - deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw); - - /* there is at least one more byte, otherwise we wouldn't be here */ - buf[1] = r104.tw_sm_c_104.data2_reg; - if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; - if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; - } - return 0; -} - -static int flexcop_i2c_write4(struct flexcop_device *fc, - flexcop_ibi_value r100, u8 *buf) -{ - flexcop_ibi_value r104; - int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */ - r104.raw = 0; - - /* there is at least one byte, otherwise we wouldn't be here */ - r100.tw_sm_c_100.data1_reg = buf[0]; - r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0; - r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; - r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; - - deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw); - - /* write the additional i2c data before doing the actual i2c operation */ - fc->write_ibi_reg(fc, tw_sm_c_104, r104); - return flexcop_i2c_operation(fc, &r100); -} - -int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, - flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) -{ - int ret; - -#ifdef DUMP_I2C_MESSAGES - int i; -#endif - - u16 bytes_to_transfer; - flexcop_ibi_value r100; - - deb_i2c("op = %d\n",op); - r100.raw = 0; - r100.tw_sm_c_100.chipaddr = chipaddr; - r100.tw_sm_c_100.twoWS_rw = op; - r100.tw_sm_c_100.twoWS_port_reg = i2c->port; - -#ifdef DUMP_I2C_MESSAGES - printk(KERN_DEBUG "%d ", i2c->port); - if (op == FC_READ) - printk("rd("); - else - printk("wr("); - printk("%02x): %02x ", chipaddr, addr); -#endif - - /* in that case addr is the only value -> - * we write it twice as baseaddr and val0 - * BBTI is doing it like that for ISL6421 at least */ - if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { - buf = &addr; - len = 1; - } - - while (len != 0) { - bytes_to_transfer = len > 4 ? 4 : len; - - r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; - r100.tw_sm_c_100.baseaddr = addr; - - if (op == FC_READ) - ret = flexcop_i2c_read4(i2c, r100, buf); - else - ret = flexcop_i2c_write4(i2c->fc, r100, buf); - -#ifdef DUMP_I2C_MESSAGES - for (i = 0; i < bytes_to_transfer; i++) - printk("%02x ", buf[i]); -#endif - - if (ret < 0) - return ret; - - buf += bytes_to_transfer; - addr += bytes_to_transfer; - len -= bytes_to_transfer; - } - -#ifdef DUMP_I2C_MESSAGES - printk("\n"); -#endif - - return 0; -} -/* exported for PCI i2c */ -EXPORT_SYMBOL(flexcop_i2c_request); - -/* master xfer callback for demodulator */ -static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); - int i, ret = 0; - - /* Some drivers use 1 byte or 0 byte reads as probes, which this - * driver doesn't support. These probes will always fail, so this - * hack makes them always succeed. If one knew how, it would of - * course be better to actually do the read. */ - if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) - return 1; - - if (mutex_lock_interruptible(&i2c->fc->i2c_mutex)) - return -ERESTARTSYS; - - for (i = 0; i < num; i++) { - /* reading */ - if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) { - ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr, - msgs[i].buf[0], msgs[i+1].buf, - msgs[i+1].len); - i++; /* skip the following message */ - } else /* writing */ - ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr, - msgs[i].buf[0], &msgs[i].buf[1], - msgs[i].len - 1); - if (ret < 0) { - deb_i2c("i2c master_xfer failed"); - break; - } - } - - mutex_unlock(&i2c->fc->i2c_mutex); - - if (ret == 0) - ret = num; - return ret; -} - -static u32 flexcop_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm flexcop_algo = { - .master_xfer = flexcop_master_xfer, - .functionality = flexcop_i2c_func, -}; - -int flexcop_i2c_init(struct flexcop_device *fc) -{ - int ret; - mutex_init(&fc->i2c_mutex); - - fc->fc_i2c_adap[0].fc = fc; - fc->fc_i2c_adap[1].fc = fc; - fc->fc_i2c_adap[2].fc = fc; - fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD; - fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; - fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; - - strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", - sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); - strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", - sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); - strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", - sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); - - i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); - i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); - i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]); - - fc->fc_i2c_adap[0].i2c_adap.algo = - fc->fc_i2c_adap[1].i2c_adap.algo = - fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo; - fc->fc_i2c_adap[0].i2c_adap.algo_data = - fc->fc_i2c_adap[1].i2c_adap.algo_data = - fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL; - fc->fc_i2c_adap[0].i2c_adap.dev.parent = - fc->fc_i2c_adap[1].i2c_adap.dev.parent = - fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev; - - ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap); - if (ret < 0) - return ret; - - ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap); - if (ret < 0) - goto adap_1_failed; - - ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap); - if (ret < 0) - goto adap_2_failed; - - fc->init_state |= FC_STATE_I2C_INIT; - return 0; - -adap_2_failed: - i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); -adap_1_failed: - i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); - return ret; -} - -void flexcop_i2c_exit(struct flexcop_device *fc) -{ - if (fc->init_state & FC_STATE_I2C_INIT) { - i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap); - i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); - i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); - } - fc->init_state &= ~FC_STATE_I2C_INIT; -} diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c deleted file mode 100644 index f06f3a9070f..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-misc.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-misc.c - miscellaneous functions - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -void flexcop_determine_revision(struct flexcop_device *fc) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); - - switch (v.misc_204.Rev_N_sig_revision_hi) { - case 0x2: - deb_info("found a FlexCopII.\n"); - fc->rev = FLEXCOP_II; - break; - case 0x3: - deb_info("found a FlexCopIIb.\n"); - fc->rev = FLEXCOP_IIB; - break; - case 0x0: - deb_info("found a FlexCopIII.\n"); - fc->rev = FLEXCOP_III; - break; - default: - err("unknown FlexCop Revision: %x. Please report this to " - "linux-dvb@linuxtv.org.", - v.misc_204.Rev_N_sig_revision_hi); - break; - } - - if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) - deb_info("this FlexCop has " - "the additional 32 hardware pid filter.\n"); - else - deb_info("this FlexCop has " - "the 6 basic main hardware pid filter.\n"); - /* bus parts have to decide if hw pid filtering is used or not. */ -} - -static const char *flexcop_revision_names[] = { - "Unknown chip", - "FlexCopII", - "FlexCopIIb", - "FlexCopIII", -}; - -static const char *flexcop_device_names[] = { - [FC_UNK] = "Unknown device", - [FC_CABLE] = "Cable2PC/CableStar 2 DVB-C", - [FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T", - [FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation", - [FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation", - [FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", - [FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)", - [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6", - [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", - [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8", -}; - -static const char *flexcop_bus_names[] = { - "USB", - "PCI", -}; - -void flexcop_device_name(struct flexcop_device *fc, - const char *prefix, const char *suffix) -{ - info("%s '%s' at the '%s' bus controlled by a '%s' %s", - prefix, flexcop_device_names[fc->dev_type], - flexcop_bus_names[fc->bus_type], - flexcop_revision_names[fc->rev], suffix); -} - -void flexcop_dump_reg(struct flexcop_device *fc, - flexcop_ibi_register reg, int num) -{ - flexcop_ibi_value v; - int i; - for (i = 0; i < num; i++) { - v = fc->read_ibi_reg(fc, reg+4*i); - deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw); - } - deb_rdump("\n"); -} -EXPORT_SYMBOL(flexcop_dump_reg); diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c deleted file mode 100644 index 44f8fb5f17f..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-pci.c - covers the PCI part including DMA transfers - * see flexcop.c for copyright information - */ - -#define FC_LOG_PREFIX "flexcop-pci" -#include "flexcop-common.h" - -static int enable_pid_filtering = 1; -module_param(enable_pid_filtering, int, 0444); -MODULE_PARM_DESC(enable_pid_filtering, - "enable hardware pid filtering: supported values: 0 (fullts), 1"); - -static int irq_chk_intv = 100; -module_param(irq_chk_intv, int, 0644); -MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); - -#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) -#define DEBSTATUS "" -#else -#define dprintk(level,args...) -#define DEBSTATUS " (debugging is not enabled)" -#endif - -#define deb_info(args...) dprintk(0x01, args) -#define deb_reg(args...) dprintk(0x02, args) -#define deb_ts(args...) dprintk(0x04, args) -#define deb_irq(args...) dprintk(0x08, args) -#define deb_chk(args...) dprintk(0x10, args) - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." - DEBSTATUS); - -#define DRIVER_VERSION "0.1" -#define DRIVER_NAME "flexcop-pci" -#define DRIVER_AUTHOR "Patrick Boettcher " - -struct flexcop_pci { - struct pci_dev *pdev; - -#define FC_PCI_INIT 0x01 -#define FC_PCI_DMA_INIT 0x02 - int init_state; - - void __iomem *io_mem; - u32 irq; - /* buffersize (at least for DMA1, need to be % 188 == 0, - * this logic is required */ -#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) -#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) - struct flexcop_dma dma[2]; - - int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ - u32 last_dma1_cur_pos; - /* position of the pointer last time the timer/packet irq occurred */ - int count; - int count_prev; - int stream_problem; - - spinlock_t irq_lock; - unsigned long last_irq; - - struct delayed_work irq_check_work; - struct flexcop_device *fc_dev; -}; - -static int lastwreg, lastwval, lastrreg, lastrval; - -static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register r) -{ - struct flexcop_pci *fc_pci = fc->bus_specific; - flexcop_ibi_value v; - v.raw = readl(fc_pci->io_mem + r); - - if (lastrreg != r || lastrval != v.raw) { - lastrreg = r; lastrval = v.raw; - deb_reg("new rd: %3x: %08x\n", r, v.raw); - } - - return v; -} - -static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register r, flexcop_ibi_value v) -{ - struct flexcop_pci *fc_pci = fc->bus_specific; - - if (lastwreg != r || lastwval != v.raw) { - lastwreg = r; lastwval = v.raw; - deb_reg("new wr: %3x: %08x\n", r, v.raw); - } - - writel(v.raw, fc_pci->io_mem + r); - return 0; -} - -static void flexcop_pci_irq_check_work(struct work_struct *work) -{ - struct flexcop_pci *fc_pci = - container_of(work, struct flexcop_pci, irq_check_work.work); - struct flexcop_device *fc = fc_pci->fc_dev; - - if (fc->feedcount) { - - if (fc_pci->count == fc_pci->count_prev) { - deb_chk("no IRQ since the last check\n"); - if (fc_pci->stream_problem++ == 3) { - struct dvb_demux_feed *feed; - deb_info("flexcop-pci: stream problem, resetting pid filter\n"); - - spin_lock_irq(&fc->demux.lock); - list_for_each_entry(feed, &fc->demux.feed_list, - list_head) { - flexcop_pid_feed_control(fc, feed, 0); - } - - list_for_each_entry(feed, &fc->demux.feed_list, - list_head) { - flexcop_pid_feed_control(fc, feed, 1); - } - spin_unlock_irq(&fc->demux.lock); - - fc_pci->stream_problem = 0; - } - } else { - fc_pci->stream_problem = 0; - fc_pci->count_prev = fc_pci->count; - } - } - - schedule_delayed_work(&fc_pci->irq_check_work, - msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); -} - -/* When PID filtering is turned on, we use the timer IRQ, because small amounts - * of data need to be passed to the user space instantly as well. When PID - * filtering is turned off, we use the page-change-IRQ */ -static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) -{ - struct flexcop_pci *fc_pci = dev_id; - struct flexcop_device *fc = fc_pci->fc_dev; - unsigned long flags; - flexcop_ibi_value v; - irqreturn_t ret = IRQ_HANDLED; - - spin_lock_irqsave(&fc_pci->irq_lock, flags); - v = fc->read_ibi_reg(fc, irq_20c); - - /* errors */ - if (v.irq_20c.Data_receiver_error) - deb_chk("data receiver error\n"); - if (v.irq_20c.Continuity_error_flag) - deb_chk("Contunuity error flag is set\n"); - if (v.irq_20c.LLC_SNAP_FLAG_set) - deb_chk("LLC_SNAP_FLAG_set is set\n"); - if (v.irq_20c.Transport_Error) - deb_chk("Transport error\n"); - - if ((fc_pci->count % 1000) == 0) - deb_chk("%d valid irq took place so far\n", fc_pci->count); - - if (v.irq_20c.DMA1_IRQ_Status == 1) { - if (fc_pci->active_dma1_addr == 0) - flexcop_pass_dmx_packets(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr0, - fc_pci->dma[0].size / 188); - else - flexcop_pass_dmx_packets(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr1, - fc_pci->dma[0].size / 188); - - deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr); - fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; - /* for the timer IRQ we only can use buffer dmx feeding, because we don't have - * complete TS packets when reading from the DMA memory */ - } else if (v.irq_20c.DMA1_Timer_Status == 1) { - dma_addr_t cur_addr = - fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; - u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; - - deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, " - "last_cur_pos: %08x ", - jiffies_to_usecs(jiffies - fc_pci->last_irq), - v.raw, (unsigned long long)cur_addr, cur_pos, - fc_pci->last_dma1_cur_pos); - fc_pci->last_irq = jiffies; - - /* buffer end was reached, restarted from the beginning - * pass the data from last_cur_pos to the buffer end to the demux - */ - if (cur_pos < fc_pci->last_dma1_cur_pos) { - deb_irq(" end was reached: passing %d bytes ", - (fc_pci->dma[0].size*2 - 1) - - fc_pci->last_dma1_cur_pos); - flexcop_pass_dmx_data(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr0 + - fc_pci->last_dma1_cur_pos, - (fc_pci->dma[0].size*2) - - fc_pci->last_dma1_cur_pos); - fc_pci->last_dma1_cur_pos = 0; - } - - if (cur_pos > fc_pci->last_dma1_cur_pos) { - deb_irq(" passing %d bytes ", - cur_pos - fc_pci->last_dma1_cur_pos); - flexcop_pass_dmx_data(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr0 + - fc_pci->last_dma1_cur_pos, - cur_pos - fc_pci->last_dma1_cur_pos); - } - deb_irq("\n"); - - fc_pci->last_dma1_cur_pos = cur_pos; - fc_pci->count++; - } else { - deb_irq("isr for flexcop called, " - "apparently without reason (%08x)\n", v.raw); - ret = IRQ_NONE; - } - - spin_unlock_irqrestore(&fc_pci->irq_lock, flags); - return ret; -} - -static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) -{ - struct flexcop_pci *fc_pci = fc->bus_specific; - if (onoff) { - flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1); - flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2); - flexcop_dma_config_timer(fc, FC_DMA_1, 0); - flexcop_dma_xfer_control(fc, FC_DMA_1, - FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1); - deb_irq("DMA xfer enabled\n"); - - fc_pci->last_dma1_cur_pos = 0; - flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1); - deb_irq("IRQ enabled\n"); - fc_pci->count_prev = fc_pci->count; - } else { - flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0); - deb_irq("IRQ disabled\n"); - - flexcop_dma_xfer_control(fc, FC_DMA_1, - FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0); - deb_irq("DMA xfer disabled\n"); - } - return 0; -} - -static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) -{ - int ret; - ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0], - FC_DEFAULT_DMA1_BUFSIZE); - if (ret != 0) - return ret; - - ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1], - FC_DEFAULT_DMA2_BUFSIZE); - if (ret != 0) { - flexcop_dma_free(&fc_pci->dma[0]); - return ret; - } - - flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA | - FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); - flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO | - FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); - fc_pci->init_state |= FC_PCI_DMA_INIT; - return ret; -} - -static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci) -{ - if (fc_pci->init_state & FC_PCI_DMA_INIT) { - flexcop_dma_free(&fc_pci->dma[0]); - flexcop_dma_free(&fc_pci->dma[1]); - } - fc_pci->init_state &= ~FC_PCI_DMA_INIT; -} - -static int flexcop_pci_init(struct flexcop_pci *fc_pci) -{ - int ret; - - info("card revision %x", fc_pci->pdev->revision); - - if ((ret = pci_enable_device(fc_pci->pdev)) != 0) - return ret; - pci_set_master(fc_pci->pdev); - - if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) - goto err_pci_disable_device; - - fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); - - if (!fc_pci->io_mem) { - err("cannot map io memory\n"); - ret = -EIO; - goto err_pci_release_regions; - } - - pci_set_drvdata(fc_pci->pdev, fc_pci); - spin_lock_init(&fc_pci->irq_lock); - if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, - IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) - goto err_pci_iounmap; - - fc_pci->init_state |= FC_PCI_INIT; - return ret; - -err_pci_iounmap: - pci_iounmap(fc_pci->pdev, fc_pci->io_mem); - pci_set_drvdata(fc_pci->pdev, NULL); -err_pci_release_regions: - pci_release_regions(fc_pci->pdev); -err_pci_disable_device: - pci_disable_device(fc_pci->pdev); - return ret; -} - -static void flexcop_pci_exit(struct flexcop_pci *fc_pci) -{ - if (fc_pci->init_state & FC_PCI_INIT) { - free_irq(fc_pci->pdev->irq, fc_pci); - pci_iounmap(fc_pci->pdev, fc_pci->io_mem); - pci_set_drvdata(fc_pci->pdev, NULL); - pci_release_regions(fc_pci->pdev); - pci_disable_device(fc_pci->pdev); - } - fc_pci->init_state &= ~FC_PCI_INIT; -} - -static int flexcop_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct flexcop_device *fc; - struct flexcop_pci *fc_pci; - int ret = -ENOMEM; - - if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) { - err("out of memory\n"); - return -ENOMEM; - } - - /* general flexcop init */ - fc_pci = fc->bus_specific; - fc_pci->fc_dev = fc; - - fc->read_ibi_reg = flexcop_pci_read_ibi_reg; - fc->write_ibi_reg = flexcop_pci_write_ibi_reg; - fc->i2c_request = flexcop_i2c_request; - fc->get_mac_addr = flexcop_eeprom_check_mac_addr; - fc->stream_control = flexcop_pci_stream_control; - - if (enable_pid_filtering) - info("will use the HW PID filter."); - else - info("will pass the complete TS to the demuxer."); - - fc->pid_filtering = enable_pid_filtering; - fc->bus_type = FC_PCI; - fc->dev = &pdev->dev; - fc->owner = THIS_MODULE; - - /* bus specific part */ - fc_pci->pdev = pdev; - if ((ret = flexcop_pci_init(fc_pci)) != 0) - goto err_kfree; - - /* init flexcop */ - if ((ret = flexcop_device_initialize(fc)) != 0) - goto err_pci_exit; - - /* init dma */ - if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) - goto err_fc_exit; - - INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); - - if (irq_chk_intv > 0) - schedule_delayed_work(&fc_pci->irq_check_work, - msecs_to_jiffies(irq_chk_intv < 100 ? - 100 : - irq_chk_intv)); - return ret; - -err_fc_exit: - flexcop_device_exit(fc); -err_pci_exit: - flexcop_pci_exit(fc_pci); -err_kfree: - flexcop_device_kfree(fc); - return ret; -} - -/* in theory every _exit function should be called exactly two times, - * here and in the bail-out-part of the _init-function - */ -static void flexcop_pci_remove(struct pci_dev *pdev) -{ - struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); - - if (irq_chk_intv > 0) - cancel_delayed_work(&fc_pci->irq_check_work); - - flexcop_pci_dma_exit(fc_pci); - flexcop_device_exit(fc_pci->fc_dev); - flexcop_pci_exit(fc_pci); - flexcop_device_kfree(fc_pci->fc_dev); -} - -static struct pci_device_id flexcop_pci_tbl[] = { - { PCI_DEVICE(0x13d0, 0x2103) }, - { }, -}; - -MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); - -static struct pci_driver flexcop_pci_driver = { - .name = "b2c2_flexcop_pci", - .id_table = flexcop_pci_tbl, - .probe = flexcop_pci_probe, - .remove = flexcop_pci_remove, -}; - -static int __init flexcop_pci_module_init(void) -{ - return pci_register_driver(&flexcop_pci_driver); -} - -static void __exit flexcop_pci_module_exit(void) -{ - pci_unregister_driver(&flexcop_pci_driver); -} - -module_init(flexcop_pci_module_init); -module_exit(flexcop_pci_module_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h deleted file mode 100644 index dc4528dcbb9..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_REG_H__ -#define __FLEXCOP_REG_H__ - -typedef enum { - FLEXCOP_UNK = 0, - FLEXCOP_II, - FLEXCOP_IIB, - FLEXCOP_III, -} flexcop_revision_t; - -typedef enum { - FC_UNK = 0, - FC_CABLE, - FC_AIR_DVBT, - FC_AIR_ATSC1, - FC_AIR_ATSC2, - FC_AIR_ATSC3, - FC_SKY_REV23, - FC_SKY_REV26, - FC_SKY_REV27, - FC_SKY_REV28, -} flexcop_device_type_t; - -typedef enum { - FC_USB = 0, - FC_PCI, -} flexcop_bus_t; - -/* FlexCop IBI Registers */ -#if defined(__LITTLE_ENDIAN) -#include "flexcop_ibi_value_le.h" -#else -#if defined(__BIG_ENDIAN) -#include "flexcop_ibi_value_be.h" -#else -#error no endian defined -#endif -#endif - -#define fc_data_Tag_ID_DVB 0x3e -#define fc_data_Tag_ID_ATSC 0x3f -#define fc_data_Tag_ID_IDSB 0x8b - -#define fc_key_code_default 0x1 -#define fc_key_code_even 0x2 -#define fc_key_code_odd 0x3 - -extern flexcop_ibi_value ibi_zero; - -typedef enum { - FC_I2C_PORT_DEMOD = 1, - FC_I2C_PORT_EEPROM = 2, - FC_I2C_PORT_TUNER = 3, -} flexcop_i2c_port_t; - -typedef enum { - FC_WRITE = 0, - FC_READ = 1, -} flexcop_access_op_t; - -typedef enum { - FC_SRAM_DEST_NET = 1, - FC_SRAM_DEST_CAI = 2, - FC_SRAM_DEST_CAO = 4, - FC_SRAM_DEST_MEDIA = 8 -} flexcop_sram_dest_t; - -typedef enum { - FC_SRAM_DEST_TARGET_WAN_USB = 0, - FC_SRAM_DEST_TARGET_DMA1 = 1, - FC_SRAM_DEST_TARGET_DMA2 = 2, - FC_SRAM_DEST_TARGET_FC3_CA = 3 -} flexcop_sram_dest_target_t; - -typedef enum { - FC_SRAM_2_32KB = 0, /* 64KB */ - FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ - FC_SRAM_1_128KB = 2, /* 128KB */ - FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ -} flexcop_sram_type_t; - -typedef enum { - FC_WAN_SPEED_4MBITS = 0, - FC_WAN_SPEED_8MBITS = 1, - FC_WAN_SPEED_12MBITS = 2, - FC_WAN_SPEED_16MBITS = 3, -} flexcop_wan_speed_t; - -typedef enum { - FC_DMA_1 = 1, - FC_DMA_2 = 2, -} flexcop_dma_index_t; - -typedef enum { - FC_DMA_SUBADDR_0 = 1, - FC_DMA_SUBADDR_1 = 2, -} flexcop_dma_addr_index_t; - -/* names of the particular registers */ -typedef enum { - dma1_000 = 0x000, - dma1_004 = 0x004, - dma1_008 = 0x008, - dma1_00c = 0x00c, - dma2_010 = 0x010, - dma2_014 = 0x014, - dma2_018 = 0x018, - dma2_01c = 0x01c, - - tw_sm_c_100 = 0x100, - tw_sm_c_104 = 0x104, - tw_sm_c_108 = 0x108, - tw_sm_c_10c = 0x10c, - tw_sm_c_110 = 0x110, - - lnb_switch_freq_200 = 0x200, - misc_204 = 0x204, - ctrl_208 = 0x208, - irq_20c = 0x20c, - sw_reset_210 = 0x210, - misc_214 = 0x214, - mbox_v8_to_host_218 = 0x218, - mbox_host_to_v8_21c = 0x21c, - - pid_filter_300 = 0x300, - pid_filter_304 = 0x304, - pid_filter_308 = 0x308, - pid_filter_30c = 0x30c, - index_reg_310 = 0x310, - pid_n_reg_314 = 0x314, - mac_low_reg_318 = 0x318, - mac_high_reg_31c = 0x31c, - - data_tag_400 = 0x400, - card_id_408 = 0x408, - card_id_40c = 0x40c, - mac_address_418 = 0x418, - mac_address_41c = 0x41c, - - ci_600 = 0x600, - pi_604 = 0x604, - pi_608 = 0x608, - dvb_reg_60c = 0x60c, - - sram_ctrl_reg_700 = 0x700, - net_buf_reg_704 = 0x704, - cai_buf_reg_708 = 0x708, - cao_buf_reg_70c = 0x70c, - media_buf_reg_710 = 0x710, - sram_dest_reg_714 = 0x714, - net_buf_reg_718 = 0x718, - wan_ctrl_reg_71c = 0x71c, -} flexcop_ibi_register; - -#define flexcop_set_ibi_value(reg,attr,val) { \ - flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ - v.reg.attr = val; \ - fc->write_ibi_reg(fc,reg,v); \ -} - -#endif diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c deleted file mode 100644 index f2199e43e80..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-sram.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-sram.c - functions for controlling the SRAM - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -static void flexcop_sram_set_chip(struct flexcop_device *fc, - flexcop_sram_type_t type) -{ - flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type); -} - -int flexcop_sram_init(struct flexcop_device *fc) -{ - switch (fc->rev) { - case FLEXCOP_II: - case FLEXCOP_IIB: - flexcop_sram_set_chip(fc, FC_SRAM_1_32KB); - break; - case FLEXCOP_III: - flexcop_sram_set_chip(fc, FC_SRAM_1_48KB); - break; - default: - return -EINVAL; - } - return 0; -} - -int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, - flexcop_sram_dest_target_t target) -{ - flexcop_ibi_value v; - v = fc->read_ibi_reg(fc, sram_dest_reg_714); - - if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { - err("SRAM destination target to available on FlexCopII(b)\n"); - return -EINVAL; - } - deb_sram("sram dest: %x target: %x\n", dest, target); - - if (dest & FC_SRAM_DEST_NET) - v.sram_dest_reg_714.NET_Dest = target; - if (dest & FC_SRAM_DEST_CAI) - v.sram_dest_reg_714.CAI_Dest = target; - if (dest & FC_SRAM_DEST_CAO) - v.sram_dest_reg_714.CAO_Dest = target; - if (dest & FC_SRAM_DEST_MEDIA) - v.sram_dest_reg_714.MEDIA_Dest = target; - - fc->write_ibi_reg(fc,sram_dest_reg_714,v); - udelay(1000); /* TODO delay really necessary */ - - return 0; -} -EXPORT_SYMBOL(flexcop_sram_set_dest); - -void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) -{ - flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); -} -EXPORT_SYMBOL(flexcop_wan_set_speed); - -void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); - v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; - v.sram_dest_reg_714.ctrl_sramdma = sramdma; - v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; - fc->write_ibi_reg(fc,sram_dest_reg_714,v); -} -EXPORT_SYMBOL(flexcop_sram_ctrl); - -#if 0 -static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04000000 | (*buf << 0x10); - - retries = 2; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __func__); - - write_reg_dw(adapter, 0x700, command); - - buf++; - addr++; - } -} - -static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command, value; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04008000; - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __func__); - - write_reg_dw(adapter, 0x700, command); - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __func__); - - value = read_reg_dw(adapter, 0x700) >> 0x10; - - *buf = (value & 0xff); - - addr++; - buf++; - } -} - -static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - while (len != 0) { - length = len; - /* check if the address range belongs to the same - * 32K memory chip. If not, the data is read - * from one chip at a time */ - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_read_chunk(adapter, addr, buf, length); - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - while (len != 0) { - length = len; - - /* check if the address range belongs to the same - * 32K memory chip. If not, the data is - * written to one chip at a time */ - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_write_chunk(adapter, addr, buf, length); - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_set_size(struct adapter *adapter, u32 mask) -{ - write_reg_dw(adapter, 0x71c, - (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); -} - -static void sram_init(struct adapter *adapter) -{ - u32 tmp; - tmp = read_reg_dw(adapter, 0x71c); - write_reg_dw(adapter, 0x71c, 1); - - if (read_reg_dw(adapter, 0x71c) != 0) { - write_reg_dw(adapter, 0x71c, tmp); - adapter->dw_sram_type = tmp & 0x30000; - ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); - } else { - adapter->dw_sram_type = 0x10000; - ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); - } -} - -static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) -{ - u8 tmp1, tmp2; - dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr); - - sram_set_size(adapter, mask); - sram_init(adapter); - - tmp2 = 0xa5; - tmp1 = 0x4f; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2); - - if (tmp2 != 0xa5) - return 0; - - tmp2 = 0x5a; - tmp1 = 0xf4; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2); - - if (tmp2 != 0x5a) - return 0; - return 1; -} - -static u32 sram_length(struct adapter *adapter) -{ - if (adapter->dw_sram_type == 0x10000) - return 32768; /* 32K */ - if (adapter->dw_sram_type == 0x00000) - return 65536; /* 64K */ - if (adapter->dw_sram_type == 0x20000) - return 131072; /* 128K */ - return 32768; /* 32K */ -} - -/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. - - for 128K there are 4x32K chips at bank 0,1,2,3. - - for 64K there are 2x32K chips at bank 1,2. - - for 32K there is one 32K chip at bank 0. - - FlexCop works only with one bank at a time. The bank is selected - by bits 28-29 of the 0x700 register. - - bank 0 covers addresses 0x00000-0x07fff - bank 1 covers addresses 0x08000-0x0ffff - bank 2 covers addresses 0x10000-0x17fff - bank 3 covers addresses 0x18000-0x1ffff */ - -static int flexcop_sram_detect(struct flexcop_device *fc) -{ - flexcop_ibi_value r208, r71c_0, vr71c_1; - r208 = fc->read_ibi_reg(fc, ctrl_208); - fc->write_ibi_reg(fc, ctrl_208, ibi_zero); - - r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); - write_reg_dw(adapter, 0x71c, 1); - tmp3 = read_reg_dw(adapter, 0x71c); - dprintk("%s: tmp3 = %x\n", __func__, tmp3); - write_reg_dw(adapter, 0x71c, tmp2); - - // check for internal SRAM ??? - tmp3--; - if (tmp3 != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 32K\n", __func__); - return 32; - } - - if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { - sram_set_size(adapter, 0x20000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 128K\n", __func__); - return 128; - } - - if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { - sram_set_size(adapter, 0x00000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 64K\n", __func__); - return 64; - } - - if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 32K\n", __func__); - return 32; - } - - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: SRAM detection failed. Set to 32K \n", __func__); - return 0; -} - -static void sll_detect_sram_size(struct adapter *adapter) -{ - sram_detect_for_flex2(adapter); -} - -#endif diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c deleted file mode 100644 index 8b6275f8590..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-usb.c - covers the USB part - * see flexcop.c for copyright information - */ -#define FC_LOG_PREFIX "flexcop_usb" -#include "flexcop-usb.h" -#include "flexcop-common.h" - -/* Version information */ -#define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver" -#define DRIVER_AUTHOR "Patrick Boettcher " - -/* debug */ -#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) - -#define debug_dump(b, l, method) do {\ - int i; \ - for (i = 0; i < l; i++) \ - method("%02x ", b[i]); \ - method("\n"); \ -} while (0) - -#define DEBSTATUS "" -#else -#define dprintk(level, args...) -#define debug_dump(b, l, method) -#define DEBSTATUS " (debugging is not enabled)" -#endif - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2," - "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); -#undef DEBSTATUS - -#define deb_info(args...) dprintk(0x01, args) -#define deb_ts(args...) dprintk(0x02, args) -#define deb_ctrl(args...) dprintk(0x04, args) -#define deb_i2c(args...) dprintk(0x08, args) -#define deb_v8(args...) dprintk(0x10, args) - -/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits - * in the IBI address, to make the V8 code simpler. - * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used) - * in general: 0000 0HHH 000L LL00 - * IBI ADDRESS FORMAT: RHHH BLLL - * - * where R is the read(1)/write(0) bit, B is the busy bit - * and HHH and LLL are the two sets of three bits from the PCI address. - */ -#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \ - (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) -#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \ - (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) - -/* - * DKT 020228 - * - forget about this VENDOR_BUFFER_SIZE, read and write register - * deal with DWORD or 4 bytes, that should be should from now on - * - from now on, we don't support anything older than firm 1.00 - * I eliminated the write register as a 2 trip of writing hi word and lo word - * and force this to write only 4 bytes at a time. - * NOTE: this should work with all the firmware from 1.00 and newer - */ -static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read) -{ - struct flexcop_usb *fc_usb = fc->bus_specific; - u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; - u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; - u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | - (read ? 0x80 : 0); - - int len = usb_control_msg(fc_usb->udev, - read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, - request, - request_type, /* 0xc0 read or 0x40 write */ - wAddress, - 0, - val, - sizeof(u32), - B2C2_WAIT_FOR_OPERATION_RDW * HZ); - - if (len != sizeof(u32)) { - err("error while %s dword from %d (%d).", read ? "reading" : - "writing", wAddress, wRegOffsPCI); - return -EIO; - } - return 0; -} -/* - * DKT 010817 - add support for V8 memory read/write and flash update - */ -static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, - flexcop_usb_request_t req, u8 page, u16 wAddress, - u8 *pbBuffer, u32 buflen) -{ - u8 request_type = USB_TYPE_VENDOR; - u16 wIndex; - int nWaitTime, pipe, len; - wIndex = page << 8; - - switch (req) { - case B2C2_USB_READ_V8_MEM: - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; - request_type |= USB_DIR_IN; - pipe = B2C2_USB_CTRL_PIPE_IN; - break; - case B2C2_USB_WRITE_V8_MEM: - wIndex |= pbBuffer[0]; - request_type |= USB_DIR_OUT; - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; - pipe = B2C2_USB_CTRL_PIPE_OUT; - break; - case B2C2_USB_FLASH_BLOCK: - request_type |= USB_DIR_OUT; - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; - pipe = B2C2_USB_CTRL_PIPE_OUT; - break; - default: - deb_info("unsupported request for v8_mem_req %x.\n", req); - return -EINVAL; - } - deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req, - wAddress, wIndex, buflen); - - len = usb_control_msg(fc_usb->udev, pipe, - req, - request_type, - wAddress, - wIndex, - pbBuffer, - buflen, - nWaitTime * HZ); - - debug_dump(pbBuffer, len, deb_v8); - return len == buflen ? 0 : -EIO; -} - -#define bytes_left_to_read_on_page(paddr,buflen) \ - ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ - ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) - -static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, - flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, - u32 addr, int extended, u8 *buf, u32 len) -{ - int i,ret = 0; - u16 wMax; - u32 pagechunk = 0; - - switch(req) { - case B2C2_USB_READ_V8_MEM: - wMax = USB_MEM_READ_MAX; - break; - case B2C2_USB_WRITE_V8_MEM: - wMax = USB_MEM_WRITE_MAX; - break; - case B2C2_USB_FLASH_BLOCK: - wMax = USB_FLASH_MAX; - break; - default: - return -EINVAL; - break; - } - for (i = 0; i < len;) { - pagechunk = - wMax < bytes_left_to_read_on_page(addr, len) ? - wMax : - bytes_left_to_read_on_page(addr, len); - deb_info("%x\n", - (addr & V8_MEMORY_PAGE_MASK) | - (V8_MEMORY_EXTENDED*extended)); - - ret = flexcop_usb_v8_memory_req(fc_usb, req, - page_start + (addr / V8_MEMORY_PAGE_SIZE), - (addr & V8_MEMORY_PAGE_MASK) | - (V8_MEMORY_EXTENDED*extended), - &buf[i], pagechunk); - - if (ret < 0) - return ret; - addr += pagechunk; - len -= pagechunk; - } - return 0; -} - -static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) -{ - return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM, - V8_MEMORY_PAGE_FLASH, 0x1f010, 1, - fc->dvb_adapter.proposed_mac, 6); -} - -#if 0 -static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, - flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, - u16 buflen, u8 *pvBuffer) -{ - u16 wValue; - u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR; - int nWaitTime = 2, - pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len; - wValue = (func << 8) | extra; - - len = usb_control_msg(fc_usb->udev,pipe, - B2C2_USB_UTILITY, - request_type, - wValue, - wIndex, - pvBuffer, - buflen, - nWaitTime * HZ); - return len == buflen ? 0 : -EIO; -} -#endif - -/* usb i2c stuff */ -static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, - flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, - u8 chipaddr, u8 addr, u8 *buf, u8 buflen) -{ - struct flexcop_usb *fc_usb = i2c->fc->bus_specific; - u16 wValue, wIndex; - int nWaitTime,pipe,len; - u8 request_type = USB_TYPE_VENDOR; - - switch (func) { - case USB_FUNC_I2C_WRITE: - case USB_FUNC_I2C_MULTIWRITE: - case USB_FUNC_I2C_REPEATWRITE: - /* DKT 020208 - add this to support special case of DiSEqC */ - case USB_FUNC_I2C_CHECKWRITE: - pipe = B2C2_USB_CTRL_PIPE_OUT; - nWaitTime = 2; - request_type |= USB_DIR_OUT; - break; - case USB_FUNC_I2C_READ: - case USB_FUNC_I2C_REPEATREAD: - pipe = B2C2_USB_CTRL_PIPE_IN; - nWaitTime = 2; - request_type |= USB_DIR_IN; - break; - default: - deb_info("unsupported function for i2c_req %x\n", func); - return -EINVAL; - } - wValue = (func << 8) | (i2c->port << 4); - wIndex = (chipaddr << 8 ) | addr; - - deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n", - func, request_type, req, - wValue & 0xff, wValue >> 8, - wIndex & 0xff, wIndex >> 8); - - len = usb_control_msg(fc_usb->udev,pipe, - req, - request_type, - wValue, - wIndex, - buf, - buflen, - nWaitTime * HZ); - return len == buflen ? 0 : -EREMOTEIO; -} - -/* actual bus specific access functions, - make sure prototype are/will be equal to pci */ -static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register reg) -{ - flexcop_ibi_value val; - val.raw = 0; - flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1); - return val; -} - -static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register reg, flexcop_ibi_value val) -{ - return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0); -} - -static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c, - flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) -{ - if (op == FC_READ) - return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, - USB_FUNC_I2C_READ, chipaddr, addr, buf, len); - else - return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, - USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len); -} - -static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, - u8 *buffer, int buffer_length) -{ - u8 *b; - int l; - - deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", - fc_usb->tmp_buffer_length, buffer_length); - - if (fc_usb->tmp_buffer_length > 0) { - memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, - buffer_length); - fc_usb->tmp_buffer_length += buffer_length; - b = fc_usb->tmp_buffer; - l = fc_usb->tmp_buffer_length; - } else { - b=buffer; - l=buffer_length; - } - - while (l >= 190) { - if (*b == 0xff) { - switch (*(b+1) & 0x03) { - case 0x01: /* media packet */ - if (*(b+2) == 0x47) - flexcop_pass_dmx_packets( - fc_usb->fc_dev, b+2, 1); - else - deb_ts("not ts packet %*ph\n", 4, b+2); - b += 190; - l -= 190; - break; - default: - deb_ts("wrong packet type\n"); - l = 0; - break; - } - } else { - deb_ts("wrong header\n"); - l = 0; - } - } - - if (l>0) - memcpy(fc_usb->tmp_buffer, b, l); - fc_usb->tmp_buffer_length = l; -} - -static void flexcop_usb_urb_complete(struct urb *urb) -{ - struct flexcop_usb *fc_usb = urb->context; - int i; - - if (urb->actual_length > 0) - deb_ts("urb completed, bufsize: %d actlen; %d\n", - urb->transfer_buffer_length, urb->actual_length); - - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status < 0) { - err("iso frame descriptor %d has an error: %d\n", i, - urb->iso_frame_desc[i].status); - } else - if (urb->iso_frame_desc[i].actual_length > 0) { - deb_ts("passed %d bytes to the demux\n", - urb->iso_frame_desc[i].actual_length); - - flexcop_usb_process_frame(fc_usb, - urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - usb_submit_urb(urb,GFP_ATOMIC); -} - -static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) -{ - /* submit/kill iso packets */ - return 0; -} - -static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) -{ - int i; - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) - if (fc_usb->iso_urb[i] != NULL) { - deb_ts("unlinking/killing urb no. %d\n",i); - usb_kill_urb(fc_usb->iso_urb[i]); - usb_free_urb(fc_usb->iso_urb[i]); - } - - if (fc_usb->iso_buffer != NULL) - pci_free_consistent(NULL, - fc_usb->buffer_size, fc_usb->iso_buffer, - fc_usb->dma_addr); -} - -static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) -{ - u16 frame_size = le16_to_cpu( - fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); - int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * - frame_size, i, j, ret; - int buffer_offset = 0; - - deb_ts("creating %d iso-urbs with %d frames " - "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, - B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); - - fc_usb->iso_buffer = pci_alloc_consistent(NULL, - bufsize, &fc_usb->dma_addr); - if (fc_usb->iso_buffer == NULL) - return -ENOMEM; - - memset(fc_usb->iso_buffer, 0, bufsize); - fc_usb->buffer_size = bufsize; - - /* creating iso urbs */ - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { - fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, - GFP_ATOMIC); - if (fc_usb->iso_urb[i] == NULL) { - ret = -ENOMEM; - goto urb_error; - } - } - - /* initialising and submitting iso urbs */ - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { - int frame_offset = 0; - struct urb *urb = fc_usb->iso_urb[i]; - deb_ts("initializing and submitting urb no. %d " - "(buf_offset: %d).\n", i, buffer_offset); - - urb->dev = fc_usb->udev; - urb->context = fc_usb; - urb->complete = flexcop_usb_urb_complete; - urb->pipe = B2C2_USB_DATA_PIPE; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; - urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; - urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; - - buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; - for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { - deb_ts("urb no: %d, frame: %d, frame_offset: %d\n", - i, j, frame_offset); - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = frame_size; - frame_offset += frame_size; - } - - if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { - err("submitting urb %d failed with %d.", i, ret); - goto urb_error; - } - deb_ts("submitted urb no. %d.\n",i); - } - - /* SRAM */ - flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA | - FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, - FC_SRAM_DEST_TARGET_WAN_USB); - flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS); - flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1); - return 0; - -urb_error: - flexcop_usb_transfer_exit(fc_usb); - return ret; -} - -static int flexcop_usb_init(struct flexcop_usb *fc_usb) -{ - /* use the alternate setting with the larges buffer */ - usb_set_interface(fc_usb->udev,0,1); - switch (fc_usb->udev->speed) { - case USB_SPEED_LOW: - err("cannot handle USB speed because it is too slow."); - return -ENODEV; - break; - case USB_SPEED_FULL: - info("running at FULL speed."); - break; - case USB_SPEED_HIGH: - info("running at HIGH speed."); - break; - case USB_SPEED_UNKNOWN: /* fall through */ - default: - err("cannot handle USB speed because it is unknown."); - return -ENODEV; - } - usb_set_intfdata(fc_usb->uintf, fc_usb); - return 0; -} - -static void flexcop_usb_exit(struct flexcop_usb *fc_usb) -{ - usb_set_intfdata(fc_usb->uintf, NULL); -} - -static int flexcop_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct flexcop_usb *fc_usb = NULL; - struct flexcop_device *fc = NULL; - int ret; - - if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { - err("out of memory\n"); - return -ENOMEM; - } - - /* general flexcop init */ - fc_usb = fc->bus_specific; - fc_usb->fc_dev = fc; - - fc->read_ibi_reg = flexcop_usb_read_ibi_reg; - fc->write_ibi_reg = flexcop_usb_write_ibi_reg; - fc->i2c_request = flexcop_usb_i2c_request; - fc->get_mac_addr = flexcop_usb_get_mac_addr; - - fc->stream_control = flexcop_usb_stream_control; - - fc->pid_filtering = 1; - fc->bus_type = FC_USB; - - fc->dev = &udev->dev; - fc->owner = THIS_MODULE; - - /* bus specific part */ - fc_usb->udev = udev; - fc_usb->uintf = intf; - if ((ret = flexcop_usb_init(fc_usb)) != 0) - goto err_kfree; - - /* init flexcop */ - if ((ret = flexcop_device_initialize(fc)) != 0) - goto err_usb_exit; - - /* xfer init */ - if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) - goto err_fc_exit; - - info("%s successfully initialized and connected.", DRIVER_NAME); - return 0; - -err_fc_exit: - flexcop_device_exit(fc); -err_usb_exit: - flexcop_usb_exit(fc_usb); -err_kfree: - flexcop_device_kfree(fc); - return ret; -} - -static void flexcop_usb_disconnect(struct usb_interface *intf) -{ - struct flexcop_usb *fc_usb = usb_get_intfdata(intf); - flexcop_usb_transfer_exit(fc_usb); - flexcop_device_exit(fc_usb->fc_dev); - flexcop_usb_exit(fc_usb); - flexcop_device_kfree(fc_usb->fc_dev); - info("%s successfully deinitialized and disconnected.", DRIVER_NAME); -} - -static struct usb_device_id flexcop_usb_table [] = { - { USB_DEVICE(0x0af7, 0x0101) }, - { } -}; -MODULE_DEVICE_TABLE (usb, flexcop_usb_table); - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver flexcop_usb_driver = { - .name = "b2c2_flexcop_usb", - .probe = flexcop_usb_probe, - .disconnect = flexcop_usb_disconnect, - .id_table = flexcop_usb_table, -}; - -module_usb_driver(flexcop_usb_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h deleted file mode 100644 index 92529a9c447..00000000000 --- a/drivers/media/dvb/b2c2/flexcop-usb.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-usb.h - header file for the USB part - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_USB_H_INCLUDED__ -#define __FLEXCOP_USB_H_INCLUDED__ - -#include - -/* transfer parameters */ -#define B2C2_USB_FRAMES_PER_ISO 4 -#define B2C2_USB_NUM_ISO_URB 4 - -#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0) -#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0) -#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81) - -struct flexcop_usb { - struct usb_device *udev; - struct usb_interface *uintf; - - u8 *iso_buffer; - int buffer_size; - dma_addr_t dma_addr; - - struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; - struct flexcop_device *fc_dev; - - u8 tmp_buffer[1023+190]; - int tmp_buffer_length; -}; - -#if 0 -/* request types TODO What is its use?*/ -typedef enum { - -} flexcop_usb_request_type_t; -#endif - -/* request */ -typedef enum { - B2C2_USB_WRITE_V8_MEM = 0x04, - B2C2_USB_READ_V8_MEM = 0x05, - B2C2_USB_READ_REG = 0x08, - B2C2_USB_WRITE_REG = 0x0A, - B2C2_USB_WRITEREGHI = 0x0B, - B2C2_USB_FLASH_BLOCK = 0x10, - B2C2_USB_I2C_REQUEST = 0x11, - B2C2_USB_UTILITY = 0x12, -} flexcop_usb_request_t; - -/* function definition for I2C_REQUEST */ -typedef enum { - USB_FUNC_I2C_WRITE = 0x01, - USB_FUNC_I2C_MULTIWRITE = 0x02, - USB_FUNC_I2C_READ = 0x03, - USB_FUNC_I2C_REPEATWRITE = 0x04, - USB_FUNC_GET_DESCRIPTOR = 0x05, - USB_FUNC_I2C_REPEATREAD = 0x06, - /* DKT 020208 - add this to support special case of DiSEqC */ - USB_FUNC_I2C_CHECKWRITE = 0x07, - USB_FUNC_I2C_CHECKRESULT = 0x08, -} flexcop_usb_i2c_function_t; - -/* function definition for UTILITY request 0x12 - * DKT 020304 - new utility function */ -typedef enum { - UTILITY_SET_FILTER = 0x01, - UTILITY_DATA_ENABLE = 0x02, - UTILITY_FLEX_MULTIWRITE = 0x03, - UTILITY_SET_BUFFER_SIZE = 0x04, - UTILITY_FLEX_OPERATOR = 0x05, - UTILITY_FLEX_RESET300_START = 0x06, - UTILITY_FLEX_RESET300_STOP = 0x07, - UTILITY_FLEX_RESET300 = 0x08, - UTILITY_SET_ISO_SIZE = 0x09, - UTILITY_DATA_RESET = 0x0A, - UTILITY_GET_DATA_STATUS = 0x10, - UTILITY_GET_V8_REG = 0x11, - /* DKT 020326 - add function for v1.14 */ - UTILITY_SRAM_WRITE = 0x12, - UTILITY_SRAM_READ = 0x13, - UTILITY_SRAM_TESTFILL = 0x14, - UTILITY_SRAM_TESTSET = 0x15, - UTILITY_SRAM_TESTVERIFY = 0x16, -} flexcop_usb_utility_function_t; - -#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ) -#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ) - -#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ) - -typedef enum { - V8_MEMORY_PAGE_DVB_CI = 0x20, - V8_MEMORY_PAGE_DVB_DS = 0x40, - V8_MEMORY_PAGE_MULTI2 = 0x60, - V8_MEMORY_PAGE_FLASH = 0x80 -} flexcop_usb_mem_page_t; - -#define V8_MEMORY_EXTENDED (1 << 15) -#define USB_MEM_READ_MAX 32 -#define USB_MEM_WRITE_MAX 1 -#define USB_FLASH_MAX 8 -#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */ -#define V8_MEMORY_PAGE_MASK 0x7FFF - -#endif diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c deleted file mode 100644 index b1e8c99f469..00000000000 --- a/drivers/media/dvb/b2c2/flexcop.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop.c - main module part - * Copyright (C) 2004-9 Patrick Boettcher - * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc - * - * Acknowledgements: - * John Jurrius from BBTI, Inc. for extensive support - * with code examples and data books - * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) - * - * Contributions to the skystar2-driver have been done by - * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) - * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) - * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu) - * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac - * filtering) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * 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 Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "flexcop.h" - -#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" -#define DRIVER_AUTHOR "Patrick Boettcher demux->priv; - return flexcop_pid_feed_control(fc, dvbdmxfeed, 1); -} - -static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct flexcop_device *fc = dvbdmxfeed->demux->priv; - return flexcop_pid_feed_control(fc, dvbdmxfeed, 0); -} - -static int flexcop_dvb_init(struct flexcop_device *fc) -{ - int ret = dvb_register_adapter(&fc->dvb_adapter, - "FlexCop Digital TV device", fc->owner, - fc->dev, adapter_nr); - if (ret < 0) { - err("error registering DVB adapter"); - return ret; - } - fc->dvb_adapter.priv = fc; - - fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING - | DMX_MEMORY_BASED_FILTERING); - fc->demux.priv = fc; - fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; - fc->demux.start_feed = flexcop_dvb_start_feed; - fc->demux.stop_feed = flexcop_dvb_stop_feed; - fc->demux.write_to_decoder = NULL; - - ret = dvb_dmx_init(&fc->demux); - if (ret < 0) { - err("dvb_dmx failed: error %d", ret); - goto err_dmx; - } - - fc->hw_frontend.source = DMX_FRONTEND_0; - - fc->dmxdev.filternum = fc->demux.feednum; - fc->dmxdev.demux = &fc->demux.dmx; - fc->dmxdev.capabilities = 0; - ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter); - if (ret < 0) { - err("dvb_dmxdev_init failed: error %d", ret); - goto err_dmx_dev; - } - - ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend); - if (ret < 0) { - err("adding hw_frontend to dmx failed: error %d", ret); - goto err_dmx_add_hw_frontend; - } - - fc->mem_frontend.source = DMX_MEMORY_FE; - ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend); - if (ret < 0) { - err("adding mem_frontend to dmx failed: error %d", ret); - goto err_dmx_add_mem_frontend; - } - - ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend); - if (ret < 0) { - err("connect frontend failed: error %d", ret); - goto err_connect_frontend; - } - - ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); - if (ret < 0) { - err("dvb_net_init failed: error %d", ret); - goto err_net; - } - - fc->init_state |= FC_STATE_DVB_INIT; - return 0; - -err_net: - fc->demux.dmx.disconnect_frontend(&fc->demux.dmx); -err_connect_frontend: - fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend); -err_dmx_add_mem_frontend: - fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend); -err_dmx_add_hw_frontend: - dvb_dmxdev_release(&fc->dmxdev); -err_dmx_dev: - dvb_dmx_release(&fc->demux); -err_dmx: - dvb_unregister_adapter(&fc->dvb_adapter); - return ret; -} - -static void flexcop_dvb_exit(struct flexcop_device *fc) -{ - if (fc->init_state & FC_STATE_DVB_INIT) { - dvb_net_release(&fc->dvbnet); - - fc->demux.dmx.close(&fc->demux.dmx); - fc->demux.dmx.remove_frontend(&fc->demux.dmx, - &fc->mem_frontend); - fc->demux.dmx.remove_frontend(&fc->demux.dmx, - &fc->hw_frontend); - dvb_dmxdev_release(&fc->dmxdev); - dvb_dmx_release(&fc->demux); - dvb_unregister_adapter(&fc->dvb_adapter); - deb_info("deinitialized dvb stuff\n"); - } - fc->init_state &= ~FC_STATE_DVB_INIT; -} - -/* these methods are necessary to achieve the long-term-goal of hiding the - * struct flexcop_device from the bus-parts */ -void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) -{ - dvb_dmx_swfilter(&fc->demux, buf, len); -} -EXPORT_SYMBOL(flexcop_pass_dmx_data); - -void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) -{ - dvb_dmx_swfilter_packets(&fc->demux, buf, no); -} -EXPORT_SYMBOL(flexcop_pass_dmx_packets); - -static void flexcop_reset(struct flexcop_device *fc) -{ - flexcop_ibi_value v210, v204; - - /* reset the flexcop itself */ - fc->write_ibi_reg(fc,ctrl_208,ibi_zero); - - v210.raw = 0; - v210.sw_reset_210.reset_block_000 = 1; - v210.sw_reset_210.reset_block_100 = 1; - v210.sw_reset_210.reset_block_200 = 1; - v210.sw_reset_210.reset_block_300 = 1; - v210.sw_reset_210.reset_block_400 = 1; - v210.sw_reset_210.reset_block_500 = 1; - v210.sw_reset_210.reset_block_600 = 1; - v210.sw_reset_210.reset_block_700 = 1; - v210.sw_reset_210.Block_reset_enable = 0xb2; - v210.sw_reset_210.Special_controls = 0xc259; - fc->write_ibi_reg(fc,sw_reset_210,v210); - msleep(1); - - /* reset the periphical devices */ - - v204 = fc->read_ibi_reg(fc,misc_204); - v204.misc_204.Per_reset_sig = 0; - fc->write_ibi_reg(fc,misc_204,v204); - msleep(1); - v204.misc_204.Per_reset_sig = 1; - fc->write_ibi_reg(fc,misc_204,v204); -} - -void flexcop_reset_block_300(struct flexcop_device *fc) -{ - flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208), - v210 = fc->read_ibi_reg(fc, sw_reset_210); - - deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw); - fc->write_ibi_reg(fc,ctrl_208,ibi_zero); - - v210.sw_reset_210.reset_block_300 = 1; - v210.sw_reset_210.Block_reset_enable = 0xb2; - - fc->write_ibi_reg(fc,sw_reset_210,v210); - fc->write_ibi_reg(fc,ctrl_208,v208_save); -} - -struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) -{ - void *bus; - struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), - GFP_KERNEL); - if (!fc) { - err("no memory"); - return NULL; - } - - bus = kzalloc(bus_specific_len, GFP_KERNEL); - if (!bus) { - err("no memory"); - kfree(fc); - return NULL; - } - - fc->bus_specific = bus; - - return fc; -} -EXPORT_SYMBOL(flexcop_device_kmalloc); - -void flexcop_device_kfree(struct flexcop_device *fc) -{ - kfree(fc->bus_specific); - kfree(fc); -} -EXPORT_SYMBOL(flexcop_device_kfree); - -int flexcop_device_initialize(struct flexcop_device *fc) -{ - int ret; - ibi_zero.raw = 0; - - flexcop_reset(fc); - flexcop_determine_revision(fc); - flexcop_sram_init(fc); - flexcop_hw_filter_init(fc); - flexcop_smc_ctrl(fc, 0); - - ret = flexcop_dvb_init(fc); - if (ret) - goto error; - - /* i2c has to be done before doing EEProm stuff - - * because the EEProm is accessed via i2c */ - ret = flexcop_i2c_init(fc); - if (ret) - goto error; - - /* do the MAC address reading after initializing the dvb_adapter */ - if (fc->get_mac_addr(fc, 0) == 0) { - u8 *b = fc->dvb_adapter.proposed_mac; - info("MAC address = %pM", b); - flexcop_set_mac_filter(fc,b); - flexcop_mac_filter_ctrl(fc,1); - } else - warn("reading of MAC address failed.\n"); - - ret = flexcop_frontend_init(fc); - if (ret) - goto error; - - flexcop_device_name(fc,"initialization of","complete"); - return 0; - -error: - flexcop_device_exit(fc); - return ret; -} -EXPORT_SYMBOL(flexcop_device_initialize); - -void flexcop_device_exit(struct flexcop_device *fc) -{ - flexcop_frontend_exit(fc); - flexcop_i2c_exit(fc); - flexcop_dvb_exit(fc); -} -EXPORT_SYMBOL(flexcop_device_exit); - -static int flexcop_module_init(void) -{ - info(DRIVER_NAME " loaded successfully"); - return 0; -} - -static void flexcop_module_cleanup(void) -{ - info(DRIVER_NAME " unloaded successfully"); -} - -module_init(flexcop_module_init); -module_exit(flexcop_module_cleanup); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h deleted file mode 100644 index 897b10c85ad..00000000000 --- a/drivers/media/dvb/b2c2/flexcop.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop.h - private header file for all flexcop-chip-source files - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_H__ -#define __FLEXCOP_H___ - -#define FC_LOG_PREFIX "b2c2-flexcop" -#include "flexcop-common.h" - -extern int b2c2_flexcop_debug; - -/* debug */ -#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) -#else -#define dprintk(level,args...) -#endif - -#define deb_info(args...) dprintk(0x01, args) -#define deb_tuner(args...) dprintk(0x02, args) -#define deb_i2c(args...) dprintk(0x04, args) -#define deb_ts(args...) dprintk(0x08, args) -#define deb_sram(args...) dprintk(0x10, args) -#define deb_rdump(args...) dprintk(0x20, args) - -#endif diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h deleted file mode 100644 index 8f64bdbd72b..00000000000 --- a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h +++ /dev/null @@ -1,455 +0,0 @@ -/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * register descriptions - * see flexcop.c for copyright information - */ -/* This file is automatically generated, do not edit things here. */ -#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ -#define __FLEXCOP_IBI_VALUE_INCLUDED__ - -typedef union { - u32 raw; - - struct { - u32 dma_address0 :30; - u32 dma_0No_update : 1; - u32 dma_0start : 1; - } dma_0x0; - - struct { - u32 dma_addr_size :24; - u32 DMA_maxpackets : 8; - } dma_0x4_remap; - - struct { - u32 dma_addr_size :24; - u32 unused : 1; - u32 dma1timer : 7; - } dma_0x4_read; - - struct { - u32 dma_addr_size :24; - u32 dmatimer : 7; - u32 unused : 1; - } dma_0x4_write; - - struct { - u32 dma_cur_addr :30; - u32 unused : 2; - } dma_0x8; - - struct { - u32 dma_address1 :30; - u32 remap_enable : 1; - u32 dma_1start : 1; - } dma_0xc; - - struct { - u32 st_done : 1; - u32 no_base_addr_ack_error : 1; - u32 twoWS_port_reg : 2; - u32 total_bytes : 2; - u32 twoWS_rw : 1; - u32 working_start : 1; - u32 data1_reg : 8; - u32 baseaddr : 8; - u32 reserved1 : 1; - u32 chipaddr : 7; - } tw_sm_c_100; - - struct { - u32 unused : 6; - u32 force_stop : 1; - u32 exlicit_stops : 1; - u32 data4_reg : 8; - u32 data3_reg : 8; - u32 data2_reg : 8; - } tw_sm_c_104; - - struct { - u32 reserved2 :19; - u32 tlo1 : 5; - u32 reserved1 : 2; - u32 thi1 : 6; - } tw_sm_c_108; - - struct { - u32 reserved2 :19; - u32 tlo1 : 5; - u32 reserved1 : 2; - u32 thi1 : 6; - } tw_sm_c_10c; - - struct { - u32 reserved2 :19; - u32 tlo1 : 5; - u32 reserved1 : 2; - u32 thi1 : 6; - } tw_sm_c_110; - - struct { - u32 LNB_CTLPrescaler_sig : 2; - u32 LNB_CTLLowCount_sig :15; - u32 LNB_CTLHighCount_sig :15; - } lnb_switch_freq_200; - - struct { - u32 Rev_N_sig_reserved2 : 1; - u32 Rev_N_sig_caps : 1; - u32 Rev_N_sig_reserved1 : 2; - u32 Rev_N_sig_revision_hi : 4; - u32 reserved :20; - u32 Per_reset_sig : 1; - u32 LNB_L_H_sig : 1; - u32 ACPI3_sig : 1; - u32 ACPI1_sig : 1; - } misc_204; - - struct { - u32 unused : 9; - u32 Mailbox_from_V8_Enable_sig : 1; - u32 DMA2_Size_IRQ_Enable_sig : 1; - u32 DMA1_Size_IRQ_Enable_sig : 1; - u32 DMA2_Timer_Enable_sig : 1; - u32 DMA2_IRQ_Enable_sig : 1; - u32 DMA1_Timer_Enable_sig : 1; - u32 DMA1_IRQ_Enable_sig : 1; - u32 Rcv_Data_sig : 1; - u32 MAC_filter_Mode_sig : 1; - u32 Multi2_Enable_sig : 1; - u32 Per_CA_Enable_sig : 1; - u32 SMC_Enable_sig : 1; - u32 CA_Enable_sig : 1; - u32 WAN_CA_Enable_sig : 1; - u32 WAN_Enable_sig : 1; - u32 Mask_filter_sig : 1; - u32 Null_filter_sig : 1; - u32 ECM_filter_sig : 1; - u32 EMM_filter_sig : 1; - u32 PMT_filter_sig : 1; - u32 PCR_filter_sig : 1; - u32 Stream2_filter_sig : 1; - u32 Stream1_filter_sig : 1; - } ctrl_208; - - struct { - u32 reserved :21; - u32 Transport_Error : 1; - u32 LLC_SNAP_FLAG_set : 1; - u32 Continuity_error_flag : 1; - u32 Data_receiver_error : 1; - u32 Mailbox_from_V8_Status_sig : 1; - u32 DMA2_Size_IRQ_Status : 1; - u32 DMA1_Size_IRQ_Status : 1; - u32 DMA2_Timer_Status : 1; - u32 DMA2_IRQ_Status : 1; - u32 DMA1_Timer_Status : 1; - u32 DMA1_IRQ_Status : 1; - } irq_20c; - - struct { - u32 Special_controls :16; - u32 Block_reset_enable : 8; - u32 reset_block_700 : 1; - u32 reset_block_600 : 1; - u32 reset_block_500 : 1; - u32 reset_block_400 : 1; - u32 reset_block_300 : 1; - u32 reset_block_200 : 1; - u32 reset_block_100 : 1; - u32 reset_block_000 : 1; - } sw_reset_210; - - struct { - u32 unused2 :20; - u32 polarity_PS_ERR_sig : 1; - u32 polarity_PS_SYNC_sig : 1; - u32 polarity_PS_VALID_sig : 1; - u32 polarity_PS_CLK_sig : 1; - u32 unused1 : 3; - u32 s2p_sel_sig : 1; - u32 section_pkg_enable_sig : 1; - u32 halt_V8_sig : 1; - u32 v2WS_oe_sig : 1; - u32 vuart_oe_sig : 1; - } misc_214; - - struct { - u32 Mailbox_from_V8 :32; - } mbox_v8_to_host_218; - - struct { - u32 sysramaccess_busmuster : 1; - u32 sysramaccess_write : 1; - u32 unused : 7; - u32 sysramaccess_addr :15; - u32 sysramaccess_data : 8; - } mbox_host_to_v8_21c; - - struct { - u32 debug_fifo_problem : 1; - u32 debug_flag_write_status00 : 1; - u32 Stream2_trans : 1; - u32 Stream2_PID :13; - u32 debug_flag_pid_saved : 1; - u32 MAC_Multicast_filter : 1; - u32 Stream1_trans : 1; - u32 Stream1_PID :13; - } pid_filter_300; - - struct { - u32 reserved : 2; - u32 PMT_trans : 1; - u32 PMT_PID :13; - u32 debug_overrun2 : 1; - u32 debug_overrun3 : 1; - u32 PCR_trans : 1; - u32 PCR_PID :13; - } pid_filter_304; - - struct { - u32 reserved : 2; - u32 ECM_trans : 1; - u32 ECM_PID :13; - u32 EMM_filter_6 : 1; - u32 EMM_filter_4 : 1; - u32 EMM_trans : 1; - u32 EMM_PID :13; - } pid_filter_308; - - struct { - u32 unused2 : 3; - u32 Group_mask :13; - u32 unused1 : 2; - u32 Group_trans : 1; - u32 Group_PID :13; - } pid_filter_30c_ext_ind_0_7; - - struct { - u32 unused :15; - u32 net_master_read :17; - } pid_filter_30c_ext_ind_1; - - struct { - u32 unused :15; - u32 net_master_write :17; - } pid_filter_30c_ext_ind_2; - - struct { - u32 unused :15; - u32 next_net_master_write :17; - } pid_filter_30c_ext_ind_3; - - struct { - u32 reserved2 : 5; - u32 stack_read :10; - u32 reserved1 : 6; - u32 state_write :10; - u32 unused1 : 1; - } pid_filter_30c_ext_ind_4; - - struct { - u32 unused :22; - u32 stack_cnt :10; - } pid_filter_30c_ext_ind_5; - - struct { - u32 unused : 4; - u32 data_size_reg :12; - u32 write_status4 : 2; - u32 write_status1 : 2; - u32 pid_fsm_save_reg300 : 2; - u32 pid_fsm_save_reg4 : 2; - u32 pid_fsm_save_reg3 : 2; - u32 pid_fsm_save_reg2 : 2; - u32 pid_fsm_save_reg1 : 2; - u32 pid_fsm_save_reg0 : 2; - } pid_filter_30c_ext_ind_6; - - struct { - u32 unused :22; - u32 pass_alltables : 1; - u32 AB_select : 1; - u32 extra_index_reg : 3; - u32 index_reg : 5; - } index_reg_310; - - struct { - u32 reserved :17; - u32 PID_enable_bit : 1; - u32 PID_trans : 1; - u32 PID :13; - } pid_n_reg_314; - - struct { - u32 reserved : 6; - u32 HighAB_bit : 1; - u32 Enable_bit : 1; - u32 A6_byte : 8; - u32 A5_byte : 8; - u32 A4_byte : 8; - } mac_low_reg_318; - - struct { - u32 reserved : 8; - u32 A3_byte : 8; - u32 A2_byte : 8; - u32 A1_byte : 8; - } mac_high_reg_31c; - - struct { - u32 data_Tag_ID :16; - u32 reserved :16; - } data_tag_400; - - struct { - u32 Card_IDbyte3 : 8; - u32 Card_IDbyte4 : 8; - u32 Card_IDbyte5 : 8; - u32 Card_IDbyte6 : 8; - } card_id_408; - - struct { - u32 Card_IDbyte1 : 8; - u32 Card_IDbyte2 : 8; - } card_id_40c; - - struct { - u32 MAC6 : 8; - u32 MAC3 : 8; - u32 MAC2 : 8; - u32 MAC1 : 8; - } mac_address_418; - - struct { - u32 reserved :16; - u32 MAC8 : 8; - u32 MAC7 : 8; - } mac_address_41c; - - struct { - u32 reserved :21; - u32 txbuffempty : 1; - u32 ReceiveByteFrameError : 1; - u32 ReceiveDataReady : 1; - u32 transmitter_data_byte : 8; - } ci_600; - - struct { - u32 pi_component_reg : 3; - u32 pi_rw : 1; - u32 pi_ha :20; - u32 pi_d : 8; - } pi_604; - - struct { - u32 pi_busy_n : 1; - u32 pi_wait_n : 1; - u32 pi_timeout_status : 1; - u32 pi_CiMax_IRQ_n : 1; - u32 config_cclk : 1; - u32 config_cs_n : 1; - u32 config_wr_n : 1; - u32 config_Prog_n : 1; - u32 config_Init_stat : 1; - u32 config_Done_stat : 1; - u32 pcmcia_b_mod_pwr_n : 1; - u32 pcmcia_a_mod_pwr_n : 1; - u32 reserved : 3; - u32 Timer_addr : 5; - u32 unused : 1; - u32 timer_data : 7; - u32 Timer_Load_req : 1; - u32 Timer_Read_req : 1; - u32 oncecycle_read : 1; - u32 serialReset : 1; - } pi_608; - - struct { - u32 reserved : 6; - u32 rw_flag : 1; - u32 dvb_en : 1; - u32 key_array_row : 5; - u32 key_array_col : 3; - u32 key_code : 2; - u32 key_enable : 1; - u32 PID :13; - } dvb_reg_60c; - - struct { - u32 start_sram_ibi : 1; - u32 reserved2 : 1; - u32 ce_pin_reg : 1; - u32 oe_pin_reg : 1; - u32 reserved1 : 3; - u32 sc_xfer_bit : 1; - u32 sram_data : 8; - u32 sram_rw : 1; - u32 sram_addr :15; - } sram_ctrl_reg_700; - - struct { - u32 net_addr_write :16; - u32 net_addr_read :16; - } net_buf_reg_704; - - struct { - u32 cai_cnt : 4; - u32 reserved2 : 6; - u32 cai_write :11; - u32 reserved1 : 5; - u32 cai_read :11; - } cai_buf_reg_708; - - struct { - u32 cao_cnt : 4; - u32 reserved2 : 6; - u32 cap_write :11; - u32 reserved1 : 5; - u32 cao_read :11; - } cao_buf_reg_70c; - - struct { - u32 media_cnt : 4; - u32 reserved2 : 6; - u32 media_write :11; - u32 reserved1 : 5; - u32 media_read :11; - } media_buf_reg_710; - - struct { - u32 reserved :17; - u32 ctrl_maximumfill : 1; - u32 ctrl_sramdma : 1; - u32 ctrl_usb_wan : 1; - u32 cao_ovflow_error : 1; - u32 cai_ovflow_error : 1; - u32 media_ovflow_error : 1; - u32 net_ovflow_error : 1; - u32 MEDIA_Dest : 2; - u32 CAO_Dest : 2; - u32 CAI_Dest : 2; - u32 NET_Dest : 2; - } sram_dest_reg_714; - - struct { - u32 reserved3 :11; - u32 net_addr_write : 1; - u32 reserved2 : 3; - u32 net_addr_read : 1; - u32 reserved1 : 4; - u32 net_cnt :12; - } net_buf_reg_718; - - struct { - u32 reserved3 : 4; - u32 wan_pkt_frame : 4; - u32 reserved2 : 4; - u32 sram_memmap : 2; - u32 sram_chip : 2; - u32 wan_wait_state : 8; - u32 reserved1 : 6; - u32 wan_speed_sig : 2; - } wan_ctrl_reg_71c; -} flexcop_ibi_value; - -#endif diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h deleted file mode 100644 index c75830d7d94..00000000000 --- a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h +++ /dev/null @@ -1,455 +0,0 @@ -/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * register descriptions - * see flexcop.c for copyright information - */ -/* This file is automatically generated, do not edit things here. */ -#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ -#define __FLEXCOP_IBI_VALUE_INCLUDED__ - -typedef union { - u32 raw; - - struct { - u32 dma_0start : 1; - u32 dma_0No_update : 1; - u32 dma_address0 :30; - } dma_0x0; - - struct { - u32 DMA_maxpackets : 8; - u32 dma_addr_size :24; - } dma_0x4_remap; - - struct { - u32 dma1timer : 7; - u32 unused : 1; - u32 dma_addr_size :24; - } dma_0x4_read; - - struct { - u32 unused : 1; - u32 dmatimer : 7; - u32 dma_addr_size :24; - } dma_0x4_write; - - struct { - u32 unused : 2; - u32 dma_cur_addr :30; - } dma_0x8; - - struct { - u32 dma_1start : 1; - u32 remap_enable : 1; - u32 dma_address1 :30; - } dma_0xc; - - struct { - u32 chipaddr : 7; - u32 reserved1 : 1; - u32 baseaddr : 8; - u32 data1_reg : 8; - u32 working_start : 1; - u32 twoWS_rw : 1; - u32 total_bytes : 2; - u32 twoWS_port_reg : 2; - u32 no_base_addr_ack_error : 1; - u32 st_done : 1; - } tw_sm_c_100; - - struct { - u32 data2_reg : 8; - u32 data3_reg : 8; - u32 data4_reg : 8; - u32 exlicit_stops : 1; - u32 force_stop : 1; - u32 unused : 6; - } tw_sm_c_104; - - struct { - u32 thi1 : 6; - u32 reserved1 : 2; - u32 tlo1 : 5; - u32 reserved2 :19; - } tw_sm_c_108; - - struct { - u32 thi1 : 6; - u32 reserved1 : 2; - u32 tlo1 : 5; - u32 reserved2 :19; - } tw_sm_c_10c; - - struct { - u32 thi1 : 6; - u32 reserved1 : 2; - u32 tlo1 : 5; - u32 reserved2 :19; - } tw_sm_c_110; - - struct { - u32 LNB_CTLHighCount_sig :15; - u32 LNB_CTLLowCount_sig :15; - u32 LNB_CTLPrescaler_sig : 2; - } lnb_switch_freq_200; - - struct { - u32 ACPI1_sig : 1; - u32 ACPI3_sig : 1; - u32 LNB_L_H_sig : 1; - u32 Per_reset_sig : 1; - u32 reserved :20; - u32 Rev_N_sig_revision_hi : 4; - u32 Rev_N_sig_reserved1 : 2; - u32 Rev_N_sig_caps : 1; - u32 Rev_N_sig_reserved2 : 1; - } misc_204; - - struct { - u32 Stream1_filter_sig : 1; - u32 Stream2_filter_sig : 1; - u32 PCR_filter_sig : 1; - u32 PMT_filter_sig : 1; - u32 EMM_filter_sig : 1; - u32 ECM_filter_sig : 1; - u32 Null_filter_sig : 1; - u32 Mask_filter_sig : 1; - u32 WAN_Enable_sig : 1; - u32 WAN_CA_Enable_sig : 1; - u32 CA_Enable_sig : 1; - u32 SMC_Enable_sig : 1; - u32 Per_CA_Enable_sig : 1; - u32 Multi2_Enable_sig : 1; - u32 MAC_filter_Mode_sig : 1; - u32 Rcv_Data_sig : 1; - u32 DMA1_IRQ_Enable_sig : 1; - u32 DMA1_Timer_Enable_sig : 1; - u32 DMA2_IRQ_Enable_sig : 1; - u32 DMA2_Timer_Enable_sig : 1; - u32 DMA1_Size_IRQ_Enable_sig : 1; - u32 DMA2_Size_IRQ_Enable_sig : 1; - u32 Mailbox_from_V8_Enable_sig : 1; - u32 unused : 9; - } ctrl_208; - - struct { - u32 DMA1_IRQ_Status : 1; - u32 DMA1_Timer_Status : 1; - u32 DMA2_IRQ_Status : 1; - u32 DMA2_Timer_Status : 1; - u32 DMA1_Size_IRQ_Status : 1; - u32 DMA2_Size_IRQ_Status : 1; - u32 Mailbox_from_V8_Status_sig : 1; - u32 Data_receiver_error : 1; - u32 Continuity_error_flag : 1; - u32 LLC_SNAP_FLAG_set : 1; - u32 Transport_Error : 1; - u32 reserved :21; - } irq_20c; - - struct { - u32 reset_block_000 : 1; - u32 reset_block_100 : 1; - u32 reset_block_200 : 1; - u32 reset_block_300 : 1; - u32 reset_block_400 : 1; - u32 reset_block_500 : 1; - u32 reset_block_600 : 1; - u32 reset_block_700 : 1; - u32 Block_reset_enable : 8; - u32 Special_controls :16; - } sw_reset_210; - - struct { - u32 vuart_oe_sig : 1; - u32 v2WS_oe_sig : 1; - u32 halt_V8_sig : 1; - u32 section_pkg_enable_sig : 1; - u32 s2p_sel_sig : 1; - u32 unused1 : 3; - u32 polarity_PS_CLK_sig : 1; - u32 polarity_PS_VALID_sig : 1; - u32 polarity_PS_SYNC_sig : 1; - u32 polarity_PS_ERR_sig : 1; - u32 unused2 :20; - } misc_214; - - struct { - u32 Mailbox_from_V8 :32; - } mbox_v8_to_host_218; - - struct { - u32 sysramaccess_data : 8; - u32 sysramaccess_addr :15; - u32 unused : 7; - u32 sysramaccess_write : 1; - u32 sysramaccess_busmuster : 1; - } mbox_host_to_v8_21c; - - struct { - u32 Stream1_PID :13; - u32 Stream1_trans : 1; - u32 MAC_Multicast_filter : 1; - u32 debug_flag_pid_saved : 1; - u32 Stream2_PID :13; - u32 Stream2_trans : 1; - u32 debug_flag_write_status00 : 1; - u32 debug_fifo_problem : 1; - } pid_filter_300; - - struct { - u32 PCR_PID :13; - u32 PCR_trans : 1; - u32 debug_overrun3 : 1; - u32 debug_overrun2 : 1; - u32 PMT_PID :13; - u32 PMT_trans : 1; - u32 reserved : 2; - } pid_filter_304; - - struct { - u32 EMM_PID :13; - u32 EMM_trans : 1; - u32 EMM_filter_4 : 1; - u32 EMM_filter_6 : 1; - u32 ECM_PID :13; - u32 ECM_trans : 1; - u32 reserved : 2; - } pid_filter_308; - - struct { - u32 Group_PID :13; - u32 Group_trans : 1; - u32 unused1 : 2; - u32 Group_mask :13; - u32 unused2 : 3; - } pid_filter_30c_ext_ind_0_7; - - struct { - u32 net_master_read :17; - u32 unused :15; - } pid_filter_30c_ext_ind_1; - - struct { - u32 net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_2; - - struct { - u32 next_net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_3; - - struct { - u32 unused1 : 1; - u32 state_write :10; - u32 reserved1 : 6; - u32 stack_read :10; - u32 reserved2 : 5; - } pid_filter_30c_ext_ind_4; - - struct { - u32 stack_cnt :10; - u32 unused :22; - } pid_filter_30c_ext_ind_5; - - struct { - u32 pid_fsm_save_reg0 : 2; - u32 pid_fsm_save_reg1 : 2; - u32 pid_fsm_save_reg2 : 2; - u32 pid_fsm_save_reg3 : 2; - u32 pid_fsm_save_reg4 : 2; - u32 pid_fsm_save_reg300 : 2; - u32 write_status1 : 2; - u32 write_status4 : 2; - u32 data_size_reg :12; - u32 unused : 4; - } pid_filter_30c_ext_ind_6; - - struct { - u32 index_reg : 5; - u32 extra_index_reg : 3; - u32 AB_select : 1; - u32 pass_alltables : 1; - u32 unused :22; - } index_reg_310; - - struct { - u32 PID :13; - u32 PID_trans : 1; - u32 PID_enable_bit : 1; - u32 reserved :17; - } pid_n_reg_314; - - struct { - u32 A4_byte : 8; - u32 A5_byte : 8; - u32 A6_byte : 8; - u32 Enable_bit : 1; - u32 HighAB_bit : 1; - u32 reserved : 6; - } mac_low_reg_318; - - struct { - u32 A1_byte : 8; - u32 A2_byte : 8; - u32 A3_byte : 8; - u32 reserved : 8; - } mac_high_reg_31c; - - struct { - u32 reserved :16; - u32 data_Tag_ID :16; - } data_tag_400; - - struct { - u32 Card_IDbyte6 : 8; - u32 Card_IDbyte5 : 8; - u32 Card_IDbyte4 : 8; - u32 Card_IDbyte3 : 8; - } card_id_408; - - struct { - u32 Card_IDbyte2 : 8; - u32 Card_IDbyte1 : 8; - } card_id_40c; - - struct { - u32 MAC1 : 8; - u32 MAC2 : 8; - u32 MAC3 : 8; - u32 MAC6 : 8; - } mac_address_418; - - struct { - u32 MAC7 : 8; - u32 MAC8 : 8; - u32 reserved :16; - } mac_address_41c; - - struct { - u32 transmitter_data_byte : 8; - u32 ReceiveDataReady : 1; - u32 ReceiveByteFrameError : 1; - u32 txbuffempty : 1; - u32 reserved :21; - } ci_600; - - struct { - u32 pi_d : 8; - u32 pi_ha :20; - u32 pi_rw : 1; - u32 pi_component_reg : 3; - } pi_604; - - struct { - u32 serialReset : 1; - u32 oncecycle_read : 1; - u32 Timer_Read_req : 1; - u32 Timer_Load_req : 1; - u32 timer_data : 7; - u32 unused : 1; - u32 Timer_addr : 5; - u32 reserved : 3; - u32 pcmcia_a_mod_pwr_n : 1; - u32 pcmcia_b_mod_pwr_n : 1; - u32 config_Done_stat : 1; - u32 config_Init_stat : 1; - u32 config_Prog_n : 1; - u32 config_wr_n : 1; - u32 config_cs_n : 1; - u32 config_cclk : 1; - u32 pi_CiMax_IRQ_n : 1; - u32 pi_timeout_status : 1; - u32 pi_wait_n : 1; - u32 pi_busy_n : 1; - } pi_608; - - struct { - u32 PID :13; - u32 key_enable : 1; - u32 key_code : 2; - u32 key_array_col : 3; - u32 key_array_row : 5; - u32 dvb_en : 1; - u32 rw_flag : 1; - u32 reserved : 6; - } dvb_reg_60c; - - struct { - u32 sram_addr :15; - u32 sram_rw : 1; - u32 sram_data : 8; - u32 sc_xfer_bit : 1; - u32 reserved1 : 3; - u32 oe_pin_reg : 1; - u32 ce_pin_reg : 1; - u32 reserved2 : 1; - u32 start_sram_ibi : 1; - } sram_ctrl_reg_700; - - struct { - u32 net_addr_read :16; - u32 net_addr_write :16; - } net_buf_reg_704; - - struct { - u32 cai_read :11; - u32 reserved1 : 5; - u32 cai_write :11; - u32 reserved2 : 6; - u32 cai_cnt : 4; - } cai_buf_reg_708; - - struct { - u32 cao_read :11; - u32 reserved1 : 5; - u32 cap_write :11; - u32 reserved2 : 6; - u32 cao_cnt : 4; - } cao_buf_reg_70c; - - struct { - u32 media_read :11; - u32 reserved1 : 5; - u32 media_write :11; - u32 reserved2 : 6; - u32 media_cnt : 4; - } media_buf_reg_710; - - struct { - u32 NET_Dest : 2; - u32 CAI_Dest : 2; - u32 CAO_Dest : 2; - u32 MEDIA_Dest : 2; - u32 net_ovflow_error : 1; - u32 media_ovflow_error : 1; - u32 cai_ovflow_error : 1; - u32 cao_ovflow_error : 1; - u32 ctrl_usb_wan : 1; - u32 ctrl_sramdma : 1; - u32 ctrl_maximumfill : 1; - u32 reserved :17; - } sram_dest_reg_714; - - struct { - u32 net_cnt :12; - u32 reserved1 : 4; - u32 net_addr_read : 1; - u32 reserved2 : 3; - u32 net_addr_write : 1; - u32 reserved3 :11; - } net_buf_reg_718; - - struct { - u32 wan_speed_sig : 2; - u32 reserved1 : 6; - u32 wan_wait_state : 8; - u32 sram_chip : 2; - u32 sram_memmap : 2; - u32 reserved2 : 4; - u32 wan_pkt_frame : 4; - u32 reserved3 : 4; - } wan_ctrl_reg_71c; -} flexcop_ibi_value; - -#endif diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig deleted file mode 100644 index 8668e634c7e..00000000000 --- a/drivers/media/dvb/bt8xx/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config DVB_BT8XX - tristate "BT8xx based PCI cards" - depends on DVB_CORE && PCI && I2C && VIDEO_BT848 - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_SP887X if !DVB_FE_CUSTOMISE - select DVB_NXT6000 if !DVB_FE_CUSTOMISE - select DVB_CX24110 if !DVB_FE_CUSTOMISE - select DVB_OR51211 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - help - Support for PCI cards based on the Bt8xx PCI bridge. Examples are - the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, - the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and - some AVerMedia 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 if you own such a device and want to use it. diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile deleted file mode 100644 index 36591ae505f..00000000000 --- a/drivers/media/dvb/bt8xx/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/video/bt8xx -ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c deleted file mode 100644 index b34fa95185e..00000000000 --- a/drivers/media/dvb/bt8xx/bt878.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card - * - * Copyright (C) 2002 Peter Hettkamp - * - * large parts based on the bttv driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) - * & Marcus Metzler (mocm@metzlerbros.de) - * (c) 1999,2000 Gerd Knorr - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "bt878.h" -#include "dst_priv.h" - - -/**************************************/ -/* Miscellaneous utility definitions */ -/**************************************/ - -static unsigned int bt878_verbose = 1; -static unsigned int bt878_debug; - -module_param_named(verbose, bt878_verbose, int, 0444); -MODULE_PARM_DESC(verbose, - "verbose startup messages, default is 1 (yes)"); -module_param_named(debug, bt878_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); - -int bt878_num; -struct bt878 bt878[BT878_MAX]; - -EXPORT_SYMBOL(bt878_num); -EXPORT_SYMBOL(bt878); - -#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr))) -#define btread(adr) bmtread(bt->bt878_mem+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#if defined(dprintk) -#undef dprintk -#endif -#define dprintk(fmt, arg...) \ - do { \ - if (bt878_debug) \ - printk(KERN_DEBUG fmt, ##arg); \ - } while (0) - -static void bt878_mem_free(struct bt878 *bt) -{ - if (bt->buf_cpu) { - pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, - bt->buf_dma); - bt->buf_cpu = NULL; - } - - if (bt->risc_cpu) { - pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, - bt->risc_dma); - bt->risc_cpu = NULL; - } -} - -static int bt878_mem_alloc(struct bt878 *bt) -{ - if (!bt->buf_cpu) { - bt->buf_size = 128 * 1024; - - bt->buf_cpu = - pci_alloc_consistent(bt->dev, bt->buf_size, - &bt->buf_dma); - - if (!bt->buf_cpu) - return -ENOMEM; - - memset(bt->buf_cpu, 0, bt->buf_size); - } - - if (!bt->risc_cpu) { - bt->risc_size = PAGE_SIZE; - bt->risc_cpu = - pci_alloc_consistent(bt->dev, bt->risc_size, - &bt->risc_dma); - - if (!bt->risc_cpu) { - bt878_mem_free(bt); - return -ENOMEM; - } - - memset(bt->risc_cpu, 0, bt->risc_size); - } - - return 0; -} - -/* RISC instructions */ -#define RISC_WRITE (0x01 << 28) -#define RISC_JUMP (0x07 << 28) -#define RISC_SYNC (0x08 << 28) - -/* RISC bits */ -#define RISC_WR_SOL (1 << 27) -#define RISC_WR_EOL (1 << 26) -#define RISC_IRQ (1 << 24) -#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) -#define RISC_SYNC_RESYNC (1 << 15) -#define RISC_SYNC_FM1 0x06 -#define RISC_SYNC_VRO 0x0C - -#define RISC_FLUSH() bt->risc_pos = 0 -#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) - -static int bt878_make_risc(struct bt878 *bt) -{ - bt->block_bytes = bt->buf_size >> 4; - bt->block_count = 1 << 4; - bt->line_bytes = bt->block_bytes; - bt->line_count = bt->block_count; - - while (bt->line_bytes > 4095) { - bt->line_bytes >>= 1; - bt->line_count <<= 1; - } - - if (bt->line_count > 255) { - printk(KERN_ERR "bt878: buffer size error!\n"); - return -EINVAL; - } - return 0; -} - - -static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) -{ - u32 buf_pos = 0; - u32 line; - - RISC_FLUSH(); - RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); - RISC_INSTR(0); - - dprintk("bt878: risc len lines %u, bytes per line %u\n", - bt->line_count, bt->line_bytes); - for (line = 0; line < bt->line_count; line++) { - // At the beginning of every block we issue an IRQ with previous (finished) block number set - if (!(buf_pos % bt->block_bytes)) - RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | - RISC_IRQ | - RISC_STATUS(((buf_pos / - bt->block_bytes) + - (bt->block_count - - 1)) % - bt->block_count) | bt-> - line_bytes); - else - RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | - bt->line_bytes); - RISC_INSTR(bt->buf_dma + buf_pos); - buf_pos += bt->line_bytes; - } - - RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO); - RISC_INSTR(0); - - RISC_INSTR(RISC_JUMP); - RISC_INSTR(bt->risc_dma); - - btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); -} - -/*****************************/ -/* Start/Stop grabbing funcs */ -/*****************************/ - -void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, - u32 irq_err_ignore) -{ - u32 int_mask; - - dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg); - /* complete the writing of the risc dma program now we have - * the card specifics - */ - bt878_risc_program(bt, op_sync_orin); - controlreg &= ~0x1f; - controlreg |= 0x1b; - - btwrite(bt->risc_dma, BT878_ARISC_START); - - /* original int mask had : - * 6 2 8 4 0 - * 1111 1111 1000 0000 0000 - * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI - * Hacked for DST to: - * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI - */ - int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | - BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | - BT878_AFBUS | BT878_ARISCI; - - - /* ignore pesky bits */ - int_mask &= ~irq_err_ignore; - - btwrite(int_mask, BT878_AINT_MASK); - btwrite(controlreg, BT878_AGPIO_DMA_CTL); -} - -void bt878_stop(struct bt878 *bt) -{ - u32 stat; - int i = 0; - - dprintk("bt878 debug: bt878_stop\n"); - - btwrite(0, BT878_AINT_MASK); - btand(~0x13, BT878_AGPIO_DMA_CTL); - - do { - stat = btread(BT878_AINT_STAT); - if (!(stat & BT878_ARISC_EN)) - break; - i++; - } while (i < 500); - - dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n", - bt->nr, i, stat); -} - -EXPORT_SYMBOL(bt878_start); -EXPORT_SYMBOL(bt878_stop); - -/*****************************/ -/* Interrupt service routine */ -/*****************************/ - -static irqreturn_t bt878_irq(int irq, void *dev_id) -{ - u32 stat, astat, mask; - int count; - struct bt878 *bt; - - bt = (struct bt878 *) dev_id; - - count = 0; - while (1) { - stat = btread(BT878_AINT_STAT); - mask = btread(BT878_AINT_MASK); - if (!(astat = (stat & mask))) - return IRQ_NONE; /* this interrupt is not for me */ -/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ - btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */ - - - if (astat & (BT878_ASCERR | BT878_AOCERR)) { - if (bt878_verbose) { - printk(KERN_INFO - "bt878(%d): irq%s%s risc_pc=%08x\n", - bt->nr, - (astat & BT878_ASCERR) ? " SCERR" : - "", - (astat & BT878_AOCERR) ? " OCERR" : - "", btread(BT878_ARISC_PC)); - } - } - if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { - if (bt878_verbose) { - printk(KERN_INFO - "bt878(%d): irq%s%s%s risc_pc=%08x\n", - bt->nr, - (astat & BT878_APABORT) ? " PABORT" : - "", - (astat & BT878_ARIPERR) ? " RIPERR" : - "", - (astat & BT878_APPERR) ? " PPERR" : - "", btread(BT878_ARISC_PC)); - } - } - if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { - if (bt878_verbose) { - printk(KERN_INFO - "bt878(%d): irq%s%s%s risc_pc=%08x\n", - bt->nr, - (astat & BT878_AFDSR) ? " FDSR" : "", - (astat & BT878_AFTRGT) ? " FTRGT" : - "", - (astat & BT878_AFBUS) ? " FBUS" : "", - btread(BT878_ARISC_PC)); - } - } - if (astat & BT878_ARISCI) { - bt->finished_block = (stat & BT878_ARISCS) >> 28; - tasklet_schedule(&bt->tasklet); - break; - } - count++; - if (count > 20) { - btwrite(0, BT878_AINT_MASK); - printk(KERN_ERR - "bt878(%d): IRQ lockup, cleared int mask\n", - bt->nr); - break; - } - } - return IRQ_HANDLED; -} - -int -bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp) -{ - int retval; - - retval = 0; - if (mutex_lock_interruptible(&bt->gpio_lock)) - return -ERESTARTSYS; - /* special gpio signal */ - switch (cmd) { - case DST_IG_ENABLE: - // dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable); - retval = bttv_gpio_enable(bt->bttv_nr, - mp->enb.mask, - mp->enb.enable); - break; - case DST_IG_WRITE: - // dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals); - retval = bttv_write_gpio(bt->bttv_nr, - mp->outp.mask, - mp->outp.highvals); - - break; - case DST_IG_READ: - /* read */ - retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value); - // dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value); - break; - case DST_IG_TS: - /* Set packet size */ - bt->TS_Size = mp->psize; - break; - - default: - retval = -EINVAL; - break; - } - mutex_unlock(&bt->gpio_lock); - return retval; -} - -EXPORT_SYMBOL(bt878_device_control); - -#define BROOKTREE_878_DEVICE(vend, dev, name) \ - { \ - .vendor = PCI_VENDOR_ID_BROOKTREE, \ - .device = PCI_DEVICE_ID_BROOKTREE_878, \ - .subvendor = (vend), .subdevice = (dev), \ - .driver_data = (unsigned long) name \ - } - -static struct pci_device_id bt878_pci_tbl[] __devinitdata = { - BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), - BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), - BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), - BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), - BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), - BROOKTREE_878_DEVICE(0x270f, 0xfc00, - "ChainTech digitop DST-1000 DVB-S"), - BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), - BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), - BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), - BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), - BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), - BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), - { } -}; - -MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); - -static const char * __devinit card_name(const struct pci_device_id *id) -{ - return id->driver_data ? (const char *)id->driver_data : "Unknown"; -} - -/***********************/ -/* PCI device handling */ -/***********************/ - -static int __devinit bt878_probe(struct pci_dev *dev, - const struct pci_device_id *pci_id) -{ - int result = 0; - unsigned char lat; - struct bt878 *bt; -#if defined(__powerpc__) - unsigned int cmd; -#endif - unsigned int cardid; - - printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", - bt878_num); - if (bt878_num >= BT878_MAX) { - printk(KERN_ERR "bt878: Too many devices inserted\n"); - result = -ENOMEM; - goto fail0; - } - if (pci_enable_device(dev)) - return -EIO; - - cardid = dev->subsystem_device << 16; - cardid |= dev->subsystem_vendor; - - printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", - __func__, cardid, card_name(pci_id)); - - bt = &bt878[bt878_num]; - bt->dev = dev; - bt->nr = bt878_num; - bt->shutdown = 0; - - bt->id = dev->device; - bt->irq = dev->irq; - bt->bt878_adr = pci_resource_start(dev, 0); - if (!request_mem_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0), "bt878")) { - result = -EBUSY; - goto fail0; - } - - bt->revision = dev->revision; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - - - printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", - bt878_num, bt->id, bt->revision, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - printk("irq: %d, latency: %d, memory: 0x%lx\n", - bt->irq, lat, bt->bt878_adr); - - -#if defined(__powerpc__) - /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ - /* response on cards with no firmware is not enabled by OF */ - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY); - pci_write_config_dword(dev, PCI_COMMAND, cmd); -#endif - -#ifdef __sparc__ - bt->bt878_mem = (unsigned char *) bt->bt878_adr; -#else - bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000); -#endif - - /* clear interrupt mask */ - btwrite(0, BT848_INT_MASK); - - result = request_irq(bt->irq, bt878_irq, - IRQF_SHARED | IRQF_DISABLED, "bt878", - (void *) bt); - if (result == -EINVAL) { - printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", - bt878_num); - goto fail1; - } - if (result == -EBUSY) { - printk(KERN_ERR - "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n", - bt878_num, bt->irq); - goto fail1; - } - if (result < 0) - goto fail1; - - pci_set_master(dev); - pci_set_drvdata(dev, bt); - - if ((result = bt878_mem_alloc(bt))) { - printk(KERN_ERR "bt878: failed to allocate memory!\n"); - goto fail2; - } - - bt878_make_risc(bt); - btwrite(0, BT878_AINT_MASK); - bt878_num++; - - return 0; - - fail2: - free_irq(bt->irq, bt); - fail1: - release_mem_region(pci_resource_start(bt->dev, 0), - pci_resource_len(bt->dev, 0)); - fail0: - pci_disable_device(dev); - return result; -} - -static void __devexit bt878_remove(struct pci_dev *pci_dev) -{ - u8 command; - struct bt878 *bt = pci_get_drvdata(pci_dev); - - if (bt878_verbose) - printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); - - /* turn off all capturing, DMA and IRQs */ - btand(~0x13, BT878_AGPIO_DMA_CTL); - - /* first disable interrupts before unmapping the memory! */ - btwrite(0, BT878_AINT_MASK); - btwrite(~0U, BT878_AINT_STAT); - - /* disable PCI bus-mastering */ - pci_read_config_byte(bt->dev, PCI_COMMAND, &command); - /* Should this be &=~ ?? */ - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte(bt->dev, PCI_COMMAND, command); - - free_irq(bt->irq, bt); - printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); - if (bt->bt878_mem) - iounmap(bt->bt878_mem); - - release_mem_region(pci_resource_start(bt->dev, 0), - pci_resource_len(bt->dev, 0)); - /* wake up any waiting processes - because shutdown flag is set, no new processes (in this queue) - are expected - */ - bt->shutdown = 1; - bt878_mem_free(bt); - - pci_set_drvdata(pci_dev, NULL); - pci_disable_device(pci_dev); - return; -} - -static struct pci_driver bt878_pci_driver = { - .name = "bt878", - .id_table = bt878_pci_tbl, - .probe = bt878_probe, - .remove = __devexit_p(bt878_remove), -}; - -/*******************************/ -/* Module management functions */ -/*******************************/ - -static int __init bt878_init_module(void) -{ - bt878_num = 0; - - printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", - (BT878_VERSION_CODE >> 16) & 0xff, - (BT878_VERSION_CODE >> 8) & 0xff, - BT878_VERSION_CODE & 0xff); - - return pci_register_driver(&bt878_pci_driver); -} - -static void __exit bt878_cleanup_module(void) -{ - pci_unregister_driver(&bt878_pci_driver); -} - -module_init(bt878_init_module); -module_exit(bt878_cleanup_module); - -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h deleted file mode 100644 index d19b59299d7..00000000000 --- a/drivers/media/dvb/bt8xx/bt878.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - bt878.h - Bt878 audio module (register offsets) - - Copyright (C) 2002 Peter Hettkamp - - 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 _BT878_H_ -#define _BT878_H_ - -#include -#include -#include -#include -#include - -#include "bt848.h" -#include "bttv.h" - -#define BT878_VERSION_CODE 0x000000 - -#define BT878_AINT_STAT 0x100 -#define BT878_ARISCS (0xf<<28) -#define BT878_ARISC_EN (1<<27) -#define BT878_ASCERR (1<<19) -#define BT878_AOCERR (1<<18) -#define BT878_APABORT (1<<17) -#define BT878_ARIPERR (1<<16) -#define BT878_APPERR (1<<15) -#define BT878_AFDSR (1<<14) -#define BT878_AFTRGT (1<<13) -#define BT878_AFBUS (1<<12) -#define BT878_ARISCI (1<<11) -#define BT878_AOFLOW (1<<3) - -#define BT878_AINT_MASK 0x104 - -#define BT878_AGPIO_DMA_CTL 0x10c -#define BT878_A_GAIN (0xf<<28) -#define BT878_A_G2X (1<<27) -#define BT878_A_PWRDN (1<<26) -#define BT878_A_SEL (3<<24) -#define BT878_DA_SCE (1<<23) -#define BT878_DA_LRI (1<<22) -#define BT878_DA_MLB (1<<21) -#define BT878_DA_LRD (0x1f<<16) -#define BT878_DA_DPM (1<<15) -#define BT878_DA_SBR (1<<14) -#define BT878_DA_ES2 (1<<13) -#define BT878_DA_LMT (1<<12) -#define BT878_DA_SDR (0xf<<8) -#define BT878_DA_IOM (3<<6) -#define BT878_DA_APP (1<<5) -#define BT878_ACAP_EN (1<<4) -#define BT878_PKTP (3<<2) -#define BT878_RISC_EN (1<<1) -#define BT878_FIFO_EN 1 - -#define BT878_APACK_LEN 0x110 -#define BT878_AFP_LEN (0xff<<16) -#define BT878_ALP_LEN 0xfff - -#define BT878_ARISC_START 0x114 - -#define BT878_ARISC_PC 0x120 - -/* BT878 FUNCTION 0 REGISTERS */ -#define BT878_GPIO_DMA_CTL 0x10c - -/* Interrupt register */ -#define BT878_INT_STAT 0x100 -#define BT878_INT_MASK 0x104 -#define BT878_I2CRACK (1<<25) -#define BT878_I2CDONE (1<<8) - -#define BT878_MAX 4 - -#define BT878_RISC_SYNC_MASK (1 << 15) - - -#define BTTV_BOARD_UNKNOWN 0x00 -#define BTTV_BOARD_PINNACLESAT 0x5e -#define BTTV_BOARD_NEBULA_DIGITV 0x68 -#define BTTV_BOARD_PC_HDTV 0x70 -#define BTTV_BOARD_TWINHAN_DST 0x71 -#define BTTV_BOARD_AVDVBT_771 0x7b -#define BTTV_BOARD_AVDVBT_761 0x7c -#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 -#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 - -extern int bt878_num; - -struct bt878 { - struct mutex gpio_lock; - unsigned int nr; - unsigned int bttv_nr; - struct i2c_adapter *adapter; - struct pci_dev *dev; - unsigned int id; - unsigned int TS_Size; - unsigned char revision; - unsigned int irq; - unsigned long bt878_adr; - volatile void __iomem *bt878_mem; /* function 1 */ - - volatile u32 finished_block; - volatile u32 last_block; - u32 block_count; - u32 block_bytes; - u32 line_bytes; - u32 line_count; - - u32 buf_size; - u8 *buf_cpu; - dma_addr_t buf_dma; - - u32 risc_size; - __le32 *risc_cpu; - dma_addr_t risc_dma; - u32 risc_pos; - - struct tasklet_struct tasklet; - int shutdown; -}; - -extern struct bt878 bt878[BT878_MAX]; - -void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, - u32 irq_err_ignore); -void bt878_stop(struct bt878 *bt); - -#if defined(__powerpc__) /* big-endian */ -static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) -{ - st_le32(addr, val); - eieio(); -} - -#define bmtwrite(dat,adr) io_st_le32((adr),(dat)) -#define bmtread(adr) ld_le32((adr)) -#else -#define bmtwrite(dat,adr) writel((dat), (adr)) -#define bmtread(adr) readl(adr) -#endif - -#endif diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c deleted file mode 100644 index 430b3eb1181..00000000000 --- a/drivers/media/dvb/bt8xx/dst.c +++ /dev/null @@ -1,1873 +0,0 @@ -/* - Frontend/Card driver for TwinHan DST Frontend - Copyright (C) 2003 Jamie Honan - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "dst_priv.h" -#include "dst_common.h" - -static unsigned int verbose = 1; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); - -static unsigned int dst_addons; -module_param(dst_addons, int, 0644); -MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); - -static unsigned int dst_algo; -module_param(dst_algo, int, 0644); -MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); - -#define HAS_LOCK 1 -#define ATTEMPT_TUNE 2 -#define HAS_POWER 4 - -#define DST_ERROR 0 -#define DST_NOTICE 1 -#define DST_INFO 2 -#define DST_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > DST_ERROR) && (x > y)) \ - printk(KERN_ERR "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_INFO) && (x > y)) \ - printk(KERN_INFO "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ##arg); \ - } \ -} while(0) - -static int dst_command(struct dst_state *state, u8 *data, u8 len); - -static void dst_packsize(struct dst_state *state, int psize) -{ - union dst_gpio_packet bits; - - bits.psize = psize; - bt878_device_control(state->bt, DST_IG_TS, &bits); -} - -static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, - u32 outhigh, int delay) -{ - union dst_gpio_packet enb; - union dst_gpio_packet bits; - int err; - - enb.enb.mask = mask; - enb.enb.enable = enbb; - - dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); - if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); - return -EREMOTEIO; - } - udelay(1000); - /* because complete disabling means no output, no need to do output packet */ - if (enbb == 0) - return 0; - if (delay) - msleep(10); - bits.outp.mask = enbb; - bits.outp.highvals = outhigh; - if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); - return -EREMOTEIO; - } - - return 0; -} - -static int dst_gpio_inb(struct dst_state *state, u8 *result) -{ - union dst_gpio_packet rd_packet; - int err; - - *result = 0; - if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); - return -EREMOTEIO; - } - *result = (u8) rd_packet.rd.value; - - return 0; -} - -int rdc_reset_state(struct dst_state *state) -{ - dprintk(verbose, DST_INFO, 1, "Resetting state machine"); - if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - msleep(10); - if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - msleep(10); - return -1; - } - - return 0; -} -EXPORT_SYMBOL(rdc_reset_state); - -static int rdc_8820_reset(struct dst_state *state) -{ - dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); - if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - udelay(1000); - if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - - return 0; -} - -static int dst_pio_enable(struct dst_state *state) -{ - if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - udelay(1000); - - return 0; -} - -int dst_pio_disable(struct dst_state *state) -{ - if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - if (state->type_flags & DST_TYPE_HAS_FW_1) - udelay(1000); - - return 0; -} -EXPORT_SYMBOL(dst_pio_disable); - -int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) -{ - u8 reply; - int i; - - for (i = 0; i < 200; i++) { - if (dst_gpio_inb(state, &reply) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); - return -1; - } - if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { - dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); - return 1; - } - msleep(10); - } - dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); - - return 0; -} -EXPORT_SYMBOL(dst_wait_dst_ready); - -int dst_error_recovery(struct dst_state *state) -{ - dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); - dst_pio_disable(state); - msleep(10); - dst_pio_enable(state); - msleep(10); - - return 0; -} -EXPORT_SYMBOL(dst_error_recovery); - -int dst_error_bailout(struct dst_state *state) -{ - dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); - rdc_8820_reset(state); - dst_pio_disable(state); - msleep(10); - - return 0; -} -EXPORT_SYMBOL(dst_error_bailout); - -int dst_comm_init(struct dst_state *state) -{ - dprintk(verbose, DST_INFO, 1, "Initializing DST."); - if ((dst_pio_enable(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); - return -1; - } - if ((rdc_reset_state(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); - return -1; - } - if (state->type_flags & DST_TYPE_HAS_FW_1) - msleep(100); - else - msleep(5); - - return 0; -} -EXPORT_SYMBOL(dst_comm_init); - -int write_dst(struct dst_state *state, u8 *data, u8 len) -{ - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = data, - .len = len - }; - - int err; - u8 cnt, i; - - dprintk(verbose, DST_NOTICE, 0, "writing [ "); - for (i = 0; i < len; i++) - dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); - dprintk(verbose, DST_NOTICE, 0, "]\n"); - - for (cnt = 0; cnt < 2; cnt++) { - if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); - dst_error_recovery(state); - continue; - } else - break; - } - if (cnt >= 2) { - dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); - dst_error_bailout(state); - - return -1; - } - - return 0; -} -EXPORT_SYMBOL(write_dst); - -int read_dst(struct dst_state *state, u8 *ret, u8 len) -{ - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = ret, - .len = len - }; - - int err; - int cnt; - - for (cnt = 0; cnt < 2; cnt++) { - if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); - dst_error_recovery(state); - continue; - } else - break; - } - if (cnt >= 2) { - dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); - dst_error_bailout(state); - - return -1; - } - dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); - for (err = 1; err < len; err++) - dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); - if (err > 1) - dprintk(verbose, DST_DEBUG, 0, "\n"); - - return 0; -} -EXPORT_SYMBOL(read_dst); - -static int dst_set_polarization(struct dst_state *state) -{ - switch (state->voltage) { - case SEC_VOLTAGE_13: /* Vertical */ - dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); - state->tx_tuna[8] &= ~0x40; - break; - case SEC_VOLTAGE_18: /* Horizontal */ - dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); - state->tx_tuna[8] |= 0x40; - break; - case SEC_VOLTAGE_OFF: - break; - } - - return 0; -} - -static int dst_set_freq(struct dst_state *state, u32 freq) -{ - state->frequency = freq; - dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); - - if (state->dst_type == DST_TYPE_IS_SAT) { - freq = freq / 1000; - if (freq < 950 || freq > 2150) - return -EINVAL; - state->tx_tuna[2] = (freq >> 8); - state->tx_tuna[3] = (u8) freq; - state->tx_tuna[4] = 0x01; - state->tx_tuna[8] &= ~0x04; - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { - if (freq < 1531) - state->tx_tuna[8] |= 0x04; - } - } else if (state->dst_type == DST_TYPE_IS_TERR) { - freq = freq / 1000; - if (freq < 137000 || freq > 858000) - return -EINVAL; - state->tx_tuna[2] = (freq >> 16) & 0xff; - state->tx_tuna[3] = (freq >> 8) & 0xff; - state->tx_tuna[4] = (u8) freq; - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - freq = freq / 1000; - state->tx_tuna[2] = (freq >> 16) & 0xff; - state->tx_tuna[3] = (freq >> 8) & 0xff; - state->tx_tuna[4] = (u8) freq; - } else if (state->dst_type == DST_TYPE_IS_ATSC) { - freq = freq / 1000; - if (freq < 51000 || freq > 858000) - return -EINVAL; - state->tx_tuna[2] = (freq >> 16) & 0xff; - state->tx_tuna[3] = (freq >> 8) & 0xff; - state->tx_tuna[4] = (u8) freq; - state->tx_tuna[5] = 0x00; /* ATSC */ - state->tx_tuna[6] = 0x00; - if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) - state->tx_tuna[7] = 0x00; /* Digital */ - } else - return -EINVAL; - - return 0; -} - -static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) -{ - state->bandwidth = bandwidth; - - if (state->dst_type != DST_TYPE_IS_TERR) - return -EOPNOTSUPP; - - switch (bandwidth) { - case 6000000: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x06; - else { - state->tx_tuna[6] = 0x06; - state->tx_tuna[7] = 0x00; - } - break; - case 7000000: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x07; - else { - state->tx_tuna[6] = 0x07; - state->tx_tuna[7] = 0x00; - } - break; - case 8000000: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x08; - else { - state->tx_tuna[6] = 0x08; - state->tx_tuna[7] = 0x00; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) -{ - state->inversion = inversion; - switch (inversion) { - case INVERSION_OFF: /* Inversion = Normal */ - state->tx_tuna[8] &= ~0x80; - break; - case INVERSION_ON: - state->tx_tuna[8] |= 0x80; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) -{ - state->fec = fec; - return 0; -} - -static fe_code_rate_t dst_get_fec(struct dst_state *state) -{ - return state->fec; -} - -static int dst_set_symbolrate(struct dst_state *state, u32 srate) -{ - u32 symcalc; - u64 sval; - - state->symbol_rate = srate; - if (state->dst_type == DST_TYPE_IS_TERR) { - return -EOPNOTSUPP; - } - dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); - srate /= 1000; - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_SYMDIV) { - sval = srate; - sval <<= 20; - do_div(sval, 88000); - symcalc = (u32) sval; - dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); - state->tx_tuna[5] = (u8) (symcalc >> 12); - state->tx_tuna[6] = (u8) (symcalc >> 4); - state->tx_tuna[7] = (u8) (symcalc << 4); - } else { - state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; - state->tx_tuna[6] = (u8) (srate >> 8); - state->tx_tuna[7] = (u8) srate; - } - state->tx_tuna[8] &= ~0x20; - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { - if (srate > 8000) - state->tx_tuna[8] |= 0x20; - } - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); - if (!strncmp(state->fw_name, "DCTNEW", 6)) { - state->tx_tuna[5] = (u8) (srate >> 8); - state->tx_tuna[6] = (u8) srate; - state->tx_tuna[7] = 0x00; - } else if (!strncmp(state->fw_name, "DCT-CI", 6)) { - state->tx_tuna[5] = 0x00; - state->tx_tuna[6] = (u8) (srate >> 8); - state->tx_tuna[7] = (u8) srate; - } - } - return 0; -} - -static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) -{ - if (state->dst_type != DST_TYPE_IS_CABLE) - return -EOPNOTSUPP; - - state->modulation = modulation; - switch (modulation) { - case QAM_16: - state->tx_tuna[8] = 0x10; - break; - case QAM_32: - state->tx_tuna[8] = 0x20; - break; - case QAM_64: - state->tx_tuna[8] = 0x40; - break; - case QAM_128: - state->tx_tuna[8] = 0x80; - break; - case QAM_256: - if (!strncmp(state->fw_name, "DCTNEW", 6)) - state->tx_tuna[8] = 0xff; - else if (!strncmp(state->fw_name, "DCT-CI", 6)) - state->tx_tuna[8] = 0x00; - break; - case QPSK: - case QAM_AUTO: - case VSB_8: - case VSB_16: - default: - return -EINVAL; - - } - - return 0; -} - -static fe_modulation_t dst_get_modulation(struct dst_state *state) -{ - return state->modulation; -} - - -u8 dst_check_sum(u8 *buf, u32 len) -{ - u32 i; - u8 val = 0; - if (!len) - return 0; - for (i = 0; i < len; i++) { - val += buf[i]; - } - return ((~val) + 1); -} -EXPORT_SYMBOL(dst_check_sum); - -static void dst_type_flags_print(struct dst_state *state) -{ - u32 type_flags = state->type_flags; - - dprintk(verbose, DST_ERROR, 0, "DST type flags :"); - if (type_flags & DST_TYPE_HAS_TS188) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); - if (type_flags & DST_TYPE_HAS_NEWTUNE_2) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); - if (type_flags & DST_TYPE_HAS_TS204) - dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); - if (type_flags & DST_TYPE_HAS_VLF) - dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); - if (type_flags & DST_TYPE_HAS_SYMDIV) - dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); - if (type_flags & DST_TYPE_HAS_FW_1) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); - if (type_flags & DST_TYPE_HAS_FW_2) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); - if (type_flags & DST_TYPE_HAS_FW_3) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); - dprintk(verbose, DST_ERROR, 0, "\n"); -} - - -static int dst_type_print(struct dst_state *state, u8 type) -{ - char *otype; - switch (type) { - case DST_TYPE_IS_SAT: - otype = "satellite"; - break; - - case DST_TYPE_IS_TERR: - otype = "terrestrial"; - break; - - case DST_TYPE_IS_CABLE: - otype = "cable"; - break; - - case DST_TYPE_IS_ATSC: - otype = "atsc"; - break; - - default: - dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); - return -EINVAL; - } - dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); - - return 0; -} - -static struct tuner_types tuner_list[] = { - { - .tuner_type = TUNER_TYPE_L64724, - .tuner_name = "L 64724", - .board_name = "UNKNOWN", - .fw_name = "UNKNOWN" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1020", - .fw_name = "DST-MOT" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1020", - .fw_name = "DST-03T" - }, - - { - .tuner_type = TUNER_TYPE_MB86A15, - .tuner_name = "MB 86A15", - .board_name = "VP1022", - .fw_name = "DST-03T" - }, - - { - .tuner_type = TUNER_TYPE_MB86A15, - .tuner_name = "MB 86A15", - .board_name = "VP1025", - .fw_name = "DST-03T" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1030", - .fw_name = "DST-CI" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1030", - .fw_name = "DSTMCI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2021", - .fw_name = "DCTNEW" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2030", - .fw_name = "DCT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2031", - .fw_name = "DCT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2040", - .fw_name = "DCT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP3020", - .fw_name = "DTTFTA" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP3021", - .fw_name = "DTTFTA" - }, - - { - .tuner_type = TUNER_TYPE_TDA10046, - .tuner_name = "TDA10046", - .board_name = "VP3040", - .fw_name = "DTT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP3051", - .fw_name = "DTTNXT" - }, - - { - .tuner_type = TUNER_TYPE_NXT200x, - .tuner_name = "NXT200x", - .board_name = "VP3220", - .fw_name = "ATSCDI" - }, - - { - .tuner_type = TUNER_TYPE_NXT200x, - .tuner_name = "NXT200x", - .board_name = "VP3250", - .fw_name = "ATSCAD" - }, -}; - -/* - Known cards list - Satellite - ------------------- - 200103A - VP-1020 DST-MOT LG(old), TS=188 - - VP-1020 DST-03T LG(new), TS=204 - VP-1022 DST-03T LG(new), TS=204 - VP-1025 DST-03T LG(new), TS=204 - - VP-1030 DSTMCI, LG(new), TS=188 - VP-1032 DSTMCI, LG(new), TS=188 - - Cable - ------------------- - VP-2030 DCT-CI, Samsung, TS=204 - VP-2021 DCT-CI, Unknown, TS=204 - VP-2031 DCT-CI, Philips, TS=188 - VP-2040 DCT-CI, Philips, TS=188, with CA daughter board - VP-2040 DCT-CI, Philips, TS=204, without CA daughter board - - Terrestrial - ------------------- - VP-3050 DTTNXT TS=188 - VP-3040 DTT-CI, Philips, TS=188 - VP-3040 DTT-CI, Philips, TS=204 - - ATSC - ------------------- - VP-3220 ATSCDI, TS=188 - VP-3250 ATSCAD, TS=188 - -*/ - -static struct dst_types dst_tlist[] = { - { - .device_id = "200103A", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-020", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-030", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-03T", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, - .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 - | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, - .tuner_type = TUNER_TYPE_MULTI - }, - - { - .device_id = "DST-MOT", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-CI", - .offset = 1, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, - .dst_feature = DST_TYPE_HAS_CA, - .tuner_type = 0 - }, /* An OEM board */ - - { - .device_id = "DSTMCI", - .offset = 1, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF, - .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 - | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, - .tuner_type = TUNER_TYPE_MULTI - }, - - { - .device_id = "DSTFCI", - .offset = 1, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* unknown to vendor */ - - { - .device_id = "DCT-CI", - .offset = 1, - .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, - .dst_feature = DST_TYPE_HAS_CA, - .tuner_type = 0 - }, - - { - .device_id = "DCTNEW", - .offset = 1, - .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, - .dst_feature = 0, - .tuner_type = 0 - }, - - { - .device_id = "DTT-CI", - .offset = 1, - .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, - .dst_feature = DST_TYPE_HAS_CA, - .tuner_type = 0 - }, - - { - .device_id = "DTTDIG", - .offset = 1, - .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0, - .tuner_type = 0 - }, - - { - .device_id = "DTTNXT", - .offset = 1, - .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = DST_TYPE_HAS_ANALOG, - .tuner_type = 0 - }, - - { - .device_id = "ATSCDI", - .offset = 1, - .dst_type = DST_TYPE_IS_ATSC, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0, - .tuner_type = 0 - }, - - { - .device_id = "ATSCAD", - .offset = 1, - .dst_type = DST_TYPE_IS_ATSC, - .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, - .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, - .tuner_type = 0 - }, - - { } - -}; - -static int dst_get_mac(struct dst_state *state) -{ - u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_mac[7] = dst_check_sum(get_mac, 7); - if (dst_command(state, get_mac, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memset(&state->mac_address, '\0', 8); - memcpy(&state->mac_address, &state->rxbuffer, 6); - dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); - - return 0; -} - -static int dst_fw_ver(struct dst_state *state) -{ - u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_ver[7] = dst_check_sum(get_ver, 7); - if (dst_command(state, get_ver, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memcpy(&state->fw_version, &state->rxbuffer, 8); - dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", - state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, - state->fw_version[1], - state->fw_version[5], state->fw_version[6], - state->fw_version[4], state->fw_version[3], state->fw_version[2]); - - return 0; -} - -static int dst_card_type(struct dst_state *state) -{ - int j; - struct tuner_types *p_tuner_list = NULL; - - u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_type[7] = dst_check_sum(get_type, 7); - if (dst_command(state, get_type, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memset(&state->card_info, '\0', 8); - memcpy(&state->card_info, &state->rxbuffer, 7); - dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); - - for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { - if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { - state->tuner_type = p_tuner_list->tuner_type; - dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", - p_tuner_list->tuner_name, p_tuner_list->tuner_type); - } - } - - return 0; -} - -static int dst_get_vendor(struct dst_state *state) -{ - u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_vendor[7] = dst_check_sum(get_vendor, 7); - if (dst_command(state, get_vendor, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memset(&state->vendor, '\0', 8); - memcpy(&state->vendor, &state->rxbuffer, 7); - dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); - - return 0; -} - -static void debug_dst_buffer(struct dst_state *state) -{ - int i; - - if (verbose > 2) { - printk("%s: [", __func__); - for (i = 0; i < 8; i++) - printk(" %02x", state->rxbuffer[i]); - printk("]\n"); - } -} - -static int dst_check_stv0299(struct dst_state *state) -{ - u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - check_stv0299[7] = dst_check_sum(check_stv0299, 7); - if (dst_command(state, check_stv0299, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); - return -1; - } - debug_dst_buffer(state); - - if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { - dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); - state->tuner_type = TUNER_TYPE_STV0299; - return 0; - } - - return -1; -} - -static int dst_check_mb86a15(struct dst_state *state) -{ - u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); - if (dst_command(state, check_mb86a15, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); - return -1; - } - debug_dst_buffer(state); - - if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); - state->tuner_type = TUNER_TYPE_MB86A15; - return 0; - } - - return -1; -} - -static int dst_get_tuner_info(struct dst_state *state) -{ - u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); - get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); - dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); - if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - if (dst_command(state, get_tuner_1, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); - goto force; - } - } else { - if (dst_command(state, get_tuner_2, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); - goto force; - } - } - memcpy(&state->board_info, &state->rxbuffer, 8); - if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); - } - if (state->board_info[0] == 0xbc) { - if (state->dst_type != DST_TYPE_IS_ATSC) - state->type_flags |= DST_TYPE_HAS_TS188; - else - state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; - - if (state->board_info[1] == 0x01) { - state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; - dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); - } - } - - return 0; -force: - if (!strncmp(state->fw_name, "DCT-CI", 6)) { - state->type_flags |= DST_TYPE_HAS_TS204; - dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); - } - - return -1; -} - -static int dst_get_device_id(struct dst_state *state) -{ - u8 reply; - - int i, j; - struct dst_types *p_dst_type = NULL; - struct tuner_types *p_tuner_list = NULL; - - u8 use_dst_type = 0; - u32 use_type_flags = 0; - - static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; - - state->tuner_type = 0; - device_type[7] = dst_check_sum(device_type, 7); - - if (write_dst(state, device_type, FIXED_COMM)) - return -1; /* Write failed */ - if ((dst_pio_disable(state)) < 0) - return -1; - if (read_dst(state, &reply, GET_ACK)) - return -1; /* Read failure */ - if (reply != ACK) { - dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); - return -1; /* Unack'd write */ - } - if (!dst_wait_dst_ready(state, DEVICE_INIT)) - return -1; /* DST not ready yet */ - if (read_dst(state, state->rxbuffer, FIXED_COMM)) - return -1; - - dst_pio_disable(state); - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk(verbose, DST_INFO, 1, "Checksum failure!"); - return -1; /* Checksum failure */ - } - state->rxbuffer[7] = '\0'; - - for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { - if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { - use_type_flags = p_dst_type->type_flags; - use_dst_type = p_dst_type->dst_type; - - /* Card capabilities */ - state->dst_hw_cap = p_dst_type->dst_feature; - dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); - strncpy(&state->fw_name[0], p_dst_type->device_id, 6); - /* Multiple tuners */ - if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { - switch (use_dst_type) { - case DST_TYPE_IS_SAT: - /* STV0299 check */ - if (dst_check_stv0299(state) < 0) { - dprintk(verbose, DST_ERROR, 1, "Unsupported"); - state->tuner_type = TUNER_TYPE_MB86A15; - } - break; - default: - break; - } - if (dst_check_mb86a15(state) < 0) - dprintk(verbose, DST_ERROR, 1, "Unsupported"); - /* Single tuner */ - } else { - state->tuner_type = p_dst_type->tuner_type; - } - for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { - if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && - p_tuner_list->tuner_type == state->tuner_type) { - dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", - p_dst_type->device_id, p_tuner_list->tuner_name); - } - } - break; - } - } - - if (i >= ARRAY_SIZE(dst_tlist)) { - dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); - dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); - use_dst_type = DST_TYPE_IS_SAT; - use_type_flags = DST_TYPE_HAS_SYMDIV; - } - dst_type_print(state, use_dst_type); - state->type_flags = use_type_flags; - state->dst_type = use_dst_type; - dst_type_flags_print(state); - - return 0; -} - -static int dst_probe(struct dst_state *state) -{ - mutex_init(&state->dst_mutex); - if (dst_addons & DST_TYPE_HAS_CA) { - if ((rdc_8820_reset(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); - return -1; - } - msleep(4000); - } else { - msleep(100); - } - if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); - return -1; - } - msleep(100); - if (dst_get_device_id(state) < 0) { - dprintk(verbose, DST_ERROR, 1, "unknown device."); - return -1; - } - if (dst_get_mac(state) < 0) { - dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); - } - if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { - if (dst_get_tuner_info(state) < 0) - dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); - } - if (state->type_flags & DST_TYPE_HAS_TS204) { - dst_packsize(state, 204); - } - if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { - if (dst_fw_ver(state) < 0) { - dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); - return 0; - } - if (dst_card_type(state) < 0) { - dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); - return 0; - } - if (dst_get_vendor(state) < 0) { - dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); - return 0; - } - } - - return 0; -} - -static int dst_command(struct dst_state *state, u8 *data, u8 len) -{ - u8 reply; - - mutex_lock(&state->dst_mutex); - if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); - goto error; - } - if (write_dst(state, data, len)) { - dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); - if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); - goto error; - } - goto error; - } - if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); - goto error; - } - if (state->type_flags & DST_TYPE_HAS_FW_1) - mdelay(3); - if (read_dst(state, &reply, GET_ACK)) { - dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); - if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_INFO, 1, "Recovery Failed."); - goto error; - } - goto error; - } - if (reply != ACK) { - dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); - goto error; - } - if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) - goto error; - if (state->type_flags & DST_TYPE_HAS_FW_1) - mdelay(3); - else - udelay(2000); - if (!dst_wait_dst_ready(state, NO_DELAY)) - goto error; - if (read_dst(state, state->rxbuffer, FIXED_COMM)) { - dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); - if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_INFO, 1, "Recovery failed."); - goto error; - } - goto error; - } - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk(verbose, DST_INFO, 1, "checksum failure"); - goto error; - } - mutex_unlock(&state->dst_mutex); - return 0; - -error: - mutex_unlock(&state->dst_mutex); - return -EIO; - -} - -static int dst_get_signal(struct dst_state *state) -{ - int retval; - u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - //dprintk("%s: Getting Signal strength and other parameters\n", __func__); - if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { - state->decode_lock = state->decode_strength = state->decode_snr = 0; - return 0; - } - if (0 == (state->diseq_flags & HAS_LOCK)) { - state->decode_lock = state->decode_strength = state->decode_snr = 0; - return 0; - } - if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { - retval = dst_command(state, get_signal, 8); - if (retval < 0) - return retval; - if (state->dst_type == DST_TYPE_IS_SAT) { - state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; - state->decode_strength = state->rxbuffer[5] << 8; - state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; - } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { - state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; - state->decode_strength = state->rxbuffer[4] << 8; - state->decode_snr = state->rxbuffer[3] << 8; - } else if (state->dst_type == DST_TYPE_IS_ATSC) { - state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; - state->decode_strength = state->rxbuffer[4] << 8; - state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; - } - state->cur_jiff = jiffies; - } - return 0; -} - -static int dst_tone_power_cmd(struct dst_state *state) -{ - u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; - - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - paket[4] = state->tx_tuna[4]; - paket[2] = state->tx_tuna[2]; - paket[3] = state->tx_tuna[3]; - paket[7] = dst_check_sum (paket, 7); - return dst_command(state, paket, 8); -} - -static int dst_get_tuna(struct dst_state *state) -{ - int retval; - - if ((state->diseq_flags & ATTEMPT_TUNE) == 0) - return 0; - state->diseq_flags &= ~(HAS_LOCK); - if (!dst_wait_dst_ready(state, NO_DELAY)) - return -EIO; - if ((state->type_flags & DST_TYPE_HAS_VLF) && - !(state->dst_type == DST_TYPE_IS_ATSC)) - - retval = read_dst(state, state->rx_tuna, 10); - else - retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); - if (retval < 0) { - dprintk(verbose, DST_DEBUG, 1, "read not successful"); - return retval; - } - if ((state->type_flags & DST_TYPE_HAS_VLF) && - !(state->dst_type == DST_TYPE_IS_ATSC)) { - - if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { - dprintk(verbose, DST_INFO, 1, "checksum failure ? "); - return -EIO; - } - } else { - if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { - dprintk(verbose, DST_INFO, 1, "checksum failure? "); - return -EIO; - } - } - if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) - return 0; - if (state->dst_type == DST_TYPE_IS_SAT) { - state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; - } else { - state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; - } - state->decode_freq = state->decode_freq * 1000; - state->decode_lock = 1; - state->diseq_flags |= HAS_LOCK; - - return 1; -} - -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); - -static int dst_write_tuna(struct dvb_frontend *fe) -{ - struct dst_state *state = fe->demodulator_priv; - int retval; - u8 reply; - - dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); - state->decode_freq = 0; - state->decode_lock = state->decode_strength = state->decode_snr = 0; - if (state->dst_type == DST_TYPE_IS_SAT) { - if (!(state->diseq_flags & HAS_POWER)) - dst_set_voltage(fe, SEC_VOLTAGE_13); - } - state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); - mutex_lock(&state->dst_mutex); - if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); - goto error; - } -// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { - if ((state->type_flags & DST_TYPE_HAS_VLF) && - (!(state->dst_type == DST_TYPE_IS_ATSC))) { - - state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); - retval = write_dst(state, &state->tx_tuna[0], 10); - } else { - state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); - retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); - } - if (retval < 0) { - dst_pio_disable(state); - dprintk(verbose, DST_DEBUG, 1, "write not successful"); - goto werr; - } - if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); - goto error; - } - if ((read_dst(state, &reply, GET_ACK) < 0)) { - dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); - goto error; - } - if (reply != ACK) { - dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); - goto error; - } - state->diseq_flags |= ATTEMPT_TUNE; - retval = dst_get_tuna(state); -werr: - mutex_unlock(&state->dst_mutex); - return retval; - -error: - mutex_unlock(&state->dst_mutex); - return -EIO; -} - -/* - * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 - * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 - * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 - * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 - * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 - * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec - * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 - * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 - * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 - */ - -static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) -{ - struct dst_state *state = fe->demodulator_priv; - u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; - - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - if (cmd->msg_len > 0 && cmd->msg_len < 5) - memcpy(&paket[3], cmd->msg, cmd->msg_len); - else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) - memcpy(&paket[2], cmd->msg, cmd->msg_len); - else - return -EINVAL; - paket[7] = dst_check_sum(&paket[0], 7); - return dst_command(state, paket, 8); -} - -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - int need_cmd, retval = 0; - struct dst_state *state = fe->demodulator_priv; - - state->voltage = voltage; - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - - need_cmd = 0; - - switch (voltage) { - case SEC_VOLTAGE_13: - case SEC_VOLTAGE_18: - if ((state->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - state->diseq_flags |= HAS_POWER; - state->tx_tuna[4] = 0x01; - break; - case SEC_VOLTAGE_OFF: - need_cmd = 1; - state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - state->tx_tuna[4] = 0x00; - break; - default: - return -EINVAL; - } - - if (need_cmd) - retval = dst_tone_power_cmd(state); - - return retval; -} - -static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct dst_state *state = fe->demodulator_priv; - - state->tone = tone; - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - - switch (tone) { - case SEC_TONE_OFF: - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - state->tx_tuna[2] = 0x00; - else - state->tx_tuna[2] = 0xff; - break; - - case SEC_TONE_ON: - state->tx_tuna[2] = 0x02; - break; - default: - return -EINVAL; - } - return dst_tone_power_cmd(state); -} - -static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) -{ - struct dst_state *state = fe->demodulator_priv; - - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - state->minicmd = minicmd; - switch (minicmd) { - case SEC_MINI_A: - state->tx_tuna[3] = 0x02; - break; - case SEC_MINI_B: - state->tx_tuna[3] = 0xff; - break; - } - return dst_tone_power_cmd(state); -} - - -static int dst_init(struct dvb_frontend *fe) -{ - struct dst_state *state = fe->demodulator_priv; - - static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; - static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; - static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - - state->inversion = INVERSION_OFF; - state->voltage = SEC_VOLTAGE_13; - state->tone = SEC_TONE_OFF; - state->diseq_flags = 0; - state->k22 = 0x02; - state->bandwidth = 7000000; - state->cur_jiff = jiffies; - if (state->dst_type == DST_TYPE_IS_SAT) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); - else if (state->dst_type == DST_TYPE_IS_TERR) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); - else if (state->dst_type == DST_TYPE_IS_CABLE) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); - else if (state->dst_type == DST_TYPE_IS_ATSC) - memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); - - return 0; -} - -static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct dst_state *state = fe->demodulator_priv; - - *status = 0; - if (state->diseq_flags & HAS_LOCK) { -// dst_get_signal(state); // don't require(?) to ask MCU - if (state->decode_lock) - *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; - } - - return 0; -} - -static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct dst_state *state = fe->demodulator_priv; - - int retval = dst_get_signal(state); - *strength = state->decode_strength; - - return retval; -} - -static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct dst_state *state = fe->demodulator_priv; - - int retval = dst_get_signal(state); - *snr = state->decode_snr; - - return retval; -} - -static int dst_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int retval = -EINVAL; - struct dst_state *state = fe->demodulator_priv; - - if (p != NULL) { - retval = dst_set_freq(state, p->frequency); - if(retval != 0) - return retval; - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); - - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->fec_inner); - dst_set_symbolrate(state, p->symbol_rate); - dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); - - } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->bandwidth_hz); - else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->fec_inner); - dst_set_symbolrate(state, p->symbol_rate); - dst_set_modulation(state, p->modulation); - } - retval = dst_write_tuna(fe); - } - - return retval; -} - -static int dst_tune_frontend(struct dvb_frontend* fe, - bool re_tune, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status) -{ - struct dst_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - - if (re_tune) { - dst_set_freq(state, p->frequency); - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); - - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->fec_inner); - dst_set_symbolrate(state, p->symbol_rate); - dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); - - } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->bandwidth_hz); - else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->fec_inner); - dst_set_symbolrate(state, p->symbol_rate); - dst_set_modulation(state, p->modulation); - } - dst_write_tuna(fe); - } - - if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) - dst_read_status(fe, status); - - *delay = HZ/10; - return 0; -} - -static int dst_get_tuning_algo(struct dvb_frontend *fe) -{ - return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; -} - -static int dst_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct dst_state *state = fe->demodulator_priv; - - p->frequency = state->decode_freq; - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - p->inversion = state->inversion; - p->symbol_rate = state->symbol_rate; - p->fec_inner = dst_get_fec(state); - } else if (state->dst_type == DST_TYPE_IS_TERR) { - p->bandwidth_hz = state->bandwidth; - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - p->symbol_rate = state->symbol_rate; - p->fec_inner = dst_get_fec(state); - p->modulation = dst_get_modulation(state); - } - - return 0; -} - -static void dst_release(struct dvb_frontend *fe) -{ - struct dst_state *state = fe->demodulator_priv; - if (state->dst_ca) { - dvb_unregister_device(state->dst_ca); -#ifdef CONFIG_MEDIA_ATTACH - symbol_put(dst_ca_attach); -#endif - } - kfree(state); -} - -static struct dvb_frontend_ops dst_dvbt_ops; -static struct dvb_frontend_ops dst_dvbs_ops; -static struct dvb_frontend_ops dst_dvbc_ops; -static struct dvb_frontend_ops dst_atsc_ops; - -struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) -{ - /* check if the ASIC is there */ - if (dst_probe(state) < 0) { - kfree(state); - return NULL; - } - /* determine settings based on type */ - /* create dvb_frontend */ - switch (state->dst_type) { - case DST_TYPE_IS_TERR: - memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); - break; - case DST_TYPE_IS_CABLE: - memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); - break; - case DST_TYPE_IS_SAT: - memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); - break; - case DST_TYPE_IS_ATSC: - memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); - break; - default: - dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); - kfree(state); - return NULL; - } - state->frontend.demodulator_priv = state; - - return state; /* Manu (DST is a card not a frontend) */ -} - -EXPORT_SYMBOL(dst_attach); - -static struct dvb_frontend_ops dst_dvbt_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "DST DVB-T", - .frequency_min = 137000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, -}; - -static struct dvb_frontend_ops dst_dvbs_ops = { - .delsys = { SYS_DVBS }, - .info = { - .name = "DST DVB-S", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - /* . symbol_rate_tolerance = ???,*/ - .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, - .diseqc_send_burst = dst_send_burst, - .diseqc_send_master_cmd = dst_set_diseqc, - .set_voltage = dst_set_voltage, - .set_tone = dst_set_tone, -}; - -static struct dvb_frontend_ops dst_dvbc_ops = { - .delsys = { SYS_DVBC_ANNEX_A }, - .info = { - .name = "DST DVB-C", - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, -}; - -static struct dvb_frontend_ops dst_atsc_ops = { - .delsys = { SYS_ATSC }, - .info = { - .name = "DST ATSC", - .frequency_stepsize = 62500, - .frequency_min = 510000000, - .frequency_max = 858000000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, -}; - -MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); -MODULE_AUTHOR("Jamie Honan, Manu Abraham"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c deleted file mode 100644 index ee3884fbc9c..00000000000 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - CA-driver for TwinHan DST Frontend/Card - - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "dvbdev.h" -#include "dvb_frontend.h" -#include "dst_ca.h" -#include "dst_common.h" - -#define DST_CA_ERROR 0 -#define DST_CA_NOTICE 1 -#define DST_CA_INFO 2 -#define DST_CA_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > DST_CA_ERROR) && (x > y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((x > DST_CA_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((x > DST_CA_INFO) && (x > y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((x > DST_CA_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ## arg); \ - } \ -} while(0) - - -static DEFINE_MUTEX(dst_ca_mutex); -static unsigned int verbose = 5; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); - -/* Need some more work */ -static int ca_set_slot_descr(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - -/* Need some more work */ -static int ca_set_pid(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - -static void put_command_and_length(u8 *data, int command, int length) -{ - data[0] = (command >> 16) & 0xff; - data[1] = (command >> 8) & 0xff; - data[2] = command & 0xff; - data[3] = length; -} - -static void put_checksum(u8 *check_string, int length) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum."); - dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length); - check_string[length] = dst_check_sum (check_string, length); - dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]); -} - -static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) -{ - u8 reply; - - mutex_lock(&state->dst_mutex); - dst_comm_init(state); - msleep(65); - - if (write_dst(state, data, len)) { - dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); - dst_error_recovery(state); - goto error; - } - if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); - goto error; - } - if (read_dst(state, &reply, GET_ACK) < 0) { - dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); - dst_error_recovery(state); - goto error; - } - if (read) { - if (! dst_wait_dst_ready(state, LONG_DELAY)) { - dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); - goto error; - } - if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ - dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); - dst_error_recovery(state); - goto error; - } - } - mutex_unlock(&state->dst_mutex); - return 0; - -error: - mutex_unlock(&state->dst_mutex); - return -EIO; -} - - -static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read) -{ - u8 dst_ca_comm_err = 0; - - while (dst_ca_comm_err < RETRIES) { - dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); - if (dst_ci_command(state, data, ca_string, len, read)) { // If error - dst_error_recovery(state); - dst_ca_comm_err++; // work required here. - } else { - break; - } - } - - if(dst_ca_comm_err == RETRIES) - return -1; - - return 0; -} - - - -static int ca_get_app_info(struct dst_state *state) -{ - int length, str_length; - static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; - - put_checksum(&command[0], command[0]); - if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); - dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); - dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", - state->messages[7], (state->messages[8] << 8) | state->messages[9], - (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12])); - dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); - - // Transform dst message to correct application_info message - length = state->messages[5]; - str_length = length - 6; - if (str_length < 0) { - str_length = 0; - dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering."); - } - - // First, the command and length fields - put_command_and_length(&state->messages[0], CA_APP_INFO, length); - - // Copy application_type, application_manufacturer and manufacturer_code - memcpy(&state->messages[4], &state->messages[7], 5); - - // Set string length and copy string - state->messages[9] = str_length; - memcpy(&state->messages[10], &state->messages[12], str_length); - - return 0; -} - -static int ca_get_ca_info(struct dst_state *state) -{ - int srcPtr, dstPtr, i, num_ids; - static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; - const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; - - put_checksum(&slot_command[0], slot_command[0]); - if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); - - // Print raw data - dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); - for (i = 0; i < state->messages[0] + 1; i++) { - dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); - } - dprintk(verbose, DST_CA_INFO, 0, "]\n"); - - // Set the command and length of the output - num_ids = state->messages[in_num_ids_pos]; - if (num_ids >= 100) { - num_ids = 100; - dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering."); - } - put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2); - - dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); - srcPtr = in_system_id_pos; - dstPtr = out_system_id_pos; - for(i = 0; i < num_ids; i++) { - dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); - // Append to output - state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; - state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; - srcPtr += 2; - dstPtr += 2; - } - dprintk(verbose, DST_CA_INFO, 0, "]\n"); - - return 0; -} - -static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg) -{ - int i; - u8 slot_cap[256]; - static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff}; - - put_checksum(&slot_command[0], slot_command[0]); - if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); - - /* Will implement the rest soon */ - - dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); - dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); - for (i = 0; i < slot_cap[0] + 1; i++) - dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); - dprintk(verbose, DST_CA_INFO, 0, "\n"); - - p_ca_caps->slot_num = 1; - p_ca_caps->slot_type = 1; - p_ca_caps->descr_num = slot_cap[7]; - p_ca_caps->descr_type = 1; - - if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps))) - return -EFAULT; - - return 0; -} - -/* Need some more work */ -static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) -{ - return -EOPNOTSUPP; -} - - -static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg) -{ - int i; - static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; - - u8 *slot_info = state->messages; - - put_checksum(&slot_command[0], 7); - if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); - - /* Will implement the rest soon */ - - dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); - dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); - for (i = 0; i < 8; i++) - dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); - dprintk(verbose, DST_CA_INFO, 0, "\n"); - - if (slot_info[4] & 0x80) { - p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; - p_ca_slot_info->num = 1; - p_ca_slot_info->type = CA_CI; - } else if (slot_info[4] & 0x40) { - p_ca_slot_info->flags = CA_CI_MODULE_READY; - p_ca_slot_info->num = 1; - p_ca_slot_info->type = CA_CI; - } else - p_ca_slot_info->flags = 0; - - if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info))) - return -EFAULT; - - return 0; -} - - -static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) -{ - u8 i = 0; - u32 command = 0; - - if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) - return -EFAULT; - - if (p_ca_message->msg) { - dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", - 3, p_ca_message->msg); - - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; - } - dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); - - switch (command) { - case CA_APP_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - case CA_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - } - } - - return 0; -} - -static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) -{ - if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { - hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ - hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ - } else { - if (length > 247) { - dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); - return -1; - } - hw_buffer->msg[0] = (length & 0xff) + 7; - hw_buffer->msg[1] = 0x40; - hw_buffer->msg[2] = 0x03; - hw_buffer->msg[3] = 0x00; - hw_buffer->msg[4] = 0x03; - hw_buffer->msg[5] = length & 0xff; - hw_buffer->msg[6] = 0x00; - - /* - * Need to compute length for EN50221 section 8.3.2, for the time being - * assuming 8.3.2 is not applicable - */ - memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); - } - - return 0; -} - -static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) -{ - if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); - dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); - rdc_reset_state(state); - return -1; - } - dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); - - return 0; -} - -static u32 asn_1_decode(u8 *asn_1_array) -{ - u8 length_field = 0, word_count = 0, count = 0; - u32 length = 0; - - length_field = asn_1_array[0]; - dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); - if (length_field < 0x80) { - length = length_field & 0x7f; - dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); - } else { - word_count = length_field & 0x7f; - for (count = 0; count < word_count; count++) { - length = length << 8; - length += asn_1_array[count + 1]; - dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); - } - } - return length; -} - -static int debug_string(u8 *msg, u32 length, u32 offset) -{ - u32 i; - - dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); - for (i = offset; i < length; i++) - dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); - dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); - - return 0; -} - - -static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) -{ - u32 length = 0; - u8 tag_length = 8; - - length = asn_1_decode(&p_ca_message->msg[3]); - dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); - debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ - - memset(hw_buffer->msg, '\0', length); - handle_dst_tag(state, p_ca_message, hw_buffer, length); - put_checksum(hw_buffer->msg, hw_buffer->msg[0]); - - debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ - write_to_8820(state, hw_buffer, (length + tag_length), reply); - - return 0; -} - - -/* Board supports CA PMT reply ? */ -static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) -{ - int ca_pmt_reply_test = 0; - - /* Do test board */ - /* Not there yet but soon */ - - /* CA PMT Reply capable */ - if (ca_pmt_reply_test) { - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; - } - - /* Process CA PMT Reply */ - /* will implement soon */ - dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); - } - /* CA PMT Reply not capable */ - if (!ca_pmt_reply_test) { - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; - } - dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); - /* put a dummy message */ - - } - return 0; -} - -static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) -{ - int i = 0; - - u32 command = 0; - struct ca_msg *hw_buffer; - int result = 0; - - if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - return -ENOMEM; - } - dprintk(verbose, DST_CA_DEBUG, 1, " "); - - if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) { - result = -EFAULT; - goto free_mem_and_exit; - } - - - if (p_ca_message->msg) { - /* EN50221 tag */ - command = 0; - - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; - } - dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); - - switch (command) { - case CA_PMT: - dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); - break; - case CA_PMT_REPLY: - dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); - /* Have to handle the 2 basic types of cards here */ - if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); - break; - case CA_APP_INFO_ENQUIRY: // only for debugging - dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); - - if ((ca_get_app_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); - break; - case CA_INFO_ENQUIRY: - dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); - - if ((ca_get_ca_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); - break; - } - } -free_mem_and_exit: - kfree (hw_buffer); - - return result; -} - -static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg) -{ - struct dvb_device *dvbdev; - struct dst_state *state; - struct ca_slot_info *p_ca_slot_info; - struct ca_caps *p_ca_caps; - struct ca_msg *p_ca_message; - void __user *arg = (void __user *)ioctl_arg; - int result = 0; - - mutex_lock(&dst_ca_mutex); - dvbdev = file->private_data; - state = (struct dst_state *)dvbdev->priv; - p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); - p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL); - p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL); - if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) { - dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - result = -ENOMEM; - goto free_mem_and_exit; - } - - /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ - switch (cmd) { - case CA_SEND_MSG: - dprintk(verbose, DST_CA_INFO, 1, " Sending message"); - if ((ca_send_message(state, p_ca_message, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); - result = -1; - goto free_mem_and_exit; - } - break; - case CA_GET_MSG: - dprintk(verbose, DST_CA_INFO, 1, " Getting message"); - if ((ca_get_message(state, p_ca_message, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); - break; - case CA_RESET: - dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); - dst_error_bailout(state); - msleep(4000); - break; - case CA_GET_SLOT_INFO: - dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); - if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); - break; - case CA_GET_CAP: - dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); - if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); - break; - case CA_GET_DESCR_INFO: - dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); - if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); - break; - case CA_SET_DESCR: - dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); - if ((ca_set_slot_descr()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); - break; - case CA_SET_PID: - dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); - if ((ca_set_pid()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); - default: - result = -EOPNOTSUPP; - }; - free_mem_and_exit: - kfree (p_ca_message); - kfree (p_ca_slot_info); - kfree (p_ca_caps); - - mutex_unlock(&dst_ca_mutex); - return result; -} - -static int dst_ca_open(struct inode *inode, struct file *file) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); - try_module_get(THIS_MODULE); - - return 0; -} - -static int dst_ca_release(struct inode *inode, struct file *file) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); - module_put(THIS_MODULE); - - return 0; -} - -static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) -{ - ssize_t bytes_read = 0; - - dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); - - return bytes_read; -} - -static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); - - return 0; -} - -static const struct file_operations dst_ca_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dst_ca_ioctl, - .open = dst_ca_open, - .release = dst_ca_release, - .read = dst_ca_read, - .write = dst_ca_write, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_ca = { - .priv = NULL, - .users = 1, - .readers = 1, - .writers = 1, - .fops = &dst_ca_fops -}; - -struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) -{ - struct dvb_device *dvbdev; - - dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); - if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) { - dst->dst_ca = dvbdev; - return dst->dst_ca; - } - - return NULL; -} - -EXPORT_SYMBOL(dst_ca_attach); - -MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dst_ca.h b/drivers/media/dvb/bt8xx/dst_ca.h deleted file mode 100644 index 59cd0ddd6d8..00000000000 --- a/drivers/media/dvb/bt8xx/dst_ca.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - CA-driver for TwinHan DST Frontend/Card - - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _DST_CA_H_ -#define _DST_CA_H_ - -#define RETRIES 5 - - -#define CA_APP_INFO_ENQUIRY 0x9f8020 -#define CA_APP_INFO 0x9f8021 -#define CA_ENTER_MENU 0x9f8022 -#define CA_INFO_ENQUIRY 0x9f8030 -#define CA_INFO 0x9f8031 -#define CA_PMT 0x9f8032 -#define CA_PMT_REPLY 0x9f8033 - -#define CA_CLOSE_MMI 0x9f8800 -#define CA_DISPLAY_CONTROL 0x9f8801 -#define CA_DISPLAY_REPLY 0x9f8802 -#define CA_TEXT_LAST 0x9f8803 -#define CA_TEXT_MORE 0x9f8804 -#define CA_KEYPAD_CONTROL 0x9f8805 -#define CA_KEYPRESS 0x9f8806 - -#define CA_ENQUIRY 0x9f8807 -#define CA_ANSWER 0x9f8808 -#define CA_MENU_LAST 0x9f8809 -#define CA_MENU_MORE 0x9f880a -#define CA_MENU_ANSWER 0x9f880b -#define CA_LIST_LAST 0x9f880c -#define CA_LIST_MORE 0x9f880d - - -struct dst_ca_private { - struct dst_state *dst; - struct dvb_device *dvbdev; -}; - - -#endif diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h deleted file mode 100644 index d70d98f1a57..00000000000 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - Frontend-driver for TwinHan DST Frontend - - Copyright (C) 2003 Jamie Honan - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef DST_COMMON_H -#define DST_COMMON_H - -#include -#include -#include -#include "bt878.h" - -#include "dst_ca.h" - - -#define NO_DELAY 0 -#define LONG_DELAY 1 -#define DEVICE_INIT 2 - -#define DELAY 1 - -#define DST_TYPE_IS_SAT 0 -#define DST_TYPE_IS_TERR 1 -#define DST_TYPE_IS_CABLE 2 -#define DST_TYPE_IS_ATSC 3 - -#define DST_TYPE_HAS_TS188 1 -#define DST_TYPE_HAS_TS204 2 -#define DST_TYPE_HAS_SYMDIV 4 -#define DST_TYPE_HAS_FW_1 8 -#define DST_TYPE_HAS_FW_2 16 -#define DST_TYPE_HAS_FW_3 32 -#define DST_TYPE_HAS_FW_BUILD 64 -#define DST_TYPE_HAS_OBS_REGS 128 -#define DST_TYPE_HAS_INC_COUNT 256 -#define DST_TYPE_HAS_MULTI_FE 512 -#define DST_TYPE_HAS_NEWTUNE_2 1024 -#define DST_TYPE_HAS_DBOARD 2048 -#define DST_TYPE_HAS_VLF 4096 - -/* Card capability list */ - -#define DST_TYPE_HAS_MAC 1 -#define DST_TYPE_HAS_DISEQC3 2 -#define DST_TYPE_HAS_DISEQC4 4 -#define DST_TYPE_HAS_DISEQC5 8 -#define DST_TYPE_HAS_MOTO 16 -#define DST_TYPE_HAS_CA 32 -#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ -#define DST_TYPE_HAS_SESSION 128 - -#define TUNER_TYPE_MULTI 1 -#define TUNER_TYPE_UNKNOWN 2 -/* DVB-S */ -#define TUNER_TYPE_L64724 4 -#define TUNER_TYPE_STV0299 8 -#define TUNER_TYPE_MB86A15 16 - -/* DVB-T */ -#define TUNER_TYPE_TDA10046 32 - -/* ATSC */ -#define TUNER_TYPE_NXT200x 64 - - -#define RDC_8820_PIO_0_DISABLE 0 -#define RDC_8820_PIO_0_ENABLE 1 -#define RDC_8820_INT 2 -#define RDC_8820_RESET 4 - -/* DST Communication */ -#define GET_REPLY 1 -#define NO_REPLY 0 - -#define GET_ACK 1 -#define FIXED_COMM 8 - -#define ACK 0xff - -struct dst_state { - - struct i2c_adapter* i2c; - - struct bt878* bt; - - /* configuration settings */ - const struct dst_config* config; - - struct dvb_frontend frontend; - - /* private ASIC data */ - u8 tx_tuna[10]; - u8 rx_tuna[10]; - u8 rxbuffer[10]; - u8 diseq_flags; - u8 dst_type; - u32 type_flags; - u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - u32 decode_freq; - u8 decode_lock; - u16 decode_strength; - u16 decode_snr; - unsigned long cur_jiff; - u8 k22; - u32 bandwidth; - u32 dst_hw_cap; - u8 dst_fw_version; - fe_sec_mini_cmd_t minicmd; - fe_modulation_t modulation; - u8 messages[256]; - u8 mac_address[8]; - u8 fw_version[8]; - u8 card_info[8]; - u8 vendor[8]; - u8 board_info[8]; - u32 tuner_type; - char *tuner_name; - struct mutex dst_mutex; - u8 fw_name[8]; - struct dvb_device *dst_ca; -}; - -struct tuner_types { - u32 tuner_type; - char *tuner_name; - char *board_name; - char *fw_name; -}; - -struct dst_types { - char *device_id; - int offset; - u8 dst_type; - u32 type_flags; - u32 dst_feature; - u32 tuner_type; -}; - -struct dst_config -{ - /* the ASIC i2c address */ - u8 demod_address; -}; - -int rdc_reset_state(struct dst_state *state); - -int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); -int dst_pio_disable(struct dst_state *state); -int dst_error_recovery(struct dst_state* state); -int dst_error_bailout(struct dst_state *state); -int dst_comm_init(struct dst_state* state); - -int write_dst(struct dst_state *state, u8 * data, u8 len); -int read_dst(struct dst_state *state, u8 * ret, u8 len); -u8 dst_check_sum(u8 * buf, u32 len); -struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); -struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); - - -#endif // DST_COMMON_H diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h deleted file mode 100644 index 3974a4c6ebe..00000000000 --- a/drivers/media/dvb/bt8xx/dst_priv.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend - * - * Copyright (C) 2003 Jamie Honan - */ - -struct dst_gpio_enable { - u32 mask; - u32 enable; -}; - -struct dst_gpio_output { - u32 mask; - u32 highvals; -}; - -struct dst_gpio_read { - unsigned long value; -}; - -union dst_gpio_packet { - struct dst_gpio_enable enb; - struct dst_gpio_output outp; - struct dst_gpio_read rd; - int psize; -}; - -#define DST_IG_ENABLE 0 -#define DST_IG_WRITE 1 -#define DST_IG_READ 2 -#define DST_IG_TS 3 - -struct bt878; - -int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c deleted file mode 100644 index 81fab9adc1c..00000000000 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ /dev/null @@ -1,975 +0,0 @@ -/* - * Bt8xx based DVB adapter driver - * - * Copyright (C) 2002,2003 Florian Schirmer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#define pr_fmt(fmt) "dvb_bt8xx: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb-bt8xx.h" -#include "bt878.h" - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk( args... ) \ - do { \ - if (debug) printk(KERN_DEBUG args); \ - } while (0) - -#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - -static void dvb_bt8xx_task(unsigned long data) -{ - struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; - - //printk("%d ", card->bt->finished_block); - - while (card->bt->last_block != card->bt->finished_block) { - (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) - (&card->demux, - &card->bt->buf_cpu[card->bt->last_block * - card->bt->block_bytes], - card->bt->block_bytes); - card->bt->last_block = (card->bt->last_block + 1) % - card->bt->block_count; - } -} - -static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux*dvbdmx = dvbdmxfeed->demux; - struct dvb_bt8xx_card *card = dvbdmx->priv; - int rc; - - dprintk("dvb_bt8xx: start_feed\n"); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - mutex_lock(&card->lock); - card->nfeeds++; - rc = card->nfeeds; - if (card->nfeeds == 1) - bt878_start(card->bt, card->gpio_mode, - card->op_sync_orin, card->irq_err_ignore); - mutex_unlock(&card->lock); - return rc; -} - -static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct dvb_bt8xx_card *card = dvbdmx->priv; - - dprintk("dvb_bt8xx: stop_feed\n"); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - mutex_lock(&card->lock); - card->nfeeds--; - if (card->nfeeds == 0) - bt878_stop(card->bt); - mutex_unlock(&card->lock); - - return 0; -} - -static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) -{ - if ((adev->subsystem_vendor == bdev->subsystem_vendor) && - (adev->subsystem_device == bdev->subsystem_device) && - (adev->bus->number == bdev->bus->number) && - (PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn))) - return 1; - return 0; -} - -static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) -{ - unsigned int card_nr; - - /* Hmm, n squared. Hope n is small */ - for (card_nr = 0; card_nr < bt878_num; card_nr++) - if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) - return &bt878[card_nr]; - return NULL; -} - -static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; - static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 div; - unsigned char bs = 0; - unsigned char cp = 0; - - if (buf_len < 5) - return -EINVAL; - - div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (c->frequency < 542000000) - cp = 0xb4; - else if (c->frequency < 771000000) - cp = 0xbc; - else - cp = 0xf4; - - if (c->frequency == 0) - bs = 0x03; - else if (c->frequency < 443250000) - bs = 0x02; - else - bs = 0x08; - - pllbuf[0] = 0x60; - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; - - return 5; -} - -static struct mt352_config thomson_dtt7579_config = { - .demod_address = 0x0f, - .demod_init = thomson_dtt7579_demod_init, -}; - -static struct zl10353_config thomson_dtt7579_zl10353_config = { - .demod_address = 0x0f, -}; - -static int cx24108_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 freq = c->frequency; - int i, a, n, pump; - u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; - u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; - - #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ - dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); - - /* This is really the bit driving the tuner chip cx24108 */ - - if (freq<950000) - freq = 950000; /* kHz */ - else if (freq>2150000) - freq = 2150000; /* satellite IF is 950..2150MHz */ - - /* decide which VCO to use for the input frequency */ - for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); - dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq); - band=bandsel[i]; - /* the gain values must be set by SetSymbolrate */ - /* compute the pll divider needed, from Conexant data sheet, - resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4, - depending on the divider bit. It is set to /4 on the 2 lowest - bands */ - n=((i<=2?2:1)*freq*10L)/(XTAL/100); - a=n%32; n/=32; if(a==0) n--; - pump=(freq<(osci[i-1]+osci[i])/2); - pll=0xf8000000| - ((pump?1:2)<<(14+11))| - ((n&0x1ff)<<(5+11))| - ((a&0x1f)<<11); - /* everything is shifted left 11 bits to left-align the bits in the - 32bit word. Output to the tuner goes MSB-aligned, after all */ - dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a); - cx24110_pll_write(fe,band); - /* set vga and vca to their widest-band settings, as a precaution. - SetSymbolrate might not be called to set this up */ - cx24110_pll_write(fe,0x500c0000); - cx24110_pll_write(fe,0x83f1f800); - cx24110_pll_write(fe,pll); - //writereg(client,0x56,0x7f); - - return 0; -} - -static int pinnsat_tuner_init(struct dvb_frontend* fe) -{ - struct dvb_bt8xx_card *card = fe->dvb->priv; - - bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */ - bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */ - - return 0; -} - -static int pinnsat_tuner_sleep(struct dvb_frontend* fe) -{ - struct dvb_bt8xx_card *card = fe->dvb->priv; - - bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */ - - return 0; -} - -static struct cx24110_config pctvsat_config = { - .demod_address = 0x55, -}; - -static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; - u8 cfg, cpump, band_select; - u8 data[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (36000000 + c->frequency + 83333) / 166666; - cfg = 0x88; - - if (c->frequency < 175000000) - cpump = 2; - else if (c->frequency < 390000000) - cpump = 1; - else if (c->frequency < 470000000) - cpump = 2; - else if (c->frequency < 750000000) - cpump = 2; - else - cpump = 3; - - if (c->frequency < 175000000) - band_select = 0x0e; - else if (c->frequency < 470000000) - band_select = 0x05; - else - band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(card->i2c_adapter, &msg, 1); - return (div * 166666 - 36000000); -} - -static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; - - return request_firmware(fw, name, &bt->bt->dev->dev); -} - -static struct sp887x_config microtune_mt7202dtf_config = { - .demod_address = 0x70, - .request_firmware = microtune_mt7202dtf_request_firmware, -}; - -static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x40, 0x40 }; - static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); - udelay(2000); - mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 div; - unsigned char bs = 0; - unsigned char cp = 0; - - if (buf_len < 5) return -EINVAL; - - div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (c->frequency < 150000000) - cp = 0xB4; - else if (c->frequency < 173000000) - cp = 0xBC; - else if (c->frequency < 250000000) - cp = 0xB4; - else if (c->frequency < 400000000) - cp = 0xBC; - else if (c->frequency < 420000000) - cp = 0xF4; - else if (c->frequency < 470000000) - cp = 0xFC; - else if (c->frequency < 600000000) - cp = 0xBC; - else if (c->frequency < 730000000) - cp = 0xF4; - else - cp = 0xFC; - - if (c->frequency < 150000000) - bs = 0x01; - else if (c->frequency < 173000000) - bs = 0x01; - else if (c->frequency < 250000000) - bs = 0x02; - else if (c->frequency < 400000000) - bs = 0x02; - else if (c->frequency < 420000000) - bs = 0x02; - else if (c->frequency < 470000000) - bs = 0x02; - else if (c->frequency < 600000000) - bs = 0x08; - else if (c->frequency < 730000000) - bs = 0x08; - else - bs = 0x08; - - pllbuf[0] = 0x61; - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; - - return 5; -} - -static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, - .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, -}; - -static struct dst_config dst_config = { - .demod_address = 0x55, -}; - -static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; - - return request_firmware(fw, name, &bt->bt->dev->dev); -} - -static void or51211_setmode(struct dvb_frontend * fe, int mode) -{ - struct dvb_bt8xx_card *bt = fe->dvb->priv; - bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */ - msleep(20); -} - -static void or51211_reset(struct dvb_frontend * fe) -{ - struct dvb_bt8xx_card *bt = fe->dvb->priv; - - /* RESET DEVICE - * reset is controlled by GPIO-0 - * when set to 0 causes reset and when to 1 for normal op - * must remain reset for 128 clock cycles on a 50Mhz clock - * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4 - * We assume that the reset has be held low long enough or we - * have been reset by a power on. When the driver is unloaded - * reset set to 0 so if reloaded we have been reset. - */ - /* reset & PRM1,2&4 are outputs */ - int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); - if (ret != 0) - printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); - bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ - msleep(20); - /* Now set for normal operation */ - bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001); - /* wait for operation to begin */ - msleep(500); -} - -static void or51211_sleep(struct dvb_frontend * fe) -{ - struct dvb_bt8xx_card *bt = fe->dvb->priv; - bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000); -} - -static struct or51211_config or51211_config = { - .demod_address = 0x15, - .request_firmware = or51211_request_firmware, - .setmode = or51211_setmode, - .reset = or51211_reset, - .sleep = or51211_sleep, -}; - -static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; - - div = (c->frequency + 36166667) / 166667; - - buf[0] = (div >> 8) & 0x7F; - buf[1] = div & 0xFF; - buf[2] = 0x85; - if ((c->frequency >= 47000000) && (c->frequency < 153000000)) - buf[3] = 0x01; - else if ((c->frequency >= 153000000) && (c->frequency < 430000000)) - buf[3] = 0x02; - else if ((c->frequency >= 430000000) && (c->frequency < 824000000)) - buf[3] = 0x0C; - else if ((c->frequency >= 824000000) && (c->frequency < 863000000)) - buf[3] = 0x8C; - else - return -EINVAL; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(card->i2c_adapter, &msg, 1); - return 0; -} - -static struct nxt6000_config vp3021_alps_tded4_config = { - .demod_address = 0x0a, - .clock_inversion = 1, -}; - -static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) -{ - u32 div; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - if (buf_len < 5) - return -EINVAL; - - div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - pllbuf[0] = 0x61; - pllbuf[1] = (div >> 8) & 0x7F; - pllbuf[2] = div & 0xFF; - pllbuf[3] = 0x85; - - dprintk("frequency %u, div %u\n", c->frequency, div); - - if (c->frequency < 470000000) - pllbuf[4] = 0x02; - else if (c->frequency > 823000000) - pllbuf[4] = 0x88; - else - pllbuf[4] = 0x08; - - if (c->bandwidth_hz == 8000000) - pllbuf[4] |= 0x04; - - return 5; -} - -static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) -{ - /* - * Reset the frontend, must be called before trying - * to initialise the MT352 or mt352_attach - * will fail. Same goes for the nxt6000 frontend. - * - */ - - int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); - if (ret != 0) - printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); - - /* Pulse the reset line */ - bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ - bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ - msleep(100); - - bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ -} - -static struct mt352_config digitv_alps_tded4_config = { - .demod_address = 0x0a, - .demod_init = digitv_alps_tded4_demod_init, -}; - -static struct lgdt330x_config tdvs_tua6034_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ -}; - -static void lgdt330x_reset(struct dvb_bt8xx_card *bt) -{ - /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ - - /* Pulse the reset line */ - bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ - bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ - msleep(100); - - bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ - msleep(100); -} - -static void frontend_init(struct dvb_bt8xx_card *card, u32 type) -{ - struct dst_state* state = NULL; - - switch(type) { - case BTTV_BOARD_DVICO_DVBT_LITE: - card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter); - - if (card->fe == NULL) - card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config, - card->i2c_adapter); - - if (card->fe != NULL) { - card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; - card->fe->ops.info.frequency_min = 174000000; - card->fe->ops.info.frequency_max = 862000000; - } - break; - - case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: - lgdt330x_reset(card); - card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); - if (card->fe != NULL) { - dvb_attach(simple_tuner_attach, card->fe, - card->i2c_adapter, 0x61, - TUNER_LG_TDVS_H06XF); - dprintk ("dvb_bt8xx: lgdt330x detected\n"); - } - break; - - case BTTV_BOARD_NEBULA_DIGITV: - /* - * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); - * this would be a cleaner solution than trying each frontend in turn. - */ - - /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ - digitv_alps_tded4_reset(card); - card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); - if (card->fe != NULL) { - card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; - dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); - break; - } - - /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ - digitv_alps_tded4_reset(card); - card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter); - - if (card->fe != NULL) { - card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; - dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); - } - break; - - case BTTV_BOARD_AVDVBT_761: - card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter); - if (card->fe) { - card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; - } - break; - - case BTTV_BOARD_AVDVBT_771: - card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); - if (card->fe != NULL) { - card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; - card->fe->ops.info.frequency_min = 174000000; - card->fe->ops.info.frequency_max = 862000000; - } - break; - - case BTTV_BOARD_TWINHAN_DST: - /* DST is not a frontend driver !!! */ - state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); - if (!state) { - pr_err("No memory\n"); - break; - } - /* Setup the Card */ - state->config = &dst_config; - state->i2c = card->i2c_adapter; - state->bt = card->bt; - state->dst_ca = NULL; - /* DST is not a frontend, attaching the ASIC */ - if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { - pr_err("%s: Could not find a Twinhan DST\n", __func__); - break; - } - /* Attach other DST peripherals if any */ - /* Conditional Access device */ - card->fe = &state->frontend; - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - dvb_attach(dst_ca_attach, state, &card->dvb_adapter); - break; - - case BTTV_BOARD_PINNACLESAT: - card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter); - if (card->fe) { - card->fe->ops.tuner_ops.init = pinnsat_tuner_init; - card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; - card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; - } - break; - - case BTTV_BOARD_PC_HDTV: - card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); - if (card->fe != NULL) - dvb_attach(simple_tuner_attach, card->fe, - card->i2c_adapter, 0x61, - TUNER_PHILIPS_FCV1236D); - break; - } - - if (card->fe == NULL) - pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - card->bt->dev->vendor, - card->bt->dev->device, - card->bt->dev->subsystem_vendor, - card->bt->dev->subsystem_device); - else - if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { - pr_err("Frontend registration failed!\n"); - dvb_frontend_detach(card->fe); - card->fe = NULL; - } -} - -static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) -{ - int result; - - result = dvb_register_adapter(&card->dvb_adapter, card->card_name, - THIS_MODULE, &card->bt->dev->dev, - adapter_nr); - if (result < 0) { - pr_err("dvb_register_adapter failed (errno = %d)\n", result); - return result; - } - card->dvb_adapter.priv = card; - - card->bt->adapter = card->i2c_adapter; - - memset(&card->demux, 0, sizeof(struct dvb_demux)); - - card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; - - card->demux.priv = card; - card->demux.filternum = 256; - card->demux.feednum = 256; - card->demux.start_feed = dvb_bt8xx_start_feed; - card->demux.stop_feed = dvb_bt8xx_stop_feed; - card->demux.write_to_decoder = NULL; - - result = dvb_dmx_init(&card->demux); - if (result < 0) { - pr_err("dvb_dmx_init failed (errno = %d)\n", result); - goto err_unregister_adaptor; - } - - card->dmxdev.filternum = 256; - card->dmxdev.demux = &card->demux.dmx; - card->dmxdev.capabilities = 0; - - result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter); - if (result < 0) { - pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); - goto err_dmx_release; - } - - card->fe_hw.source = DMX_FRONTEND_0; - - result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw); - if (result < 0) { - pr_err("dvb_dmx_init failed (errno = %d)\n", result); - goto err_dmxdev_release; - } - - card->fe_mem.source = DMX_MEMORY_FE; - - result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem); - if (result < 0) { - pr_err("dvb_dmx_init failed (errno = %d)\n", result); - goto err_remove_hw_frontend; - } - - result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw); - if (result < 0) { - pr_err("dvb_dmx_init failed (errno = %d)\n", result); - goto err_remove_mem_frontend; - } - - result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); - if (result < 0) { - pr_err("dvb_net_init failed (errno = %d)\n", result); - goto err_disconnect_frontend; - } - - tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); - - frontend_init(card, type); - - return 0; - -err_disconnect_frontend: - card->demux.dmx.disconnect_frontend(&card->demux.dmx); -err_remove_mem_frontend: - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); -err_remove_hw_frontend: - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); -err_dmxdev_release: - dvb_dmxdev_release(&card->dmxdev); -err_dmx_release: - dvb_dmx_release(&card->demux); -err_unregister_adaptor: - dvb_unregister_adapter(&card->dvb_adapter); - return result; -} - -static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) -{ - struct dvb_bt8xx_card *card; - struct pci_dev* bttv_pci_dev; - int ret; - - if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) - return -ENOMEM; - - mutex_init(&card->lock); - card->bttv_nr = sub->core->nr; - strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name)); - card->i2c_adapter = &sub->core->i2c_adap; - - switch(sub->core->type) { - case BTTV_BOARD_PINNACLESAT: - card->gpio_mode = 0x0400c060; - /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, - BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - break; - - case BTTV_BOARD_DVICO_DVBT_LITE: - card->gpio_mode = 0x0400C060; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - /* 26, 15, 14, 6, 5 - * A_PWRDN DA_DPM DA_SBR DA_IOM_DA - * DA_APP(parallel) */ - break; - - case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: - card->gpio_mode = 0x0400c060; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - break; - - case BTTV_BOARD_NEBULA_DIGITV: - case BTTV_BOARD_AVDVBT_761: - card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - /* A_PWRDN DA_SBR DA_APP (high speed serial) */ - break; - - case BTTV_BOARD_AVDVBT_771: //case 0x07711461: - card->gpio_mode = 0x0400402B; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ - break; - - case BTTV_BOARD_TWINHAN_DST: - card->gpio_mode = 0x2204f2c; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | - BT878_APPERR | BT878_AFBUS; - /* 25,21,14,11,10,9,8,3,2 then - * 0x33 = 5,4,1,0 - * A_SEL=SML, DA_MLB, DA_SBR, - * DA_SDR=f, fifo trigger = 32 DWORDS - * IOM = 0 == audio A/D - * DPM = 0 == digital audio mode - * == async data parallel port - * then 0x33 (13 is set by start_capture) - * DA_APP = async data parallel port, - * ACAP_EN = 1, - * RISC+FIFO ENABLE */ - break; - - case BTTV_BOARD_PC_HDTV: - card->gpio_mode = 0x0100EC7B; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - break; - - default: - pr_err("Unknown bttv card type: %d\n", sub->core->type); - kfree(card); - return -ENODEV; - } - - dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); - - if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { - pr_err("no pci device for card %d\n", card->bttv_nr); - kfree(card); - return -ENODEV; - } - - if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { - pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr); - pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n"); - - kfree(card); - return -ENODEV; - } - - mutex_init(&card->bt->gpio_lock); - card->bt->bttv_nr = sub->core->nr; - - if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { - kfree(card); - return ret; - } - - dev_set_drvdata(&sub->dev, card); - return 0; -} - -static void dvb_bt8xx_remove(struct bttv_sub_device *sub) -{ - struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); - - dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); - - bt878_stop(card->bt); - tasklet_kill(&card->bt->tasklet); - dvb_net_release(&card->dvbnet); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - if (card->fe) { - dvb_unregister_frontend(card->fe); - dvb_frontend_detach(card->fe); - } - dvb_unregister_adapter(&card->dvb_adapter); - - kfree(card); -} - -static struct bttv_sub_driver driver = { - .drv = { - .name = "dvb-bt8xx", - }, - .probe = dvb_bt8xx_probe, - .remove = dvb_bt8xx_remove, - /* FIXME: - * .shutdown = dvb_bt8xx_shutdown, - * .suspend = dvb_bt8xx_suspend, - * .resume = dvb_bt8xx_resume, - */ -}; - -static int __init dvb_bt8xx_init(void) -{ - return bttv_sub_register(&driver, "dvb"); -} - -static void __exit dvb_bt8xx_exit(void) -{ - bttv_sub_unregister(&driver); -} - -module_init(dvb_bt8xx_init); -module_exit(dvb_bt8xx_exit); - -MODULE_DESCRIPTION("Bt8xx based DVB adapter driver"); -MODULE_AUTHOR("Florian Schirmer "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h deleted file mode 100644 index 4499ed2ac0e..00000000000 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Bt8xx based DVB adapter driver - * - * Copyright (C) 2002,2003 Florian Schirmer - * Copyright (C) 2002 Peter Hettkamp - * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH - * Copyright (C) 1998,1999 Christian Theiss - * - * 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 DVB_BT8XX_H -#define DVB_BT8XX_H - -#include -#include -#include "dvbdev.h" -#include "dvb_net.h" -#include "bttv.h" -#include "mt352.h" -#include "sp887x.h" -#include "dst_common.h" -#include "nxt6000.h" -#include "cx24110.h" -#include "or51211.h" -#include "lgdt330x.h" -#include "zl10353.h" -#include "tuner-simple.h" - -struct dvb_bt8xx_card { - struct mutex lock; - int nfeeds; - char card_name[32]; - struct dvb_adapter dvb_adapter; - struct bt878 *bt; - unsigned int bttv_nr; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - u32 gpio_mode; - u32 op_sync_orin; - u32 irq_err_ignore; - struct i2c_adapter *i2c_adapter; - struct dvb_net dvbnet; - - struct dvb_frontend* fe; -}; - -#endif /* DVB_BT8XX_H */ diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig deleted file mode 100644 index d099e1a12c8..00000000000 --- a/drivers/media/dvb/ddbridge/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config DVB_DDBRIDGE - tristate "Digital Devices bridge support" - depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE - ---help--- - Support for cards with the Digital Devices PCI express bridge: - - Octopus PCIe Bridge - - Octopus mini PCIe Bridge - - Octopus LE - - DuoFlex S2 Octopus - - DuoFlex CT Octopus - - cineS2(v6) - - Say Y if you own such a card and want to use it. diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile deleted file mode 100644 index 9d083c98ce5..00000000000 --- a/drivers/media/dvb/ddbridge/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the ddbridge device driver -# - -ddbridge-objs := ddbridge-core.o - -obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c deleted file mode 100644 index ebf3f05839d..00000000000 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ /dev/null @@ -1,1723 +0,0 @@ -/* - * ddbridge.c: Digital Devices PCIe bridge driver - * - * Copyright (C) 2010-2011 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ddbridge.h" - -#include "ddbridge-regs.h" - -#include "tda18271c2dd.h" -#include "stv6110x.h" -#include "stv090x.h" -#include "lnbh24.h" -#include "drxk.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* MSI had problems with lost interrupts, fixed but needs testing */ -#undef CONFIG_PCI_MSI - -/******************************************************************************/ - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) -{ - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; -} - -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} - -static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) -{ - u8 msg[2] = {reg>>8, reg&0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} - -static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) -{ - struct ddb *dev = i2c->dev; - int stat; - u32 val; - - i2c->done = 0; - ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); - stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); - if (stat <= 0) { - printk(KERN_ERR "I2C timeout\n"); - { /* MSI debugging*/ - u32 istat = ddbreadl(INTERRUPT_STATUS); - printk(KERN_ERR "IRS %08x\n", istat); - ddbwritel(istat, INTERRUPT_ACK); - } - return -EIO; - } - val = ddbreadl(i2c->regs+I2C_COMMAND); - if (val & 0x70000) - return -EIO; - return 0; -} - -static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msg[], int num) -{ - struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); - struct ddb *dev = i2c->dev; - u8 addr = 0; - - if (num) - addr = msg[0].addr; - - if (num == 2 && msg[1].flags & I2C_M_RD && - !(msg[0].flags & I2C_M_RD)) { - memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, - msg[0].buf, msg[0].len); - ddbwritel(msg[0].len|(msg[1].len << 16), - i2c->regs+I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 1)) { - memcpy_fromio(msg[1].buf, - dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, - msg[1].len); - return num; - } - } - - if (num == 1 && !(msg[0].flags & I2C_M_RD)) { - ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); - ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 2)) - return num; - } - if (num == 1 && (msg[0].flags & I2C_M_RD)) { - ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 3)) { - ddbcpyfrom(msg[0].buf, - I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); - return num; - } - } - return -EIO; -} - - -static u32 ddb_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -struct i2c_algorithm ddb_i2c_algo = { - .master_xfer = ddb_i2c_master_xfer, - .functionality = ddb_i2c_functionality, -}; - -static void ddb_i2c_release(struct ddb *dev) -{ - int i; - struct ddb_i2c *i2c; - struct i2c_adapter *adap; - - for (i = 0; i < dev->info->port_num; i++) { - i2c = &dev->i2c[i]; - adap = &i2c->adap; - i2c_del_adapter(adap); - } -} - -static int ddb_i2c_init(struct ddb *dev) -{ - int i, j, stat = 0; - struct ddb_i2c *i2c; - struct i2c_adapter *adap; - - for (i = 0; i < dev->info->port_num; i++) { - i2c = &dev->i2c[i]; - i2c->dev = dev; - i2c->nr = i; - i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); - i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); - i2c->regs = 0x80 + i * 0x20; - ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); - ddbwritel((i2c->rbuf << 16) | i2c->wbuf, - i2c->regs + I2C_TASKADDRESS); - init_waitqueue_head(&i2c->wq); - - adap = &i2c->adap; - i2c_set_adapdata(adap, i2c); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; -#else -#ifdef I2C_CLASS_TV_ANALOG - adap->class = I2C_CLASS_TV_ANALOG; -#endif -#endif - strcpy(adap->name, "ddbridge"); - adap->algo = &ddb_i2c_algo; - adap->algo_data = (void *)i2c; - adap->dev.parent = &dev->pdev->dev; - stat = i2c_add_adapter(adap); - if (stat) - break; - } - if (stat) - for (j = 0; j < i; j++) { - i2c = &dev->i2c[j]; - adap = &i2c->adap; - i2c_del_adapter(adap); - } - return stat; -} - - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -#if 0 -static void set_table(struct ddb *dev, u32 off, - dma_addr_t *pbuf, u32 num) -{ - u32 i, base; - u64 mem; - - base = DMA_BASE_ADDRESS_TABLE + off; - for (i = 0; i < num; i++) { - mem = pbuf[i]; - ddbwritel(mem & 0xffffffff, base + i * 8); - ddbwritel(mem >> 32, base + i * 8 + 4); - } -} -#endif - -static void ddb_address_table(struct ddb *dev) -{ - u32 i, j, base; - u64 mem; - dma_addr_t *pbuf; - - for (i = 0; i < dev->info->port_num * 2; i++) { - base = DMA_BASE_ADDRESS_TABLE + i * 0x100; - pbuf = dev->input[i].pbuf; - for (j = 0; j < dev->input[i].dma_buf_num; j++) { - mem = pbuf[j]; - ddbwritel(mem & 0xffffffff, base + j * 8); - ddbwritel(mem >> 32, base + j * 8 + 4); - } - } - for (i = 0; i < dev->info->port_num; i++) { - base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; - pbuf = dev->output[i].pbuf; - for (j = 0; j < dev->output[i].dma_buf_num; j++) { - mem = pbuf[j]; - ddbwritel(mem & 0xffffffff, base + j * 8); - ddbwritel(mem >> 32, base + j * 8 + 4); - } - } -} - -static void io_free(struct pci_dev *pdev, u8 **vbuf, - dma_addr_t *pbuf, u32 size, int num) -{ - int i; - - for (i = 0; i < num; i++) { - if (vbuf[i]) { - pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); - vbuf[i] = 0; - } - } -} - -static int io_alloc(struct pci_dev *pdev, u8 **vbuf, - dma_addr_t *pbuf, u32 size, int num) -{ - int i; - - for (i = 0; i < num; i++) { - vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); - if (!vbuf[i]) - return -ENOMEM; - } - return 0; -} - -static int ddb_buffers_alloc(struct ddb *dev) -{ - int i; - struct ddb_port *port; - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - switch (port->class) { - case DDB_PORT_TUNER: - if (io_alloc(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num) < 0) - return -1; - if (io_alloc(dev->pdev, port->input[1]->vbuf, - port->input[1]->pbuf, - port->input[1]->dma_buf_size, - port->input[1]->dma_buf_num) < 0) - return -1; - break; - case DDB_PORT_CI: - if (io_alloc(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num) < 0) - return -1; - if (io_alloc(dev->pdev, port->output->vbuf, - port->output->pbuf, - port->output->dma_buf_size, - port->output->dma_buf_num) < 0) - return -1; - break; - default: - break; - } - } - ddb_address_table(dev); - return 0; -} - -static void ddb_buffers_free(struct ddb *dev) -{ - int i; - struct ddb_port *port; - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - io_free(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num); - io_free(dev->pdev, port->input[1]->vbuf, - port->input[1]->pbuf, - port->input[1]->dma_buf_size, - port->input[1]->dma_buf_num); - io_free(dev->pdev, port->output->vbuf, - port->output->pbuf, - port->output->dma_buf_size, - port->output->dma_buf_num); - } -} - -static void ddb_input_start(struct ddb_input *input) -{ - struct ddb *dev = input->port->dev; - - spin_lock_irq(&input->lock); - input->cbuf = 0; - input->coff = 0; - - /* reset */ - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - ddbwritel(2, TS_INPUT_CONTROL(input->nr)); - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - - ddbwritel((1 << 16) | - (input->dma_buf_num << 11) | - (input->dma_buf_size >> 7), - DMA_BUFFER_SIZE(input->nr)); - ddbwritel(0, DMA_BUFFER_ACK(input->nr)); - - ddbwritel(1, DMA_BASE_WRITE); - ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); - ddbwritel(9, TS_INPUT_CONTROL(input->nr)); - input->running = 1; - spin_unlock_irq(&input->lock); -} - -static void ddb_input_stop(struct ddb_input *input) -{ - struct ddb *dev = input->port->dev; - - spin_lock_irq(&input->lock); - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); - input->running = 0; - spin_unlock_irq(&input->lock); -} - -static void ddb_output_start(struct ddb_output *output) -{ - struct ddb *dev = output->port->dev; - - spin_lock_irq(&output->lock); - output->cbuf = 0; - output->coff = 0; - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel((1 << 16) | - (output->dma_buf_num << 11) | - (output->dma_buf_size >> 7), - DMA_BUFFER_SIZE(output->nr + 8)); - ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); - - ddbwritel(1, DMA_BASE_READ); - ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); - /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ - ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); - output->running = 1; - spin_unlock_irq(&output->lock); -} - -static void ddb_output_stop(struct ddb_output *output) -{ - struct ddb *dev = output->port->dev; - - spin_lock_irq(&output->lock); - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); - output->running = 0; - spin_unlock_irq(&output->lock); -} - -static u32 ddb_output_free(struct ddb_output *output) -{ - u32 idx, off, stat = output->stat; - s32 diff; - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - if (output->cbuf != idx) { - if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && - (output->dma_buf_size - output->coff <= 188)) - return 0; - return 188; - } - diff = off - output->coff; - if (diff <= 0 || diff > 188) - return 188; - return 0; -} - -static ssize_t ddb_output_write(struct ddb_output *output, - const u8 *buf, size_t count) -{ - struct ddb *dev = output->port->dev; - u32 idx, off, stat = output->stat; - u32 left = count, len; - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - while (left) { - len = output->dma_buf_size - output->coff; - if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && - (off == 0)) { - if (len <= 188) - break; - len -= 188; - } - if (output->cbuf == idx) { - if (off > output->coff) { -#if 1 - len = off - output->coff; - len -= (len % 188); - if (len <= 188) - -#endif - break; - len -= 188; - } - } - if (len > left) - len = left; - if (copy_from_user(output->vbuf[output->cbuf] + output->coff, - buf, len)) - return -EIO; - left -= len; - buf += len; - output->coff += len; - if (output->coff == output->dma_buf_size) { - output->coff = 0; - output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); - } - ddbwritel((output->cbuf << 11) | (output->coff >> 7), - DMA_BUFFER_ACK(output->nr + 8)); - } - return count - left; -} - -static u32 ddb_input_avail(struct ddb_input *input) -{ - struct ddb *dev = input->port->dev; - u32 idx, off, stat = input->stat; - u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - if (ctrl & 4) { - printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); - ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); - return 0; - } - if (input->cbuf != idx) - return 188; - return 0; -} - -static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) -{ - struct ddb *dev = input->port->dev; - u32 left = count; - u32 idx, free, stat = input->stat; - int ret; - - idx = (stat >> 11) & 0x1f; - - while (left) { - if (input->cbuf == idx) - return count - left; - free = input->dma_buf_size - input->coff; - if (free > left) - free = left; - ret = copy_to_user(buf, input->vbuf[input->cbuf] + - input->coff, free); - if (ret) - return -EFAULT; - input->coff += free; - if (input->coff == input->dma_buf_size) { - input->coff = 0; - input->cbuf = (input->cbuf+1) % input->dma_buf_num; - } - left -= free; - ddbwritel((input->cbuf << 11) | (input->coff >> 7), - DMA_BUFFER_ACK(input->nr)); - } - return count; -} - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -#if 0 -static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe) -{ - int i; - - for (i = 0; i < dev->info->port_num * 2; i++) { - if (dev->input[i].fe == fe) - return &dev->input[i]; - } - return NULL; -} -#endif - -static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct ddb_input *input = fe->sec_priv; - struct ddb_port *port = input->port; - int status; - - if (enable) { - mutex_lock(&port->i2c_gate_lock); - status = input->gate_ctrl(fe, 1); - } else { - status = input->gate_ctrl(fe, 0); - mutex_unlock(&port->i2c_gate_lock); - } - return status; -} - -static int demod_attach_drxk(struct ddb_input *input) -{ - struct i2c_adapter *i2c = &input->port->i2c->adap; - struct dvb_frontend *fe; - struct drxk_config config; - - memset(&config, 0, sizeof(config)); - config.microcode_name = "drxk_a3.mc"; - config.qam_demod_parameter_count = 4; - config.adr = 0x29 + (input->nr & 1); - - fe = input->fe = dvb_attach(drxk_attach, &config, i2c); - if (!input->fe) { - printk(KERN_ERR "No DRXK found!\n"); - return -ENODEV; - } - fe->sec_priv = input; - input->gate_ctrl = fe->ops.i2c_gate_ctrl; - fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; - return 0; -} - -static int tuner_attach_tda18271(struct ddb_input *input) -{ - struct i2c_adapter *i2c = &input->port->i2c->adap; - struct dvb_frontend *fe; - - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 1); - fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); - if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); - return -ENODEV; - } - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 0); - return 0; -} - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -static struct stv090x_config stv0900 = { - .device = STV0900, - .demod_mode = STV090x_DUAL, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 27000000, - .address = 0x69, - - .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - - .repeater_level = STV090x_RPTLEVEL_16, - - .adc1_range = STV090x_ADC_1Vpp, - .adc2_range = STV090x_ADC_1Vpp, - - .diseqc_envelope_mode = true, -}; - -static struct stv090x_config stv0900_aa = { - .device = STV0900, - .demod_mode = STV090x_DUAL, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 27000000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - - .repeater_level = STV090x_RPTLEVEL_16, - - .adc1_range = STV090x_ADC_1Vpp, - .adc2_range = STV090x_ADC_1Vpp, - - .diseqc_envelope_mode = true, -}; - -static struct stv6110x_config stv6110a = { - .addr = 0x60, - .refclk = 27000000, - .clk_div = 1, -}; - -static struct stv6110x_config stv6110b = { - .addr = 0x63, - .refclk = 27000000, - .clk_div = 1, -}; - -static int demod_attach_stv0900(struct ddb_input *input, int type) -{ - struct i2c_adapter *i2c = &input->port->i2c->adap; - struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; - - input->fe = dvb_attach(stv090x_attach, feconf, i2c, - (input->nr & 1) ? STV090x_DEMODULATOR_1 - : STV090x_DEMODULATOR_0); - if (!input->fe) { - printk(KERN_ERR "No STV0900 found!\n"); - return -ENODEV; - } - if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, - 0, (input->nr & 1) ? - (0x09 - type) : (0x0b - type))) { - printk(KERN_ERR "No LNBH24 found!\n"); - return -ENODEV; - } - return 0; -} - -static int tuner_attach_stv6110(struct ddb_input *input, int type) -{ - struct i2c_adapter *i2c = &input->port->i2c->adap; - struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; - struct stv6110x_config *tunerconf = (input->nr & 1) ? - &stv6110b : &stv6110a; - struct stv6110x_devctl *ctl; - - ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); - if (!ctl) { - printk(KERN_ERR "No STV6110X found!\n"); - return -ENODEV; - } - printk(KERN_INFO "attach tuner input %d adr %02x\n", - input->nr, tunerconf->addr); - - feconf->tuner_init = ctl->tuner_init; - feconf->tuner_sleep = ctl->tuner_sleep; - feconf->tuner_set_mode = ctl->tuner_set_mode; - feconf->tuner_set_frequency = ctl->tuner_set_frequency; - feconf->tuner_get_frequency = ctl->tuner_get_frequency; - feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; - feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; - feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; - feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; - feconf->tuner_set_refclk = ctl->tuner_set_refclk; - feconf->tuner_get_status = ctl->tuner_get_status; - - return 0; -} - -static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv) -{ - dvbdemux->priv = priv; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = start_feed; - dvbdemux->stop_feed = stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - return dvb_dmx_init(dvbdemux); -} - -static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter) -{ - int ret; - - dmxdev->filternum = 256; - dmxdev->demux = &dvbdemux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adapter); - if (ret < 0) - return ret; - - hw_frontend->source = DMX_FRONTEND_0; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); - mem_frontend->source = DMX_MEMORY_FE; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); - return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); -} - -static int start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ddb_input *input = dvbdmx->priv; - - if (!input->users) - ddb_input_start(input); - - return ++input->users; -} - -static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ddb_input *input = dvbdmx->priv; - - if (--input->users) - return input->users; - - ddb_input_stop(input); - return 0; -} - - -static void dvb_input_detach(struct ddb_input *input) -{ - struct dvb_adapter *adap = &input->adap; - struct dvb_demux *dvbdemux = &input->demux; - - switch (input->attached) { - case 5: - if (input->fe2) - dvb_unregister_frontend(input->fe2); - if (input->fe) { - dvb_unregister_frontend(input->fe); - dvb_frontend_detach(input->fe); - input->fe = NULL; - } - case 4: - dvb_net_release(&input->dvbnet); - - case 3: - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &input->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &input->mem_frontend); - dvb_dmxdev_release(&input->dmxdev); - - case 2: - dvb_dmx_release(&input->demux); - - case 1: - dvb_unregister_adapter(adap); - } - input->attached = 0; -} - -static int dvb_input_attach(struct ddb_input *input) -{ - int ret; - struct ddb_port *port = input->port; - struct dvb_adapter *adap = &input->adap; - struct dvb_demux *dvbdemux = &input->demux; - - ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, - &input->port->dev->pdev->dev, - adapter_nr); - if (ret < 0) { - printk(KERN_ERR "ddbridge: Could not register adapter." - "Check if you enabled enough adapters in dvb-core!\n"); - return ret; - } - input->attached = 1; - - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - start_feed, - stop_feed, input); - if (ret < 0) - return ret; - input->attached = 2; - - ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, - &input->hw_frontend, - &input->mem_frontend, adap); - if (ret < 0) - return ret; - input->attached = 3; - - ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); - if (ret < 0) - return ret; - input->attached = 4; - - input->fe = 0; - switch (port->type) { - case DDB_TUNER_DVBS_ST: - if (demod_attach_stv0900(input, 0) < 0) - return -ENODEV; - if (tuner_attach_stv6110(input, 0) < 0) - return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } - break; - case DDB_TUNER_DVBS_ST_AA: - if (demod_attach_stv0900(input, 1) < 0) - return -ENODEV; - if (tuner_attach_stv6110(input, 1) < 0) - return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } - break; - case DDB_TUNER_DVBCT_TR: - if (demod_attach_drxk(input) < 0) - return -ENODEV; - if (tuner_attach_tda18271(input) < 0) - return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } - if (input->fe2) { - if (dvb_register_frontend(adap, input->fe2) < 0) - return -ENODEV; - input->fe2->tuner_priv = input->fe->tuner_priv; - memcpy(&input->fe2->ops.tuner_ops, - &input->fe->ops.tuner_ops, - sizeof(struct dvb_tuner_ops)); - } - break; - } - input->attached = 5; - return 0; -} - -/****************************************************************************/ -/****************************************************************************/ - -static ssize_t ts_write(struct file *file, const char *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - size_t left = count; - int stat; - - while (left) { - if (ddb_output_free(output) < 188) { - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( - output->wq, ddb_output_free(output) >= 188) < 0) - break; - } - stat = ddb_output_write(output, buf, left); - if (stat < 0) - break; - buf += stat; - left -= stat; - } - return (left == count) ? -EAGAIN : (count - left); -} - -static ssize_t ts_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - struct ddb_input *input = output->port->input[0]; - int left, read; - - count -= count % 188; - left = count; - while (left) { - if (ddb_input_avail(input) < 188) { - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( - input->wq, ddb_input_avail(input) >= 188) < 0) - break; - } - read = ddb_input_read(input, buf, left); - if (read < 0) - return read; - left -= read; - buf += read; - } - return (left == count) ? -EAGAIN : (count - left); -} - -static unsigned int ts_poll(struct file *file, poll_table *wait) -{ - /* - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - struct ddb_input *input = output->port->input[0]; - */ - unsigned int mask = 0; - -#if 0 - if (data_avail_to_read) - mask |= POLLIN | POLLRDNORM; - if (data_avail_to_write) - mask |= POLLOUT | POLLWRNORM; - - poll_wait(file, &read_queue, wait); - poll_wait(file, &write_queue, wait); -#endif - return mask; -} - -static const struct file_operations ci_fops = { - .owner = THIS_MODULE, - .read = ts_read, - .write = ts_write, - .open = dvb_generic_open, - .release = dvb_generic_release, - .poll = ts_poll, - .mmap = 0, -}; - -static struct dvb_device dvbdev_ci = { - .priv = 0, - .readers = -1, - .writers = -1, - .users = -1, - .fops = &ci_fops, -}; - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -static void input_tasklet(unsigned long data) -{ - struct ddb_input *input = (struct ddb_input *) data; - struct ddb *dev = input->port->dev; - - spin_lock(&input->lock); - if (!input->running) { - spin_unlock(&input->lock); - return; - } - input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); - - if (input->port->class == DDB_PORT_TUNER) { - if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) - printk(KERN_ERR "Overflow input %d\n", input->nr); - while (input->cbuf != ((input->stat >> 11) & 0x1f) - || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) { - dvb_dmx_swfilter_packets(&input->demux, - input->vbuf[input->cbuf], - input->dma_buf_size / 188); - - input->cbuf = (input->cbuf + 1) % input->dma_buf_num; - ddbwritel((input->cbuf << 11), - DMA_BUFFER_ACK(input->nr)); - input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); - } - } - if (input->port->class == DDB_PORT_CI) - wake_up(&input->wq); - spin_unlock(&input->lock); -} - -static void output_tasklet(unsigned long data) -{ - struct ddb_output *output = (struct ddb_output *) data; - struct ddb *dev = output->port->dev; - - spin_lock(&output->lock); - if (!output->running) { - spin_unlock(&output->lock); - return; - } - output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); - wake_up(&output->wq); - spin_unlock(&output->lock); -} - - -struct cxd2099_cfg cxd_cfg = { - .bitrate = 62000, - .adr = 0x40, - .polarity = 1, - .clock_mode = 1, -}; - -static int ddb_ci_attach(struct ddb_port *port) -{ - int ret; - - ret = dvb_register_adapter(&port->output->adap, - "DDBridge", - THIS_MODULE, - &port->dev->pdev->dev, - adapter_nr); - if (ret < 0) - return ret; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) { - dvb_unregister_adapter(&port->output->adap); - return -ENODEV; - } - ddb_input_start(port->input[0]); - ddb_output_start(port->output); - dvb_ca_en50221_init(&port->output->adap, - port->en, 0, 1); - ret = dvb_register_device(&port->output->adap, &port->output->dev, - &dvbdev_ci, (void *) port->output, - DVB_DEVICE_SEC); - return ret; -} - -static int ddb_port_attach(struct ddb_port *port) -{ - int ret = 0; - - switch (port->class) { - case DDB_PORT_TUNER: - ret = dvb_input_attach(port->input[0]); - if (ret < 0) - break; - ret = dvb_input_attach(port->input[1]); - break; - case DDB_PORT_CI: - ret = ddb_ci_attach(port); - break; - default: - break; - } - if (ret < 0) - printk(KERN_ERR "port_attach on port %d failed\n", port->nr); - return ret; -} - -static int ddb_ports_attach(struct ddb *dev) -{ - int i, ret = 0; - struct ddb_port *port; - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - ret = ddb_port_attach(port); - if (ret < 0) - break; - } - return ret; -} - -static void ddb_ports_detach(struct ddb *dev) -{ - int i; - struct ddb_port *port; - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - switch (port->class) { - case DDB_PORT_TUNER: - dvb_input_detach(port->input[0]); - dvb_input_detach(port->input[1]); - break; - case DDB_PORT_CI: - if (port->output->dev) - dvb_unregister_device(port->output->dev); - if (port->en) { - ddb_input_stop(port->input[0]); - ddb_output_stop(port->output); - dvb_ca_en50221_release(port->en); - kfree(port->en); - port->en = 0; - dvb_unregister_adapter(&port->output->adap); - } - break; - } - } -} - -/****************************************************************************/ -/****************************************************************************/ - -static int port_has_ci(struct ddb_port *port) -{ - u8 val; - return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; -} - -static int port_has_stv0900(struct ddb_port *port) -{ - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) - return 0; - return 1; -} - -static int port_has_stv0900_aa(struct ddb_port *port) -{ - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0) - return 0; - return 1; -} - -static int port_has_drxks(struct ddb_port *port) -{ - u8 val; - if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) - return 0; - if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) - return 0; - return 1; -} - -static void ddb_port_probe(struct ddb_port *port) -{ - struct ddb *dev = port->dev; - char *modname = "NO MODULE"; - - port->class = DDB_PORT_NONE; - - if (port_has_ci(port)) { - modname = "CI"; - port->class = DDB_PORT_CI; - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900_aa(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST_AA; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_drxks(port)) { - modname = "DUAL DVB-C/T"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT_TR; - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } - printk(KERN_INFO "Port %d (TAB %d): %s\n", - port->nr, port->nr+1, modname); -} - -static void ddb_input_init(struct ddb_port *port, int nr) -{ - struct ddb *dev = port->dev; - struct ddb_input *input = &dev->input[nr]; - - input->nr = nr; - input->port = port; - input->dma_buf_num = INPUT_DMA_BUFS; - input->dma_buf_size = INPUT_DMA_SIZE; - ddbwritel(0, TS_INPUT_CONTROL(nr)); - ddbwritel(2, TS_INPUT_CONTROL(nr)); - ddbwritel(0, TS_INPUT_CONTROL(nr)); - ddbwritel(0, DMA_BUFFER_ACK(nr)); - tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); - spin_lock_init(&input->lock); - init_waitqueue_head(&input->wq); -} - -static void ddb_output_init(struct ddb_port *port, int nr) -{ - struct ddb *dev = port->dev; - struct ddb_output *output = &dev->output[nr]; - output->nr = nr; - output->port = port; - output->dma_buf_num = OUTPUT_DMA_BUFS; - output->dma_buf_size = OUTPUT_DMA_SIZE; - - ddbwritel(0, TS_OUTPUT_CONTROL(nr)); - ddbwritel(2, TS_OUTPUT_CONTROL(nr)); - ddbwritel(0, TS_OUTPUT_CONTROL(nr)); - tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); - init_waitqueue_head(&output->wq); -} - -static void ddb_ports_init(struct ddb *dev) -{ - int i; - struct ddb_port *port; - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - port->dev = dev; - port->nr = i; - port->i2c = &dev->i2c[i]; - port->input[0] = &dev->input[2 * i]; - port->input[1] = &dev->input[2 * i + 1]; - port->output = &dev->output[i]; - - mutex_init(&port->i2c_gate_lock); - ddb_port_probe(port); - ddb_input_init(port, 2 * i); - ddb_input_init(port, 2 * i + 1); - ddb_output_init(port, i); - } -} - -static void ddb_ports_release(struct ddb *dev) -{ - int i; - struct ddb_port *port; - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - port->dev = dev; - tasklet_kill(&port->input[0]->tasklet); - tasklet_kill(&port->input[1]->tasklet); - tasklet_kill(&port->output->tasklet); - } -} - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -static void irq_handle_i2c(struct ddb *dev, int n) -{ - struct ddb_i2c *i2c = &dev->i2c[n]; - - i2c->done = 1; - wake_up(&i2c->wq); -} - -static irqreturn_t irq_handler(int irq, void *dev_id) -{ - struct ddb *dev = (struct ddb *) dev_id; - u32 s = ddbreadl(INTERRUPT_STATUS); - - if (!s) - return IRQ_NONE; - - do { - ddbwritel(s, INTERRUPT_ACK); - - if (s & 0x00000001) - irq_handle_i2c(dev, 0); - if (s & 0x00000002) - irq_handle_i2c(dev, 1); - if (s & 0x00000004) - irq_handle_i2c(dev, 2); - if (s & 0x00000008) - irq_handle_i2c(dev, 3); - - if (s & 0x00000100) - tasklet_schedule(&dev->input[0].tasklet); - if (s & 0x00000200) - tasklet_schedule(&dev->input[1].tasklet); - if (s & 0x00000400) - tasklet_schedule(&dev->input[2].tasklet); - if (s & 0x00000800) - tasklet_schedule(&dev->input[3].tasklet); - if (s & 0x00001000) - tasklet_schedule(&dev->input[4].tasklet); - if (s & 0x00002000) - tasklet_schedule(&dev->input[5].tasklet); - if (s & 0x00004000) - tasklet_schedule(&dev->input[6].tasklet); - if (s & 0x00008000) - tasklet_schedule(&dev->input[7].tasklet); - - if (s & 0x00010000) - tasklet_schedule(&dev->output[0].tasklet); - if (s & 0x00020000) - tasklet_schedule(&dev->output[1].tasklet); - if (s & 0x00040000) - tasklet_schedule(&dev->output[2].tasklet); - if (s & 0x00080000) - tasklet_schedule(&dev->output[3].tasklet); - - /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ - } while ((s = ddbreadl(INTERRUPT_STATUS))); - - return IRQ_HANDLED; -} - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) -{ - u32 data, shift; - - if (wlen > 4) - ddbwritel(1, SPI_CONTROL); - while (wlen > 4) { - /* FIXME: check for big-endian */ - data = swab32(*(u32 *)wbuf); - wbuf += 4; - wlen -= 4; - ddbwritel(data, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) - ; - } - - if (rlen) - ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); - else - ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); - - data = 0; - shift = ((4 - wlen) * 8); - while (wlen) { - data <<= 8; - data |= *wbuf; - wlen--; - wbuf++; - } - if (shift) - data <<= shift; - ddbwritel(data, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) - ; - - if (!rlen) { - ddbwritel(0, SPI_CONTROL); - return 0; - } - if (rlen > 4) - ddbwritel(1, SPI_CONTROL); - - while (rlen > 4) { - ddbwritel(0xffffffff, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) - ; - data = ddbreadl(SPI_DATA); - *(u32 *) rbuf = swab32(data); - rbuf += 4; - rlen -= 4; - } - ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); - ddbwritel(0xffffffff, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) - ; - - data = ddbreadl(SPI_DATA); - ddbwritel(0, SPI_CONTROL); - - if (rlen < 4) - data <<= ((4 - rlen) * 8); - - while (rlen > 0) { - *rbuf = ((data >> 24) & 0xff); - data <<= 8; - rbuf++; - rlen--; - } - return 0; -} - -#define DDB_MAGIC 'd' - -struct ddb_flashio { - __u8 *write_buf; - __u32 write_len; - __u8 *read_buf; - __u32 read_len; -}; - -#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) - -#define DDB_NAME "ddbridge" - -static u32 ddb_num; -static struct ddb *ddbs[32]; -static struct class *ddb_class; -static int ddb_major; - -static int ddb_open(struct inode *inode, struct file *file) -{ - struct ddb *dev = ddbs[iminor(inode)]; - - file->private_data = dev; - return 0; -} - -static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ddb *dev = file->private_data; - void *parg = (void *)arg; - int res; - - switch (cmd) { - case IOCTL_DDB_FLASHIO: - { - struct ddb_flashio fio; - u8 *rbuf, *wbuf; - - if (copy_from_user(&fio, parg, sizeof(fio))) - return -EFAULT; - - if (fio.write_len > 1028 || fio.read_len > 1028) - return -EINVAL; - if (fio.write_len + fio.read_len > 1028) - return -EINVAL; - - wbuf = &dev->iobuf[0]; - rbuf = wbuf + fio.write_len; - - if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) - return -EFAULT; - res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len); - if (res) - return res; - if (copy_to_user(fio.read_buf, rbuf, fio.read_len)) - return -EFAULT; - break; - } - default: - return -ENOTTY; - } - return 0; -} - -static const struct file_operations ddb_fops = { - .unlocked_ioctl = ddb_ioctl, - .open = ddb_open, -}; - -static char *ddb_devnode(struct device *device, umode_t *mode) -{ - struct ddb *dev = dev_get_drvdata(device); - - return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); -} - -static int ddb_class_create(void) -{ - ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); - if (ddb_major < 0) - return ddb_major; - - ddb_class = class_create(THIS_MODULE, DDB_NAME); - if (IS_ERR(ddb_class)) { - unregister_chrdev(ddb_major, DDB_NAME); - return -1; - } - ddb_class->devnode = ddb_devnode; - return 0; -} - -static void ddb_class_destroy(void) -{ - class_destroy(ddb_class); - unregister_chrdev(ddb_major, DDB_NAME); -} - -static int ddb_device_create(struct ddb *dev) -{ - dev->nr = ddb_num++; - dev->ddb_dev = device_create(ddb_class, NULL, - MKDEV(ddb_major, dev->nr), - dev, "ddbridge%d", dev->nr); - ddbs[dev->nr] = dev; - if (IS_ERR(dev->ddb_dev)) - return -1; - return 0; -} - -static void ddb_device_destroy(struct ddb *dev) -{ - ddb_num--; - if (IS_ERR(dev->ddb_dev)) - return; - device_destroy(ddb_class, MKDEV(ddb_major, 0)); -} - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -static void ddb_unmap(struct ddb *dev) -{ - if (dev->regs) - iounmap(dev->regs); - vfree(dev); -} - - -static void __devexit ddb_remove(struct pci_dev *pdev) -{ - struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev); - - ddb_ports_detach(dev); - ddb_i2c_release(dev); - - ddbwritel(0, INTERRUPT_ENABLE); - free_irq(dev->pdev->irq, dev); -#ifdef CONFIG_PCI_MSI - if (dev->msi) - pci_disable_msi(dev->pdev); -#endif - ddb_ports_release(dev); - ddb_buffers_free(dev); - ddb_device_destroy(dev); - - ddb_unmap(dev); - pci_set_drvdata(pdev, 0); - pci_disable_device(pdev); -} - - -static int __devinit ddb_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct ddb *dev; - int stat = 0; - int irq_flag = IRQF_SHARED; - - if (pci_enable_device(pdev) < 0) - return -ENODEV; - - dev = vmalloc(sizeof(struct ddb)); - if (dev == NULL) - return -ENOMEM; - memset(dev, 0, sizeof(struct ddb)); - - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); - dev->info = (struct ddb_info *) id->driver_data; - printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name); - - dev->regs = ioremap(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0)); - if (!dev->regs) { - stat = -ENOMEM; - goto fail; - } - printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); - -#ifdef CONFIG_PCI_MSI - if (pci_msi_enabled()) - stat = pci_enable_msi(dev->pdev); - if (stat) { - printk(KERN_INFO ": MSI not available.\n"); - } else { - irq_flag = 0; - dev->msi = 1; - } -#endif - stat = request_irq(dev->pdev->irq, irq_handler, - irq_flag, "DDBridge", (void *) dev); - if (stat < 0) - goto fail1; - ddbwritel(0, DMA_BASE_WRITE); - ddbwritel(0, DMA_BASE_READ); - ddbwritel(0xffffffff, INTERRUPT_ACK); - ddbwritel(0xfff0f, INTERRUPT_ENABLE); - ddbwritel(0, MSI1_ENABLE); - - if (ddb_i2c_init(dev) < 0) - goto fail1; - ddb_ports_init(dev); - if (ddb_buffers_alloc(dev) < 0) { - printk(KERN_INFO ": Could not allocate buffer memory\n"); - goto fail2; - } - if (ddb_ports_attach(dev) < 0) - goto fail3; - ddb_device_create(dev); - return 0; - -fail3: - ddb_ports_detach(dev); - printk(KERN_ERR "fail3\n"); - ddb_ports_release(dev); -fail2: - printk(KERN_ERR "fail2\n"); - ddb_buffers_free(dev); -fail1: - printk(KERN_ERR "fail1\n"); - if (dev->msi) - pci_disable_msi(dev->pdev); - free_irq(dev->pdev->irq, dev); -fail: - printk(KERN_ERR "fail\n"); - ddb_unmap(dev); - pci_set_drvdata(pdev, 0); - pci_disable_device(pdev); - return -1; -} - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -static struct ddb_info ddb_none = { - .type = DDB_NONE, - .name = "Digital Devices PCIe bridge", -}; - -static struct ddb_info ddb_octopus = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus DVB adapter", - .port_num = 4, -}; - -static struct ddb_info ddb_octopus_le = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus LE DVB adapter", - .port_num = 2, -}; - -static struct ddb_info ddb_v6 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine S2 V6 DVB adapter", - .port_num = 3, -}; - -#define DDVID 0xdd01 /* Digital Devices Vendor ID */ - -#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ - .vendor = _vend, .device = _dev, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long)&_driverdata } - -static const struct pci_device_id ddb_id_tbl[] __devinitdata = { - DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), - DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), - /* in case sub-ids got deleted in flash */ - DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - {0} -}; -MODULE_DEVICE_TABLE(pci, ddb_id_tbl); - - -static struct pci_driver ddb_pci_driver = { - .name = "DDBridge", - .id_table = ddb_id_tbl, - .probe = ddb_probe, - .remove = __devexit_p(ddb_remove), -}; - -static __init int module_init_ddbridge(void) -{ - printk(KERN_INFO "Digital Devices PCIE bridge driver, " - "Copyright (C) 2010-11 Digital Devices GmbH\n"); - if (ddb_class_create()) - return -1; - return pci_register_driver(&ddb_pci_driver); -} - -static __exit void module_exit_ddbridge(void) -{ - pci_unregister_driver(&ddb_pci_driver); - ddb_class_destroy(); -} - -module_init(module_init_ddbridge); -module_exit(module_exit_ddbridge); - -MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); -MODULE_AUTHOR("Ralph Metzler"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.5"); diff --git a/drivers/media/dvb/ddbridge/ddbridge-regs.h b/drivers/media/dvb/ddbridge/ddbridge-regs.h deleted file mode 100644 index a3ccb318b50..00000000000 --- a/drivers/media/dvb/ddbridge/ddbridge-regs.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * ddbridge-regs.h: Digital Devices PCIe bridge driver - * - * Copyright (C) 2010-2011 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ - -/* Register Definitions */ - -#define CUR_REGISTERMAP_VERSION 0x10000 - -#define HARDWARE_VERSION 0x00 -#define REGISTERMAP_VERSION 0x04 - -/* ------------------------------------------------------------------------- */ -/* SPI Controller */ - -#define SPI_CONTROL 0x10 -#define SPI_DATA 0x14 - -/* ------------------------------------------------------------------------- */ - -/* Interrupt controller */ -/* How many MSI's are available depends on HW (Min 2 max 8) */ -/* How many are usable also depends on Host platform */ - -#define INTERRUPT_BASE (0x40) - -#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00) -#define MSI0_ENABLE (INTERRUPT_BASE + 0x00) -#define MSI1_ENABLE (INTERRUPT_BASE + 0x04) -#define MSI2_ENABLE (INTERRUPT_BASE + 0x08) -#define MSI3_ENABLE (INTERRUPT_BASE + 0x0C) -#define MSI4_ENABLE (INTERRUPT_BASE + 0x10) -#define MSI5_ENABLE (INTERRUPT_BASE + 0x14) -#define MSI6_ENABLE (INTERRUPT_BASE + 0x18) -#define MSI7_ENABLE (INTERRUPT_BASE + 0x1C) - -#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20) -#define INTERRUPT_ACK (INTERRUPT_BASE + 0x20) - -#define INTMASK_I2C1 (0x00000001) -#define INTMASK_I2C2 (0x00000002) -#define INTMASK_I2C3 (0x00000004) -#define INTMASK_I2C4 (0x00000008) - -#define INTMASK_CIRQ1 (0x00000010) -#define INTMASK_CIRQ2 (0x00000020) -#define INTMASK_CIRQ3 (0x00000040) -#define INTMASK_CIRQ4 (0x00000080) - -#define INTMASK_TSINPUT1 (0x00000100) -#define INTMASK_TSINPUT2 (0x00000200) -#define INTMASK_TSINPUT3 (0x00000400) -#define INTMASK_TSINPUT4 (0x00000800) -#define INTMASK_TSINPUT5 (0x00001000) -#define INTMASK_TSINPUT6 (0x00002000) -#define INTMASK_TSINPUT7 (0x00004000) -#define INTMASK_TSINPUT8 (0x00008000) - -#define INTMASK_TSOUTPUT1 (0x00010000) -#define INTMASK_TSOUTPUT2 (0x00020000) -#define INTMASK_TSOUTPUT3 (0x00040000) -#define INTMASK_TSOUTPUT4 (0x00080000) - -/* ------------------------------------------------------------------------- */ -/* I2C Master Controller */ - -#define I2C_BASE (0x80) /* Byte offset */ - -#define I2C_COMMAND (0x00) -#define I2C_TIMING (0x04) -#define I2C_TASKLENGTH (0x08) /* High read, low write */ -#define I2C_TASKADDRESS (0x0C) /* High read, low write */ - -#define I2C_MONITOR (0x1C) - -#define I2C_BASE_1 (I2C_BASE + 0x00) -#define I2C_BASE_2 (I2C_BASE + 0x20) -#define I2C_BASE_3 (I2C_BASE + 0x40) -#define I2C_BASE_4 (I2C_BASE + 0x60) - -#define I2C_BASE_N(i) (I2C_BASE + (i) * 0x20) - -#define I2C_TASKMEM_BASE (0x1000) /* Byte offset */ -#define I2C_TASKMEM_SIZE (0x1000) - -#define I2C_SPEED_400 (0x04030404) -#define I2C_SPEED_200 (0x09080909) -#define I2C_SPEED_154 (0x0C0B0C0C) -#define I2C_SPEED_100 (0x13121313) -#define I2C_SPEED_77 (0x19181919) -#define I2C_SPEED_50 (0x27262727) - - -/* ------------------------------------------------------------------------- */ -/* DMA Controller */ - -#define DMA_BASE_WRITE (0x100) -#define DMA_BASE_READ (0x140) - -#define DMA_CONTROL (0x00) /* 64 */ -#define DMA_ERROR (0x04) /* 65 ( only read instance ) */ - -#define DMA_DIAG_CONTROL (0x1C) /* 71 */ -#define DMA_DIAG_PACKETCOUNTER_LOW (0x20) /* 72 */ -#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24) /* 73 */ -#define DMA_DIAG_TIMECOUNTER_LOW (0x28) /* 74 */ -#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C) /* 75 */ -#define DMA_DIAG_RECHECKCOUNTER (0x30) /* 76 ( Split completions on read ) */ -#define DMA_DIAG_WAITTIMEOUTINIT (0x34) /* 77 */ -#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38) /* 78 */ -#define DMA_DIAG_WAITCOUNTER (0x3C) /* 79 */ - -/* ------------------------------------------------------------------------- */ -/* DMA Buffer */ - -#define TS_INPUT_BASE (0x200) -#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 16 + 0x00) - -#define TS_OUTPUT_BASE (0x280) -#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 16 + 0x00) - -#define DMA_BUFFER_BASE (0x300) - -#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 16 + 0x00) -#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 16 + 0x04) -#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 16 + 0x08) -#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 16 + 0x0c) - -#define DMA_BASE_ADDRESS_TABLE (0x2000) -#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) - diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h deleted file mode 100644 index 8b1b41d2a52..00000000000 --- a/drivers/media/dvb/ddbridge/ddbridge.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * ddbridge.h: Digital Devices PCIe bridge driver - * - * Copyright (C) 2010-2011 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#ifndef _DDBRIDGE_H_ -#define _DDBRIDGE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_ringbuffer.h" -#include "dvb_ca_en50221.h" -#include "dvb_net.h" -#include "cxd2099.h" - -#define DDB_MAX_I2C 4 -#define DDB_MAX_PORT 4 -#define DDB_MAX_INPUT 8 -#define DDB_MAX_OUTPUT 4 - -struct ddb_info { - int type; -#define DDB_NONE 0 -#define DDB_OCTOPUS 1 - char *name; - int port_num; - u32 port_type[DDB_MAX_PORT]; -}; - -/* DMA_SIZE MUST be divisible by 188 and 128 !!! */ - -#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ -#define INPUT_DMA_BUFS 8 -#define INPUT_DMA_SIZE (128*47*21) - -#define OUTPUT_DMA_MAX_BUFS 32 -#define OUTPUT_DMA_BUFS 8 -#define OUTPUT_DMA_SIZE (128*47*21) - -struct ddb; -struct ddb_port; - -struct ddb_input { - struct ddb_port *port; - u32 nr; - int attached; - - dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; - u8 *vbuf[INPUT_DMA_MAX_BUFS]; - u32 dma_buf_num; - u32 dma_buf_size; - - struct tasklet_struct tasklet; - spinlock_t lock; - wait_queue_head_t wq; - int running; - u32 stat; - u32 cbuf; - u32 coff; - - struct dvb_adapter adap; - struct dvb_device *dev; - struct dvb_frontend *fe; - struct dvb_frontend *fe2; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvbnet; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - int users; - int (*gate_ctrl)(struct dvb_frontend *, int); -}; - -struct ddb_output { - struct ddb_port *port; - u32 nr; - dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; - u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; - u32 dma_buf_num; - u32 dma_buf_size; - struct tasklet_struct tasklet; - spinlock_t lock; - wait_queue_head_t wq; - int running; - u32 stat; - u32 cbuf; - u32 coff; - - struct dvb_adapter adap; - struct dvb_device *dev; -}; - -struct ddb_i2c { - struct ddb *dev; - u32 nr; - struct i2c_adapter adap; - struct i2c_adapter adap2; - u32 regs; - u32 rbuf; - u32 wbuf; - int done; - wait_queue_head_t wq; -}; - -struct ddb_port { - struct ddb *dev; - u32 nr; - struct ddb_i2c *i2c; - struct mutex i2c_gate_lock; - u32 class; -#define DDB_PORT_NONE 0 -#define DDB_PORT_CI 1 -#define DDB_PORT_TUNER 2 - u32 type; -#define DDB_TUNER_NONE 0 -#define DDB_TUNER_DVBS_ST 1 -#define DDB_TUNER_DVBS_ST_AA 2 -#define DDB_TUNER_DVBCT_TR 16 -#define DDB_TUNER_DVBCT_ST 17 - u32 adr; - - struct ddb_input *input[2]; - struct ddb_output *output; - struct dvb_ca_en50221 *en; -}; - -struct ddb { - struct pci_dev *pdev; - unsigned char *regs; - struct ddb_port port[DDB_MAX_PORT]; - struct ddb_i2c i2c[DDB_MAX_I2C]; - struct ddb_input input[DDB_MAX_INPUT]; - struct ddb_output output[DDB_MAX_OUTPUT]; - - struct device *ddb_dev; - int nr; - u8 iobuf[1028]; - - struct ddb_info *info; - int msi; -}; - -/****************************************************************************/ - -#define ddbwritel(_val, _adr) writel((_val), \ - (char *) (dev->regs+(_adr))) -#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) -#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ - (dev->regs+(_adr)), (_src), (_count)) -#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ - (dev->regs+(_adr)), (_count)) - -/****************************************************************************/ - -#endif diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig deleted file mode 100644 index f3de0a4d63f..00000000000 --- a/drivers/media/dvb/dm1105/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config DVB_DM1105 - tristate "SDMC DM1105 based PCI cards" - depends on DVB_CORE && PCI && I2C - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - depends on RC_CORE - help - Support for cards based on the SDMC DM1105 PCI chip like - DvbWorld 2002 - - 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/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile deleted file mode 100644 index 327585143c8..00000000000 --- a/drivers/media/dvb/dm1105/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_DM1105) += dm1105.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c deleted file mode 100644 index a609b3a9b14..00000000000 --- a/drivers/media/dvb/dm1105/dm1105.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip - * - * Copyright (C) 2008 Igor M. Liplianin - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" -#include "dvb-pll.h" - -#include "stv0299.h" -#include "stv0288.h" -#include "stb6000.h" -#include "si21xx.h" -#include "cx24116.h" -#include "z0194a.h" -#include "ds3000.h" - -#define MODULE_NAME "dm1105" - -#define UNSET (-1U) - -#define DM1105_BOARD_NOAUTO UNSET -#define DM1105_BOARD_UNKNOWN 0 -#define DM1105_BOARD_DVBWORLD_2002 1 -#define DM1105_BOARD_DVBWORLD_2004 2 -#define DM1105_BOARD_AXESS_DM05 3 -#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO 4 - -/* ----------------------------------------------- */ -/* - * PCI ID's - */ -#ifndef PCI_VENDOR_ID_TRIGEM -#define PCI_VENDOR_ID_TRIGEM 0x109f -#endif -#ifndef PCI_VENDOR_ID_AXESS -#define PCI_VENDOR_ID_AXESS 0x195d -#endif -#ifndef PCI_DEVICE_ID_DM1105 -#define PCI_DEVICE_ID_DM1105 0x036f -#endif -#ifndef PCI_DEVICE_ID_DW2002 -#define PCI_DEVICE_ID_DW2002 0x2002 -#endif -#ifndef PCI_DEVICE_ID_DW2004 -#define PCI_DEVICE_ID_DW2004 0x2004 -#endif -#ifndef PCI_DEVICE_ID_DM05 -#define PCI_DEVICE_ID_DM05 0x1105 -#endif -/* ----------------------------------------------- */ -/* sdmc dm1105 registers */ - -/* TS Control */ -#define DM1105_TSCTR 0x00 -#define DM1105_DTALENTH 0x04 - -/* GPIO Interface */ -#define DM1105_GPIOVAL 0x08 -#define DM1105_GPIOCTR 0x0c - -/* PID serial number */ -#define DM1105_PIDN 0x10 - -/* Odd-even secret key select */ -#define DM1105_CWSEL 0x14 - -/* Host Command Interface */ -#define DM1105_HOST_CTR 0x18 -#define DM1105_HOST_AD 0x1c - -/* PCI Interface */ -#define DM1105_CR 0x30 -#define DM1105_RST 0x34 -#define DM1105_STADR 0x38 -#define DM1105_RLEN 0x3c -#define DM1105_WRP 0x40 -#define DM1105_INTCNT 0x44 -#define DM1105_INTMAK 0x48 -#define DM1105_INTSTS 0x4c - -/* CW Value */ -#define DM1105_ODD 0x50 -#define DM1105_EVEN 0x58 - -/* PID Value */ -#define DM1105_PID 0x60 - -/* IR Control */ -#define DM1105_IRCTR 0x64 -#define DM1105_IRMODE 0x68 -#define DM1105_SYSTEMCODE 0x6c -#define DM1105_IRCODE 0x70 - -/* Unknown Values */ -#define DM1105_ENCRYPT 0x74 -#define DM1105_VER 0x7c - -/* I2C Interface */ -#define DM1105_I2CCTR 0x80 -#define DM1105_I2CSTS 0x81 -#define DM1105_I2CDAT 0x82 -#define DM1105_I2C_RA 0x83 -/* ----------------------------------------------- */ -/* Interrupt Mask Bits */ - -#define INTMAK_TSIRQM 0x01 -#define INTMAK_HIRQM 0x04 -#define INTMAK_IRM 0x08 -#define INTMAK_ALLMASK (INTMAK_TSIRQM | \ - INTMAK_HIRQM | \ - INTMAK_IRM) -#define INTMAK_NONEMASK 0x00 - -/* Interrupt Status Bits */ -#define INTSTS_TSIRQ 0x01 -#define INTSTS_HIRQ 0x04 -#define INTSTS_IR 0x08 - -/* IR Control Bits */ -#define DM1105_IR_EN 0x01 -#define DM1105_SYS_CHK 0x02 -#define DM1105_REP_FLG 0x08 - -/* EEPROM addr */ -#define IIC_24C01_addr 0xa0 -/* Max board count */ -#define DM1105_MAX 0x04 - -#define DRIVER_NAME "dm1105" -#define DM1105_I2C_GPIO_NAME "dm1105-gpio" - -#define DM1105_DMA_PACKETS 47 -#define DM1105_DMA_PACKET_LENGTH (128*4) -#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) - -/* */ -#define GPIO08 (1 << 8) -#define GPIO13 (1 << 13) -#define GPIO14 (1 << 14) -#define GPIO15 (1 << 15) -#define GPIO16 (1 << 16) -#define GPIO17 (1 << 17) -#define GPIO_ALL 0x03ffff - -/* GPIO's for LNB power control */ -#define DM1105_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) -#define DM1105_LNB_OFF GPIO17 -#define DM1105_LNB_13V (GPIO16 | GPIO08) -#define DM1105_LNB_18V GPIO08 - -/* GPIO's for LNB power control for Axess DM05 */ -#define DM05_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) -#define DM05_LNB_OFF GPIO17/* actually 13v */ -#define DM05_LNB_13V GPIO17 -#define DM05_LNB_18V (GPIO17 | GPIO16) - -/* GPIO's for LNB power control for unbranded with I2C on GPIO */ -#define UNBR_LNB_MASK (GPIO17 | GPIO16) -#define UNBR_LNB_OFF 0 -#define UNBR_LNB_13V GPIO17 -#define UNBR_LNB_18V (GPIO17 | GPIO16) - -static unsigned int card[] = {[0 ... 3] = UNSET }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); - -static int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); - -static unsigned int dm1105_devcount; - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct dm1105_board { - char *name; - struct { - u32 mask, off, v13, v18; - } lnb; - u32 gpio_scl, gpio_sda; -}; - -struct dm1105_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - -static const struct dm1105_board dm1105_boards[] = { - [DM1105_BOARD_UNKNOWN] = { - .name = "UNKNOWN/GENERIC", - .lnb = { - .mask = DM1105_LNB_MASK, - .off = DM1105_LNB_OFF, - .v13 = DM1105_LNB_13V, - .v18 = DM1105_LNB_18V, - }, - }, - [DM1105_BOARD_DVBWORLD_2002] = { - .name = "DVBWorld PCI 2002", - .lnb = { - .mask = DM1105_LNB_MASK, - .off = DM1105_LNB_OFF, - .v13 = DM1105_LNB_13V, - .v18 = DM1105_LNB_18V, - }, - }, - [DM1105_BOARD_DVBWORLD_2004] = { - .name = "DVBWorld PCI 2004", - .lnb = { - .mask = DM1105_LNB_MASK, - .off = DM1105_LNB_OFF, - .v13 = DM1105_LNB_13V, - .v18 = DM1105_LNB_18V, - }, - }, - [DM1105_BOARD_AXESS_DM05] = { - .name = "Axess/EasyTv DM05", - .lnb = { - .mask = DM05_LNB_MASK, - .off = DM05_LNB_OFF, - .v13 = DM05_LNB_13V, - .v18 = DM05_LNB_18V, - }, - }, - [DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = { - .name = "Unbranded DM1105 with i2c on GPIOs", - .lnb = { - .mask = UNBR_LNB_MASK, - .off = UNBR_LNB_OFF, - .v13 = UNBR_LNB_13V, - .v18 = UNBR_LNB_18V, - }, - .gpio_scl = GPIO14, - .gpio_sda = GPIO13, - }, -}; - -static const struct dm1105_subid dm1105_subids[] = { - { - .subvendor = 0x0000, - .subdevice = 0x2002, - .card = DM1105_BOARD_DVBWORLD_2002, - }, { - .subvendor = 0x0001, - .subdevice = 0x2002, - .card = DM1105_BOARD_DVBWORLD_2002, - }, { - .subvendor = 0x0000, - .subdevice = 0x2004, - .card = DM1105_BOARD_DVBWORLD_2004, - }, { - .subvendor = 0x0001, - .subdevice = 0x2004, - .card = DM1105_BOARD_DVBWORLD_2004, - }, { - .subvendor = 0x195d, - .subdevice = 0x1105, - .card = DM1105_BOARD_AXESS_DM05, - }, -}; - -static void dm1105_card_list(struct pci_dev *pci) -{ - int i; - - if (0 == pci->subsystem_vendor && - 0 == pci->subsystem_device) { - printk(KERN_ERR - "dm1105: Your board has no valid PCI Subsystem ID\n" - "dm1105: and thus can't be autodetected\n" - "dm1105: Please pass card= insmod option to\n" - "dm1105: workaround that. Redirect complaints to\n" - "dm1105: the vendor of the TV card. Best regards,\n" - "dm1105: -- tux\n"); - } else { - printk(KERN_ERR - "dm1105: Your board isn't known (yet) to the driver.\n" - "dm1105: You can try to pick one of the existing\n" - "dm1105: card configs via card= insmod option.\n" - "dm1105: Updating to the latest version might help\n" - "dm1105: as well.\n"); - } - printk(KERN_ERR "Here is a list of valid choices for the card= " - "insmod option:\n"); - for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++) - printk(KERN_ERR "dm1105: card=%d -> %s\n", - i, dm1105_boards[i].name); -} - -/* infrared remote control */ -struct infrared { - struct rc_dev *dev; - char input_phys[32]; - struct work_struct work; - u32 ir_command; -}; - -struct dm1105_dev { - /* pci */ - struct pci_dev *pdev; - u8 __iomem *io_mem; - - /* ir */ - struct infrared ir; - - /* dvb */ - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct dmxdev dmxdev; - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - unsigned int full_ts_users; - unsigned int boardnr; - int nr; - - /* i2c */ - struct i2c_adapter i2c_adap; - struct i2c_adapter i2c_bb_adap; - struct i2c_algo_bit_data i2c_bit; - - /* irq */ - struct work_struct work; - struct workqueue_struct *wq; - char wqn[16]; - - /* dma */ - dma_addr_t dma_addr; - unsigned char *ts_buf; - u32 wrp; - u32 nextwrp; - u32 buffer_size; - unsigned int PacketErrorCount; - unsigned int dmarst; - spinlock_t lock; -}; - -#define dm_io_mem(reg) ((unsigned long)(&dev->io_mem[reg])) - -#define dm_readb(reg) inb(dm_io_mem(reg)) -#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg))) - -#define dm_readw(reg) inw(dm_io_mem(reg)) -#define dm_writew(reg, value) outw((value), (dm_io_mem(reg))) - -#define dm_readl(reg) inl(dm_io_mem(reg)) -#define dm_writel(reg, value) outl((value), (dm_io_mem(reg))) - -#define dm_andorl(reg, mask, value) \ - outl((inl(dm_io_mem(reg)) & ~(mask)) |\ - ((value) & (mask)), (dm_io_mem(reg))) - -#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit)) -#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0) - -/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines, - so we can use only 3 GPIO's from GPIO15 to GPIO17. - Here I don't check whether HOST is enebled as it is not implemented yet. - */ -static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask) -{ - if (mask & 0xfffc0000) - printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); - - if (mask & 0x0003ffff) - dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff); - -} - -static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask) -{ - if (mask & 0xfffc0000) - printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); - - if (mask & 0x0003ffff) - dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff); - -} - -static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val) -{ - if (mask & 0xfffc0000) - printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); - - if (mask & 0x0003ffff) - dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val); - -} - -static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask) -{ - if (mask & 0xfffc0000) - printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); - - if (mask & 0x0003ffff) - return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff; - - return 0; -} - -static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput) -{ - if (mask & 0xfffc0000) - printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); - - if ((mask & 0x0003ffff) && asoutput) - dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff); - else if ((mask & 0x0003ffff) && !asoutput) - dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff); - -} - -static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state) -{ - if (state) - dm1105_gpio_enable(dev, line, 0); - else { - dm1105_gpio_enable(dev, line, 1); - dm1105_gpio_clear(dev, line); - } -} - -static void dm1105_setsda(void *data, int state) -{ - struct dm1105_dev *dev = data; - - dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state); -} - -static void dm1105_setscl(void *data, int state) -{ - struct dm1105_dev *dev = data; - - dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state); -} - -static int dm1105_getsda(void *data) -{ - struct dm1105_dev *dev = data; - - return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda) - ? 1 : 0; -} - -static int dm1105_getscl(void *data) -{ - struct dm1105_dev *dev = data; - - return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl) - ? 1 : 0; -} - -static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) -{ - struct dm1105_dev *dev ; - - int addr, rc, i, j, k, len, byte, data; - u8 status; - - dev = i2c_adap->algo_data; - for (i = 0; i < num; i++) { - dm_writeb(DM1105_I2CCTR, 0x00); - if (msgs[i].flags & I2C_M_RD) { - /* read bytes */ - addr = msgs[i].addr << 1; - addr |= 1; - dm_writeb(DM1105_I2CDAT, addr); - for (byte = 0; byte < msgs[i].len; byte++) - dm_writeb(DM1105_I2CDAT + byte + 1, 0); - - dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); - for (j = 0; j < 55; j++) { - mdelay(10); - status = dm_readb(DM1105_I2CSTS); - if ((status & 0xc0) == 0x40) - break; - } - if (j >= 55) - return -1; - - for (byte = 0; byte < msgs[i].len; byte++) { - rc = dm_readb(DM1105_I2CDAT + byte + 1); - if (rc < 0) - goto err; - msgs[i].buf[byte] = rc; - } - } else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { - /* prepaired for cx24116 firmware */ - /* Write in small blocks */ - len = msgs[i].len - 1; - k = 1; - do { - dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); - dm_writeb(DM1105_I2CDAT + 1, 0xf7); - for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { - data = msgs[i].buf[k + byte]; - dm_writeb(DM1105_I2CDAT + byte + 2, data); - } - dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len)); - for (j = 0; j < 25; j++) { - mdelay(10); - status = dm_readb(DM1105_I2CSTS); - if ((status & 0xc0) == 0x40) - break; - } - - if (j >= 25) - return -1; - - k += 48; - len -= 48; - } while (len > 0); - } else { - /* write bytes */ - dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); - for (byte = 0; byte < msgs[i].len; byte++) { - data = msgs[i].buf[byte]; - dm_writeb(DM1105_I2CDAT + byte + 1, data); - } - dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); - for (j = 0; j < 25; j++) { - mdelay(10); - status = dm_readb(DM1105_I2CSTS); - if ((status & 0xc0) == 0x40) - break; - } - - if (j >= 25) - return -1; - } - } - return num; - err: - return rc; -} - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dm1105_algo = { - .master_xfer = dm1105_i2c_xfer, - .functionality = functionality, -}; - -static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed) -{ - return container_of(feed->demux, struct dm1105_dev, demux); -} - -static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) -{ - return container_of(fe->dvb, struct dm1105_dev, dvb_adapter); -} - -static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); - - dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1); - if (voltage == SEC_VOLTAGE_18) - dm1105_gpio_andor(dev, - dm1105_boards[dev->boardnr].lnb.mask, - dm1105_boards[dev->boardnr].lnb.v18); - else if (voltage == SEC_VOLTAGE_13) - dm1105_gpio_andor(dev, - dm1105_boards[dev->boardnr].lnb.mask, - dm1105_boards[dev->boardnr].lnb.v13); - else - dm1105_gpio_andor(dev, - dm1105_boards[dev->boardnr].lnb.mask, - dm1105_boards[dev->boardnr].lnb.off); - - return 0; -} - -static void dm1105_set_dma_addr(struct dm1105_dev *dev) -{ - dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr)); -} - -static int __devinit dm1105_dma_map(struct dm1105_dev *dev) -{ - dev->ts_buf = pci_alloc_consistent(dev->pdev, - 6 * DM1105_DMA_BYTES, - &dev->dma_addr); - - return !dev->ts_buf; -} - -static void dm1105_dma_unmap(struct dm1105_dev *dev) -{ - pci_free_consistent(dev->pdev, - 6 * DM1105_DMA_BYTES, - dev->ts_buf, - dev->dma_addr); -} - -static void dm1105_enable_irqs(struct dm1105_dev *dev) -{ - dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK); - dm_writeb(DM1105_CR, 1); -} - -static void dm1105_disable_irqs(struct dm1105_dev *dev) -{ - dm_writeb(DM1105_INTMAK, INTMAK_IRM); - dm_writeb(DM1105_CR, 0); -} - -static int dm1105_start_feed(struct dvb_demux_feed *f) -{ - struct dm1105_dev *dev = feed_to_dm1105_dev(f); - - if (dev->full_ts_users++ == 0) - dm1105_enable_irqs(dev); - - return 0; -} - -static int dm1105_stop_feed(struct dvb_demux_feed *f) -{ - struct dm1105_dev *dev = feed_to_dm1105_dev(f); - - if (--dev->full_ts_users == 0) - dm1105_disable_irqs(dev); - - return 0; -} - -/* ir work handler */ -static void dm1105_emit_key(struct work_struct *work) -{ - struct infrared *ir = container_of(work, struct infrared, work); - u32 ircom = ir->ir_command; - u8 data; - - if (ir_debug) - printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom); - - data = (ircom >> 8) & 0x7f; - - rc_keydown(ir->dev, data, 0); -} - -/* work handler */ -static void dm1105_dmx_buffer(struct work_struct *work) -{ - struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work); - unsigned int nbpackets; - u32 oldwrp = dev->wrp; - u32 nextwrp = dev->nextwrp; - - if (!((dev->ts_buf[oldwrp] == 0x47) && - (dev->ts_buf[oldwrp + 188] == 0x47) && - (dev->ts_buf[oldwrp + 188 * 2] == 0x47))) { - dev->PacketErrorCount++; - /* bad packet found */ - if ((dev->PacketErrorCount >= 2) && - (dev->dmarst == 0)) { - dm_writeb(DM1105_RST, 1); - dev->wrp = 0; - dev->PacketErrorCount = 0; - dev->dmarst = 0; - return; - } - } - - if (nextwrp < oldwrp) { - memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp); - nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188; - } else - nbpackets = (nextwrp - oldwrp) / 188; - - dev->wrp = nextwrp; - dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets); -} - -static irqreturn_t dm1105_irq(int irq, void *dev_id) -{ - struct dm1105_dev *dev = dev_id; - - /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ - unsigned int intsts = dm_readb(DM1105_INTSTS); - dm_writeb(DM1105_INTSTS, intsts); - - switch (intsts) { - case INTSTS_TSIRQ: - case (INTSTS_TSIRQ | INTSTS_IR): - dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR); - queue_work(dev->wq, &dev->work); - break; - case INTSTS_IR: - dev->ir.ir_command = dm_readl(DM1105_IRCODE); - schedule_work(&dev->ir.work); - break; - } - - return IRQ_HANDLED; -} - -int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) -{ - struct rc_dev *dev; - int err = -ENOMEM; - - dev = rc_allocate_device(); - if (!dev) - return -ENOMEM; - - snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), - "pci-%s/ir0", pci_name(dm1105->pdev)); - - dev->driver_name = MODULE_NAME; - dev->map_name = RC_MAP_DM1105_NEC; - dev->driver_type = RC_DRIVER_SCANCODE; - dev->input_name = "DVB on-card IR receiver"; - dev->input_phys = dm1105->ir.input_phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.version = 1; - if (dm1105->pdev->subsystem_vendor) { - dev->input_id.vendor = dm1105->pdev->subsystem_vendor; - dev->input_id.product = dm1105->pdev->subsystem_device; - } else { - dev->input_id.vendor = dm1105->pdev->vendor; - dev->input_id.product = dm1105->pdev->device; - } - dev->dev.parent = &dm1105->pdev->dev; - - INIT_WORK(&dm1105->ir.work, dm1105_emit_key); - - err = rc_register_device(dev); - if (err < 0) { - rc_free_device(dev); - return err; - } - - dm1105->ir.dev = dev; - return 0; -} - -void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105) -{ - rc_unregister_device(dm1105->ir.dev); -} - -static int __devinit dm1105_hw_init(struct dm1105_dev *dev) -{ - dm1105_disable_irqs(dev); - - dm_writeb(DM1105_HOST_CTR, 0); - - /*DATALEN 188,*/ - dm_writeb(DM1105_DTALENTH, 188); - /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/ - dm_writew(DM1105_TSCTR, 0xc10a); - - /* map DMA and set address */ - dm1105_dma_map(dev); - dm1105_set_dma_addr(dev); - /* big buffer */ - dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES); - dm_writeb(DM1105_INTCNT, 47); - - /* IR NEC mode enable */ - dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK)); - dm_writeb(DM1105_IRMODE, 0); - dm_writew(DM1105_SYSTEMCODE, 0); - - return 0; -} - -static void dm1105_hw_exit(struct dm1105_dev *dev) -{ - dm1105_disable_irqs(dev); - - /* IR disable */ - dm_writeb(DM1105_IRCTR, 0); - dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK); - - dm1105_dma_unmap(dev); -} - -static struct stv0299_config sharp_z0194a_config = { - .demod_address = 0x68, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static struct stv0288_config earda_config = { - .demod_address = 0x68, - .min_delay_ms = 100, -}; - -static struct si21xx_config serit_config = { - .demod_address = 0x68, - .min_delay_ms = 100, - -}; - -static struct cx24116_config serit_sp2633_config = { - .demod_address = 0x55, -}; - -static struct ds3000_config dvbworld_ds3000_config = { - .demod_address = 0x68, -}; - -static int __devinit frontend_init(struct dm1105_dev *dev) -{ - int ret; - - switch (dev->boardnr) { - case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO: - dm1105_gpio_enable(dev, GPIO15, 1); - dm1105_gpio_clear(dev, GPIO15); - msleep(100); - dm1105_gpio_set(dev, GPIO15); - msleep(200); - dev->fe = dvb_attach( - stv0299_attach, &sharp_z0194a_config, - &dev->i2c_bb_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - dvb_attach(dvb_pll_attach, dev->fe, 0x60, - &dev->i2c_bb_adap, DVB_PLL_OPERA1); - break; - } - - dev->fe = dvb_attach( - stv0288_attach, &earda_config, - &dev->i2c_bb_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - dvb_attach(stb6000_attach, dev->fe, 0x61, - &dev->i2c_bb_adap); - break; - } - - dev->fe = dvb_attach( - si21xx_attach, &serit_config, - &dev->i2c_bb_adap); - if (dev->fe) - dev->fe->ops.set_voltage = dm1105_set_voltage; - break; - case DM1105_BOARD_DVBWORLD_2004: - dev->fe = dvb_attach( - cx24116_attach, &serit_sp2633_config, - &dev->i2c_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - break; - } - - dev->fe = dvb_attach( - ds3000_attach, &dvbworld_ds3000_config, - &dev->i2c_adap); - if (dev->fe) - dev->fe->ops.set_voltage = dm1105_set_voltage; - - break; - case DM1105_BOARD_DVBWORLD_2002: - case DM1105_BOARD_AXESS_DM05: - default: - dev->fe = dvb_attach( - stv0299_attach, &sharp_z0194a_config, - &dev->i2c_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - dvb_attach(dvb_pll_attach, dev->fe, 0x60, - &dev->i2c_adap, DVB_PLL_OPERA1); - break; - } - - dev->fe = dvb_attach( - stv0288_attach, &earda_config, - &dev->i2c_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - dvb_attach(stb6000_attach, dev->fe, 0x61, - &dev->i2c_adap); - break; - } - - dev->fe = dvb_attach( - si21xx_attach, &serit_config, - &dev->i2c_adap); - if (dev->fe) - dev->fe->ops.set_voltage = dm1105_set_voltage; - - } - - if (!dev->fe) { - dev_err(&dev->pdev->dev, "could not attach frontend\n"); - return -ENODEV; - } - - ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe); - if (ret < 0) { - if (dev->fe->ops.release) - dev->fe->ops.release(dev->fe); - dev->fe = NULL; - return ret; - } - - return 0; -} - -static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac) -{ - static u8 command[1] = { 0x28 }; - - struct i2c_msg msg[] = { - { - .addr = IIC_24C01_addr >> 1, - .flags = 0, - .buf = command, - .len = 1 - }, { - .addr = IIC_24C01_addr >> 1, - .flags = I2C_M_RD, - .buf = mac, - .len = 6 - }, - }; - - dm1105_i2c_xfer(&dev->i2c_adap, msg , 2); - dev_info(&dev->pdev->dev, "MAC %pM\n", mac); -} - -static int __devinit dm1105_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct dm1105_dev *dev; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret = -ENOMEM; - int i; - - dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - /* board config */ - dev->nr = dm1105_devcount; - dev->boardnr = UNSET; - if (card[dev->nr] < ARRAY_SIZE(dm1105_boards)) - dev->boardnr = card[dev->nr]; - for (i = 0; UNSET == dev->boardnr && - i < ARRAY_SIZE(dm1105_subids); i++) - if (pdev->subsystem_vendor == - dm1105_subids[i].subvendor && - pdev->subsystem_device == - dm1105_subids[i].subdevice) - dev->boardnr = dm1105_subids[i].card; - - if (UNSET == dev->boardnr) { - dev->boardnr = DM1105_BOARD_UNKNOWN; - dm1105_card_list(pdev); - } - - dm1105_devcount++; - dev->pdev = pdev; - dev->buffer_size = 5 * DM1105_DMA_BYTES; - dev->PacketErrorCount = 0; - dev->dmarst = 0; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_kfree; - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - 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; - - dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); - if (!dev->io_mem) { - ret = -EIO; - goto err_pci_release_regions; - } - - spin_lock_init(&dev->lock); - pci_set_drvdata(pdev, dev); - - ret = dm1105_hw_init(dev); - if (ret < 0) - goto err_pci_iounmap; - - /* i2c */ - i2c_set_adapdata(&dev->i2c_adap, dev); - strcpy(dev->i2c_adap.name, DRIVER_NAME); - dev->i2c_adap.owner = THIS_MODULE; - dev->i2c_adap.dev.parent = &pdev->dev; - dev->i2c_adap.algo = &dm1105_algo; - dev->i2c_adap.algo_data = dev; - ret = i2c_add_adapter(&dev->i2c_adap); - - if (ret < 0) - goto err_dm1105_hw_exit; - - i2c_set_adapdata(&dev->i2c_bb_adap, dev); - strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME); - dev->i2c_bb_adap.owner = THIS_MODULE; - dev->i2c_bb_adap.dev.parent = &pdev->dev; - dev->i2c_bb_adap.algo_data = &dev->i2c_bit; - dev->i2c_bit.data = dev; - dev->i2c_bit.setsda = dm1105_setsda; - dev->i2c_bit.setscl = dm1105_setscl; - dev->i2c_bit.getsda = dm1105_getsda; - dev->i2c_bit.getscl = dm1105_getscl; - dev->i2c_bit.udelay = 10; - dev->i2c_bit.timeout = 10; - - /* Raise SCL and SDA */ - dm1105_setsda(dev, 1); - dm1105_setscl(dev, 1); - - ret = i2c_bit_add_bus(&dev->i2c_bb_adap); - if (ret < 0) - goto err_i2c_del_adapter; - - /* dvb */ - ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME, - THIS_MODULE, &pdev->dev, adapter_nr); - if (ret < 0) - goto err_i2c_del_adapters; - - dvb_adapter = &dev->dvb_adapter; - - dm1105_read_mac(dev, dvb_adapter->proposed_mac); - - dvbdemux = &dev->demux; - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = dm1105_start_feed; - dvbdemux->stop_feed = dm1105_stop_feed; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto err_dvb_unregister_adapter; - - dmx = &dvbdemux->dmx; - dev->dmxdev.filternum = 256; - dev->dmxdev.demux = dmx; - dev->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter); - if (ret < 0) - goto err_dvb_dmx_release; - - dev->hw_frontend.source = DMX_FRONTEND_0; - - ret = dmx->add_frontend(dmx, &dev->hw_frontend); - if (ret < 0) - goto err_dvb_dmxdev_release; - - dev->mem_frontend.source = DMX_MEMORY_FE; - - ret = dmx->add_frontend(dmx, &dev->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &dev->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); - if (ret < 0) - goto err_disconnect_frontend; - - ret = frontend_init(dev); - if (ret < 0) - goto err_dvb_net; - - dm1105_ir_init(dev); - - INIT_WORK(&dev->work, dm1105_dmx_buffer); - sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); - dev->wq = create_singlethread_workqueue(dev->wqn); - if (!dev->wq) - goto err_dvb_net; - - ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED, - DRIVER_NAME, dev); - if (ret < 0) - goto err_workqueue; - - return 0; - -err_workqueue: - destroy_workqueue(dev->wq); -err_dvb_net: - dvb_net_release(&dev->dvbnet); -err_disconnect_frontend: - dmx->disconnect_frontend(dmx); -err_remove_mem_frontend: - dmx->remove_frontend(dmx, &dev->mem_frontend); -err_remove_hw_frontend: - dmx->remove_frontend(dmx, &dev->hw_frontend); -err_dvb_dmxdev_release: - dvb_dmxdev_release(&dev->dmxdev); -err_dvb_dmx_release: - dvb_dmx_release(dvbdemux); -err_dvb_unregister_adapter: - dvb_unregister_adapter(dvb_adapter); -err_i2c_del_adapters: - i2c_del_adapter(&dev->i2c_bb_adap); -err_i2c_del_adapter: - i2c_del_adapter(&dev->i2c_adap); -err_dm1105_hw_exit: - dm1105_hw_exit(dev); -err_pci_iounmap: - pci_iounmap(pdev, dev->io_mem); -err_pci_release_regions: - pci_release_regions(pdev); -err_pci_disable_device: - pci_disable_device(pdev); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(dev); - return ret; -} - -static void __devexit dm1105_remove(struct pci_dev *pdev) -{ - struct dm1105_dev *dev = pci_get_drvdata(pdev); - struct dvb_adapter *dvb_adapter = &dev->dvb_adapter; - struct dvb_demux *dvbdemux = &dev->demux; - struct dmx_demux *dmx = &dvbdemux->dmx; - - dm1105_ir_exit(dev); - dmx->close(dmx); - dvb_net_release(&dev->dvbnet); - if (dev->fe) - dvb_unregister_frontend(dev->fe); - - dmx->disconnect_frontend(dmx); - dmx->remove_frontend(dmx, &dev->mem_frontend); - dmx->remove_frontend(dmx, &dev->hw_frontend); - dvb_dmxdev_release(&dev->dmxdev); - dvb_dmx_release(dvbdemux); - dvb_unregister_adapter(dvb_adapter); - if (&dev->i2c_adap) - i2c_del_adapter(&dev->i2c_adap); - - dm1105_hw_exit(dev); - synchronize_irq(pdev->irq); - free_irq(pdev->irq, dev); - pci_iounmap(pdev, dev->io_mem); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - dm1105_devcount--; - kfree(dev); -} - -static struct pci_device_id dm1105_id_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_TRIGEM, - .device = PCI_DEVICE_ID_DM1105, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - .vendor = PCI_VENDOR_ID_AXESS, - .device = PCI_DEVICE_ID_DM05, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* empty */ - }, -}; - -MODULE_DEVICE_TABLE(pci, dm1105_id_table); - -static struct pci_driver dm1105_driver = { - .name = DRIVER_NAME, - .id_table = dm1105_id_table, - .probe = dm1105_probe, - .remove = __devexit_p(dm1105_remove), -}; - -static int __init dm1105_init(void) -{ - return pci_register_driver(&dm1105_driver); -} - -static void __exit dm1105_exit(void) -{ - pci_unregister_driver(&dm1105_driver); -} - -module_init(dm1105_init); -module_exit(dm1105_exit); - -MODULE_AUTHOR("Igor M. Liplianin "); -MODULE_DESCRIPTION("SDMC DM1105 DVB driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig deleted file mode 100644 index a13a5050313..00000000000 --- a/drivers/media/dvb/mantis/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config MANTIS_CORE - tristate "Mantis/Hopper PCI bridge based devices" - depends on PCI && I2C && INPUT && RC_CORE - - help - Support for PCI cards based on the Mantis and Hopper PCi bridge. - - Say Y if you own such a device and want to use it. - -config DVB_MANTIS - tristate "MANTIS based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_MB86A16 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_TDA665x if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Mantis PCI bridge. - Say Y when you have a Mantis based DVB card and want to use it. - - If unsure say N. - -config DVB_HOPPER - tristate "HOPPER based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Hopper PCI bridge. - Say Y when you have a Hopper based DVB card and want to use it. - - If unsure say N diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile deleted file mode 100644 index f715051e445..00000000000 --- a/drivers/media/dvb/mantis/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -mantis_core-objs := mantis_ioc.o \ - mantis_uart.o \ - mantis_dma.o \ - mantis_pci.o \ - mantis_i2c.o \ - mantis_dvb.o \ - mantis_evm.o \ - mantis_hif.o \ - mantis_ca.o \ - mantis_pcmcia.o \ - mantis_input.o - -mantis-objs := mantis_cards.o \ - mantis_vp1033.o \ - mantis_vp1034.o \ - mantis_vp1041.o \ - mantis_vp2033.o \ - mantis_vp2040.o \ - mantis_vp3030.o - -hopper-objs := hopper_cards.o \ - hopper_vp3028.o - -obj-$(CONFIG_MANTIS_CORE) += mantis_core.o -obj-$(CONFIG_DVB_MANTIS) += mantis.o -obj-$(CONFIG_DVB_HOPPER) += hopper.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c deleted file mode 100644 index cc0251e0107..00000000000 --- a/drivers/media/dvb/mantis/hopper_cards.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - Hopper PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "hopper_vp3028.h" -#include "mantis_dma.h" -#include "mantis_dvb.h" -#include "mantis_uart.h" -#include "mantis_ioc.h" -#include "mantis_pci.h" -#include "mantis_i2c.h" -#include "mantis_reg.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); - -#define DRIVER_NAME "Hopper" - -static char *label[10] = { - "DMA", - "IRQ-0", - "IRQ-1", - "OCERR", - "PABRT", - "RIPRR", - "PPERR", - "FTRGT", - "RISCI", - "RACK" -}; - -static int devs; - -static irqreturn_t hopper_irq_handler(int irq, void *dev_id) -{ - u32 stat = 0, mask = 0; - u32 rst_stat = 0, rst_mask = 0; - - struct mantis_pci *mantis; - struct mantis_ca *ca; - - mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { - dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); - return IRQ_NONE; - } - ca = mantis->mantis_ca; - - stat = mmread(MANTIS_INT_STAT); - mask = mmread(MANTIS_INT_MASK); - if (!(stat & mask)) - return IRQ_NONE; - - rst_mask = MANTIS_GPIF_WRACK | - MANTIS_GPIF_OTHERR | - MANTIS_SBUF_WSTO | - MANTIS_GPIF_EXTIRQ; - - rst_stat = mmread(MANTIS_GPIF_STATUS); - rst_stat &= rst_mask; - mmwrite(rst_stat, MANTIS_GPIF_STATUS); - - mantis->mantis_int_stat = stat; - mantis->mantis_int_mask = mask; - dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); - if (stat & MANTIS_INT_RISCEN) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); - } - if (stat & MANTIS_INT_IRQ0) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); - mantis->gpif_status = rst_stat; - wake_up(&ca->hif_write_wq); - schedule_work(&ca->hif_evm_work); - } - if (stat & MANTIS_INT_IRQ1) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); - schedule_work(&mantis->uart_work); - } - if (stat & MANTIS_INT_OCERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); - } - if (stat & MANTIS_INT_PABORT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); - } - if (stat & MANTIS_INT_RIPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); - } - if (stat & MANTIS_INT_PPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); - } - if (stat & MANTIS_INT_FTRGT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); - } - if (stat & MANTIS_INT_RISCI) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); - mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; - tasklet_schedule(&mantis->tasklet); - } - if (stat & MANTIS_INT_I2CDONE) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); - wake_up(&mantis->i2c_wq); - } - mmwrite(stat, MANTIS_INT_STAT); - stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | - MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | - MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | - MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | - MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | - MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | - MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | - MANTIS_INT_PABORT | MANTIS_INT_RIPERR | - MANTIS_INT_PPERR | MANTIS_INT_FTRGT | - MANTIS_INT_RISCI); - - if (stat) - dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); - - dprintk(MANTIS_DEBUG, 0, "\n"); - return IRQ_HANDLED; -} - -static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) -{ - struct mantis_pci *mantis; - struct mantis_hwconfig *config; - int err = 0; - - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); - if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); - err = -ENOMEM; - goto fail0; - } - - mantis->num = devs; - mantis->verbose = verbose; - mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; - config->irq_handler = &hopper_irq_handler; - mantis->hwconfig = config; - - err = mantis_pci_init(mantis); - if (err) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); - goto fail1; - } - - err = mantis_stream_control(mantis, STREAM_TO_HIF); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); - goto fail1; - } - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); - goto fail2; - } - - err = mantis_get_mac(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); - goto fail2; - } - - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); - goto fail3; - } - - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); - goto fail4; - } - devs++; - - return err; - -fail4: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); - mantis_dma_exit(mantis); - -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); - mantis_i2c_exit(mantis); - -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); - mantis_pci_exit(mantis); - -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); - kfree(mantis); - -fail0: - return err; -} - -static void __devexit hopper_pci_remove(struct pci_dev *pdev) -{ - struct mantis_pci *mantis = pci_get_drvdata(pdev); - - if (mantis) { - mantis_dvb_exit(mantis); - mantis_dma_exit(mantis); - mantis_i2c_exit(mantis); - mantis_pci_exit(mantis); - kfree(mantis); - } - return; - -} - -static struct pci_device_id hopper_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), - { } -}; - -MODULE_DEVICE_TABLE(pci, hopper_pci_table); - -static struct pci_driver hopper_pci_driver = { - .name = DRIVER_NAME, - .id_table = hopper_pci_table, - .probe = hopper_pci_probe, - .remove = hopper_pci_remove, -}; - -static int __devinit hopper_init(void) -{ - return pci_register_driver(&hopper_pci_driver); -} - -static void __devexit hopper_exit(void) -{ - return pci_unregister_driver(&hopper_pci_driver); -} - -module_init(hopper_init); -module_exit(hopper_exit); - -MODULE_DESCRIPTION("HOPPER driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c deleted file mode 100644 index 68a29f8bdf7..00000000000 --- a/drivers/media/dvb/mantis/hopper_vp3028.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - Hopper VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "zl10353.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "hopper_vp3028.h" - -struct zl10353_config hopper_vp3028_config = { - .demod_address = 0x0f, -}; - -#define MANTIS_MODEL_NAME "VP-3028" -#define MANTIS_DEV_TYPE "DVB-T" - -static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - struct mantis_hwconfig *config = mantis->hwconfig; - int err = 0; - - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - err = mantis_frontend_power(mantis, POWER_ON); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - msleep(250); - dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); - fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter); - - if (!fe) - return -1; - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp3028_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp3028_frontend_init, - .power = GPIF_A00, - .reset = GPIF_A03, -}; diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h deleted file mode 100644 index 57239498bc8..00000000000 --- a/drivers/media/dvb/mantis/hopper_vp3028.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Hopper VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3028_H -#define __MANTIS_VP3028_H - -#include "mantis_common.h" - -#define MANTIS_VP_3028_DVB_T 0x0028 - -extern struct mantis_hwconfig vp3028_config; - -#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c deleted file mode 100644 index 3d704690900..00000000000 --- a/drivers/media/dvb/mantis/mantis_ca.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_link.h" -#include "mantis_hif.h" -#include "mantis_reg.h" - -#include "mantis_ca.h" - -static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_read_mem(ca, addr); -} - -static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_write_mem(ca, addr, data); -} - -static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_read_iom(ca, addr); -} - -static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_write_iom(ca, addr, data); -} - -static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot); - udelay(500); /* Wait.. */ - mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ - udelay(500); - mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ - msleep(1000); - dvb_ca_en50221_camready_irq(&ca->en50221, 0); - - return 0; -} - -static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot); - - return 0; -} - -static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); -/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ - - return 0; -} - -static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot); - - if (ca->slot_state == MODULE_INSERTED) { - dprintk(MANTIS_DEBUG, 1, "CA Module present and ready"); - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } else { - dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready"); - } - - return 0; -} - -int mantis_ca_init(struct mantis_pci *mantis) -{ - struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter; - struct mantis_ca *ca; - int ca_flags = 0, result; - - dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA"); - ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL); - if (!ca) { - dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .."); - result = -ENOMEM; - goto err; - } - - ca->ca_priv = mantis; - mantis->mantis_ca = ca; - ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; - /* register CA interface */ - ca->en50221.owner = THIS_MODULE; - ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem; - ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem; - ca->en50221.read_cam_control = mantis_ca_read_cam_ctl; - ca->en50221.write_cam_control = mantis_ca_write_cam_ctl; - ca->en50221.slot_reset = mantis_ca_slot_reset; - ca->en50221.slot_shutdown = mantis_ca_slot_shutdown; - ca->en50221.slot_ts_enable = mantis_ts_control; - ca->en50221.poll_slot_status = mantis_slot_status; - ca->en50221.data = ca; - - mutex_init(&ca->ca_lock); - - init_waitqueue_head(&ca->hif_data_wq); - init_waitqueue_head(&ca->hif_opdone_wq); - init_waitqueue_head(&ca->hif_write_wq); - - dprintk(MANTIS_ERROR, 1, "Registering EN50221 device"); - result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1); - if (result != 0) { - dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result); - goto err; - } - dprintk(MANTIS_ERROR, 1, "Registered EN50221 device"); - mantis_evmgr_init(ca); - return 0; -err: - kfree(ca); - return result; -} -EXPORT_SYMBOL_GPL(mantis_ca_init); - -void mantis_ca_exit(struct mantis_pci *mantis) -{ - struct mantis_ca *ca = mantis->mantis_ca; - - dprintk(MANTIS_DEBUG, 1, "Mantis CA exit"); - - mantis_evmgr_exit(ca); - dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device"); - if (ca) - dvb_ca_en50221_release(&ca->en50221); - - kfree(ca); -} -EXPORT_SYMBOL_GPL(mantis_ca_exit); diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h deleted file mode 100644 index dc63e55f7ec..00000000000 --- a/drivers/media/dvb/mantis/mantis_ca.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_CA_H -#define __MANTIS_CA_H - -extern int mantis_ca_init(struct mantis_pci *mantis); -extern void mantis_ca_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_CA_H */ diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c deleted file mode 100644 index 0207d1f064e..00000000000 --- a/drivers/media/dvb/mantis/mantis_cards.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" - -#include "mantis_vp1033.h" -#include "mantis_vp1034.h" -#include "mantis_vp1041.h" -#include "mantis_vp2033.h" -#include "mantis_vp2040.h" -#include "mantis_vp3030.h" - -#include "mantis_dma.h" -#include "mantis_ca.h" -#include "mantis_dvb.h" -#include "mantis_uart.h" -#include "mantis_ioc.h" -#include "mantis_pci.h" -#include "mantis_i2c.h" -#include "mantis_reg.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); - -static int devs; - -#define DRIVER_NAME "Mantis" - -static char *label[10] = { - "DMA", - "IRQ-0", - "IRQ-1", - "OCERR", - "PABRT", - "RIPRR", - "PPERR", - "FTRGT", - "RISCI", - "RACK" -}; - -static irqreturn_t mantis_irq_handler(int irq, void *dev_id) -{ - u32 stat = 0, mask = 0; - u32 rst_stat = 0, rst_mask = 0; - - struct mantis_pci *mantis; - struct mantis_ca *ca; - - mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { - dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); - return IRQ_NONE; - } - ca = mantis->mantis_ca; - - stat = mmread(MANTIS_INT_STAT); - mask = mmread(MANTIS_INT_MASK); - if (!(stat & mask)) - return IRQ_NONE; - - rst_mask = MANTIS_GPIF_WRACK | - MANTIS_GPIF_OTHERR | - MANTIS_SBUF_WSTO | - MANTIS_GPIF_EXTIRQ; - - rst_stat = mmread(MANTIS_GPIF_STATUS); - rst_stat &= rst_mask; - mmwrite(rst_stat, MANTIS_GPIF_STATUS); - - mantis->mantis_int_stat = stat; - mantis->mantis_int_mask = mask; - dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); - if (stat & MANTIS_INT_RISCEN) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); - } - if (stat & MANTIS_INT_IRQ0) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); - mantis->gpif_status = rst_stat; - wake_up(&ca->hif_write_wq); - schedule_work(&ca->hif_evm_work); - } - if (stat & MANTIS_INT_IRQ1) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); - schedule_work(&mantis->uart_work); - } - if (stat & MANTIS_INT_OCERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); - } - if (stat & MANTIS_INT_PABORT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); - } - if (stat & MANTIS_INT_RIPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); - } - if (stat & MANTIS_INT_PPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); - } - if (stat & MANTIS_INT_FTRGT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); - } - if (stat & MANTIS_INT_RISCI) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); - mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; - tasklet_schedule(&mantis->tasklet); - } - if (stat & MANTIS_INT_I2CDONE) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); - wake_up(&mantis->i2c_wq); - } - mmwrite(stat, MANTIS_INT_STAT); - stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | - MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | - MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | - MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | - MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | - MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | - MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | - MANTIS_INT_PABORT | MANTIS_INT_RIPERR | - MANTIS_INT_PPERR | MANTIS_INT_FTRGT | - MANTIS_INT_RISCI); - - if (stat) - dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); - - dprintk(MANTIS_DEBUG, 0, "\n"); - return IRQ_HANDLED; -} - -static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) -{ - struct mantis_pci *mantis; - struct mantis_hwconfig *config; - int err = 0; - - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); - if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); - err = -ENOMEM; - goto fail0; - } - - mantis->num = devs; - mantis->verbose = verbose; - mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; - config->irq_handler = &mantis_irq_handler; - mantis->hwconfig = config; - - err = mantis_pci_init(mantis); - if (err) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); - goto fail1; - } - - err = mantis_stream_control(mantis, STREAM_TO_HIF); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); - goto fail1; - } - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); - goto fail2; - } - - err = mantis_get_mac(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); - goto fail2; - } - - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); - goto fail3; - } - - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); - goto fail4; - } - err = mantis_uart_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); - goto fail6; - } - - devs++; - - return err; - - - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); - mantis_uart_exit(mantis); - -fail6: -fail4: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); - mantis_dma_exit(mantis); - -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); - mantis_i2c_exit(mantis); - -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); - mantis_pci_exit(mantis); - -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); - kfree(mantis); - -fail0: - return err; -} - -static void __devexit mantis_pci_remove(struct pci_dev *pdev) -{ - struct mantis_pci *mantis = pci_get_drvdata(pdev); - - if (mantis) { - - mantis_uart_exit(mantis); - mantis_dvb_exit(mantis); - mantis_dma_exit(mantis); - mantis_i2c_exit(mantis); - mantis_pci_exit(mantis); - kfree(mantis); - } - return; -} - -static struct pci_device_id mantis_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), - MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), - MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), - MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), - { } -}; - -MODULE_DEVICE_TABLE(pci, mantis_pci_table); - -static struct pci_driver mantis_pci_driver = { - .name = DRIVER_NAME, - .id_table = mantis_pci_table, - .probe = mantis_pci_probe, - .remove = mantis_pci_remove, -}; - -static int __devinit mantis_init(void) -{ - return pci_register_driver(&mantis_pci_driver); -} - -static void __devexit mantis_exit(void) -{ - return pci_unregister_driver(&mantis_pci_driver); -} - -module_init(mantis_init); -module_exit(mantis_exit); - -MODULE_DESCRIPTION("MANTIS driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h deleted file mode 100644 index f2410cf0a6b..00000000000 --- a/drivers/media/dvb/mantis/mantis_common.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_COMMON_H -#define __MANTIS_COMMON_H - -#include -#include -#include - -#include "mantis_uart.h" - -#include "mantis_link.h" - -#define MANTIS_ERROR 0 -#define MANTIS_NOTICE 1 -#define MANTIS_INFO 2 -#define MANTIS_DEBUG 3 -#define MANTIS_TMG 9 - -#define dprintk(y, z, format, arg...) do { \ - if (z) { \ - if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \ - printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \ - printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \ - printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \ - printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \ - printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - } else { \ - if (mantis->verbose > y) \ - printk(format , ##arg); \ - } \ -} while(0) - -#define mwrite(dat, addr) writel((dat), addr) -#define mread(addr) readl(addr) - -#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr))) -#define mmread(addr) mread(mantis->mmio + (addr)) - -#define MANTIS_TS_188 0 -#define MANTIS_TS_204 1 - -#define TWINHAN_TECHNOLOGIES 0x1822 -#define MANTIS 0x4e35 - -#define TECHNISAT 0x1ae4 -#define TERRATEC 0x153b - -#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ - .vendor = TWINHAN_TECHNOLOGIES, \ - .device = MANTIS, \ - .subvendor = (__subven), \ - .subdevice = (__subdev), \ - .driver_data = (unsigned long) (__configptr) \ -} - -enum mantis_i2c_mode { - MANTIS_PAGE_MODE = 0, - MANTIS_BYTE_MODE, -}; - -struct mantis_pci; - -struct mantis_hwconfig { - char *model_name; - char *dev_type; - u32 ts_size; - - enum mantis_baud baud_rate; - enum mantis_parity parity; - u32 bytes; - - irqreturn_t (*irq_handler)(int irq, void *dev_id); - int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe); - - u8 power; - u8 reset; - - enum mantis_i2c_mode i2c_mode; -}; - -struct mantis_pci { - unsigned int verbose; - - /* PCI stuff */ - u16 vendor_id; - u16 device_id; - u16 subsystem_vendor; - u16 subsystem_device; - - u8 latency; - - struct pci_dev *pdev; - - unsigned long mantis_addr; - void __iomem *mmio; - - u8 irq; - u8 revision; - - unsigned int num; - - /* RISC Core */ - u32 busy_block; - u32 last_block; - u8 *buf_cpu; - dma_addr_t buf_dma; - u32 *risc_cpu; - dma_addr_t risc_dma; - - struct tasklet_struct tasklet; - - struct i2c_adapter adapter; - int i2c_rc; - wait_queue_head_t i2c_wq; - struct mutex i2c_lock; - - /* DVB stuff */ - struct dvb_adapter dvb_adapter; - struct dvb_frontend *fe; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net dvbnet; - - u8 feeds; - - struct mantis_hwconfig *hwconfig; - - u32 mantis_int_stat; - u32 mantis_int_mask; - - /* board specific */ - u8 mac_address[8]; - u32 sub_vendor_id; - u32 sub_device_id; - - /* A12 A13 A14 */ - u32 gpio_status; - - u32 gpif_status; - - struct mantis_ca *mantis_ca; - - wait_queue_head_t uart_wq; - struct work_struct uart_work; - spinlock_t uart_lock; - - struct rc_dev *rc; - char input_name[80]; - char input_phys[80]; -}; - -#define MANTIS_HIF_STATUS (mantis->gpio_status) - -#endif /* __MANTIS_COMMON_H */ diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c deleted file mode 100644 index 684d9061fe2..00000000000 --- a/drivers/media/dvb/mantis/mantis_core.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "mantis_common.h" -#include "mantis_core.h" -#include "mantis_vp1033.h" -#include "mantis_vp1034.h" -#include "mantis_vp1041.h" -#include "mantis_vp2033.h" -#include "mantis_vp2040.h" -#include "mantis_vp3030.h" - -static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) -{ - int err; - struct i2c_msg msg[] = { - { - .addr = 0x50, - .flags = 0, - .buf = data, - .len = 1 - }, { - .addr = 0x50, - .flags = I2C_M_RD, - .buf = data, - .len = length - }, - }; - - err = i2c_transfer(&mantis->adapter, msg, 2); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, - "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", - err, data[0], data[1]); - - return err; - } - - return 0; -} - -static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) -{ - int err; - - struct i2c_msg msg = { - .addr = 0x50, - .flags = 0, - .buf = data, - .len = length - }; - - err = i2c_transfer(&mantis->adapter, &msg, 1); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, - "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", - err, length, data[0], data[1]); - - return err; - } - - return 0; -} - -static int get_mac_address(struct mantis_pci *mantis) -{ - int err; - - mantis->mac_address[0] = 0x08; - err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); - - return err; - } - dprintk(verbose, MANTIS_ERROR, 0, - " MAC Address=[%pM]\n", mantis->mac_address); - - return 0; -} - -#define MANTIS_MODEL_UNKNOWN "UNKNOWN" -#define MANTIS_DEV_UNKNOWN "UNKNOWN" - -struct mantis_hwconfig unknown_device = { - .model_name = MANTIS_MODEL_UNKNOWN, - .dev_type = MANTIS_DEV_UNKNOWN, -}; - -static void mantis_load_config(struct mantis_pci *mantis) -{ - switch (mantis->subsystem_device) { - case MANTIS_VP_1033_DVB_S: /* VP-1033 */ - mantis->hwconfig = &vp1033_mantis_config; - break; - case MANTIS_VP_1034_DVB_S: /* VP-1034 */ - mantis->hwconfig = &vp1034_mantis_config; - break; - case MANTIS_VP_1041_DVB_S2: /* VP-1041 */ - case TECHNISAT_SKYSTAR_HD2: - mantis->hwconfig = &vp1041_mantis_config; - break; - case MANTIS_VP_2033_DVB_C: /* VP-2033 */ - mantis->hwconfig = &vp2033_mantis_config; - break; - case MANTIS_VP_2040_DVB_C: /* VP-2040 */ - case CINERGY_C: /* VP-2040 clone */ - case TECHNISAT_CABLESTAR_HD2: - mantis->hwconfig = &vp2040_mantis_config; - break; - case MANTIS_VP_3030_DVB_T: /* VP-3030 */ - mantis->hwconfig = &vp3030_mantis_config; - break; - default: - mantis->hwconfig = &unknown_device; - break; - } -} - -int mantis_core_init(struct mantis_pci *mantis) -{ - int err = 0; - - mantis_load_config(mantis); - dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", - mantis->hwconfig->model_name, mantis->hwconfig->dev_type, - mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); - dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", - mantis->revision, - mantis->subsystem_vendor, mantis->subsystem_device); - dprintk(verbose, MANTIS_ERROR, 0, - "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", - mantis->pdev->irq, mantis->latency, - mantis->mantis_addr, mantis->mantis_mmio); - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); - return err; - } - err = get_mac_address(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); - return err; - } - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); - return err; - } - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); - return err; - } - err = mantis_uart_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); - return err; - } - - return 0; -} - -int mantis_core_exit(struct mantis_pci *mantis) -{ - mantis_dma_stop(mantis); - dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); - - mantis_uart_exit(mantis); - dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); - - if (mantis_dma_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); - if (mantis_dvb_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); - if (mantis_i2c_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); - - return 0; -} - -/* Turn the given bit on or off. */ -void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) -{ - u32 cur; - - cur = mmread(MANTIS_GPIF_ADDR); - if (value) - mantis->gpio_status = cur | (1 << bitpos); - else - mantis->gpio_status = cur & (~(1 << bitpos)); - - mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); - mmwrite(0x00, MANTIS_GPIF_DOUT); - udelay(100); -} - -/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ -void mantis_set_direction(struct mantis_pci *mantis, int direction) -{ - u32 reg; - - reg = mmread(0x28); - dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); - if (direction == 0x01) { - /* to CI */ - reg |= 0x04; - mmwrite(reg, 0x28); - reg &= 0xff - 0x04; - mmwrite(reg, 0x28); - } else { - reg &= 0xff - 0x04; - mmwrite(reg, 0x28); - reg |= 0x04; - mmwrite(reg, 0x28); - } -} diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h deleted file mode 100644 index 833ee42e694..00000000000 --- a/drivers/media/dvb/mantis/mantis_core.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_CORE_H -#define __MANTIS_CORE_H - -#include "mantis_common.h" - - -#define FE_TYPE_SAT 0 -#define FE_TYPE_CAB 1 -#define FE_TYPE_TER 2 - -#define FE_TYPE_TS204 0 -#define FE_TYPE_TS188 1 - - -struct vendorname { - u8 *sub_vendor_name; - u32 sub_vendor_id; -}; - -struct devicetype { - u8 *sub_device_name; - u32 sub_device_id; - u8 device_type; - u32 type_flags; -}; - - -extern int mantis_dma_init(struct mantis_pci *mantis); -extern int mantis_dma_exit(struct mantis_pci *mantis); -extern void mantis_dma_start(struct mantis_pci *mantis); -extern void mantis_dma_stop(struct mantis_pci *mantis); -extern int mantis_i2c_init(struct mantis_pci *mantis); -extern int mantis_i2c_exit(struct mantis_pci *mantis); -extern int mantis_core_init(struct mantis_pci *mantis); -extern int mantis_core_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c deleted file mode 100644 index 566c407175a..00000000000 --- a/drivers/media/dvb/mantis/mantis_dma.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_dma.h" - -#define RISC_WRITE (0x01 << 28) -#define RISC_JUMP (0x07 << 28) -#define RISC_IRQ (0x01 << 24) - -#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) -#define RISC_FLUSH(risc_pos) (risc_pos = 0) -#define RISC_INSTR(risc_pos, opcode) (mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode)) - -#define MANTIS_BUF_SIZE (64 * 1024) -#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE / 4) -#define MANTIS_DMA_TR_BYTES (2 * 1024) /* upper limit: 4095 bytes. */ -#define MANTIS_BLOCK_COUNT (MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES) - -#define MANTIS_DMA_TR_UNITS (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES) -/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */ -#define MANTIS_RISC_SIZE PAGE_SIZE /* RISC program must fit here. */ - -int mantis_dma_exit(struct mantis_pci *mantis) -{ - if (mantis->buf_cpu) { - dprintk(MANTIS_ERROR, 1, - "DMA=0x%lx cpu=0x%p size=%d", - (unsigned long) mantis->buf_dma, - mantis->buf_cpu, - MANTIS_BUF_SIZE); - - pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, - mantis->buf_cpu, mantis->buf_dma); - - mantis->buf_cpu = NULL; - } - if (mantis->risc_cpu) { - dprintk(MANTIS_ERROR, 1, - "RISC=0x%lx cpu=0x%p size=%lx", - (unsigned long) mantis->risc_dma, - mantis->risc_cpu, - MANTIS_RISC_SIZE); - - pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, - mantis->risc_cpu, mantis->risc_dma); - - mantis->risc_cpu = NULL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_dma_exit); - -static inline int mantis_alloc_buffers(struct mantis_pci *mantis) -{ - if (!mantis->buf_cpu) { - mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, - MANTIS_BUF_SIZE, - &mantis->buf_dma); - if (!mantis->buf_cpu) { - dprintk(MANTIS_ERROR, 1, - "DMA buffer allocation failed"); - - goto err; - } - dprintk(MANTIS_ERROR, 1, - "DMA=0x%lx cpu=0x%p size=%d", - (unsigned long) mantis->buf_dma, - mantis->buf_cpu, MANTIS_BUF_SIZE); - } - if (!mantis->risc_cpu) { - mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, - MANTIS_RISC_SIZE, - &mantis->risc_dma); - - if (!mantis->risc_cpu) { - dprintk(MANTIS_ERROR, 1, - "RISC program allocation failed"); - - mantis_dma_exit(mantis); - - goto err; - } - dprintk(MANTIS_ERROR, 1, - "RISC=0x%lx cpu=0x%p size=%lx", - (unsigned long) mantis->risc_dma, - mantis->risc_cpu, MANTIS_RISC_SIZE); - } - - return 0; -err: - dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); - return -ENOMEM; -} - -int mantis_dma_init(struct mantis_pci *mantis) -{ - int err = 0; - - dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); - if (mantis_alloc_buffers(mantis) < 0) { - dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); - - /* Stop RISC Engine */ - mmwrite(0, MANTIS_DMA_CTL); - - goto err; - } - - return 0; -err: - return err; -} -EXPORT_SYMBOL_GPL(mantis_dma_init); - -static inline void mantis_risc_program(struct mantis_pci *mantis) -{ - u32 buf_pos = 0; - u32 line, step; - u32 risc_pos; - - dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); - RISC_FLUSH(risc_pos); - - dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u", - MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES); - - for (line = 0; line < MANTIS_BLOCK_COUNT; line++) { - for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) { - dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step); - if (step == 0) { - RISC_INSTR(risc_pos, RISC_WRITE | - RISC_IRQ | - RISC_STATUS(line) | - MANTIS_DMA_TR_BYTES); - } else { - RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES); - } - RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos); - buf_pos += MANTIS_DMA_TR_BYTES; - } - } - RISC_INSTR(risc_pos, RISC_JUMP); - RISC_INSTR(risc_pos, mantis->risc_dma); -} - -void mantis_dma_start(struct mantis_pci *mantis) -{ - dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); - - mantis_risc_program(mantis); - mmwrite(mantis->risc_dma, MANTIS_RISC_START); - mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - mmwrite(0, MANTIS_DMA_CTL); - mantis->last_block = mantis->busy_block = 0; - - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); - - mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN - | MANTIS_RISC_EN, MANTIS_DMA_CTL); - -} - -void mantis_dma_stop(struct mantis_pci *mantis) -{ - dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); - - mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); - - mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | - MANTIS_DCAP_EN | - MANTIS_RISC_EN)), MANTIS_DMA_CTL); - - mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); - - mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | - MANTIS_INT_RISCEN), MANTIS_INT_MASK); -} - - -void mantis_dma_xfer(unsigned long data) -{ - struct mantis_pci *mantis = (struct mantis_pci *) data; - struct mantis_hwconfig *config = mantis->hwconfig; - - while (mantis->last_block != mantis->busy_block) { - dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", - mantis->last_block, mantis->busy_block); - - (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) - (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); - mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; - } -} diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h deleted file mode 100644 index 6be00fa8209..00000000000 --- a/drivers/media/dvb/mantis/mantis_dma.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_DMA_H -#define __MANTIS_DMA_H - -extern int mantis_dma_init(struct mantis_pci *mantis); -extern int mantis_dma_exit(struct mantis_pci *mantis); -extern void mantis_dma_start(struct mantis_pci *mantis); -extern void mantis_dma_stop(struct mantis_pci *mantis); -extern void mantis_dma_xfer(unsigned long data); - -#endif /* __MANTIS_DMA_H */ diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c deleted file mode 100644 index 5d15c6b74d9..00000000000 --- a/drivers/media/dvb/mantis/mantis_dvb.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - Mantis PCI bridge driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_dma.h" -#include "mantis_ca.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - - switch (power) { - case POWER_ON: - dprintk(MANTIS_DEBUG, 1, "Power ON"); - mantis_gpio_set_bits(mantis, config->power, POWER_ON); - msleep(100); - mantis_gpio_set_bits(mantis, config->power, POWER_ON); - msleep(100); - break; - - case POWER_OFF: - dprintk(MANTIS_DEBUG, 1, "Power OFF"); - mantis_gpio_set_bits(mantis, config->power, POWER_OFF); - msleep(100); - break; - - default: - dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); - return -1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_frontend_power); - -void mantis_frontend_soft_reset(struct mantis_pci *mantis) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - - dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - msleep(100); - - return; -} -EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); - -static int mantis_frontend_shutdown(struct mantis_pci *mantis) -{ - int err; - - mantis_frontend_soft_reset(mantis); - err = mantis_frontend_power(mantis, POWER_OFF); - if (err != 0) { - dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); - return 1; - } - - return 0; -} - -static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct mantis_pci *mantis = dvbdmx->priv; - - dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); - if (!dvbdmx->dmx.frontend) { - dprintk(MANTIS_DEBUG, 1, "no frontend ?"); - return -EINVAL; - } - - mantis->feeds++; - dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); - - if (mantis->feeds == 1) { - dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); - mantis_dma_start(mantis); - tasklet_enable(&mantis->tasklet); - } - - return mantis->feeds; -} - -static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct mantis_pci *mantis = dvbdmx->priv; - - dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); - if (!dvbdmx->dmx.frontend) { - dprintk(MANTIS_DEBUG, 1, "no frontend ?"); - return -EINVAL; - } - - mantis->feeds--; - if (mantis->feeds == 0) { - dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); - tasklet_disable(&mantis->tasklet); - mantis_dma_stop(mantis); - } - - return 0; -} - -int __devinit mantis_dvb_init(struct mantis_pci *mantis) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - int result = -1; - - dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); - - result = dvb_register_adapter(&mantis->dvb_adapter, - "Mantis DVB adapter", - THIS_MODULE, - &mantis->pdev->dev, - adapter_nr); - - if (result < 0) { - - dprintk(MANTIS_ERROR, 1, "Error registering adapter"); - return -ENODEV; - } - - mantis->dvb_adapter.priv = mantis; - mantis->demux.dmx.capabilities = DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - - mantis->demux.priv = mantis; - mantis->demux.filternum = 256; - mantis->demux.feednum = 256; - mantis->demux.start_feed = mantis_dvb_start_feed; - mantis->demux.stop_feed = mantis_dvb_stop_feed; - mantis->demux.write_to_decoder = NULL; - - dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); - result = dvb_dmx_init(&mantis->demux); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - - goto err0; - } - - mantis->dmxdev.filternum = 256; - mantis->dmxdev.demux = &mantis->demux.dmx; - mantis->dmxdev.capabilities = 0; - dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); - - result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); - if (result < 0) { - - dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); - goto err1; - } - - mantis->fe_hw.source = DMX_FRONTEND_0; - result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); - if (result < 0) { - - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - goto err2; - } - - mantis->fe_mem.source = DMX_MEMORY_FE; - result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - goto err3; - } - - result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - goto err4; - } - - dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); - tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); - tasklet_disable(&mantis->tasklet); - if (mantis->hwconfig) { - result = config->frontend_init(mantis, mantis->fe); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); - goto err5; - } else { - if (mantis->fe == NULL) { - dprintk(MANTIS_ERROR, 1, "FE "); - goto err5; - } - - if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { - dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); - - if (mantis->fe->ops.release) - mantis->fe->ops.release(mantis->fe); - - mantis->fe = NULL; - goto err5; - } - } - } - - return 0; - - /* Error conditions .. */ -err5: - tasklet_kill(&mantis->tasklet); - dvb_net_release(&mantis->dvbnet); - if (mantis->fe) { - dvb_unregister_frontend(mantis->fe); - dvb_frontend_detach(mantis->fe); - } -err4: - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); - -err3: - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); - -err2: - dvb_dmxdev_release(&mantis->dmxdev); - -err1: - dvb_dmx_release(&mantis->demux); - -err0: - dvb_unregister_adapter(&mantis->dvb_adapter); - - return result; -} -EXPORT_SYMBOL_GPL(mantis_dvb_init); - -int __devexit mantis_dvb_exit(struct mantis_pci *mantis) -{ - int err; - - if (mantis->fe) { - /* mantis_ca_exit(mantis); */ - err = mantis_frontend_shutdown(mantis); - if (err != 0) - dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); - dvb_unregister_frontend(mantis->fe); - dvb_frontend_detach(mantis->fe); - } - - tasklet_kill(&mantis->tasklet); - dvb_net_release(&mantis->dvbnet); - - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); - - dvb_dmxdev_release(&mantis->dmxdev); - dvb_dmx_release(&mantis->demux); - - dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); - dvb_unregister_adapter(&mantis->dvb_adapter); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_dvb_exit); diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h deleted file mode 100644 index 464199db304..00000000000 --- a/drivers/media/dvb/mantis/mantis_dvb.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_DVB_H -#define __MANTIS_DVB_H - -enum mantis_power { - POWER_OFF = 0, - POWER_ON = 1 -}; - -extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power); -extern void mantis_frontend_soft_reset(struct mantis_pci *mantis); - -extern int mantis_dvb_init(struct mantis_pci *mantis); -extern int mantis_dvb_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_DVB_H */ diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c deleted file mode 100644 index 71ce52875c3..00000000000 --- a/drivers/media/dvb/mantis/mantis_evm.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_link.h" -#include "mantis_hif.h" -#include "mantis_reg.h" - -static void mantis_hifevm_work(struct work_struct *work) -{ - struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_stat; - - gpif_stat = mmread(MANTIS_GPIF_STATUS); - - if (gpif_stat & MANTIS_GPIF_DETSTAT) { - if (gpif_stat & MANTIS_CARD_PLUGIN) { - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num); - mmwrite(0xdada0000, MANTIS_CARD_RESET); - mantis_event_cam_plugin(ca); - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - } - } else { - if (gpif_stat & MANTIS_CARD_PLUGOUT) { - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num); - mmwrite(0xdada0000, MANTIS_CARD_RESET); - mantis_event_cam_unplug(ca); - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - } - - if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num); - - if (mantis->gpif_status & MANTIS_SBUF_WSTO) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num); - - if (mantis->gpif_status & MANTIS_GPIF_OTHERR) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num); - - if (gpif_stat & MANTIS_SBUF_OVFLW) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num); - - if (gpif_stat & MANTIS_GPIF_BRRDY) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num); - - if (gpif_stat & MANTIS_GPIF_INTSTAT) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num); - - if (gpif_stat & MANTIS_SBUF_EMPTY) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num); - - if (gpif_stat & MANTIS_SBUF_OPDONE) { - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num); - ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL; - ca->hif_event = MANTIS_SBUF_OPDONE; - wake_up(&ca->hif_opdone_wq); - } -} - -int mantis_evmgr_init(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager"); - INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work); - mantis_pcmcia_init(ca); - schedule_work(&ca->hif_evm_work); - mantis_hif_init(ca); - return 0; -} - -void mantis_evmgr_exit(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); - flush_work_sync(&ca->hif_evm_work); - mantis_hif_exit(ca); - mantis_pcmcia_exit(ca); -} diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c deleted file mode 100644 index 10c68df7e16..00000000000 --- a/drivers/media/dvb/mantis/mantis_hif.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" - -#include "mantis_hif.h" -#include "mantis_link.h" /* temporary due to physical layer stuff */ - -#include "mantis_reg.h" - - -static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - int rc = 0; - - if (wait_event_timeout(ca->hif_opdone_wq, - ca->hif_event & MANTIS_SBUF_OPDONE, - msecs_to_jiffies(500)) == -ERESTARTSYS) { - - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num); - rc = -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete"); - ca->hif_event &= ~MANTIS_SBUF_OPDONE; - return rc; -} - -static int mantis_hif_write_wait(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 opdone = 0, timeout = 0; - int rc = 0; - - if (wait_event_timeout(ca->hif_write_wq, - mantis->gpif_status & MANTIS_GPIF_WRACK, - msecs_to_jiffies(500)) == -ERESTARTSYS) { - - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num); - rc = -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "Write Acknowledged"); - mantis->gpif_status &= ~MANTIS_GPIF_WRACK; - while (!opdone) { - opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE); - udelay(500); - timeout++; - if (timeout > 100) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num); - rc = -ETIMEDOUT; - break; - } - } - dprintk(MANTIS_DEBUG, 1, "HIF Write success"); - return rc; -} - - -int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 hif_addr = 0, data, count = 4; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(hif_addr, MANTIS_GPIF_BRADDR); - mmwrite(count, MANTIS_GPIF_BRBYTES); - udelay(20); - mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - if (mantis_hif_sbuf_opdone_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - data = mmread(MANTIS_GPIF_DIN); - mutex_unlock(&ca->ca_lock); - dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data); - return (data >> 24) & 0xff; -} - -int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data) -{ - struct mantis_slot *slot = ca->slot; - struct mantis_pci *mantis = ca->ca_priv; - u32 hif_addr = 0; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_HIFRDWRN; - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */ - mmwrite(hif_addr, MANTIS_GPIF_ADDR); - mmwrite(data, MANTIS_GPIF_DOUT); - - if (mantis_hif_write_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr); - mutex_unlock(&ca->ca_lock); - - return 0; -} - -int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 data, hif_addr = 0; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr |= MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(hif_addr, MANTIS_GPIF_BRADDR); - mmwrite(1, MANTIS_GPIF_BRBYTES); - udelay(20); - mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - if (mantis_hif_sbuf_opdone_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - data = mmread(MANTIS_GPIF_DIN); - dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data); - udelay(50); - mutex_unlock(&ca->ca_lock); - - return (u8) data; -} - -int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 hif_addr = 0; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr &= ~MANTIS_GPIF_HIFRDWRN; - hif_addr |= MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(hif_addr, MANTIS_GPIF_ADDR); - mmwrite(data, MANTIS_GPIF_DOUT); - - if (mantis_hif_write_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr); - mutex_unlock(&ca->ca_lock); - udelay(50); - - return 0; -} - -int mantis_hif_init(struct mantis_ca *ca) -{ - struct mantis_slot *slot = ca->slot; - struct mantis_pci *mantis = ca->ca_priv; - u32 irqcfg; - - slot[0].slave_cfg = 0x70773028; - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num); - - mutex_lock(&ca->ca_lock); - irqcfg = mmread(MANTIS_GPIF_IRQCFG); - irqcfg = MANTIS_MASK_BRRDY | - MANTIS_MASK_WRACK | - MANTIS_MASK_EXTIRQ | - MANTIS_MASK_WSTO | - MANTIS_MASK_OTHERR | - MANTIS_MASK_OVFLW; - - mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); - mutex_unlock(&ca->ca_lock); - - return 0; -} - -void mantis_hif_exit(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 irqcfg; - - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num); - mutex_lock(&ca->ca_lock); - irqcfg = mmread(MANTIS_GPIF_IRQCFG); - irqcfg &= ~MANTIS_MASK_BRRDY; - mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); - mutex_unlock(&ca->ca_lock); -} diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h deleted file mode 100644 index 9094f9ed236..00000000000 --- a/drivers/media/dvb/mantis/mantis_hif.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_HIF_H -#define __MANTIS_HIF_H - -#define MANTIS_HIF_MEMRD 1 -#define MANTIS_HIF_MEMWR 2 -#define MANTIS_HIF_IOMRD 3 -#define MANTIS_HIF_IOMWR 4 - -#endif /* __MANTIS_HIF_H */ diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c deleted file mode 100644 index e7794517fe2..00000000000 --- a/drivers/media/dvb/mantis/mantis_i2c.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_i2c.h" - -#define TRIALS 10000 - -static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) -{ - u32 rxd, i, stat, trials; - - dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", - __func__, msg->addr); - - for (i = 0; i < msg->len; i++) { - rxd = (msg->addr << 25) | (1 << 24) - | MANTIS_I2C_RATE_3 - | MANTIS_I2C_STOP - | MANTIS_I2C_PGMODE; - - if (i == (msg->len - 1)) - rxd &= ~MANTIS_I2C_STOP; - - mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); - mmwrite(rxd, MANTIS_I2CDATA_CTL); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CDONE) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CRACK) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); - - rxd = mmread(MANTIS_I2CDATA_CTL); - msg->buf[i] = (u8)((rxd >> 8) & 0xFF); - dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); - } - dprintk(MANTIS_INFO, 0, "]\n"); - - return 0; -} - -static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) -{ - int i; - u32 txd = 0, stat, trials; - - dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", - __func__, msg->addr); - - for (i = 0; i < msg->len; i++) { - dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); - txd = (msg->addr << 25) | (msg->buf[i] << 8) - | MANTIS_I2C_RATE_3 - | MANTIS_I2C_STOP - | MANTIS_I2C_PGMODE; - - if (i == (msg->len - 1)) - txd &= ~MANTIS_I2C_STOP; - - mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); - mmwrite(txd, MANTIS_I2CDATA_CTL); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CDONE) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CRACK) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); - } - dprintk(MANTIS_INFO, 0, "]\n"); - - return 0; -} - -static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) -{ - int ret = 0, i = 0, trials; - u32 stat, data, txd; - struct mantis_pci *mantis; - struct mantis_hwconfig *config; - - mantis = i2c_get_adapdata(adapter); - BUG_ON(!mantis); - config = mantis->hwconfig; - BUG_ON(!config); - - dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); - mutex_lock(&mantis->i2c_lock); - - while (i < num) { - /* Byte MODE */ - if ((config->i2c_mode & MANTIS_BYTE_MODE) && - ((i + 1) < num) && - (msgs[i].len < 2) && - (msgs[i + 1].len < 2) && - (msgs[i + 1].flags & I2C_M_RD)) { - - dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); - - /* Read operation */ - txd = msgs[i].addr << 25 | (0x1 << 24) - | (msgs[i].buf[0] << 16) - | MANTIS_I2C_RATE_3; - - mmwrite(txd, MANTIS_I2CDATA_CTL); - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CDONE) - break; - } - - /* check for xfer completion */ - if (stat & MANTIS_INT_I2CDONE) { - /* check xfer was acknowledged */ - if (stat & MANTIS_INT_I2CRACK) { - data = mmread(MANTIS_I2CDATA_CTL); - msgs[i + 1].buf[0] = (data >> 8) & 0xff; - dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); - } else { - /* I/O error */ - dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); - ret = -EIO; - break; - } - } else { - /* I/O error */ - dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); - ret = -EIO; - break; - } - i += 2; /* Write/Read operation in one go */ - } - - if (i < num) { - if (msgs[i].flags & I2C_M_RD) - ret = mantis_i2c_read(mantis, &msgs[i]); - else - ret = mantis_i2c_write(mantis, &msgs[i]); - - i++; - if (ret < 0) - goto bail_out; - } - - } - - mutex_unlock(&mantis->i2c_lock); - - return num; - -bail_out: - mutex_unlock(&mantis->i2c_lock); - return ret; -} - -static u32 mantis_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm mantis_algo = { - .master_xfer = mantis_i2c_xfer, - .functionality = mantis_i2c_func, -}; - -int __devinit mantis_i2c_init(struct mantis_pci *mantis) -{ - u32 intstat, intmask; - struct i2c_adapter *i2c_adapter = &mantis->adapter; - struct pci_dev *pdev = mantis->pdev; - - init_waitqueue_head(&mantis->i2c_wq); - mutex_init(&mantis->i2c_lock); - strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); - i2c_set_adapdata(i2c_adapter, mantis); - - i2c_adapter->owner = THIS_MODULE; - i2c_adapter->algo = &mantis_algo; - i2c_adapter->algo_data = NULL; - i2c_adapter->timeout = 500; - i2c_adapter->retries = 3; - i2c_adapter->dev.parent = &pdev->dev; - - mantis->i2c_rc = i2c_add_adapter(i2c_adapter); - if (mantis->i2c_rc < 0) - return mantis->i2c_rc; - - dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); - - intstat = mmread(MANTIS_INT_STAT); - intmask = mmread(MANTIS_INT_MASK); - mmwrite(intstat, MANTIS_INT_STAT); - dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_i2c_init); - -int mantis_i2c_exit(struct mantis_pci *mantis) -{ - u32 intmask; - - dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); - - dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); - return i2c_del_adapter(&mantis->adapter); -} -EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h deleted file mode 100644 index 1342df2faed..00000000000 --- a/drivers/media/dvb/mantis/mantis_i2c.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_I2C_H -#define __MANTIS_I2C_H - -#define I2C_STOP (1 << 0) -#define I2C_READ (1 << 1) - -extern int mantis_i2c_init(struct mantis_pci *mantis); -extern int mantis_i2c_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_I2C_H */ diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c deleted file mode 100644 index db6d54d3fec..00000000000 --- a/drivers/media/dvb/mantis/mantis_input.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_uart.h" - -#define MODULE_NAME "mantis_core" -#define RC_MAP_MANTIS "rc-mantis" - -static struct rc_map_table mantis_ir_table[] = { - { 0x29, KEY_POWER }, - { 0x28, KEY_FAVORITES }, - { 0x30, KEY_TEXT }, - { 0x17, KEY_INFO }, /* Preview */ - { 0x23, KEY_EPG }, - { 0x3b, KEY_F22 }, /* Record List */ - { 0x3c, KEY_1 }, - { 0x3e, KEY_2 }, - { 0x39, KEY_3 }, - { 0x36, KEY_4 }, - { 0x22, KEY_5 }, - { 0x20, KEY_6 }, - { 0x32, KEY_7 }, - { 0x26, KEY_8 }, - { 0x24, KEY_9 }, - { 0x2a, KEY_0 }, - - { 0x33, KEY_CANCEL }, - { 0x2c, KEY_BACK }, - { 0x15, KEY_CLEAR }, - { 0x3f, KEY_TAB }, - { 0x10, KEY_ENTER }, - { 0x14, KEY_UP }, - { 0x0d, KEY_RIGHT }, - { 0x0e, KEY_DOWN }, - { 0x11, KEY_LEFT }, - - { 0x21, KEY_VOLUMEUP }, - { 0x35, KEY_VOLUMEDOWN }, - { 0x3d, KEY_CHANNELDOWN }, - { 0x3a, KEY_CHANNELUP }, - { 0x2e, KEY_RECORD }, - { 0x2b, KEY_PLAY }, - { 0x13, KEY_PAUSE }, - { 0x25, KEY_STOP }, - - { 0x1f, KEY_REWIND }, - { 0x2d, KEY_FASTFORWARD }, - { 0x1e, KEY_PREVIOUS }, /* Replay |< */ - { 0x1d, KEY_NEXT }, /* Skip >| */ - - { 0x0b, KEY_CAMERA }, /* Capture */ - { 0x0f, KEY_LANGUAGE }, /* SAP */ - { 0x18, KEY_MODE }, /* PIP */ - { 0x12, KEY_ZOOM }, /* Full screen */ - { 0x1c, KEY_SUBTITLE }, - { 0x2f, KEY_MUTE }, - { 0x16, KEY_F20 }, /* L/R */ - { 0x38, KEY_F21 }, /* Hibernate */ - - { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ - { 0x31, KEY_AGAIN }, /* Recall */ - { 0x1a, KEY_KPPLUS }, /* Zoom+ */ - { 0x19, KEY_KPMINUS }, /* Zoom- */ - { 0x27, KEY_RED }, - { 0x0C, KEY_GREEN }, - { 0x01, KEY_YELLOW }, - { 0x00, KEY_BLUE }, -}; - -static struct rc_map_list ir_mantis_map = { - .map = { - .scan = mantis_ir_table, - .size = ARRAY_SIZE(mantis_ir_table), - .rc_type = RC_TYPE_UNKNOWN, - .name = RC_MAP_MANTIS, - } -}; - -int mantis_input_init(struct mantis_pci *mantis) -{ - struct rc_dev *dev; - int err; - - err = rc_map_register(&ir_mantis_map); - if (err) - goto out; - - dev = rc_allocate_device(); - if (!dev) { - dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); - err = -ENOMEM; - goto out_map; - } - - sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); - sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); - - dev->input_name = mantis->input_name; - dev->input_phys = mantis->input_phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.vendor = mantis->vendor_id; - dev->input_id.product = mantis->device_id; - dev->input_id.version = 1; - dev->driver_name = MODULE_NAME; - dev->map_name = RC_MAP_MANTIS; - dev->dev.parent = &mantis->pdev->dev; - - err = rc_register_device(dev); - if (err) { - dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err); - goto out_dev; - } - - mantis->rc = dev; - return 0; - -out_dev: - rc_free_device(dev); -out_map: - rc_map_unregister(&ir_mantis_map); -out: - return err; -} - -int mantis_exit(struct mantis_pci *mantis) -{ - rc_unregister_device(mantis->rc); - rc_map_unregister(&ir_mantis_map); - return 0; -} - diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c deleted file mode 100644 index 24fcdc63d6d..00000000000 --- a/drivers/media/dvb/mantis/mantis_ioc.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_ioc.h" - -static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length) -{ - struct i2c_adapter *adapter = &mantis->adapter; - int err; - u8 buf = reg; - - struct i2c_msg msg[] = { - { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length }, - }; - - err = i2c_transfer(adapter, msg, 2); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", - err, data[0], data[1]); - - return err; - } - - return 0; -} -int mantis_get_mac(struct mantis_pci *mantis) -{ - int err; - u8 mac_addr[6] = {0}; - - err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err); - - return err; - } - - dprintk(MANTIS_ERROR, 0, " MAC Address=[%pM]\n", mac_addr); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_get_mac); - -/* Turn the given bit on or off. */ -void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) -{ - u32 cur; - - dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value); - cur = mmread(MANTIS_GPIF_ADDR); - if (value) - mantis->gpio_status = cur | (1 << bitpos); - else - mantis->gpio_status = cur & (~(1 << bitpos)); - - dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status); - mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); - mmwrite(0x00, MANTIS_GPIF_DOUT); -} -EXPORT_SYMBOL_GPL(mantis_gpio_set_bits); - -int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl) -{ - u32 reg; - - reg = mmread(MANTIS_CONTROL); - switch (stream_ctl) { - case STREAM_TO_HIF: - dprintk(MANTIS_DEBUG, 1, "Set stream to HIF"); - reg &= 0xff - MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - reg |= MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - break; - - case STREAM_TO_CAM: - dprintk(MANTIS_DEBUG, 1, "Set stream to CAM"); - reg |= MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - reg &= 0xff - MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - break; - default: - dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl); - return -1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_stream_control); diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h deleted file mode 100644 index d56e002b295..00000000000 --- a/drivers/media/dvb/mantis/mantis_ioc.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_IOC_H -#define __MANTIS_IOC_H - -#define GPIF_A00 0x00 -#define GPIF_A01 0x01 -#define GPIF_A02 0x02 -#define GPIF_A03 0x03 -#define GPIF_A04 0x04 -#define GPIF_A05 0x05 -#define GPIF_A06 0x06 -#define GPIF_A07 0x07 -#define GPIF_A08 0x08 -#define GPIF_A09 0x09 -#define GPIF_A10 0x0a -#define GPIF_A11 0x0b - -#define GPIF_A12 0x0c -#define GPIF_A13 0x0d -#define GPIF_A14 0x0e - -enum mantis_stream_control { - STREAM_TO_HIF = 0, - STREAM_TO_CAM -}; - -extern int mantis_get_mac(struct mantis_pci *mantis); -extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value); - -extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl); - -#endif /* __MANTIS_IOC_H */ diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h deleted file mode 100644 index 2a814774a00..00000000000 --- a/drivers/media/dvb/mantis/mantis_link.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_LINK_H -#define __MANTIS_LINK_H - -#include -#include -#include "dvb_ca_en50221.h" - -enum mantis_sbuf_status { - MANTIS_SBUF_DATA_AVAIL = 1, - MANTIS_SBUF_DATA_EMPTY = 2, - MANTIS_SBUF_DATA_OVFLW = 3 -}; - -struct mantis_slot { - u32 timeout; - u32 slave_cfg; - u32 bar; -}; - -/* Physical layer */ -enum mantis_slot_state { - MODULE_INSERTED = 3, - MODULE_XTRACTED = 4 -}; - -struct mantis_ca { - struct mantis_slot slot[4]; - - struct work_struct hif_evm_work; - - u32 hif_event; - wait_queue_head_t hif_opdone_wq; - wait_queue_head_t hif_brrdyw_wq; - wait_queue_head_t hif_data_wq; - wait_queue_head_t hif_write_wq; /* HIF Write op */ - - enum mantis_sbuf_status sbuf_status; - - enum mantis_slot_state slot_state; - - void *ca_priv; - - struct dvb_ca_en50221 en50221; - struct mutex ca_lock; -}; - -/* CA */ -extern void mantis_event_cam_plugin(struct mantis_ca *ca); -extern void mantis_event_cam_unplug(struct mantis_ca *ca); -extern int mantis_pcmcia_init(struct mantis_ca *ca); -extern void mantis_pcmcia_exit(struct mantis_ca *ca); -extern int mantis_evmgr_init(struct mantis_ca *ca); -extern void mantis_evmgr_exit(struct mantis_ca *ca); - -/* HIF */ -extern int mantis_hif_init(struct mantis_ca *ca); -extern void mantis_hif_exit(struct mantis_ca *ca); -extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr); -extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data); -extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr); -extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data); - -#endif /* __MANTIS_LINK_H */ diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c deleted file mode 100644 index 371558af2d9..00000000000 --- a/drivers/media/dvb/mantis/mantis_pci.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_pci.h" - -#define DRIVER_NAME "Mantis Core" - -int __devinit mantis_pci_init(struct mantis_pci *mantis) -{ - u8 latency; - struct mantis_hwconfig *config = mantis->hwconfig; - struct pci_dev *pdev = mantis->pdev; - int err, ret = 0; - - dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", - config->model_name, - config->dev_type, - mantis->pdev->bus->number, - PCI_SLOT(mantis->pdev->devfn), - PCI_FUNC(mantis->pdev->devfn)); - - err = pci_enable_device(pdev); - if (err != 0) { - ret = -ENODEV; - dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err); - goto fail0; - } - - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err != 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); - ret = -ENOMEM; - goto fail1; - } - - pci_set_master(pdev); - - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), - DRIVER_NAME)) { - - dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !"); - ret = -ENODEV; - goto fail1; - } - - mantis->mmio = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - - if (!mantis->mmio) { - dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !"); - ret = -ENODEV; - goto fail2; - } - - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); - mantis->latency = latency; - mantis->revision = pdev->revision; - - dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", - mantis->revision, - mantis->pdev->subsystem_vendor, - mantis->pdev->subsystem_device); - - dprintk(MANTIS_ERROR, 0, - "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", - mantis->pdev->irq, - mantis->latency, - mantis->mantis_addr, - mantis->mmio); - - err = request_irq(pdev->irq, - config->irq_handler, - IRQF_SHARED, - DRIVER_NAME, - mantis); - - if (err != 0) { - - dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err); - ret = -ENODEV; - goto fail3; - } - - pci_set_drvdata(pdev, mantis); - return ret; - - /* Error conditions */ -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret); - if (mantis->mmio) - iounmap(mantis->mmio); - -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret); - pci_disable_device(pdev); - -fail0: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret); - pci_set_drvdata(pdev, NULL); - return ret; -} -EXPORT_SYMBOL_GPL(mantis_pci_init); - -void mantis_pci_exit(struct mantis_pci *mantis) -{ - struct pci_dev *pdev = mantis->pdev; - - dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio); - free_irq(pdev->irq, mantis); - if (mantis->mmio) { - iounmap(mantis->mmio); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - } - - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} -EXPORT_SYMBOL_GPL(mantis_pci_exit); - -MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h deleted file mode 100644 index 65f00451908..00000000000 --- a/drivers/media/dvb/mantis/mantis_pci.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_PCI_H -#define __MANTIS_PCI_H - -extern int mantis_pci_init(struct mantis_pci *mantis); -extern void mantis_pci_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_PCI_H */ diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c deleted file mode 100644 index 2f188c08966..00000000000 --- a/drivers/media/dvb/mantis/mantis_pcmcia.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_link.h" /* temporary due to physical layer stuff */ -#include "mantis_reg.h" - -/* - * If Slot state is already PLUG_IN event and we are called - * again, definitely it is jitter alone - */ -void mantis_event_cam_plugin(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_irqcfg; - - if (ca->slot_state == MODULE_XTRACTED) { - dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num); - udelay(50); - mmwrite(0xda000000, MANTIS_CARD_RESET); - gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); - gpif_irqcfg |= MANTIS_MASK_PLUGOUT; - gpif_irqcfg &= ~MANTIS_MASK_PLUGIN; - mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); - udelay(500); - ca->slot_state = MODULE_INSERTED; - } - udelay(100); -} - -/* - * If Slot state is already UN_PLUG event and we are called - * again, definitely it is jitter alone - */ -void mantis_event_cam_unplug(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_irqcfg; - - if (ca->slot_state == MODULE_INSERTED) { - dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num); - udelay(50); - mmwrite(0x00da0000, MANTIS_CARD_RESET); - gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); - gpif_irqcfg |= MANTIS_MASK_PLUGIN; - gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT; - mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); - udelay(500); - ca->slot_state = MODULE_XTRACTED; - } - udelay(100); -} - -int mantis_pcmcia_init(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_stat, card_stat; - - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); - gpif_stat = mmread(MANTIS_GPIF_STATUS); - card_stat = mmread(MANTIS_GPIF_IRQCFG); - - if (gpif_stat & MANTIS_GPIF_DETSTAT) { - dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num); - mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG); - ca->slot_state = MODULE_INSERTED; - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - } else { - dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num); - mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG); - ca->slot_state = MODULE_XTRACTED; - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - - return 0; -} - -void mantis_pcmcia_exit(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); - mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); -} diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h deleted file mode 100644 index 7761f9dc7fe..00000000000 --- a/drivers/media/dvb/mantis/mantis_reg.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_REG_H -#define __MANTIS_REG_H - -/* Interrupts */ -#define MANTIS_INT_STAT 0x00 -#define MANTIS_INT_MASK 0x04 - -#define MANTIS_INT_RISCSTAT (0x0f << 28) -#define MANTIS_INT_RISCEN (0x01 << 27) -#define MANTIS_INT_I2CRACK (0x01 << 26) - -/* #define MANTIS_INT_GPIF (0xff << 12) */ - -#define MANTIS_INT_PCMCIA7 (0x01 << 19) -#define MANTIS_INT_PCMCIA6 (0x01 << 18) -#define MANTIS_INT_PCMCIA5 (0x01 << 17) -#define MANTIS_INT_PCMCIA4 (0x01 << 16) -#define MANTIS_INT_PCMCIA3 (0x01 << 15) -#define MANTIS_INT_PCMCIA2 (0x01 << 14) -#define MANTIS_INT_PCMCIA1 (0x01 << 13) -#define MANTIS_INT_PCMCIA0 (0x01 << 12) -#define MANTIS_INT_IRQ1 (0x01 << 11) -#define MANTIS_INT_IRQ0 (0x01 << 10) -#define MANTIS_INT_OCERR (0x01 << 8) -#define MANTIS_INT_PABORT (0x01 << 7) -#define MANTIS_INT_RIPERR (0x01 << 6) -#define MANTIS_INT_PPERR (0x01 << 5) -#define MANTIS_INT_FTRGT (0x01 << 3) -#define MANTIS_INT_RISCI (0x01 << 1) -#define MANTIS_INT_I2CDONE (0x01 << 0) - -/* DMA */ -#define MANTIS_DMA_CTL 0x08 -#define MANTIS_GPIF_RD (0xff << 24) -#define MANTIS_GPIF_WR (0xff << 16) -#define MANTIS_CPU_DO (0x01 << 10) -#define MANTIS_DRV_DO (0x01 << 9) -#define MANTIS_I2C_RD (0x01 << 7) -#define MANTIS_I2C_WR (0x01 << 6) -#define MANTIS_DCAP_MODE (0x01 << 5) -#define MANTIS_FIFO_TP_4 (0x00 << 3) -#define MANTIS_FIFO_TP_8 (0x01 << 3) -#define MANTIS_FIFO_TP_16 (0x02 << 3) -#define MANTIS_FIFO_EN (0x01 << 2) -#define MANTIS_DCAP_EN (0x01 << 1) -#define MANTIS_RISC_EN (0x01 << 0) - -/* DEBUG */ -#define MANTIS_DEBUGREG 0x0c -#define MANTIS_DATINV (0x0e << 7) -#define MANTIS_TOP_DEBUGSEL (0x07 << 4) -#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0) - -#define MANTIS_RISC_START 0x10 -#define MANTIS_RISC_PC 0x14 - -/* I2C */ -#define MANTIS_I2CDATA_CTL 0x18 -#define MANTIS_I2C_RATE_1 (0x00 << 6) -#define MANTIS_I2C_RATE_2 (0x01 << 6) -#define MANTIS_I2C_RATE_3 (0x02 << 6) -#define MANTIS_I2C_RATE_4 (0x03 << 6) -#define MANTIS_I2C_STOP (0x01 << 5) -#define MANTIS_I2C_PGMODE (0x01 << 3) - -/* DATA */ -#define MANTIS_CMD_DATA_R1 0x20 -#define MANTIS_CMD_DATA_3 (0xff << 24) -#define MANTIS_CMD_DATA_2 (0xff << 16) -#define MANTIS_CMD_DATA_1 (0xff << 8) -#define MANTIS_CMD_DATA_0 (0xff << 0) - -#define MANTIS_CMD_DATA_R2 0x24 -#define MANTIS_CMD_DATA_7 (0xff << 24) -#define MANTIS_CMD_DATA_6 (0xff << 16) -#define MANTIS_CMD_DATA_5 (0xff << 8) -#define MANTIS_CMD_DATA_4 (0xff << 0) - -#define MANTIS_CONTROL 0x28 -#define MANTIS_DET (0x01 << 7) -#define MANTIS_DAT_CF_EN (0x01 << 6) -#define MANTIS_ACS (0x03 << 4) -#define MANTIS_VCCEN (0x01 << 3) -#define MANTIS_BYPASS (0x01 << 2) -#define MANTIS_MRST (0x01 << 1) -#define MANTIS_CRST_INT (0x01 << 0) - -#define MANTIS_GPIF_CFGSLA 0x84 -#define MANTIS_GPIF_WAITSMPL (0x07 << 28) -#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) -#define MANTIS_GPIF_WAITPOL (0x01 << 24) -#define MANTIS_GPIF_NCDELAY (0x07 << 20) -#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) -#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) -#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) -#define MANTIS_GPIF_DEVTYPE (0x07 << 4) -#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) -#define MANTIS_GPIF_FETCHCMD (0x03 << 1) -#define MANTIS_GPIF_HWORDDEV (0x01 << 0) - -#define MANTIS_GPIF_WSTOPER 0x90 -#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) -#define MANTIS_GPIF_PARBOOTN (0x01 << 29) -#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) -#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) -#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) -#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) -#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) -#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) -#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) - -#define MANTIS_GPIF_CS2RW 0x94 -#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) -#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) -#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) -#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) -#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) -#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) -#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) -#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) - -#define MANTIS_GPIF_IRQCFG 0x98 -#define MANTIS_GPIF_IRQPOL (0x01 << 8) -#define MANTIS_MASK_WRACK (0x01 << 7) -#define MANTIS_MASK_BRRDY (0x01 << 6) -#define MANTIS_MASK_OVFLW (0x01 << 5) -#define MANTIS_MASK_OTHERR (0x01 << 4) -#define MANTIS_MASK_WSTO (0x01 << 3) -#define MANTIS_MASK_EXTIRQ (0x01 << 2) -#define MANTIS_MASK_PLUGIN (0x01 << 1) -#define MANTIS_MASK_PLUGOUT (0x01 << 0) - -#define MANTIS_GPIF_STATUS 0x9c -#define MANTIS_SBUF_KILLOP (0x01 << 15) -#define MANTIS_SBUF_OPDONE (0x01 << 14) -#define MANTIS_SBUF_EMPTY (0x01 << 13) -#define MANTIS_GPIF_DETSTAT (0x01 << 9) -#define MANTIS_GPIF_INTSTAT (0x01 << 8) -#define MANTIS_GPIF_WRACK (0x01 << 7) -#define MANTIS_GPIF_BRRDY (0x01 << 6) -#define MANTIS_SBUF_OVFLW (0x01 << 5) -#define MANTIS_GPIF_OTHERR (0x01 << 4) -#define MANTIS_SBUF_WSTO (0x01 << 3) -#define MANTIS_GPIF_EXTIRQ (0x01 << 2) -#define MANTIS_CARD_PLUGIN (0x01 << 1) -#define MANTIS_CARD_PLUGOUT (0x01 << 0) - -#define MANTIS_GPIF_BRADDR 0xa0 -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) -#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) - -#define MANTIS_GPIF_BRBYTES 0xa4 -#define MANTIS_GPIF_BRCNT (0xfff << 0) - -#define MANTIS_PCMCIA_RESET 0xa8 -#define MANTIS_PCMCIA_RSTVAL (0xff << 0) - -#define MANTIS_CARD_RESET 0xac - -#define MANTIS_GPIF_ADDR 0xb0 -#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) -#define MANTIS_GPIF_HIFADDR (0xfffffff << 0) - -#define MANTIS_GPIF_DOUT 0xb4 -#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0) - -#define MANTIS_GPIF_DIN 0xb8 -#define MANTIS_GPIF_HIFDIN (0xfffffff << 0) - -#define MANTIS_GPIF_SPARE 0xbc -#define MANTIS_GPIF_LOGICRD (0xffff << 16) -#define MANTIS_GPIF_LOGICRW (0xffff << 0) - -#endif /* __MANTIS_REG_H */ diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c deleted file mode 100644 index 18340dafa42..00000000000 --- a/drivers/media/dvb/mantis/mantis_uart.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_uart.h" - -struct mantis_uart_params { - enum mantis_baud baud_rate; - enum mantis_parity parity; -}; - -static struct { - char string[7]; -} rates[5] = { - { "9600" }, - { "19200" }, - { "38400" }, - { "57600" }, - { "115200" } -}; - -static struct { - char string[5]; -} parity[3] = { - { "NONE" }, - { "ODD" }, - { "EVEN" } -}; - -#define UART_MAX_BUF 16 - -int mantis_uart_read(struct mantis_pci *mantis, u8 *data) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - u32 stat = 0, i; - - /* get data */ - for (i = 0; i < (config->bytes + 1); i++) { - - stat = mmread(MANTIS_UART_STAT); - - if (stat & MANTIS_UART_RXFIFO_FULL) { - dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); - } - data[i] = mmread(MANTIS_UART_RXD) & 0x3f; - - dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); - - if (data[i] & (1 << 7)) { - dprintk(MANTIS_ERROR, 1, "UART framing error"); - return -EINVAL; - } - if (data[i] & (1 << 6)) { - dprintk(MANTIS_ERROR, 1, "UART parity error"); - return -EINVAL; - } - } - - return 0; -} - -static void mantis_uart_work(struct work_struct *work) -{ - struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); - struct mantis_hwconfig *config = mantis->hwconfig; - u8 buf[16]; - int i; - - mantis_uart_read(mantis, buf); - - for (i = 0; i < (config->bytes + 1); i++) - dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); - - dprintk(MANTIS_DEBUG, 0, "\n"); -} - -static int mantis_uart_setup(struct mantis_pci *mantis, - struct mantis_uart_params *params) -{ - u32 reg; - - mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); - - reg = mmread(MANTIS_UART_BAUD); - - switch (params->baud_rate) { - case MANTIS_BAUD_9600: - reg |= 0xd8; - break; - case MANTIS_BAUD_19200: - reg |= 0x6c; - break; - case MANTIS_BAUD_38400: - reg |= 0x36; - break; - case MANTIS_BAUD_57600: - reg |= 0x23; - break; - case MANTIS_BAUD_115200: - reg |= 0x11; - break; - default: - return -EINVAL; - } - - mmwrite(reg, MANTIS_UART_BAUD); - - return 0; -} - -int mantis_uart_init(struct mantis_pci *mantis) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - struct mantis_uart_params params; - - /* default parity: */ - params.baud_rate = config->baud_rate; - params.parity = config->parity; - dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s", - rates[params.baud_rate].string, - parity[params.parity].string); - - init_waitqueue_head(&mantis->uart_wq); - spin_lock_init(&mantis->uart_lock); - - INIT_WORK(&mantis->uart_work, mantis_uart_work); - - /* disable interrupt */ - mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); - - mantis_uart_setup(mantis, ¶ms); - - /* default 1 byte */ - mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); - - /* flush buffer */ - mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); - - /* enable interrupt */ - mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); - mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); - - schedule_work(&mantis->uart_work); - dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_uart_init); - -void mantis_uart_exit(struct mantis_pci *mantis) -{ - /* disable interrupt */ - mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); - flush_work_sync(&mantis->uart_work); -} -EXPORT_SYMBOL_GPL(mantis_uart_exit); diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h deleted file mode 100644 index ffb62a0a5a1..00000000000 --- a/drivers/media/dvb/mantis/mantis_uart.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_UART_H -#define __MANTIS_UART_H - -#define MANTIS_UART_CTL 0xe0 -#define MANTIS_UART_RXINT (1 << 4) -#define MANTIS_UART_RXFLUSH (1 << 2) - -#define MANTIS_UART_RXD 0xe8 -#define MANTIS_UART_BAUD 0xec - -#define MANTIS_UART_STAT 0xf0 -#define MANTIS_UART_RXFIFO_DATA (1 << 7) -#define MANTIS_UART_RXFIFO_EMPTY (1 << 6) -#define MANTIS_UART_RXFIFO_FULL (1 << 3) -#define MANTIS_UART_FRAME_ERR (1 << 2) -#define MANTIS_UART_PARITY_ERR (1 << 1) -#define MANTIS_UART_RXTHRESH_INT (1 << 0) - -enum mantis_baud { - MANTIS_BAUD_9600 = 0, - MANTIS_BAUD_19200, - MANTIS_BAUD_38400, - MANTIS_BAUD_57600, - MANTIS_BAUD_115200 -}; - -enum mantis_parity { - MANTIS_PARITY_NONE = 0, - MANTIS_PARITY_EVEN, - MANTIS_PARITY_ODD, -}; - -struct mantis_pci; - -extern int mantis_uart_init(struct mantis_pci *mantis); -extern void mantis_uart_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_UART_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c deleted file mode 100644 index ad013e93ed1..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp1033.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - Mantis VP-1033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "stv0299.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp1033.h" -#include "mantis_reg.h" - -u8 lgtdqcs001f_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x2a, - 0x05, 0x85, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x00, - 0x0c, 0x01, - 0x0d, 0x81, - 0x0e, 0x44, - 0x0f, 0x94, - 0x10, 0x3c, - 0x11, 0x84, - 0x12, 0xb9, - 0x13, 0xb5, - 0x14, 0x4f, - 0x15, 0xc9, - 0x16, 0x80, - 0x17, 0x36, - 0x18, 0xfb, - 0x19, 0xcf, - 0x1a, 0xbc, - 0x1c, 0x2b, - 0x1d, 0x27, - 0x1e, 0x00, - 0x1f, 0x0b, - 0x20, 0xa1, - 0x21, 0x60, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x05, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x13, - 0xff, 0xff, -}; - -#define MANTIS_MODEL_NAME "VP-1033" -#define MANTIS_DEV_TYPE "DVB-S/DSS" - -int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct mantis_pci *mantis = fe->dvb->priv; - struct i2c_adapter *adapter = &mantis->adapter; - - u8 buf[4]; - u32 div; - - - struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; - - div = p->frequency / 250; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x83; - buf[3] = 0xc0; - - if (p->frequency < 1531000) - buf[3] |= 0x04; - else - buf[3] &= ~0x04; - if (i2c_transfer(adapter, &msg, 1) < 0) { - dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed"); - return -EIO; - } - msleep_interruptible(100); - - return 0; -} - -int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; - bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; - bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; - bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; - bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; - bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; - bclk = 0x51; - } - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, ratio & 0xf0); - - return 0; -} - -struct stv0299_config lgtdqcs001f_config = { - .demod_address = 0x68, - .inittab = lgtdqcs001f_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = lgtdqcs001f_set_symbol_rate, -}; - -static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)"); - fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter); - - if (fe) { - fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set; - dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", - lgtdqcs001f_config.demod_address); - - dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success"); - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - mantis->fe = fe; - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp1033_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp1033_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h deleted file mode 100644 index 7daaa1bf127..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp1033.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Mantis VP-1033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP1033_H -#define __MANTIS_VP1033_H - -#include "mantis_common.h" - -#define MANTIS_VP_1033_DVB_S 0x0016 - -extern struct mantis_hwconfig vp1033_config; - -#endif /* __MANTIS_VP1033_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c deleted file mode 100644 index 430ae84ce52..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp1034.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - Mantis VP-1034 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mb86a16.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp1034.h" -#include "mantis_reg.h" - -struct mb86a16_config vp1034_mb86a16_config = { - .demod_address = 0x08, - .set_voltage = vp1034_set_voltage, -}; - -#define MANTIS_MODEL_NAME "VP-1034" -#define MANTIS_DEV_TYPE "DVB-S/DSS" - -int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct mantis_pci *mantis = fe->dvb->priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk(MANTIS_ERROR, 1, "Polarization=[13V]"); - mantis_gpio_set_bits(mantis, 13, 1); - mantis_gpio_set_bits(mantis, 14, 0); - break; - case SEC_VOLTAGE_18: - dprintk(MANTIS_ERROR, 1, "Polarization=[18V]"); - mantis_gpio_set_bits(mantis, 13, 1); - mantis_gpio_set_bits(mantis, 14, 1); - break; - case SEC_VOLTAGE_OFF: - dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN"); - break; - default: - dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage); - return -EINVAL; - } - mmwrite(0x00, MANTIS_GPIF_DOUT); - - return 0; -} - -static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); - fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter); - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found MB86A16 DVB-S/DSS frontend @0x%02x", - vp1034_mb86a16_config.demod_address); - - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - mantis->fe = fe; - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp1034_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp1034_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h deleted file mode 100644 index 323f38ef8e3..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp1034.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Mantis VP-1034 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP1034_H -#define __MANTIS_VP1034_H - -#include "dvb_frontend.h" -#include "mantis_common.h" - - -#define MANTIS_VP_1034_DVB_S 0x0014 - -extern struct mantis_hwconfig vp1034_config; -extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); - -#endif /* __MANTIS_VP1034_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c deleted file mode 100644 index 07aa887a4b4..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp1041.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - Mantis VP-1041 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp1041.h" -#include "stb0899_reg.h" -#include "stb0899_drv.h" -#include "stb0899_cfg.h" -#include "stb6100_cfg.h" -#include "stb6100.h" -#include "lnbp21.h" - -#define MANTIS_MODEL_NAME "VP-1041" -#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2" - -static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { - - /* 0x0000000b, *//* SYSREG */ - { STB0899_DEV_ID , 0x30 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x99 }, - { STB0899_DISF22RX , 0xa8 }, - /* SYSREG ? */ - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0xfe }, - { STB0899_IRQSTATUS_2 , 0x03 }, - { STB0899_IRQSTATUS_1 , 0x7c }, - { STB0899_IRQSTATUS_0 , 0xf4 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x33 }, - { STB0899_IOPVALUE3 , 0x6d }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x60 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x01 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x01 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x23 }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xf7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xf1 }, - { STB0899_LDT2 , 0xe3 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfd }, - { STB0899_QDCCOMP , 0xff }, - { STB0899_POWERI , 0x0c }, - { STB0899_POWERQ , 0x0f }, - { STB0899_RCOMP , 0x6c }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x06 }, - { STB0899_AGC2I2 , 0x00 }, - { STB0899_TLIR , 0x30 }, - { STB0899_RTF , 0x7f }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xbc }, - { STB0899_CFRM , 0xea }, - { STB0899_CFRL , 0x31 }, - { STB0899_NIRM , 0x2b }, - { STB0899_NIRL , 0x80 }, - { STB0899_ISYMB , 0x1d }, - { STB0899_QSYMB , 0xa6 }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0x02 }, - { STB0899_EQUAQ1 , 0xff }, - { STB0899_EQUAI2 , 0x04 }, - { STB0899_EQUAQ2 , 0x05 }, - { STB0899_EQUAI3 , 0x02 }, - { STB0899_EQUAQ3 , 0xfd }, - { STB0899_EQUAI4 , 0x03 }, - { STB0899_EQUAQ4 , 0x07 }, - { STB0899_EQUAI5 , 0x08 }, - { STB0899_EQUAQ5 , 0xf5 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0x86 }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x0a }, - { STB0899_ECNT3L , 0xad }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xb0 }, - { STB0899_VTH23 , 0x7a }, - { STB0899_VTH34 , 0x58 }, - { STB0899_VTH56 , 0x38 }, - { STB0899_VTH67 , 0x34 }, - { STB0899_VTH78 , 0x24 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x41 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x00 }, - { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x1b }, - { STB0899_TSLLSTKL , 0xb3 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0x00 }, - { STB0899_PCKLENUL , 0xbc }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xbd }, - { STB0899_TSSTATUS , 0x90 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x95 }, - { STB0899_ERRCTRL3 , 0x8d }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x19 }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0xf0 }, - { STB0899_MATSTRL , 0x02 }, - { STB0899_UPLSTRM , 0x45 }, - { STB0899_UPLSTRL , 0x60 }, - { STB0899_DFLSTRM , 0xe3 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x47 }, - { STB0899_SYNCDSTRM , 0x05 }, - { STB0899_SYNCDSTRL , 0x18 }, - { STB0899_CFGPDELSTATUS1 , 0x19 }, - { STB0899_CFGPDELSTATUS2 , 0x2b }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x01 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -struct stb0899_config vp1041_stb0899_config = { - .init_dev = vp1041_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = vp1041_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .demod_address = 0x68, /* 0xd0 >> 1 */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL, -}; - -struct stb6100_config vp1041_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter); - if (mantis->fe) { - dprintk(MANTIS_ERROR, 1, - "found STB0899 DVB-S/DVB-S2 frontend @0x%02x", - vp1041_stb0899_config.demod_address); - - if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) { - if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0)) - dprintk(MANTIS_ERROR, 1, "No LNBP21 found!"); - } - } else { - return -EREMOTEIO; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - - - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp1041_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp1041_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h deleted file mode 100644 index 1ae5b3de808..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp1041.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Mantis VP-1041 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP1041_H -#define __MANTIS_VP1041_H - -#include "mantis_common.h" - -#define MANTIS_VP_1041_DVB_S2 0x0031 -#define SKYSTAR_HD2_10 0x0001 -#define SKYSTAR_HD2_20 0x0003 -#define CINERGY_S2_PCI_HD 0x1179 - -extern struct mantis_hwconfig vp1041_config; - -#endif /* __MANTIS_VP1041_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c deleted file mode 100644 index 1ca6837fbe4..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp2033.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - Mantis VP-2033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "tda1002x.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp2033.h" - -#define MANTIS_MODEL_NAME "VP-2033" -#define MANTIS_DEV_TYPE "DVB-C" - -struct tda1002x_config vp2033_tda1002x_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -struct tda10023_config vp2033_tda10023_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -static u8 read_pwm(struct mantis_pci *mantis) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { - {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, - {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} - }; - - if ((i2c_transfer(adapter, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct mantis_pci *mantis = fe->dvb->priv; - struct i2c_adapter *adapter = &mantis->adapter; - - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (p->frequency < 150000000 ? 0x01 : - p->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); - fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", - vp2033_tda1002x_cu1216_config.demod_address); - } else { - fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", - vp2033_tda1002x_cu1216_config.demod_address); - } - } - - if (fe) { - fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; - dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - - mantis->fe = fe; - dprintk(MANTIS_DEBUG, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp2033_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp2033_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/dvb/mantis/mantis_vp2033.h deleted file mode 100644 index c55242b79d5..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp2033.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Mantis VP-2033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP2033_H -#define __MANTIS_VP2033_H - -#include "mantis_common.h" - -#define MANTIS_VP_2033_DVB_C 0x0008 - -extern struct mantis_hwconfig vp2033_config; - -#endif /* __MANTIS_VP2033_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c deleted file mode 100644 index d480741afd7..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp2040.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - Mantis VP-2040 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "tda1002x.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp2040.h" - -#define MANTIS_MODEL_NAME "VP-2040" -#define MANTIS_DEV_TYPE "DVB-C" - -struct tda1002x_config vp2040_tda1002x_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -struct tda10023_config vp2040_tda10023_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct mantis_pci *mantis = fe->dvb->priv; - struct i2c_adapter *adapter = &mantis->adapter; - - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (p->frequency < 150000000 ? 0x01 : - p->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static u8 read_pwm(struct mantis_pci *mantis) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { - {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, - {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} - }; - - if ((i2c_transfer(adapter, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); - fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", - vp2040_tda1002x_cu1216_config.demod_address); - } else { - fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", - vp2040_tda1002x_cu1216_config.demod_address); - } - } - - if (fe) { - fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; - dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - mantis->fe = fe; - dprintk(MANTIS_DEBUG, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp2040_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp2040_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/dvb/mantis/mantis_vp2040.h deleted file mode 100644 index d125e219b68..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp2040.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Mantis VP-2040 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP2040_H -#define __MANTIS_VP2040_H - -#include "mantis_common.h" - -#define MANTIS_VP_2040_DVB_C 0x0043 -#define CINERGY_C 0x1178 -#define CABLESTAR_HD2 0x0002 - -extern struct mantis_hwconfig vp2040_config; - -#endif /* __MANTIS_VP2040_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/dvb/mantis/mantis_vp3028.c deleted file mode 100644 index 4155c838a18..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp3028.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "mantis_common.h" -#include "mantis_vp3028.h" - -struct zl10353_config mantis_vp3028_config = { - .demod_address = 0x0f, -}; - -#define MANTIS_MODEL_NAME "VP-3028" -#define MANTIS_DEV_TYPE "DVB-T" - -struct mantis_hwconfig vp3028_mantis_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, -}; diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/dvb/mantis/mantis_vp3028.h deleted file mode 100644 index b07be6adc52..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp3028.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3028_H -#define __MANTIS_VP3028_H - -#include "dvb_frontend.h" -#include "mantis_common.h" -#include "zl10353.h" - -#define MANTIS_VP_3028_DVB_T 0x0028 - -extern struct zl10353_config mantis_vp3028_config; -extern struct mantis_hwconfig vp3028_mantis_config; - -#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c deleted file mode 100644 index c09308cd3ac..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp3030.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - Mantis VP-3030 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "zl10353.h" -#include "tda665x.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp3030.h" - -struct zl10353_config mantis_vp3030_config = { - .demod_address = 0x0f, -}; - -struct tda665x_config env57h12d5_config = { - .name = "ENV57H12D5 (ET-50DT)", - .addr = 0x60, - .frequency_min = 47000000, - .frequency_max = 862000000, - .frequency_offst = 3616667, - .ref_multiplier = 6, /* 1/6 MHz */ - .ref_divider = 100000, /* 1/6 MHz */ -}; - -#define MANTIS_MODEL_NAME "VP-3030" -#define MANTIS_DEV_TYPE "DVB-T" - - -static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - struct mantis_hwconfig *config = mantis->hwconfig; - int err = 0; - - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - err = mantis_frontend_power(mantis, POWER_ON); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - - if (err == 0) { - msleep(250); - dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); - fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter); - - if (!fe) - return -1; - - dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter); - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - - } - mantis->fe = fe; - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp3030_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp3030_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, - - .i2c_mode = MANTIS_BYTE_MODE -}; diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/dvb/mantis/mantis_vp3030.h deleted file mode 100644 index 5f12c426627..00000000000 --- a/drivers/media/dvb/mantis/mantis_vp3030.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - Mantis VP-3030 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3030_H -#define __MANTIS_VP3030_H - -#include "mantis_common.h" - -#define MANTIS_VP_3030_DVB_T 0x0024 - -extern struct mantis_hwconfig vp3030_config; - -#endif /* __MANTIS_VP3030_H */ diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig deleted file mode 100644 index 64c84702ba5..00000000000 --- a/drivers/media/dvb/ngene/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config DVB_NGENE - tristate "Micronas nGene support" - depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE - ---help--- - Support for Micronas PCI express cards with nGene bridge. - diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile deleted file mode 100644 index 63997089f9d..00000000000 --- a/drivers/media/dvb/ngene/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the nGene device driver -# - -ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o - -obj-$(CONFIG_DVB_NGENE) += ngene.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c deleted file mode 100644 index a6cd6959ad1..00000000000 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * ngene-cards.c: nGene PCIe bridge driver - card specific info - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include - -#include "ngene.h" - -/* demods/tuners */ -#include "stv6110x.h" -#include "stv090x.h" -#include "lnbh24.h" -#include "lgdt330x.h" -#include "mt2131.h" -#include "tda18271c2dd.h" -#include "drxk.h" -#include "drxd.h" -#include "dvb-pll.h" - - -/****************************************************************************/ -/* Demod/tuner attachment ***************************************************/ -/****************************************************************************/ - -static int tuner_attach_stv6110(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct stv090x_config *feconf = (struct stv090x_config *) - chan->dev->card_info->fe_config[chan->number]; - struct stv6110x_config *tunerconf = (struct stv6110x_config *) - chan->dev->card_info->tuner_config[chan->number]; - struct stv6110x_devctl *ctl; - - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); - if (ctl == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); - return -ENODEV; - } - - feconf->tuner_init = ctl->tuner_init; - feconf->tuner_sleep = ctl->tuner_sleep; - feconf->tuner_set_mode = ctl->tuner_set_mode; - feconf->tuner_set_frequency = ctl->tuner_set_frequency; - feconf->tuner_get_frequency = ctl->tuner_get_frequency; - feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; - feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; - feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; - feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; - feconf->tuner_set_refclk = ctl->tuner_set_refclk; - feconf->tuner_get_status = ctl->tuner_get_status; - - return 0; -} - - -static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct ngene_channel *chan = fe->sec_priv; - int status; - - if (enable) { - down(&chan->dev->pll_mutex); - status = chan->gate_ctrl(fe, 1); - } else { - status = chan->gate_ctrl(fe, 0); - up(&chan->dev->pll_mutex); - } - return status; -} - -static int tuner_attach_tda18271(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct dvb_frontend *fe; - - i2c = &chan->dev->channel[0].i2c_adapter; - if (chan->fe->ops.i2c_gate_ctrl) - chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); - fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); - if (chan->fe->ops.i2c_gate_ctrl) - chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); - if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); - return -ENODEV; - } - - return 0; -} - -static int tuner_attach_probe(struct ngene_channel *chan) -{ - if (chan->demod_type == 0) - return tuner_attach_stv6110(chan); - if (chan->demod_type == 1) - return tuner_attach_tda18271(chan); - return -EINVAL; -} - -static int demod_attach_stv0900(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct stv090x_config *feconf = (struct stv090x_config *) - chan->dev->card_info->fe_config[chan->number]; - - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - /* Note: Both adapters share the same i2c bus, but the demod */ - /* driver requires that each demod has its own i2c adapter */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - chan->fe = dvb_attach(stv090x_attach, feconf, i2c, - (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 - : STV090x_DEMODULATOR_1); - if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); - return -ENODEV; - } - - /* store channel info */ - if (feconf->tuner_i2c_lock) - chan->fe->analog_demod_priv = chan; - - if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, - 0, chan->dev->card_info->lnb[chan->number])) { - printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - return -ENODEV; - } - - return 0; -} - -static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) -{ - struct ngene_channel *chan = fe->analog_demod_priv; - - if (lock) - down(&chan->dev->pll_mutex); - else - up(&chan->dev->pll_mutex); -} - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) -{ - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; -} - -static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) -{ - u8 msg[2] = {reg>>8, reg&0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} - -static int port_has_stv0900(struct i2c_adapter *i2c, int port) -{ - u8 val; - if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) - return 0; - return 1; -} - -static int port_has_drxk(struct i2c_adapter *i2c, int port) -{ - u8 val; - - if (i2c_read(i2c, 0x29+port, &val) < 0) - return 0; - return 1; -} - -static int demod_attach_drxk(struct ngene_channel *chan, - struct i2c_adapter *i2c) -{ - struct drxk_config config; - - memset(&config, 0, sizeof(config)); - config.microcode_name = "drxk_a3.mc"; - config.qam_demod_parameter_count = 4; - config.adr = 0x29 + (chan->number ^ 2); - - chan->fe = dvb_attach(drxk_attach, &config, i2c); - if (!chan->fe) { - printk(KERN_ERR "No DRXK found!\n"); - return -ENODEV; - } - chan->fe->sec_priv = chan; - chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; - chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; - return 0; -} - -static int cineS2_probe(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct stv090x_config *fe_conf; - u8 buf[3]; - struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; - int rc; - - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - if (port_has_stv0900(i2c, chan->number)) { - chan->demod_type = 0; - fe_conf = chan->dev->card_info->fe_config[chan->number]; - /* demod found, attach it */ - rc = demod_attach_stv0900(chan); - if (rc < 0 || chan->number < 2) - return rc; - - /* demod #2: reprogram outputs DPN1 & DPN2 */ - i2c_msg.addr = fe_conf->address; - i2c_msg.len = 3; - buf[0] = 0xf1; - switch (chan->number) { - case 2: - buf[1] = 0x5c; - buf[2] = 0xc2; - break; - case 3: - buf[1] = 0x61; - buf[2] = 0xcc; - break; - default: - return -ENODEV; - } - rc = i2c_transfer(i2c, &i2c_msg, 1); - if (rc != 1) { - printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); - return -EIO; - } - } else if (port_has_drxk(i2c, chan->number^2)) { - chan->demod_type = 1; - demod_attach_drxk(chan, i2c); - } else { - printk(KERN_ERR "No demod found on chan %d\n", chan->number); - return -ENODEV; - } - return 0; -} - - -static struct lgdt330x_config aver_m780 = { - .demod_address = 0xb2 >> 1, - .demod_chip = LGDT3303, - .serial_mpeg = 0x00, /* PARALLEL */ - .clock_polarity_flip = 1, -}; - -static struct mt2131_config m780_tunerconfig = { - 0xc0 >> 1 -}; - -/* A single func to attach the demo and tuner, rather than - * use two sep funcs like the current design mandates. - */ -static int demod_attach_lg330x(struct ngene_channel *chan) -{ - chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); - if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); - return -ENODEV; - } - - dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, - &m780_tunerconfig, 0); - - return (chan->fe) ? 0 : -ENODEV; -} - -static int demod_attach_drxd(struct ngene_channel *chan) -{ - struct drxd_config *feconf; - - feconf = chan->dev->card_info->fe_config[chan->number]; - - chan->fe = dvb_attach(drxd_attach, feconf, chan, - &chan->i2c_adapter, &chan->dev->pci_dev->dev); - if (!chan->fe) { - pr_err("No DRXD found!\n"); - return -ENODEV; - } - - if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address, - &chan->i2c_adapter, - feconf->pll_type)) { - pr_err("No pll(%d) found!\n", feconf->pll_type); - return -ENODEV; - } - return 0; -} - -/****************************************************************************/ -/* EEPROM TAGS **************************************************************/ -/****************************************************************************/ - -#define MICNG_EE_START 0x0100 -#define MICNG_EE_END 0x0FF0 - -#define MICNG_EETAG_END0 0x0000 -#define MICNG_EETAG_END1 0xFFFF - -/* 0x0001 - 0x000F reserved for housekeeping */ -/* 0xFFFF - 0xFFFE reserved for housekeeping */ - -/* Micronas assigned tags - EEProm tags for hardware support */ - -#define MICNG_EETAG_DRXD1_OSCDEVIATION 0x1000 /* 2 Bytes data */ -#define MICNG_EETAG_DRXD2_OSCDEVIATION 0x1001 /* 2 Bytes data */ - -#define MICNG_EETAG_MT2060_1_1STIF 0x1100 /* 2 Bytes data */ -#define MICNG_EETAG_MT2060_2_1STIF 0x1101 /* 2 Bytes data */ - -/* Tag range for OEMs */ - -#define MICNG_EETAG_OEM_FIRST 0xC000 -#define MICNG_EETAG_OEM_LAST 0xFFEF - -static int i2c_write_eeprom(struct i2c_adapter *adapter, - u8 adr, u16 reg, u8 data) -{ - u8 m[3] = {(reg >> 8), (reg & 0xff), data}; - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, - .len = sizeof(m)}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - pr_err(DEVICE_NAME ": Error writing EEPROM!\n"); - return -EIO; - } - return 0; -} - -static int i2c_read_eeprom(struct i2c_adapter *adapter, - u8 adr, u16 reg, u8 *data, int len) -{ - u8 msg[2] = {(reg >> 8), (reg & 0xff)}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = data, .len = len} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - pr_err(DEVICE_NAME ": Error reading EEPROM\n"); - return -EIO; - } - return 0; -} - -static int ReadEEProm(struct i2c_adapter *adapter, - u16 Tag, u32 MaxLen, u8 *data, u32 *pLength) -{ - int status = 0; - u16 Addr = MICNG_EE_START, Length, tag = 0; - u8 EETag[3]; - - while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { - if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) - return -1; - tag = (EETag[0] << 8) | EETag[1]; - if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) - return -1; - if (tag == Tag) - break; - Addr += sizeof(u16) + 1 + EETag[2]; - } - if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { - pr_err(DEVICE_NAME - ": Reached EOEE @ Tag = %04x Length = %3d\n", - tag, EETag[2]); - return -1; - } - Length = EETag[2]; - if (Length > MaxLen) - Length = (u16) MaxLen; - if (Length > 0) { - Addr += sizeof(u16) + 1; - status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length); - if (!status) { - *pLength = EETag[2]; - if (Length < EETag[2]) - ; /*status=STATUS_BUFFER_OVERFLOW; */ - } - } - return status; -} - -static int WriteEEProm(struct i2c_adapter *adapter, - u16 Tag, u32 Length, u8 *data) -{ - int status = 0; - u16 Addr = MICNG_EE_START; - u8 EETag[3]; - u16 tag = 0; - int retry, i; - - while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { - if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) - return -1; - tag = (EETag[0] << 8) | EETag[1]; - if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) - return -1; - if (tag == Tag) - break; - Addr += sizeof(u16) + 1 + EETag[2]; - } - if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { - pr_err(DEVICE_NAME - ": Reached EOEE @ Tag = %04x Length = %3d\n", - tag, EETag[2]); - return -1; - } - - if (Length > EETag[2]) - return -EINVAL; - /* Note: We write the data one byte at a time to avoid - issues with page sizes. (which are different for - each manufacture and eeprom size) - */ - Addr += sizeof(u16) + 1; - for (i = 0; i < Length; i++, Addr++) { - status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]); - - if (status) - break; - - /* Poll for finishing write cycle */ - retry = 10; - while (retry) { - u8 Tmp; - - msleep(50); - status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1); - if (status) - break; - if (Tmp != data[i]) - pr_err(DEVICE_NAME - "eeprom write error\n"); - retry -= 1; - } - if (status) { - pr_err(DEVICE_NAME - ": Timeout polling eeprom\n"); - break; - } - } - return status; -} - -static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data) -{ - int stat; - u8 buf[2]; - u32 len = 0; - - stat = ReadEEProm(adapter, tag, 2, buf, &len); - if (stat) - return stat; - if (len != 2) - return -EINVAL; - - *data = (buf[0] << 8) | buf[1]; - return 0; -} - -static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) -{ - int stat; - u8 buf[2]; - - buf[0] = data >> 8; - buf[1] = data & 0xff; - stat = WriteEEProm(adapter, tag, 2, buf); - if (stat) - return stat; - return 0; -} - -static s16 osc_deviation(void *priv, s16 deviation, int flag) -{ - struct ngene_channel *chan = priv; - struct i2c_adapter *adap = &chan->i2c_adapter; - u16 data = 0; - - if (flag) { - data = (u16) deviation; - pr_info(DEVICE_NAME ": write deviation %d\n", - deviation); - eeprom_write_ushort(adap, 0x1000 + chan->number, data); - } else { - if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data)) - data = 0; - pr_info(DEVICE_NAME ": read deviation %d\n", - (s16) data); - } - - return (s16) data; -} - -/****************************************************************************/ -/* Switch control (I2C gates, etc.) *****************************************/ -/****************************************************************************/ - - -static struct stv090x_config fe_cineS2 = { - .device = STV0900, - .demod_mode = STV090x_DUAL, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 27000000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - - .repeater_level = STV090x_RPTLEVEL_16, - - .adc1_range = STV090x_ADC_1Vpp, - .adc2_range = STV090x_ADC_1Vpp, - - .diseqc_envelope_mode = true, - - .tuner_i2c_lock = cineS2_tuner_i2c_lock, -}; - -static struct stv090x_config fe_cineS2_2 = { - .device = STV0900, - .demod_mode = STV090x_DUAL, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 27000000, - .address = 0x69, - - .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - - .repeater_level = STV090x_RPTLEVEL_16, - - .adc1_range = STV090x_ADC_1Vpp, - .adc2_range = STV090x_ADC_1Vpp, - - .diseqc_envelope_mode = true, - - .tuner_i2c_lock = cineS2_tuner_i2c_lock, -}; - -static struct stv6110x_config tuner_cineS2_0 = { - .addr = 0x60, - .refclk = 27000000, - .clk_div = 1, -}; - -static struct stv6110x_config tuner_cineS2_1 = { - .addr = 0x63, - .refclk = 27000000, - .clk_div = 1, -}; - -static struct ngene_info ngene_info_cineS2 = { - .type = NGENE_SIDEWINDER, - .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0b, 0x08}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_satixS2 = { - .type = NGENE_SIDEWINDER, - .name = "Mystique SaTiX-S2 Dual", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0b, 0x08}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_satixS2v2 = { - .type = NGENE_SIDEWINDER, - .name = "Mystique SaTiX-S2 Dual (v2)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, - NGENE_IO_TSOUT}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, - .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08, 0x0b, 0x09}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_cineS2v5 = { - .type = NGENE_SIDEWINDER, - .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, - NGENE_IO_TSOUT}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, - .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08, 0x0b, 0x09}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - - -static struct ngene_info ngene_info_duoFlex = { - .type = NGENE_SIDEWINDER, - .name = "Digital Devices DuoFlex PCIe or miniPCIe", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, - NGENE_IO_TSOUT}, - .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe}, - .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08, 0x0b, 0x09}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_m780 = { - .type = NGENE_APP, - .name = "Aver M780 ATSC/QAM-B", - - /* Channel 0 is analog, which is currently unsupported */ - .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, - .demod_attach = { NULL, demod_attach_lg330x }, - - /* Ensure these are NULL else the frame will call them (as funcs) */ - .tuner_attach = { 0, 0, 0, 0 }, - .fe_config = { NULL, &aver_m780 }, - .avf = { 0 }, - - /* A custom electrical interface config for the demod to bridge */ - .tsf = { 4, 4 }, - .fw_version = 15, -}; - -static struct drxd_config fe_terratec_dvbt_0 = { - .index = 0, - .demod_address = 0x70, - .demod_revision = 0xa2, - .demoda_address = 0x00, - .pll_address = 0x60, - .pll_type = DVB_PLL_THOMSON_DTT7520X, - .clock = 20000, - .osc_deviation = osc_deviation, -}; - -static struct drxd_config fe_terratec_dvbt_1 = { - .index = 1, - .demod_address = 0x71, - .demod_revision = 0xa2, - .demoda_address = 0x00, - .pll_address = 0x60, - .pll_type = DVB_PLL_THOMSON_DTT7520X, - .clock = 20000, - .osc_deviation = osc_deviation, -}; - -static struct ngene_info ngene_info_terratec = { - .type = NGENE_TERRATEC, - .name = "Terratec Integra/Cinergy2400i Dual DVB-T", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_drxd, demod_attach_drxd}, - .fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1}, - .i2c_access = 1, -}; - -/****************************************************************************/ - - - -/****************************************************************************/ -/* PCI Subsystem ID *********************************************************/ -/****************************************************************************/ - -#define NGENE_ID(_subvend, _subdev, _driverdata) { \ - .vendor = NGENE_VID, .device = NGENE_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long) &_driverdata } - -/****************************************************************************/ - -static const struct pci_device_id ngene_id_tbl[] __devinitdata = { - NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), - NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), - NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), - NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), - NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), - NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex), - NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), - NGENE_ID(0x1461, 0x062e, ngene_info_m780), - NGENE_ID(0x153b, 0x1167, ngene_info_terratec), - {0} -}; -MODULE_DEVICE_TABLE(pci, ngene_id_tbl); - -/****************************************************************************/ -/* Init/Exit ****************************************************************/ -/****************************************************************************/ - -static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, - enum pci_channel_state state) -{ - printk(KERN_ERR DEVICE_NAME ": PCI error\n"); - if (state == pci_channel_io_perm_failure) - return PCI_ERS_RESULT_DISCONNECT; - if (state == pci_channel_io_frozen) - return PCI_ERS_RESULT_NEED_RESET; - return PCI_ERS_RESULT_CAN_RECOVER; -} - -static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) -{ - printk(KERN_INFO DEVICE_NAME ": link reset\n"); - return 0; -} - -static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) -{ - printk(KERN_INFO DEVICE_NAME ": slot reset\n"); - return 0; -} - -static void ngene_resume(struct pci_dev *dev) -{ - printk(KERN_INFO DEVICE_NAME ": resume\n"); -} - -static struct pci_error_handlers ngene_errors = { - .error_detected = ngene_error_detected, - .link_reset = ngene_link_reset, - .slot_reset = ngene_slot_reset, - .resume = ngene_resume, -}; - -static struct pci_driver ngene_pci_driver = { - .name = "ngene", - .id_table = ngene_id_tbl, - .probe = ngene_probe, - .remove = __devexit_p(ngene_remove), - .err_handler = &ngene_errors, - .shutdown = ngene_shutdown, -}; - -static __init int module_init_ngene(void) -{ - printk(KERN_INFO - "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); - return pci_register_driver(&ngene_pci_driver); -} - -static __exit void module_exit_ngene(void) -{ - pci_unregister_driver(&ngene_pci_driver); -} - -module_init(module_init_ngene); -module_exit(module_exit_ngene); - -MODULE_DESCRIPTION("nGene"); -MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c deleted file mode 100644 index c8e0d5b99d4..00000000000 --- a/drivers/media/dvb/ngene/ngene-core.c +++ /dev/null @@ -1,1707 +0,0 @@ -/* - * ngene.c: nGene PCIe bridge driver - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ngene.h" - -static int one_adapter; -module_param(one_adapter, int, 0444); -MODULE_PARM_DESC(one_adapter, "Use only one adapter."); - -static int shutdown_workaround; -module_param(shutdown_workaround, int, 0644); -MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); - -static int debug; -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "Print debugging information."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk if (debug) printk - -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) -#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) -#define ngreadl(adr) readl(dev->iomem + (adr)) -#define ngreadb(adr) readb(dev->iomem + (adr)) -#define ngcpyto(adr, src, count) memcpy_toio((char *) \ - (dev->iomem + (adr)), (src), (count)) -#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ - (dev->iomem + (adr)), (count)) - -/****************************************************************************/ -/* nGene interrupt handler **************************************************/ -/****************************************************************************/ - -static void event_tasklet(unsigned long data) -{ - struct ngene *dev = (struct ngene *)data; - - while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { - struct EVENT_BUFFER Event = - dev->EventQueue[dev->EventQueueReadIndex]; - dev->EventQueueReadIndex = - (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); - - if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) - dev->TxEventNotify(dev, Event.TimeStamp); - if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) - dev->RxEventNotify(dev, Event.TimeStamp, - Event.RXCharacter); - } -} - -static void demux_tasklet(unsigned long data) -{ - struct ngene_channel *chan = (struct ngene_channel *)data; - struct SBufferHeader *Cur = chan->nextBuffer; - - spin_lock_irq(&chan->state_lock); - - while (Cur->ngeneBuffer.SR.Flags & 0x80) { - if (chan->mode & NGENE_IO_TSOUT) { - u32 Flags = chan->DataFormatFlags; - if (Cur->ngeneBuffer.SR.Flags & 0x20) - Flags |= BEF_OVERFLOW; - if (chan->pBufferExchange) { - if (!chan->pBufferExchange(chan, - Cur->Buffer1, - chan->Capture1Length, - Cur->ngeneBuffer.SR. - Clock, Flags)) { - /* - We didn't get data - Clear in service flag to make sure we - get called on next interrupt again. - leave fill/empty (0x80) flag alone - to avoid hardware running out of - buffers during startup, we hold only - in run state ( the source may be late - delivering data ) - */ - - if (chan->HWState == HWSTATE_RUN) { - Cur->ngeneBuffer.SR.Flags &= - ~0x40; - break; - /* Stop processing stream */ - } - } else { - /* We got a valid buffer, - so switch to run state */ - chan->HWState = HWSTATE_RUN; - } - } else { - printk(KERN_ERR DEVICE_NAME ": OOPS\n"); - if (chan->HWState == HWSTATE_RUN) { - Cur->ngeneBuffer.SR.Flags &= ~0x40; - break; /* Stop processing stream */ - } - } - if (chan->AudioDTOUpdated) { - printk(KERN_INFO DEVICE_NAME - ": Update AudioDTO = %d\n", - chan->AudioDTOValue); - Cur->ngeneBuffer.SR.DTOUpdate = - chan->AudioDTOValue; - chan->AudioDTOUpdated = 0; - } - } else { - if (chan->HWState == HWSTATE_RUN) { - u32 Flags = chan->DataFormatFlags; - IBufferExchange *exch1 = chan->pBufferExchange; - IBufferExchange *exch2 = chan->pBufferExchange2; - if (Cur->ngeneBuffer.SR.Flags & 0x01) - Flags |= BEF_EVEN_FIELD; - if (Cur->ngeneBuffer.SR.Flags & 0x20) - Flags |= BEF_OVERFLOW; - spin_unlock_irq(&chan->state_lock); - if (exch1) - exch1(chan, Cur->Buffer1, - chan->Capture1Length, - Cur->ngeneBuffer.SR.Clock, - Flags); - if (exch2) - exch2(chan, Cur->Buffer2, - chan->Capture2Length, - Cur->ngeneBuffer.SR.Clock, - Flags); - spin_lock_irq(&chan->state_lock); - } else if (chan->HWState != HWSTATE_STOP) - chan->HWState = HWSTATE_RUN; - } - Cur->ngeneBuffer.SR.Flags = 0x00; - Cur = Cur->Next; - } - chan->nextBuffer = Cur; - - spin_unlock_irq(&chan->state_lock); -} - -static irqreturn_t irq_handler(int irq, void *dev_id) -{ - struct ngene *dev = (struct ngene *)dev_id; - u32 icounts = 0; - irqreturn_t rc = IRQ_NONE; - u32 i = MAX_STREAM; - u8 *tmpCmdDoneByte; - - if (dev->BootFirmware) { - icounts = ngreadl(NGENE_INT_COUNTS); - if (icounts != dev->icounts) { - ngwritel(0, FORCE_NMI); - dev->cmd_done = 1; - wake_up(&dev->cmd_wq); - dev->icounts = icounts; - rc = IRQ_HANDLED; - } - return rc; - } - - ngwritel(0, FORCE_NMI); - - spin_lock(&dev->cmd_lock); - tmpCmdDoneByte = dev->CmdDoneByte; - if (tmpCmdDoneByte && - (*tmpCmdDoneByte || - (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { - dev->CmdDoneByte = NULL; - dev->cmd_done = 1; - wake_up(&dev->cmd_wq); - rc = IRQ_HANDLED; - } - spin_unlock(&dev->cmd_lock); - - if (dev->EventBuffer->EventStatus & 0x80) { - u8 nextWriteIndex = - (dev->EventQueueWriteIndex + 1) & - (EVENT_QUEUE_SIZE - 1); - if (nextWriteIndex != dev->EventQueueReadIndex) { - dev->EventQueue[dev->EventQueueWriteIndex] = - *(dev->EventBuffer); - dev->EventQueueWriteIndex = nextWriteIndex; - } else { - printk(KERN_ERR DEVICE_NAME ": event overflow\n"); - dev->EventQueueOverflowCount += 1; - dev->EventQueueOverflowFlag = 1; - } - dev->EventBuffer->EventStatus &= ~0x80; - tasklet_schedule(&dev->event_tasklet); - rc = IRQ_HANDLED; - } - - while (i > 0) { - i--; - spin_lock(&dev->channel[i].state_lock); - /* if (dev->channel[i].State>=KSSTATE_RUN) { */ - if (dev->channel[i].nextBuffer) { - if ((dev->channel[i].nextBuffer-> - ngeneBuffer.SR.Flags & 0xC0) == 0x80) { - dev->channel[i].nextBuffer-> - ngeneBuffer.SR.Flags |= 0x40; - tasklet_schedule( - &dev->channel[i].demux_tasklet); - rc = IRQ_HANDLED; - } - } - spin_unlock(&dev->channel[i].state_lock); - } - - /* Request might have been processed by a previous call. */ - return IRQ_HANDLED; -} - -/****************************************************************************/ -/* nGene command interface **************************************************/ -/****************************************************************************/ - -static void dump_command_io(struct ngene *dev) -{ - u8 buf[8], *b; - - ngcpyfrom(buf, HOST_TO_NGENE, 8); - printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); - - ngcpyfrom(buf, NGENE_TO_HOST, 8); - printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); - - b = dev->hosttongene; - printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b); - - b = dev->ngenetohost; - printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b); -} - -static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) -{ - int ret; - u8 *tmpCmdDoneByte; - - dev->cmd_done = 0; - - if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { - dev->BootFirmware = 1; - dev->icounts = ngreadl(NGENE_INT_COUNTS); - ngwritel(0, NGENE_COMMAND); - ngwritel(0, NGENE_COMMAND_HI); - ngwritel(0, NGENE_STATUS); - ngwritel(0, NGENE_STATUS_HI); - ngwritel(0, NGENE_EVENT); - ngwritel(0, NGENE_EVENT_HI); - } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { - u64 fwio = dev->PAFWInterfaceBuffer; - - ngwritel(fwio & 0xffffffff, NGENE_COMMAND); - ngwritel(fwio >> 32, NGENE_COMMAND_HI); - ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); - ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); - ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); - ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); - } - - memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); - - if (dev->BootFirmware) - ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); - - spin_lock_irq(&dev->cmd_lock); - tmpCmdDoneByte = dev->ngenetohost + com->out_len; - if (!com->out_len) - tmpCmdDoneByte++; - *tmpCmdDoneByte = 0; - dev->ngenetohost[0] = 0; - dev->ngenetohost[1] = 0; - dev->CmdDoneByte = tmpCmdDoneByte; - spin_unlock_irq(&dev->cmd_lock); - - /* Notify 8051. */ - ngwritel(1, FORCE_INT); - - ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); - if (!ret) { - /*ngwritel(0, FORCE_NMI);*/ - - printk(KERN_ERR DEVICE_NAME - ": Command timeout cmd=%02x prev=%02x\n", - com->cmd.hdr.Opcode, dev->prev_cmd); - dump_command_io(dev); - return -1; - } - if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) - dev->BootFirmware = 0; - - dev->prev_cmd = com->cmd.hdr.Opcode; - - if (!com->out_len) - return 0; - - memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); - - return 0; -} - -int ngene_command(struct ngene *dev, struct ngene_command *com) -{ - int result; - - down(&dev->cmd_mutex); - result = ngene_command_mutex(dev, com); - up(&dev->cmd_mutex); - return result; -} - - -static int ngene_command_load_firmware(struct ngene *dev, - u8 *ngene_fw, u32 size) -{ -#define FIRSTCHUNK (1024) - u32 cleft; - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; - com.cmd.hdr.Length = 0; - com.in_len = 0; - com.out_len = 0; - - ngene_command(dev, &com); - - cleft = (size + 3) & ~3; - if (cleft > FIRSTCHUNK) { - ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, - cleft - FIRSTCHUNK); - cleft = FIRSTCHUNK; - } - ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); - - memset(&com, 0, sizeof(struct ngene_command)); - com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; - com.cmd.hdr.Length = 4; - com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; - com.cmd.FWLoadFinish.Length = (unsigned short)cleft; - com.in_len = 4; - com.out_len = 0; - - return ngene_command(dev, &com); -} - - -static int ngene_command_config_buf(struct ngene *dev, u8 config) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; - com.cmd.hdr.Length = 1; - com.cmd.ConfigureBuffers.config = config; - com.in_len = 1; - com.out_len = 0; - - if (ngene_command(dev, &com) < 0) - return -EIO; - return 0; -} - -static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; - com.cmd.hdr.Length = 6; - memcpy(&com.cmd.ConfigureBuffers.config, config, 6); - com.in_len = 6; - com.out_len = 0; - - if (ngene_command(dev, &com) < 0) - return -EIO; - - return 0; -} - -int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; - com.cmd.hdr.Length = 1; - com.cmd.SetGpioPin.select = select | (level << 7); - com.in_len = 1; - com.out_len = 0; - - return ngene_command(dev, &com); -} - - -/* - 02000640 is sample on rising edge. - 02000740 is sample on falling edge. - 02000040 is ignore "valid" signal - - 0: FD_CTL1 Bit 7,6 must be 0,1 - 7 disable(fw controlled) - 6 0-AUX,1-TS - 5 0-par,1-ser - 4 0-lsb/1-msb - 3,2 reserved - 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both - 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge - 2: FD_STA is read-only. 0-sync - 3: FD_INSYNC is number of 47s to trigger "in sync". - 4: FD_OUTSYNC is number of 47s to trigger "out of sync". - 5: FD_MAXBYTE1 is low-order of bytes per packet. - 6: FD_MAXBYTE2 is high-order of bytes per packet. - 7: Top byte is unused. -*/ - -/****************************************************************************/ - -static u8 TSFeatureDecoderSetup[8 * 5] = { - 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, - 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ - 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ - 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ - 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ -}; - -/* Set NGENE I2S Config to 16 bit packed */ -static u8 I2SConfiguration[] = { - 0x00, 0x10, 0x00, 0x00, - 0x80, 0x10, 0x00, 0x00, -}; - -static u8 SPDIFConfiguration[10] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -/* Set NGENE I2S Config to transport stream compatible mode */ - -static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; - -static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; - -static u8 ITUDecoderSetup[4][16] = { - {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ - 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, - {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, - {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ - 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, - {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ - 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, -}; - -/* - * 50 48 60 gleich - * 27p50 9f 00 22 80 42 69 18 ... - * 27p60 93 00 22 80 82 69 1c ... - */ - -/* Maxbyte to 1144 (for raw data) */ -static u8 ITUFeatureDecoderSetup[8] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 -}; - -void FillTSBuffer(void *Buffer, int Length, u32 Flags) -{ - u32 *ptr = Buffer; - - memset(Buffer, TS_FILLER, Length); - while (Length > 0) { - if (Flags & DF_SWAP32) - *ptr = 0x471FFF10; - else - *ptr = 0x10FF1F47; - ptr += (188 / 4); - Length -= 188; - } -} - - -static void flush_buffers(struct ngene_channel *chan) -{ - u8 val; - - do { - msleep(1); - spin_lock_irq(&chan->state_lock); - val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; - spin_unlock_irq(&chan->state_lock); - } while (val); -} - -static void clear_buffers(struct ngene_channel *chan) -{ - struct SBufferHeader *Cur = chan->nextBuffer; - - do { - memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); - if (chan->mode & NGENE_IO_TSOUT) - FillTSBuffer(Cur->Buffer1, - chan->Capture1Length, - chan->DataFormatFlags); - Cur = Cur->Next; - } while (Cur != chan->nextBuffer); - - if (chan->mode & NGENE_IO_TSOUT) { - chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = - chan->AudioDTOValue; - chan->AudioDTOUpdated = 0; - - Cur = chan->TSIdleBuffer.Head; - - do { - memset(&Cur->ngeneBuffer.SR, 0, - sizeof(Cur->ngeneBuffer.SR)); - FillTSBuffer(Cur->Buffer1, - chan->Capture1Length, - chan->DataFormatFlags); - Cur = Cur->Next; - } while (Cur != chan->TSIdleBuffer.Head); - } -} - -static int ngene_command_stream_control(struct ngene *dev, u8 stream, - u8 control, u8 mode, u8 flags) -{ - struct ngene_channel *chan = &dev->channel[stream]; - struct ngene_command com; - u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); - u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); - u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); - u16 BsSDO = 0x9B00; - - down(&dev->stream_mutex); - memset(&com, 0, sizeof(com)); - com.cmd.hdr.Opcode = CMD_CONTROL; - com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; - com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); - if (chan->mode & NGENE_IO_TSOUT) - com.cmd.StreamControl.Stream |= 0x07; - com.cmd.StreamControl.Control = control | - (flags & SFLAG_ORDER_LUMA_CHROMA); - com.cmd.StreamControl.Mode = mode; - com.in_len = sizeof(struct FW_STREAM_CONTROL); - com.out_len = 0; - - dprintk(KERN_INFO DEVICE_NAME - ": Stream=%02x, Control=%02x, Mode=%02x\n", - com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, - com.cmd.StreamControl.Mode); - - chan->Mode = mode; - - if (!(control & 0x80)) { - spin_lock_irq(&chan->state_lock); - if (chan->State == KSSTATE_RUN) { - chan->State = KSSTATE_ACQUIRE; - chan->HWState = HWSTATE_STOP; - spin_unlock_irq(&chan->state_lock); - if (ngene_command(dev, &com) < 0) { - up(&dev->stream_mutex); - return -1; - } - /* clear_buffers(chan); */ - flush_buffers(chan); - up(&dev->stream_mutex); - return 0; - } - spin_unlock_irq(&chan->state_lock); - up(&dev->stream_mutex); - return 0; - } - - if (mode & SMODE_AUDIO_CAPTURE) { - com.cmd.StreamControl.CaptureBlockCount = - chan->Capture1Length / AUDIO_BLOCK_SIZE; - com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; - } else if (mode & SMODE_TRANSPORT_STREAM) { - com.cmd.StreamControl.CaptureBlockCount = - chan->Capture1Length / TS_BLOCK_SIZE; - com.cmd.StreamControl.MaxLinesPerField = - chan->Capture1Length / TS_BLOCK_SIZE; - com.cmd.StreamControl.Buffer_Address = - chan->TSRingBuffer.PAHead; - if (chan->mode & NGENE_IO_TSOUT) { - com.cmd.StreamControl.BytesPerVBILine = - chan->Capture1Length / TS_BLOCK_SIZE; - com.cmd.StreamControl.Stream |= 0x07; - } - } else { - com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; - com.cmd.StreamControl.MaxLinesPerField = chan->nLines; - com.cmd.StreamControl.MinLinesPerField = 100; - com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; - - if (mode & SMODE_VBI_CAPTURE) { - com.cmd.StreamControl.MaxVBILinesPerField = - chan->nVBILines; - com.cmd.StreamControl.MinVBILinesPerField = 0; - com.cmd.StreamControl.BytesPerVBILine = - chan->nBytesPerVBILine; - } - if (flags & SFLAG_COLORBAR) - com.cmd.StreamControl.Stream |= 0x04; - } - - spin_lock_irq(&chan->state_lock); - if (mode & SMODE_AUDIO_CAPTURE) { - chan->nextBuffer = chan->RingBuffer.Head; - if (mode & SMODE_AUDIO_SPDIF) { - com.cmd.StreamControl.SetupDataLen = - sizeof(SPDIFConfiguration); - com.cmd.StreamControl.SetupDataAddr = BsSPI; - memcpy(com.cmd.StreamControl.SetupData, - SPDIFConfiguration, sizeof(SPDIFConfiguration)); - } else { - com.cmd.StreamControl.SetupDataLen = 4; - com.cmd.StreamControl.SetupDataAddr = BsSDI; - memcpy(com.cmd.StreamControl.SetupData, - I2SConfiguration + - 4 * dev->card_info->i2s[stream], 4); - } - } else if (mode & SMODE_TRANSPORT_STREAM) { - chan->nextBuffer = chan->TSRingBuffer.Head; - if (stream >= STREAM_AUDIOIN1) { - if (chan->mode & NGENE_IO_TSOUT) { - com.cmd.StreamControl.SetupDataLen = - sizeof(TS_I2SOutConfiguration); - com.cmd.StreamControl.SetupDataAddr = BsSDO; - memcpy(com.cmd.StreamControl.SetupData, - TS_I2SOutConfiguration, - sizeof(TS_I2SOutConfiguration)); - } else { - com.cmd.StreamControl.SetupDataLen = - sizeof(TS_I2SConfiguration); - com.cmd.StreamControl.SetupDataAddr = BsSDI; - memcpy(com.cmd.StreamControl.SetupData, - TS_I2SConfiguration, - sizeof(TS_I2SConfiguration)); - } - } else { - com.cmd.StreamControl.SetupDataLen = 8; - com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; - memcpy(com.cmd.StreamControl.SetupData, - TSFeatureDecoderSetup + - 8 * dev->card_info->tsf[stream], 8); - } - } else { - chan->nextBuffer = chan->RingBuffer.Head; - com.cmd.StreamControl.SetupDataLen = - 16 + sizeof(ITUFeatureDecoderSetup); - com.cmd.StreamControl.SetupDataAddr = BsUVI; - memcpy(com.cmd.StreamControl.SetupData, - ITUDecoderSetup[chan->itumode], 16); - memcpy(com.cmd.StreamControl.SetupData + 16, - ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); - } - clear_buffers(chan); - chan->State = KSSTATE_RUN; - if (mode & SMODE_TRANSPORT_STREAM) - chan->HWState = HWSTATE_RUN; - else - chan->HWState = HWSTATE_STARTUP; - spin_unlock_irq(&chan->state_lock); - - if (ngene_command(dev, &com) < 0) { - up(&dev->stream_mutex); - return -1; - } - up(&dev->stream_mutex); - return 0; -} - -void set_transfer(struct ngene_channel *chan, int state) -{ - u8 control = 0, mode = 0, flags = 0; - struct ngene *dev = chan->dev; - int ret; - - /* - printk(KERN_INFO DEVICE_NAME ": st %d\n", state); - msleep(100); - */ - - if (state) { - if (chan->running) { - printk(KERN_INFO DEVICE_NAME ": already running\n"); - return; - } - } else { - if (!chan->running) { - printk(KERN_INFO DEVICE_NAME ": already stopped\n"); - return; - } - } - - if (dev->card_info->switch_ctrl) - dev->card_info->switch_ctrl(chan, 1, state ^ 1); - - if (state) { - spin_lock_irq(&chan->state_lock); - - /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", - ngreadl(0x9310)); */ - dvb_ringbuffer_flush(&dev->tsout_rbuf); - control = 0x80; - if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - chan->Capture1Length = 512 * 188; - mode = SMODE_TRANSPORT_STREAM; - } - if (chan->mode & NGENE_IO_TSOUT) { - chan->pBufferExchange = tsout_exchange; - /* 0x66666666 = 50MHz *2^33 /250MHz */ - chan->AudioDTOValue = 0x80000000; - chan->AudioDTOUpdated = 1; - } - if (chan->mode & NGENE_IO_TSIN) - chan->pBufferExchange = tsin_exchange; - spin_unlock_irq(&chan->state_lock); - } else - ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", - ngreadl(0x9310)); */ - - ret = ngene_command_stream_control(dev, chan->number, - control, mode, flags); - if (!ret) - chan->running = state; - else - printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", - state); - if (!state) { - spin_lock_irq(&chan->state_lock); - chan->pBufferExchange = NULL; - dvb_ringbuffer_flush(&dev->tsout_rbuf); - spin_unlock_irq(&chan->state_lock); - } -} - - -/****************************************************************************/ -/* nGene hardware init and release functions ********************************/ -/****************************************************************************/ - -static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) -{ - struct SBufferHeader *Cur = rb->Head; - u32 j; - - if (!Cur) - return; - - for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { - if (Cur->Buffer1) - pci_free_consistent(dev->pci_dev, - rb->Buffer1Length, - Cur->Buffer1, - Cur->scList1->Address); - - if (Cur->Buffer2) - pci_free_consistent(dev->pci_dev, - rb->Buffer2Length, - Cur->Buffer2, - Cur->scList2->Address); - } - - if (rb->SCListMem) - pci_free_consistent(dev->pci_dev, rb->SCListMemSize, - rb->SCListMem, rb->PASCListMem); - - pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); -} - -static void free_idlebuffer(struct ngene *dev, - struct SRingBufferDescriptor *rb, - struct SRingBufferDescriptor *tb) -{ - int j; - struct SBufferHeader *Cur = tb->Head; - - if (!rb->Head) - return; - free_ringbuffer(dev, rb); - for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { - Cur->Buffer2 = NULL; - Cur->scList2 = NULL; - Cur->ngeneBuffer.Address_of_first_entry_2 = 0; - Cur->ngeneBuffer.Number_of_entries_2 = 0; - } -} - -static void free_common_buffers(struct ngene *dev) -{ - u32 i; - struct ngene_channel *chan; - - for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { - chan = &dev->channel[i]; - free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); - free_ringbuffer(dev, &chan->RingBuffer); - free_ringbuffer(dev, &chan->TSRingBuffer); - } - - if (dev->OverflowBuffer) - pci_free_consistent(dev->pci_dev, - OVERFLOW_BUFFER_SIZE, - dev->OverflowBuffer, dev->PAOverflowBuffer); - - if (dev->FWInterfaceBuffer) - pci_free_consistent(dev->pci_dev, - 4096, - dev->FWInterfaceBuffer, - dev->PAFWInterfaceBuffer); -} - -/****************************************************************************/ -/* Ring buffer handling *****************************************************/ -/****************************************************************************/ - -static int create_ring_buffer(struct pci_dev *pci_dev, - struct SRingBufferDescriptor *descr, u32 NumBuffers) -{ - dma_addr_t tmp; - struct SBufferHeader *Head; - u32 i; - u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; - u64 PARingBufferHead; - u64 PARingBufferCur; - u64 PARingBufferNext; - struct SBufferHeader *Cur, *Next; - - descr->Head = NULL; - descr->MemSize = 0; - descr->PAHead = 0; - descr->NumBuffers = 0; - - if (MemSize < 4096) - MemSize = 4096; - - Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); - PARingBufferHead = tmp; - - if (!Head) - return -ENOMEM; - - memset(Head, 0, MemSize); - - PARingBufferCur = PARingBufferHead; - Cur = Head; - - for (i = 0; i < NumBuffers - 1; i++) { - Next = (struct SBufferHeader *) - (((u8 *) Cur) + SIZEOF_SBufferHeader); - PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; - Cur->Next = Next; - Cur->ngeneBuffer.Next = PARingBufferNext; - Cur = Next; - PARingBufferCur = PARingBufferNext; - } - /* Last Buffer points back to first one */ - Cur->Next = Head; - Cur->ngeneBuffer.Next = PARingBufferHead; - - descr->Head = Head; - descr->MemSize = MemSize; - descr->PAHead = PARingBufferHead; - descr->NumBuffers = NumBuffers; - - return 0; -} - -static int AllocateRingBuffers(struct pci_dev *pci_dev, - dma_addr_t of, - struct SRingBufferDescriptor *pRingBuffer, - u32 Buffer1Length, u32 Buffer2Length) -{ - dma_addr_t tmp; - u32 i, j; - int status = 0; - u32 SCListMemSize = pRingBuffer->NumBuffers - * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : - NUM_SCATTER_GATHER_ENTRIES) - * sizeof(struct HW_SCATTER_GATHER_ELEMENT); - - u64 PASCListMem; - struct HW_SCATTER_GATHER_ELEMENT *SCListEntry; - u64 PASCListEntry; - struct SBufferHeader *Cur; - void *SCListMem; - - if (SCListMemSize < 4096) - SCListMemSize = 4096; - - SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); - - PASCListMem = tmp; - if (SCListMem == NULL) - return -ENOMEM; - - memset(SCListMem, 0, SCListMemSize); - - pRingBuffer->SCListMem = SCListMem; - pRingBuffer->PASCListMem = PASCListMem; - pRingBuffer->SCListMemSize = SCListMemSize; - pRingBuffer->Buffer1Length = Buffer1Length; - pRingBuffer->Buffer2Length = Buffer2Length; - - SCListEntry = SCListMem; - PASCListEntry = PASCListMem; - Cur = pRingBuffer->Head; - - for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { - u64 PABuffer; - - void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, - &tmp); - PABuffer = tmp; - - if (Buffer == NULL) - return -ENOMEM; - - Cur->Buffer1 = Buffer; - - SCListEntry->Address = PABuffer; - SCListEntry->Length = Buffer1Length; - - Cur->scList1 = SCListEntry; - Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; - Cur->ngeneBuffer.Number_of_entries_1 = - NUM_SCATTER_GATHER_ENTRIES; - - SCListEntry += 1; - PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); - -#if NUM_SCATTER_GATHER_ENTRIES > 1 - for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { - SCListEntry->Address = of; - SCListEntry->Length = OVERFLOW_BUFFER_SIZE; - SCListEntry += 1; - PASCListEntry += - sizeof(struct HW_SCATTER_GATHER_ELEMENT); - } -#endif - - if (!Buffer2Length) - continue; - - Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); - PABuffer = tmp; - - if (Buffer == NULL) - return -ENOMEM; - - Cur->Buffer2 = Buffer; - - SCListEntry->Address = PABuffer; - SCListEntry->Length = Buffer2Length; - - Cur->scList2 = SCListEntry; - Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; - Cur->ngeneBuffer.Number_of_entries_2 = - NUM_SCATTER_GATHER_ENTRIES; - - SCListEntry += 1; - PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); - -#if NUM_SCATTER_GATHER_ENTRIES > 1 - for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { - SCListEntry->Address = of; - SCListEntry->Length = OVERFLOW_BUFFER_SIZE; - SCListEntry += 1; - PASCListEntry += - sizeof(struct HW_SCATTER_GATHER_ELEMENT); - } -#endif - - } - - return status; -} - -static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, - struct SRingBufferDescriptor *pRingBuffer) -{ - int status = 0; - - /* Copy pointer to scatter gather list in TSRingbuffer - structure for buffer 2 - Load number of buffer - */ - u32 n = pRingBuffer->NumBuffers; - - /* Point to first buffer entry */ - struct SBufferHeader *Cur = pRingBuffer->Head; - int i; - /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ - for (i = 0; i < n; i++) { - Cur->Buffer2 = pIdleBuffer->Head->Buffer1; - Cur->scList2 = pIdleBuffer->Head->scList1; - Cur->ngeneBuffer.Address_of_first_entry_2 = - pIdleBuffer->Head->ngeneBuffer. - Address_of_first_entry_1; - Cur->ngeneBuffer.Number_of_entries_2 = - pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; - Cur = Cur->Next; - } - return status; -} - -static u32 RingBufferSizes[MAX_STREAM] = { - RING_SIZE_VIDEO, - RING_SIZE_VIDEO, - RING_SIZE_AUDIO, - RING_SIZE_AUDIO, - RING_SIZE_AUDIO, -}; - -static u32 Buffer1Sizes[MAX_STREAM] = { - MAX_VIDEO_BUFFER_SIZE, - MAX_VIDEO_BUFFER_SIZE, - MAX_AUDIO_BUFFER_SIZE, - MAX_AUDIO_BUFFER_SIZE, - MAX_AUDIO_BUFFER_SIZE -}; - -static u32 Buffer2Sizes[MAX_STREAM] = { - MAX_VBI_BUFFER_SIZE, - MAX_VBI_BUFFER_SIZE, - 0, - 0, - 0 -}; - - -static int AllocCommonBuffers(struct ngene *dev) -{ - int status = 0, i; - - dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, - &dev->PAFWInterfaceBuffer); - if (!dev->FWInterfaceBuffer) - return -ENOMEM; - dev->hosttongene = dev->FWInterfaceBuffer; - dev->ngenetohost = dev->FWInterfaceBuffer + 256; - dev->EventBuffer = dev->FWInterfaceBuffer + 512; - - dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, - OVERFLOW_BUFFER_SIZE, - &dev->PAOverflowBuffer); - if (!dev->OverflowBuffer) - return -ENOMEM; - memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); - - for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { - int type = dev->card_info->io_type[i]; - - dev->channel[i].State = KSSTATE_STOP; - - if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { - status = create_ring_buffer(dev->pci_dev, - &dev->channel[i].RingBuffer, - RingBufferSizes[i]); - if (status < 0) - break; - - if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { - status = AllocateRingBuffers(dev->pci_dev, - dev-> - PAOverflowBuffer, - &dev->channel[i]. - RingBuffer, - Buffer1Sizes[i], - Buffer2Sizes[i]); - if (status < 0) - break; - } else if (type & NGENE_IO_HDTV) { - status = AllocateRingBuffers(dev->pci_dev, - dev-> - PAOverflowBuffer, - &dev->channel[i]. - RingBuffer, - MAX_HDTV_BUFFER_SIZE, - 0); - if (status < 0) - break; - } - } - - if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - - status = create_ring_buffer(dev->pci_dev, - &dev->channel[i]. - TSRingBuffer, RING_SIZE_TS); - if (status < 0) - break; - - status = AllocateRingBuffers(dev->pci_dev, - dev->PAOverflowBuffer, - &dev->channel[i]. - TSRingBuffer, - MAX_TS_BUFFER_SIZE, 0); - if (status) - break; - } - - if (type & NGENE_IO_TSOUT) { - status = create_ring_buffer(dev->pci_dev, - &dev->channel[i]. - TSIdleBuffer, 1); - if (status < 0) - break; - status = AllocateRingBuffers(dev->pci_dev, - dev->PAOverflowBuffer, - &dev->channel[i]. - TSIdleBuffer, - MAX_TS_BUFFER_SIZE, 0); - if (status) - break; - FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, - &dev->channel[i].TSRingBuffer); - } - } - return status; -} - -static void ngene_release_buffers(struct ngene *dev) -{ - if (dev->iomem) - iounmap(dev->iomem); - free_common_buffers(dev); - vfree(dev->tsout_buf); - vfree(dev->tsin_buf); - vfree(dev->ain_buf); - vfree(dev->vin_buf); - vfree(dev); -} - -static int ngene_get_buffers(struct ngene *dev) -{ - if (AllocCommonBuffers(dev)) - return -ENOMEM; - if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { - dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); - if (!dev->tsout_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->tsout_rbuf, - dev->tsout_buf, TSOUT_BUF_SIZE); - } - if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { - dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); - if (!dev->tsin_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->tsin_rbuf, - dev->tsin_buf, TSIN_BUF_SIZE); - } - if (dev->card_info->io_type[2] & NGENE_IO_AIN) { - dev->ain_buf = vmalloc(AIN_BUF_SIZE); - if (!dev->ain_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); - } - if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { - dev->vin_buf = vmalloc(VIN_BUF_SIZE); - if (!dev->vin_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); - } - dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), - pci_resource_len(dev->pci_dev, 0)); - if (!dev->iomem) - return -ENOMEM; - - return 0; -} - -static void ngene_init(struct ngene *dev) -{ - int i; - - tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); - - memset_io(dev->iomem + 0xc000, 0x00, 0x220); - memset_io(dev->iomem + 0xc400, 0x00, 0x100); - - for (i = 0; i < MAX_STREAM; i++) { - dev->channel[i].dev = dev; - dev->channel[i].number = i; - } - - dev->fw_interface_version = 0; - - ngwritel(0, NGENE_INT_ENABLE); - - dev->icounts = ngreadl(NGENE_INT_COUNTS); - - dev->device_version = ngreadl(DEV_VER) & 0x0f; - printk(KERN_INFO DEVICE_NAME ": Device version %d\n", - dev->device_version); -} - -static int ngene_load_firm(struct ngene *dev) -{ - u32 size; - const struct firmware *fw = NULL; - u8 *ngene_fw; - char *fw_name; - int err, version; - - version = dev->card_info->fw_version; - - switch (version) { - default: - case 15: - version = 15; - size = 23466; - fw_name = "ngene_15.fw"; - dev->cmd_timeout_workaround = true; - break; - case 16: - size = 23498; - fw_name = "ngene_16.fw"; - dev->cmd_timeout_workaround = true; - break; - case 17: - size = 24446; - fw_name = "ngene_17.fw"; - dev->cmd_timeout_workaround = true; - break; - case 18: - size = 0; - fw_name = "ngene_18.fw"; - break; - } - - if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { - printk(KERN_ERR DEVICE_NAME - ": Could not load firmware file %s.\n", fw_name); - printk(KERN_INFO DEVICE_NAME - ": Copy %s to your hotplug directory!\n", fw_name); - return -1; - } - if (size == 0) - size = fw->size; - if (size != fw->size) { - printk(KERN_ERR DEVICE_NAME - ": Firmware %s has invalid size!", fw_name); - err = -1; - } else { - printk(KERN_INFO DEVICE_NAME - ": Loading firmware file %s.\n", fw_name); - ngene_fw = (u8 *) fw->data; - err = ngene_command_load_firmware(dev, ngene_fw, size); - } - - release_firmware(fw); - - return err; -} - -static void ngene_stop(struct ngene *dev) -{ - down(&dev->cmd_mutex); - i2c_del_adapter(&(dev->channel[0].i2c_adapter)); - i2c_del_adapter(&(dev->channel[1].i2c_adapter)); - ngwritel(0, NGENE_INT_ENABLE); - ngwritel(0, NGENE_COMMAND); - ngwritel(0, NGENE_COMMAND_HI); - ngwritel(0, NGENE_STATUS); - ngwritel(0, NGENE_STATUS_HI); - ngwritel(0, NGENE_EVENT); - ngwritel(0, NGENE_EVENT_HI); - free_irq(dev->pci_dev->irq, dev); -#ifdef CONFIG_PCI_MSI - if (dev->msi_enabled) - pci_disable_msi(dev->pci_dev); -#endif -} - -static int ngene_buffer_config(struct ngene *dev) -{ - int stat; - - if (dev->card_info->fw_version >= 17) { - u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; - u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; - u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; - u8 *bconf = tsin12_config; - - if (dev->card_info->io_type[2]&NGENE_IO_TSIN && - dev->card_info->io_type[3]&NGENE_IO_TSIN) { - bconf = tsin1234_config; - if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && - dev->ci.en) - bconf = tsio1235_config; - } - stat = ngene_command_config_free_buf(dev, bconf); - } else { - int bconf = BUFFER_CONFIG_4422; - - if (dev->card_info->io_type[3] == NGENE_IO_TSIN) - bconf = BUFFER_CONFIG_3333; - stat = ngene_command_config_buf(dev, bconf); - } - return stat; -} - - -static int ngene_start(struct ngene *dev) -{ - int stat; - int i; - - pci_set_master(dev->pci_dev); - ngene_init(dev); - - stat = request_irq(dev->pci_dev->irq, irq_handler, - IRQF_SHARED, "nGene", - (void *)dev); - if (stat < 0) - return stat; - - init_waitqueue_head(&dev->cmd_wq); - init_waitqueue_head(&dev->tx_wq); - init_waitqueue_head(&dev->rx_wq); - sema_init(&dev->cmd_mutex, 1); - sema_init(&dev->stream_mutex, 1); - sema_init(&dev->pll_mutex, 1); - sema_init(&dev->i2c_switch_mutex, 1); - spin_lock_init(&dev->cmd_lock); - for (i = 0; i < MAX_STREAM; i++) - spin_lock_init(&dev->channel[i].state_lock); - ngwritel(1, TIMESTAMPS); - - ngwritel(1, NGENE_INT_ENABLE); - - stat = ngene_load_firm(dev); - if (stat < 0) - goto fail; - -#ifdef CONFIG_PCI_MSI - /* enable MSI if kernel and card support it */ - if (pci_msi_enabled() && dev->card_info->msi_supported) { - unsigned long flags; - - ngwritel(0, NGENE_INT_ENABLE); - free_irq(dev->pci_dev->irq, dev); - stat = pci_enable_msi(dev->pci_dev); - if (stat) { - printk(KERN_INFO DEVICE_NAME - ": MSI not available\n"); - flags = IRQF_SHARED; - } else { - flags = 0; - dev->msi_enabled = true; - } - stat = request_irq(dev->pci_dev->irq, irq_handler, - flags, "nGene", dev); - if (stat < 0) - goto fail2; - ngwritel(1, NGENE_INT_ENABLE); - } -#endif - - stat = ngene_i2c_init(dev, 0); - if (stat < 0) - goto fail; - - stat = ngene_i2c_init(dev, 1); - if (stat < 0) - goto fail; - - return 0; - -fail: - ngwritel(0, NGENE_INT_ENABLE); - free_irq(dev->pci_dev->irq, dev); -#ifdef CONFIG_PCI_MSI -fail2: - if (dev->msi_enabled) - pci_disable_msi(dev->pci_dev); -#endif - return stat; -} - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -static void release_channel(struct ngene_channel *chan) -{ - struct dvb_demux *dvbdemux = &chan->demux; - struct ngene *dev = chan->dev; - - if (chan->running) - set_transfer(chan, 0); - - tasklet_kill(&chan->demux_tasklet); - - if (chan->ci_dev) { - dvb_unregister_device(chan->ci_dev); - chan->ci_dev = NULL; - } - - if (chan->fe2) - dvb_unregister_frontend(chan->fe2); - - if (chan->fe) { - dvb_unregister_frontend(chan->fe); - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - } - - if (chan->has_demux) { - dvb_net_release(&chan->dvbnet); - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &chan->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &chan->mem_frontend); - dvb_dmxdev_release(&chan->dmxdev); - dvb_dmx_release(&chan->demux); - chan->has_demux = false; - } - - if (chan->has_adapter) { - dvb_unregister_adapter(&dev->adapter[chan->number]); - chan->has_adapter = false; - } -} - -static int init_channel(struct ngene_channel *chan) -{ - int ret = 0, nr = chan->number; - struct dvb_adapter *adapter = NULL; - struct dvb_demux *dvbdemux = &chan->demux; - struct ngene *dev = chan->dev; - struct ngene_info *ni = dev->card_info; - int io = ni->io_type[nr]; - - tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); - chan->users = 0; - chan->type = io; - chan->mode = chan->type; /* for now only one mode */ - - if (io & NGENE_IO_TSIN) { - chan->fe = NULL; - if (ni->demod_attach[nr]) { - ret = ni->demod_attach[nr](chan); - if (ret < 0) - goto err; - } - if (chan->fe && ni->tuner_attach[nr]) { - ret = ni->tuner_attach[nr](chan); - if (ret < 0) - goto err; - } - } - - if (!dev->ci.en && (io & NGENE_IO_TSOUT)) - return 0; - - if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - if (nr >= STREAM_AUDIOIN1) - chan->DataFormatFlags = DF_SWAP32; - - if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { - adapter = &dev->adapter[nr]; - ret = dvb_register_adapter(adapter, "nGene", - THIS_MODULE, - &chan->dev->pci_dev->dev, - adapter_nr); - if (ret < 0) - goto err; - if (dev->first_adapter == NULL) - dev->first_adapter = adapter; - chan->has_adapter = true; - } else - adapter = dev->first_adapter; - } - - if (dev->ci.en && (io & NGENE_IO_TSOUT)) { - dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); - set_transfer(chan, 1); - chan->dev->channel[2].DataFormatFlags = DF_SWAP32; - set_transfer(&chan->dev->channel[2], 1); - dvb_register_device(adapter, &chan->ci_dev, - &ngene_dvbdev_ci, (void *) chan, - DVB_DEVICE_SEC); - if (!chan->ci_dev) - goto err; - } - - if (chan->fe) { - if (dvb_register_frontend(adapter, chan->fe) < 0) - goto err; - chan->has_demux = true; - } - if (chan->fe2) { - if (dvb_register_frontend(adapter, chan->fe2) < 0) - goto err; - chan->fe2->tuner_priv = chan->fe->tuner_priv; - memcpy(&chan->fe2->ops.tuner_ops, - &chan->fe->ops.tuner_ops, - sizeof(struct dvb_tuner_ops)); - } - - if (chan->has_demux) { - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - ngene_start_feed, - ngene_stop_feed, chan); - ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, - &chan->hw_frontend, - &chan->mem_frontend, adapter); - ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); - } - - return ret; - -err: - if (chan->fe) { - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - } - release_channel(chan); - return 0; -} - -static int init_channels(struct ngene *dev) -{ - int i, j; - - for (i = 0; i < MAX_STREAM; i++) { - dev->channel[i].number = i; - if (init_channel(&dev->channel[i]) < 0) { - for (j = i - 1; j >= 0; j--) - release_channel(&dev->channel[j]); - return -1; - } - } - return 0; -} - -static struct cxd2099_cfg cxd_cfg = { - .bitrate = 62000, - .adr = 0x40, - .polarity = 0, - .clock_mode = 0, -}; - -static void cxd_attach(struct ngene *dev) -{ - struct ngene_ci *ci = &dev->ci; - - ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); - ci->dev = dev; - return; -} - -static void cxd_detach(struct ngene *dev) -{ - struct ngene_ci *ci = &dev->ci; - - dvb_ca_en50221_release(ci->en); - kfree(ci->en); - ci->en = 0; -} - -/***********************************/ -/* workaround for shutdown failure */ -/***********************************/ - -static void ngene_unlink(struct ngene *dev) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_MEM_WRITE; - com.cmd.hdr.Length = 3; - com.cmd.MemoryWrite.address = 0x910c; - com.cmd.MemoryWrite.data = 0xff; - com.in_len = 3; - com.out_len = 1; - - down(&dev->cmd_mutex); - ngwritel(0, NGENE_INT_ENABLE); - ngene_command_mutex(dev, &com); - up(&dev->cmd_mutex); -} - -void ngene_shutdown(struct pci_dev *pdev) -{ - struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); - - if (!dev || !shutdown_workaround) - return; - - printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); - ngene_unlink(dev); - pci_disable_device(pdev); -} - -/****************************************************************************/ -/* device probe/remove calls ************************************************/ -/****************************************************************************/ - -void __devexit ngene_remove(struct pci_dev *pdev) -{ - struct ngene *dev = pci_get_drvdata(pdev); - int i; - - tasklet_kill(&dev->event_tasklet); - for (i = MAX_STREAM - 1; i >= 0; i--) - release_channel(&dev->channel[i]); - if (dev->ci.en) - cxd_detach(dev); - ngene_stop(dev); - ngene_release_buffers(dev); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); -} - -int __devinit ngene_probe(struct pci_dev *pci_dev, - const struct pci_device_id *id) -{ - struct ngene *dev; - int stat = 0; - - if (pci_enable_device(pci_dev) < 0) - return -ENODEV; - - dev = vzalloc(sizeof(struct ngene)); - if (dev == NULL) { - stat = -ENOMEM; - goto fail0; - } - - dev->pci_dev = pci_dev; - dev->card_info = (struct ngene_info *)id->driver_data; - printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); - - pci_set_drvdata(pci_dev, dev); - - /* Alloc buffers and start nGene */ - stat = ngene_get_buffers(dev); - if (stat < 0) - goto fail1; - stat = ngene_start(dev); - if (stat < 0) - goto fail1; - - cxd_attach(dev); - - stat = ngene_buffer_config(dev); - if (stat < 0) - goto fail1; - - - dev->i2c_current_bus = -1; - - /* Register DVB adapters and devices for both channels */ - if (init_channels(dev) < 0) - goto fail2; - - return 0; - -fail2: - ngene_stop(dev); -fail1: - ngene_release_buffers(dev); -fail0: - pci_disable_device(pci_dev); - pci_set_drvdata(pci_dev, NULL); - return stat; -} diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c deleted file mode 100644 index fcb16a615aa..00000000000 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * ngene-dvb.c: nGene PCIe bridge driver - DVB functions - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ngene.h" - - -/****************************************************************************/ -/* COMMAND API interface ****************************************************/ -/****************************************************************************/ - -static ssize_t ts_write(struct file *file, const char *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct ngene_channel *chan = dvbdev->priv; - struct ngene *dev = chan->dev; - - if (wait_event_interruptible(dev->tsout_rbuf.queue, - dvb_ringbuffer_free - (&dev->tsout_rbuf) >= count) < 0) - return 0; - - dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); - - return count; -} - -static ssize_t ts_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct ngene_channel *chan = dvbdev->priv; - struct ngene *dev = chan->dev; - int left, avail; - - left = count; - while (left) { - if (wait_event_interruptible( - dev->tsin_rbuf.queue, - dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) - return -EAGAIN; - avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); - if (avail > left) - avail = left; - dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); - left -= avail; - buf += avail; - } - return count; -} - -static const struct file_operations ci_fops = { - .owner = THIS_MODULE, - .read = ts_read, - .write = ts_write, - .open = dvb_generic_open, - .release = dvb_generic_release, -}; - -struct dvb_device ngene_dvbdev_ci = { - .priv = 0, - .readers = -1, - .writers = -1, - .users = -1, - .fops = &ci_fops, -}; - - -/****************************************************************************/ -/* DVB functions and API interface ******************************************/ -/****************************************************************************/ - -static void swap_buffer(u32 *p, u32 len) -{ - while (len) { - *p = swab32(*p); - p++; - len -= 4; - } -} - -/* start of filler packet */ -static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; - -/* #define DEBUG_CI_XFER */ -#ifdef DEBUG_CI_XFER -static u32 ok; -static u32 overflow; -static u32 stripped; -#endif - -void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) -{ - struct ngene_channel *chan = priv; - struct ngene *dev = chan->dev; - - - if (flags & DF_SWAP32) - swap_buffer(buf, len); - - if (dev->ci.en && chan->number == 2) { - while (len >= 188) { - if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); - wake_up(&dev->tsin_rbuf.queue); -#ifdef DEBUG_CI_XFER - ok++; -#endif - } -#ifdef DEBUG_CI_XFER - else - overflow++; -#endif - } -#ifdef DEBUG_CI_XFER - else - stripped++; - - if (ok % 100 == 0 && overflow) - printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); -#endif - buf += 188; - len -= 188; - } - return NULL; - } - - if (chan->users > 0) - dvb_dmx_swfilter(&chan->demux, buf, len); - - return NULL; -} - -void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) -{ - struct ngene_channel *chan = priv; - struct ngene *dev = chan->dev; - u32 alen; - - alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); - alen -= alen % 188; - - if (alen < len) - FillTSBuffer(buf + alen, len - alen, flags); - else - alen = len; - dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); - if (flags & DF_SWAP32) - swap_buffer((u32 *)buf, alen); - wake_up_interruptible(&dev->tsout_rbuf.queue); - return buf; -} - - - -int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ngene_channel *chan = dvbdmx->priv; - - if (chan->users == 0) { - if (!chan->dev->cmd_timeout_workaround || !chan->running) - set_transfer(chan, 1); - } - - return ++chan->users; -} - -int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ngene_channel *chan = dvbdmx->priv; - - if (--chan->users) - return chan->users; - - if (!chan->dev->cmd_timeout_workaround) - set_transfer(chan, 0); - - return 0; -} - -int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv) -{ - dvbdemux->priv = priv; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = start_feed; - dvbdemux->stop_feed = stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - return dvb_dmx_init(dvbdemux); -} - -int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter) -{ - int ret; - - dmxdev->filternum = 256; - dmxdev->demux = &dvbdemux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adapter); - if (ret < 0) - return ret; - - hw_frontend->source = DMX_FRONTEND_0; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); - mem_frontend->source = DMX_MEMORY_FE; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); - return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); -} diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c deleted file mode 100644 index d28554f8ce9..00000000000 --- a/drivers/media/dvb/ngene/ngene-i2c.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ngene-i2c.c: nGene PCIe bridge driver i2c functions - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -/* FIXME - some of these can probably be removed */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ngene.h" - -/* Firmware command for i2c operations */ -static int ngene_command_i2c_read(struct ngene *dev, u8 adr, - u8 *out, u8 outlen, u8 *in, u8 inlen, int flag) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_I2C_READ; - com.cmd.hdr.Length = outlen + 3; - com.cmd.I2CRead.Device = adr << 1; - memcpy(com.cmd.I2CRead.Data, out, outlen); - com.cmd.I2CRead.Data[outlen] = inlen; - com.cmd.I2CRead.Data[outlen + 1] = 0; - com.in_len = outlen + 3; - com.out_len = inlen + 1; - - if (ngene_command(dev, &com) < 0) - return -EIO; - - if ((com.cmd.raw8[0] >> 1) != adr) - return -EIO; - - if (flag) - memcpy(in, com.cmd.raw8, inlen + 1); - else - memcpy(in, com.cmd.raw8 + 1, inlen); - return 0; -} - -static int ngene_command_i2c_write(struct ngene *dev, u8 adr, - u8 *out, u8 outlen) -{ - struct ngene_command com; - - - com.cmd.hdr.Opcode = CMD_I2C_WRITE; - com.cmd.hdr.Length = outlen + 1; - com.cmd.I2CRead.Device = adr << 1; - memcpy(com.cmd.I2CRead.Data, out, outlen); - com.in_len = outlen + 1; - com.out_len = 1; - - if (ngene_command(dev, &com) < 0) - return -EIO; - - if (com.cmd.raw8[0] == 1) - return -EIO; - - return 0; -} - -static void ngene_i2c_set_bus(struct ngene *dev, int bus) -{ - if (!(dev->card_info->i2c_access & 2)) - return; - if (dev->i2c_current_bus == bus) - return; - - switch (bus) { - case 0: - ngene_command_gpio_set(dev, 3, 0); - ngene_command_gpio_set(dev, 2, 1); - break; - - case 1: - ngene_command_gpio_set(dev, 2, 0); - ngene_command_gpio_set(dev, 3, 1); - break; - } - dev->i2c_current_bus = bus; -} - -static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msg[], int num) -{ - struct ngene_channel *chan = - (struct ngene_channel *)i2c_get_adapdata(adapter); - struct ngene *dev = chan->dev; - - down(&dev->i2c_switch_mutex); - ngene_i2c_set_bus(dev, chan->number); - - if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD)) - if (!ngene_command_i2c_read(dev, msg[0].addr, - msg[0].buf, msg[0].len, - msg[1].buf, msg[1].len, 0)) - goto done; - - if (num == 1 && !(msg[0].flags & I2C_M_RD)) - if (!ngene_command_i2c_write(dev, msg[0].addr, - msg[0].buf, msg[0].len)) - goto done; - if (num == 1 && (msg[0].flags & I2C_M_RD)) - if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0, - msg[0].buf, msg[0].len, 0)) - goto done; - - up(&dev->i2c_switch_mutex); - return -EIO; - -done: - up(&dev->i2c_switch_mutex); - return num; -} - - -static u32 ngene_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm ngene_i2c_algo = { - .master_xfer = ngene_i2c_master_xfer, - .functionality = ngene_i2c_functionality, -}; - -int ngene_i2c_init(struct ngene *dev, int dev_nr) -{ - struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter); - - i2c_set_adapdata(adap, &(dev->channel[dev_nr])); - - strcpy(adap->name, "nGene"); - - adap->algo = &ngene_i2c_algo; - adap->algo_data = (void *)&(dev->channel[dev_nr]); - adap->dev.parent = &dev->pci_dev->dev; - - return i2c_add_adapter(adap); -} - diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h deleted file mode 100644 index 5443dc0caea..00000000000 --- a/drivers/media/dvb/ngene/ngene.h +++ /dev/null @@ -1,921 +0,0 @@ -/* - * ngene.h: nGene PCIe bridge driver - * - * Copyright (C) 2005-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#ifndef _NGENE_H_ -#define _NGENE_H_ - -#include -#include -#include -#include -#include -#include - -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_ca_en50221.h" -#include "dvb_frontend.h" -#include "dvb_ringbuffer.h" -#include "dvb_net.h" -#include "cxd2099.h" - -#define DEVICE_NAME "ngene" - -#define NGENE_VID 0x18c3 -#define NGENE_PID 0x0720 - -#ifndef VIDEO_CAP_VC1 -#define VIDEO_CAP_AVC 128 -#define VIDEO_CAP_H264 128 -#define VIDEO_CAP_VC1 256 -#define VIDEO_CAP_WMV9 256 -#define VIDEO_CAP_MPEG4 512 -#endif - -enum STREAM { - STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ - STREAM_VIDEOIN2, - STREAM_AUDIOIN1, /* I2S or SPI Input */ - STREAM_AUDIOIN2, - STREAM_AUDIOOUT, - MAX_STREAM -}; - -enum SMODE_BITS { - SMODE_AUDIO_SPDIF = 0x20, - SMODE_AVSYNC = 0x10, - SMODE_TRANSPORT_STREAM = 0x08, - SMODE_AUDIO_CAPTURE = 0x04, - SMODE_VBI_CAPTURE = 0x02, - SMODE_VIDEO_CAPTURE = 0x01 -}; - -enum STREAM_FLAG_BITS { - SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */ - SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */ - SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */ - SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */ - SFLAG_COLORBAR = 0x04, /* Select colorbar */ -}; - -#define PROGRAM_ROM 0x0000 -#define PROGRAM_SRAM 0x1000 -#define PERIPHERALS0 0x8000 -#define PERIPHERALS1 0x9000 -#define SHARED_BUFFER 0xC000 - -#define HOST_TO_NGENE (SHARED_BUFFER+0x0000) -#define NGENE_TO_HOST (SHARED_BUFFER+0x0100) -#define NGENE_COMMAND (SHARED_BUFFER+0x0200) -#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204) -#define NGENE_STATUS (SHARED_BUFFER+0x0208) -#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C) -#define NGENE_EVENT (SHARED_BUFFER+0x0210) -#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214) -#define VARIABLES (SHARED_BUFFER+0x0210) - -#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260) -#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264) -#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268) - -#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800) -#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900) -#define EEPROM_AREA (SHARED_BUFFER+0x0A00) - -#define SG_V_IN_1 (SHARED_BUFFER+0x0A80) -#define SG_VBI_1 (SHARED_BUFFER+0x0B00) -#define SG_A_IN_1 (SHARED_BUFFER+0x0B80) -#define SG_V_IN_2 (SHARED_BUFFER+0x0C00) -#define SG_VBI_2 (SHARED_BUFFER+0x0C80) -#define SG_A_IN_2 (SHARED_BUFFER+0x0D00) -#define SG_V_OUT (SHARED_BUFFER+0x0D80) -#define SG_A_OUT2 (SHARED_BUFFER+0x0E00) - -#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80) -#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00) -#define DATA_A_OUT (SHARED_BUFFER+0x0F80) -#define DATA_V_IN_1 (SHARED_BUFFER+0x1000) -#define DATA_V_IN_2 (SHARED_BUFFER+0x2000) -#define DATA_V_OUT (SHARED_BUFFER+0x3000) - -#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000) - -#define TIMESTAMPS 0xA000 -#define SCRATCHPAD 0xA080 -#define FORCE_INT 0xA088 -#define FORCE_NMI 0xA090 -#define INT_STATUS 0xA0A0 - -#define DEV_VER 0x9004 - -#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF) - -struct SG_ADDR { - u64 start; - u64 curr; - u16 curr_ptr; - u16 elements; - u32 pad[3]; -} __attribute__ ((__packed__)); - -struct SHARED_MEMORY { - /* C000 */ - u32 HostToNgene[64]; - - /* C100 */ - u32 NgeneToHost[64]; - - /* C200 */ - u64 NgeneCommand; - u64 NgeneStatus; - u64 NgeneEvent; - - /* C210 */ - u8 pad1[0xc260 - 0xc218]; - - /* C260 */ - u32 IntCounts; - u32 IntEnable; - - /* C268 */ - u8 pad2[0xd000 - 0xc268]; - -} __attribute__ ((__packed__)); - -struct BUFFER_STREAM_RESULTS { - u32 Clock; /* Stream time in 100ns units */ - u16 RemainingLines; /* Remaining lines in this field. - 0 for complete field */ - u8 FieldCount; /* Video field number */ - u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow, - Bit 0 = FieldID */ - u16 BlockCount; /* Audio block count (unused) */ - u8 Reserved[2]; - u32 DTOUpdate; -} __attribute__ ((__packed__)); - -struct HW_SCATTER_GATHER_ELEMENT { - u64 Address; - u32 Length; - u32 Reserved; -} __attribute__ ((__packed__)); - -struct BUFFER_HEADER { - u64 Next; - struct BUFFER_STREAM_RESULTS SR; - - u32 Number_of_entries_1; - u32 Reserved5; - u64 Address_of_first_entry_1; - - u32 Number_of_entries_2; - u32 Reserved7; - u64 Address_of_first_entry_2; -} __attribute__ ((__packed__)); - -struct EVENT_BUFFER { - u32 TimeStamp; - u8 GPIOStatus; - u8 UARTStatus; - u8 RXCharacter; - u8 EventStatus; - u32 Reserved[2]; -} __attribute__ ((__packed__)); - -/* Firmware commands. */ - -enum OPCODES { - CMD_NOP = 0, - CMD_FWLOAD_PREPARE = 0x01, - CMD_FWLOAD_FINISH = 0x02, - CMD_I2C_READ = 0x03, - CMD_I2C_WRITE = 0x04, - - CMD_I2C_WRITE_NOSTOP = 0x05, - CMD_I2C_CONTINUE_WRITE = 0x06, - CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07, - - CMD_DEBUG_OUTPUT = 0x09, - - CMD_CONTROL = 0x10, - CMD_CONFIGURE_BUFFER = 0x11, - CMD_CONFIGURE_FREE_BUFFER = 0x12, - - CMD_SPI_READ = 0x13, - CMD_SPI_WRITE = 0x14, - - CMD_MEM_READ = 0x20, - CMD_MEM_WRITE = 0x21, - CMD_SFR_READ = 0x22, - CMD_SFR_WRITE = 0x23, - CMD_IRAM_READ = 0x24, - CMD_IRAM_WRITE = 0x25, - CMD_SET_GPIO_PIN = 0x26, - CMD_SET_GPIO_INT = 0x27, - CMD_CONFIGURE_UART = 0x28, - CMD_WRITE_UART = 0x29, - MAX_CMD -}; - -enum RESPONSES { - OK = 0, - ERROR = 1 -}; - -struct FW_HEADER { - u8 Opcode; - u8 Length; -} __attribute__ ((__packed__)); - -struct FW_I2C_WRITE { - struct FW_HEADER hdr; - u8 Device; - u8 Data[250]; -} __attribute__ ((__packed__)); - -struct FW_I2C_CONTINUE_WRITE { - struct FW_HEADER hdr; - u8 Data[250]; -} __attribute__ ((__packed__)); - -struct FW_I2C_READ { - struct FW_HEADER hdr; - u8 Device; - u8 Data[252]; /* followed by two bytes of read data count */ -} __attribute__ ((__packed__)); - -struct FW_SPI_WRITE { - struct FW_HEADER hdr; - u8 ModeSelect; - u8 Data[250]; -} __attribute__ ((__packed__)); - -struct FW_SPI_READ { - struct FW_HEADER hdr; - u8 ModeSelect; - u8 Data[252]; /* followed by two bytes of read data count */ -} __attribute__ ((__packed__)); - -struct FW_FWLOAD_PREPARE { - struct FW_HEADER hdr; -} __attribute__ ((__packed__)); - -struct FW_FWLOAD_FINISH { - struct FW_HEADER hdr; - u16 Address; /* address of final block */ - u16 Length; -} __attribute__ ((__packed__)); - -/* - * Meaning of FW_STREAM_CONTROL::Mode bits: - * Bit 7: Loopback PEXin to PEXout using TVOut channel - * Bit 6: AVLOOP - * Bit 5: Audio select; 0=I2S, 1=SPDIF - * Bit 4: AVSYNC - * Bit 3: Enable transport stream - * Bit 2: Enable audio capture - * Bit 1: Enable ITU-Video VBI capture - * Bit 0: Enable ITU-Video capture - * - * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL) - * Bit 7: continuous capture - * Bit 6: capture one field - * Bit 5: capture one frame - * Bit 4: unused - * Bit 3: starting field; 0=odd, 1=even - * Bit 2: sample size; 0=8-bit, 1=10-bit - * Bit 1: data format; 0=UYVY, 1=YUY2 - * Bit 0: resets buffer pointers -*/ - -enum FSC_MODE_BITS { - SMODE_LOOPBACK = 0x80, - SMODE_AVLOOP = 0x40, - _SMODE_AUDIO_SPDIF = 0x20, - _SMODE_AVSYNC = 0x10, - _SMODE_TRANSPORT_STREAM = 0x08, - _SMODE_AUDIO_CAPTURE = 0x04, - _SMODE_VBI_CAPTURE = 0x02, - _SMODE_VIDEO_CAPTURE = 0x01 -}; - - -/* Meaning of FW_STREAM_CONTROL::Stream bits: - * Bit 3: Audio sample count: 0 = relative, 1 = absolute - * Bit 2: color bar select; 1=color bars, 0=CV3 decoder - * Bits 1-0: stream select, UVI1, UVI2, TVOUT - */ - -struct FW_STREAM_CONTROL { - struct FW_HEADER hdr; - u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */ - u8 Control; /* Value written to UVI1_CTL */ - u8 Mode; /* Controls clock source */ - u8 SetupDataLen; /* Length of setup data, MSB=1 write - backwards */ - u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer - for TS and Audio */ - u64 Buffer_Address; /* Address of first buffer header */ - u16 BytesPerVideoLine; - u16 MaxLinesPerField; - u16 MinLinesPerField; - u16 Reserved_1; - u16 BytesPerVBILine; - u16 MaxVBILinesPerField; - u16 MinVBILinesPerField; - u16 SetupDataAddr; /* ngene relative address of setup data */ - u8 SetupData[32]; /* setup data */ -} __attribute__((__packed__)); - -#define AUDIO_BLOCK_SIZE 256 -#define TS_BLOCK_SIZE 256 - -struct FW_MEM_READ { - struct FW_HEADER hdr; - u16 address; -} __attribute__ ((__packed__)); - -struct FW_MEM_WRITE { - struct FW_HEADER hdr; - u16 address; - u8 data; -} __attribute__ ((__packed__)); - -struct FW_SFR_IRAM_READ { - struct FW_HEADER hdr; - u8 address; -} __attribute__ ((__packed__)); - -struct FW_SFR_IRAM_WRITE { - struct FW_HEADER hdr; - u8 address; - u8 data; -} __attribute__ ((__packed__)); - -struct FW_SET_GPIO_PIN { - struct FW_HEADER hdr; - u8 select; -} __attribute__ ((__packed__)); - -struct FW_SET_GPIO_INT { - struct FW_HEADER hdr; - u8 select; -} __attribute__ ((__packed__)); - -struct FW_SET_DEBUGMODE { - struct FW_HEADER hdr; - u8 debug_flags; -} __attribute__ ((__packed__)); - -struct FW_CONFIGURE_BUFFERS { - struct FW_HEADER hdr; - u8 config; -} __attribute__ ((__packed__)); - -enum _BUFFER_CONFIGS { - /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */ - BUFFER_CONFIG_4422 = 0, - /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */ - BUFFER_CONFIG_3333 = 1, - /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */ - BUFFER_CONFIG_8022 = 2, - BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */ -}; - -struct FW_CONFIGURE_FREE_BUFFERS { - struct FW_HEADER hdr; - u8 UVI1_BufferLength; - u8 UVI2_BufferLength; - u8 TVO_BufferLength; - u8 AUD1_BufferLength; - u8 AUD2_BufferLength; - u8 TVA_BufferLength; -} __attribute__ ((__packed__)); - -struct FW_CONFIGURE_UART { - struct FW_HEADER hdr; - u8 UartControl; -} __attribute__ ((__packed__)); - -enum _UART_CONFIG { - _UART_BAUDRATE_19200 = 0, - _UART_BAUDRATE_9600 = 1, - _UART_BAUDRATE_4800 = 2, - _UART_BAUDRATE_2400 = 3, - _UART_RX_ENABLE = 0x40, - _UART_TX_ENABLE = 0x80, -}; - -struct FW_WRITE_UART { - struct FW_HEADER hdr; - u8 Data[252]; -} __attribute__ ((__packed__)); - - -struct ngene_command { - u32 in_len; - u32 out_len; - union { - u32 raw[64]; - u8 raw8[256]; - struct FW_HEADER hdr; - struct FW_I2C_WRITE I2CWrite; - struct FW_I2C_CONTINUE_WRITE I2CContinueWrite; - struct FW_I2C_READ I2CRead; - struct FW_STREAM_CONTROL StreamControl; - struct FW_FWLOAD_PREPARE FWLoadPrepare; - struct FW_FWLOAD_FINISH FWLoadFinish; - struct FW_MEM_READ MemoryRead; - struct FW_MEM_WRITE MemoryWrite; - struct FW_SFR_IRAM_READ SfrIramRead; - struct FW_SFR_IRAM_WRITE SfrIramWrite; - struct FW_SPI_WRITE SPIWrite; - struct FW_SPI_READ SPIRead; - struct FW_SET_GPIO_PIN SetGpioPin; - struct FW_SET_GPIO_INT SetGpioInt; - struct FW_SET_DEBUGMODE SetDebugMode; - struct FW_CONFIGURE_BUFFERS ConfigureBuffers; - struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers; - struct FW_CONFIGURE_UART ConfigureUart; - struct FW_WRITE_UART WriteUart; - } cmd; -} __attribute__ ((__packed__)); - -#define NGENE_INTERFACE_VERSION 0x103 -#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */ -#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */ -#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */ -#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */ -#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page - Max: (1920x1080i60) */ - -#define OVERFLOW_BUFFER_SIZE (8192) - -#define RING_SIZE_VIDEO 4 -#define RING_SIZE_AUDIO 8 -#define RING_SIZE_TS 8 - -#define NUM_SCATTER_GATHER_ENTRIES 8 - -#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \ - RING_SIZE_VIDEO * 2) + \ - (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \ - (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \ - (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \ - (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \ - (RING_SIZE_TS * PAGE_SIZE * 4) + \ - 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE) - -#define EVENT_QUEUE_SIZE 16 - -/* Gathers the current state of a single channel. */ - -struct SBufferHeader { - struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */ - struct SBufferHeader *Next; - void *Buffer1; - struct HW_SCATTER_GATHER_ELEMENT *scList1; - void *Buffer2; - struct HW_SCATTER_GATHER_ELEMENT *scList2; -}; - -/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */ -#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63) - -enum HWSTATE { - HWSTATE_STOP, - HWSTATE_STARTUP, - HWSTATE_RUN, - HWSTATE_PAUSE, -}; - -enum KSSTATE { - KSSTATE_STOP, - KSSTATE_ACQUIRE, - KSSTATE_PAUSE, - KSSTATE_RUN, -}; - -struct SRingBufferDescriptor { - struct SBufferHeader *Head; /* Points to first buffer in ring buffer - structure*/ - u64 PAHead; /* Physical address of first buffer */ - u32 MemSize; /* Memory size of allocated ring buffers - (needed for freeing) */ - u32 NumBuffers; /* Number of buffers in the ring */ - u32 Buffer1Length; /* Allocated length of Buffer 1 */ - u32 Buffer2Length; /* Allocated length of Buffer 2 */ - void *SCListMem; /* Memory to hold scatter gather lists for this - ring */ - u64 PASCListMem; /* Physical address .. */ - u32 SCListMemSize; /* Size of this memory */ -}; - -enum STREAMMODEFLAGS { - StreamMode_NONE = 0, /* Stream not used */ - StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */ - StreamMode_TSIN = 2, /* Transport stream input (all) */ - StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60 - (only stream 0) */ - StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */ -}; - - -enum BufferExchangeFlags { - BEF_EVEN_FIELD = 0x00000001, - BEF_CONTINUATION = 0x00000002, - BEF_MORE_DATA = 0x00000004, - BEF_OVERFLOW = 0x00000008, - DF_SWAP32 = 0x00010000, -}; - -typedef void *(IBufferExchange)(void *, void *, u32, u32, u32); - -struct MICI_STREAMINFO { - IBufferExchange *pExchange; - IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */ - u8 Stream; - u8 Flags; - u8 Mode; - u8 Reserved; - u16 nLinesVideo; - u16 nBytesPerLineVideo; - u16 nLinesVBI; - u16 nBytesPerLineVBI; - u32 CaptureLength; /* Used for audio and transport stream */ -}; - -/****************************************************************************/ -/* STRUCTS ******************************************************************/ -/****************************************************************************/ - -/* sound hardware definition */ -#define MIXER_ADDR_TVTUNER 0 -#define MIXER_ADDR_LAST 0 - -struct ngene_channel; - -/*struct sound chip*/ - -struct mychip { - struct ngene_channel *chan; - struct snd_card *card; - struct pci_dev *pci; - struct snd_pcm_substream *substream; - struct snd_pcm *pcm; - unsigned long port; - int irq; - spinlock_t mixer_lock; - spinlock_t lock; - int mixer_volume[MIXER_ADDR_LAST + 1][2]; - int capture_source[MIXER_ADDR_LAST + 1][2]; -}; - -#ifdef NGENE_V4L -struct ngene_overlay { - int tvnorm; - struct v4l2_rect w; - enum v4l2_field field; - struct v4l2_clip *clips; - int nclips; - int setup_ok; -}; - -struct ngene_tvnorm { - int v4l2_id; - char *name; - u16 swidth, sheight; /* scaled standard width, height */ - int tuner_norm; - int soundstd; -}; - -struct ngene_vopen { - struct ngene_channel *ch; - enum v4l2_priority prio; - int width; - int height; - int depth; - struct videobuf_queue vbuf_q; - struct videobuf_queue vbi; - int fourcc; - int picxcount; - int resources; - enum v4l2_buf_type type; - const struct ngene_format *fmt; - - const struct ngene_format *ovfmt; - struct ngene_overlay ov; -}; -#endif - -struct ngene_channel { - struct device device; - struct i2c_adapter i2c_adapter; - - struct ngene *dev; - int number; - int type; - int mode; - bool has_adapter; - bool has_demux; - int demod_type; - int (*gate_ctrl)(struct dvb_frontend *, int); - - struct dvb_frontend *fe; - struct dvb_frontend *fe2; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvbnet; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - int users; - struct video_device *v4l_dev; - struct dvb_device *ci_dev; - struct tasklet_struct demux_tasklet; - - struct SBufferHeader *nextBuffer; - enum KSSTATE State; - enum HWSTATE HWState; - u8 Stream; - u8 Flags; - u8 Mode; - IBufferExchange *pBufferExchange; - IBufferExchange *pBufferExchange2; - - spinlock_t state_lock; - u16 nLines; - u16 nBytesPerLine; - u16 nVBILines; - u16 nBytesPerVBILine; - u16 itumode; - u32 Capture1Length; - u32 Capture2Length; - struct SRingBufferDescriptor RingBuffer; - struct SRingBufferDescriptor TSRingBuffer; - struct SRingBufferDescriptor TSIdleBuffer; - - u32 DataFormatFlags; - - int AudioDTOUpdated; - u32 AudioDTOValue; - - int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); - u8 lnbh; - - /* stuff from analog driver */ - - int minor; - struct mychip *mychip; - struct snd_card *soundcard; - u8 *evenbuffer; - u8 dma_on; - int soundstreamon; - int audiomute; - int soundbuffisallocated; - int sndbuffflag; - int tun_rdy; - int dec_rdy; - int tun_dec_rdy; - int lastbufferflag; - - struct ngene_tvnorm *tvnorms; - int tvnorm_num; - int tvnorm; - -#ifdef NGENE_V4L - int videousers; - struct v4l2_prio_state prio; - struct ngene_vopen init; - int resources; - struct v4l2_framebuffer fbuf; - struct ngene_buffer *screen; /* overlay */ - struct list_head capture; /* video capture queue */ - spinlock_t s_lock; - struct semaphore reslock; -#endif - - int running; -}; - - -struct ngene_ci { - struct device device; - struct i2c_adapter i2c_adapter; - - struct ngene *dev; - struct dvb_ca_en50221 *en; -}; - -struct ngene; - -typedef void (rx_cb_t)(struct ngene *, u32, u8); -typedef void (tx_cb_t)(struct ngene *, u32); - -struct ngene { - int nr; - struct pci_dev *pci_dev; - unsigned char *iomem; - - /*struct i2c_adapter i2c_adapter;*/ - - u32 device_version; - u32 fw_interface_version; - u32 icounts; - bool msi_enabled; - bool cmd_timeout_workaround; - - u8 *CmdDoneByte; - int BootFirmware; - void *OverflowBuffer; - dma_addr_t PAOverflowBuffer; - void *FWInterfaceBuffer; - dma_addr_t PAFWInterfaceBuffer; - u8 *ngenetohost; - u8 *hosttongene; - - struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; - int EventQueueOverflowCount; - int EventQueueOverflowFlag; - struct tasklet_struct event_tasklet; - struct EVENT_BUFFER *EventBuffer; - int EventQueueWriteIndex; - int EventQueueReadIndex; - - wait_queue_head_t cmd_wq; - int cmd_done; - struct semaphore cmd_mutex; - struct semaphore stream_mutex; - struct semaphore pll_mutex; - struct semaphore i2c_switch_mutex; - int i2c_current_channel; - int i2c_current_bus; - spinlock_t cmd_lock; - - struct dvb_adapter adapter[MAX_STREAM]; - struct dvb_adapter *first_adapter; /* "one_adapter" modprobe opt */ - struct ngene_channel channel[MAX_STREAM]; - - struct ngene_info *card_info; - - tx_cb_t *TxEventNotify; - rx_cb_t *RxEventNotify; - int tx_busy; - wait_queue_head_t tx_wq; - wait_queue_head_t rx_wq; -#define UART_RBUF_LEN 4096 - u8 uart_rbuf[UART_RBUF_LEN]; - int uart_rp, uart_wp; - -#define TS_FILLER 0x6f - - u8 *tsout_buf; -#define TSOUT_BUF_SIZE (512*188*8) - struct dvb_ringbuffer tsout_rbuf; - - u8 *tsin_buf; -#define TSIN_BUF_SIZE (512*188*8) - struct dvb_ringbuffer tsin_rbuf; - - u8 *ain_buf; -#define AIN_BUF_SIZE (128*1024) - struct dvb_ringbuffer ain_rbuf; - - - u8 *vin_buf; -#define VIN_BUF_SIZE (4*1920*1080) - struct dvb_ringbuffer vin_rbuf; - - unsigned long exp_val; - int prev_cmd; - - struct ngene_ci ci; -}; - -struct ngene_info { - int type; -#define NGENE_APP 0 -#define NGENE_TERRATEC 1 -#define NGENE_SIDEWINDER 2 -#define NGENE_RACER 3 -#define NGENE_VIPER 4 -#define NGENE_PYTHON 5 -#define NGENE_VBOX_V1 6 -#define NGENE_VBOX_V2 7 - - int fw_version; - bool msi_supported; - char *name; - - int io_type[MAX_STREAM]; -#define NGENE_IO_NONE 0 -#define NGENE_IO_TV 1 -#define NGENE_IO_HDTV 2 -#define NGENE_IO_TSIN 4 -#define NGENE_IO_TSOUT 8 -#define NGENE_IO_AIN 16 - - void *fe_config[4]; - void *tuner_config[4]; - - int (*demod_attach[4])(struct ngene_channel *); - int (*tuner_attach[4])(struct ngene_channel *); - - u8 avf[4]; - u8 msp[4]; - u8 demoda[4]; - u8 lnb[4]; - int i2c_access; - u8 ntsc; - u8 tsf[4]; - u8 i2s[4]; - - int (*gate_ctrl)(struct dvb_frontend *, int); - int (*switch_ctrl)(struct ngene_channel *, int, int); -}; - -#ifdef NGENE_V4L -struct ngene_format { - char *name; - int fourcc; /* video4linux 2 */ - int btformat; /* BT848_COLOR_FMT_* */ - int format; - int btswap; /* BT848_COLOR_CTL_* */ - int depth; /* bit/pixel */ - int flags; - int hshift, vshift; /* for planar modes */ - int palette; -}; - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -struct ngene_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* ngene specific */ - const struct ngene_format *fmt; - int tvnorm; - int btformat; - int btswap; -}; -#endif - - -/* Provided by ngene-core.c */ -int __devinit ngene_probe(struct pci_dev *pci_dev, - const struct pci_device_id *id); -void __devexit ngene_remove(struct pci_dev *pdev); -void ngene_shutdown(struct pci_dev *pdev); -int ngene_command(struct ngene *dev, struct ngene_command *com); -int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); -void set_transfer(struct ngene_channel *chan, int state); -void FillTSBuffer(void *Buffer, int Length, u32 Flags); - -/* Provided by ngene-i2c.c */ -int ngene_i2c_init(struct ngene *dev, int dev_nr); - -/* Provided by ngene-dvb.c */ -extern struct dvb_device ngene_dvbdev_ci; -void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); -void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); -int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed); -int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv); -int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter); - -#endif - -/* LocalWords: Endif - */ diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig deleted file mode 100644 index 7d8e6e87bdb..00000000000 --- a/drivers/media/dvb/pluto2/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config DVB_PLUTO2 - tristate "Pluto2 cards" - depends on DVB_CORE && PCI && I2C - select I2C_ALGOBIT - select DVB_TDA1004X - help - Support for PCI cards based on the Pluto2 FPGA like the Satelco - Easywatch Mobile Terrestrial DVB-T Receiver. - - 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/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile deleted file mode 100644 index 524bf841f42..00000000000 --- a/drivers/media/dvb/pluto2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_PLUTO2) += pluto2.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c deleted file mode 100644 index f148b19a206..00000000000 --- a/drivers/media/dvb/pluto2/pluto2.c +++ /dev/null @@ -1,815 +0,0 @@ -/* - * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] - * - * Copyright (C) 2005 Andreas Oberritter - * - * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ - * by Dany Salman - * Copyright (c) 2004 TDF - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" -#include "tda1004x.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define DRIVER_NAME "pluto2" - -#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ -#define REG_PCAR 0x0020 /* PC address register */ -#define REG_TSCR 0x0024 /* TS ctrl & status */ -#define REG_MISC 0x0028 /* miscellaneous */ -#define REG_MMAC 0x002c /* MSB MAC address */ -#define REG_IMAC 0x0030 /* ISB MAC address */ -#define REG_LMAC 0x0034 /* LSB MAC address */ -#define REG_SPID 0x0038 /* SPI data */ -#define REG_SLCS 0x003c /* serial links ctrl/status */ - -#define PID0_NOFIL (0x0001 << 16) -#define PIDn_ENP (0x0001 << 15) -#define PID0_END (0x0001 << 14) -#define PID0_AFIL (0x0001 << 13) -#define PIDn_PID (0x1fff << 0) - -#define TSCR_NBPACKETS (0x00ff << 24) -#define TSCR_DEM (0x0001 << 17) -#define TSCR_DE (0x0001 << 16) -#define TSCR_RSTN (0x0001 << 15) -#define TSCR_MSKO (0x0001 << 14) -#define TSCR_MSKA (0x0001 << 13) -#define TSCR_MSKL (0x0001 << 12) -#define TSCR_OVR (0x0001 << 11) -#define TSCR_AFUL (0x0001 << 10) -#define TSCR_LOCK (0x0001 << 9) -#define TSCR_IACK (0x0001 << 8) -#define TSCR_ADEF (0x007f << 0) - -#define MISC_DVR (0x0fff << 4) -#define MISC_ALED (0x0001 << 3) -#define MISC_FRST (0x0001 << 2) -#define MISC_LED1 (0x0001 << 1) -#define MISC_LED0 (0x0001 << 0) - -#define SPID_SPIDR (0x00ff << 0) - -#define SLCS_SCL (0x0001 << 7) -#define SLCS_SDA (0x0001 << 6) -#define SLCS_CSN (0x0001 << 2) -#define SLCS_OVR (0x0001 << 1) -#define SLCS_SWC (0x0001 << 0) - -#define TS_DMA_PACKETS (8) -#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) - -#define I2C_ADDR_TDA10046 0x10 -#define I2C_ADDR_TUA6034 0xc2 -#define NHWFILTERS 8 - -struct pluto { - /* pci */ - struct pci_dev *pdev; - u8 __iomem *io_mem; - - /* dvb */ - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct dmxdev dmxdev; - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - unsigned int full_ts_users; - unsigned int users; - - /* i2c */ - struct i2c_algo_bit_data i2c_bit; - struct i2c_adapter i2c_adap; - unsigned int i2cbug; - - /* irq */ - unsigned int overflow; - unsigned int dead; - - /* dma */ - dma_addr_t dma_addr; - u8 dma_buf[TS_DMA_BYTES]; - u8 dummy[4096]; -}; - -static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) -{ - return container_of(feed->demux, struct pluto, demux); -} - -static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) -{ - return container_of(fe->dvb, struct pluto, dvb_adapter); -} - -static inline u32 pluto_readreg(struct pluto *pluto, u32 reg) -{ - return readl(&pluto->io_mem[reg]); -} - -static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) -{ - writel(val, &pluto->io_mem[reg]); -} - -static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) -{ - u32 val = readl(&pluto->io_mem[reg]); - val &= ~mask; - val |= bits; - writel(val, &pluto->io_mem[reg]); -} - -static void pluto_write_tscr(struct pluto *pluto, u32 val) -{ - /* set the number of packets */ - val &= ~TSCR_ADEF; - val |= TS_DMA_PACKETS / 2; - - pluto_writereg(pluto, REG_TSCR, val); -} - -static void pluto_setsda(void *data, int state) -{ - struct pluto *pluto = data; - - if (state) - pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); - else - pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); -} - -static void pluto_setscl(void *data, int state) -{ - struct pluto *pluto = data; - - if (state) - pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); - else - pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); - - /* try to detect i2c_inb() to workaround hardware bug: - * reset SDA to high after SCL has been set to low */ - if ((state) && (pluto->i2cbug == 0)) { - pluto->i2cbug = 1; - } else { - if ((!state) && (pluto->i2cbug == 1)) - pluto_setsda(pluto, 1); - pluto->i2cbug = 0; - } -} - -static int pluto_getsda(void *data) -{ - struct pluto *pluto = data; - - return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; -} - -static int pluto_getscl(void *data) -{ - struct pluto *pluto = data; - - return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; -} - -static void pluto_reset_frontend(struct pluto *pluto, int reenable) -{ - u32 val = pluto_readreg(pluto, REG_MISC); - - if (val & MISC_FRST) { - val &= ~MISC_FRST; - pluto_writereg(pluto, REG_MISC, val); - } - if (reenable) { - val |= MISC_FRST; - pluto_writereg(pluto, REG_MISC, val); - } -} - -static void pluto_reset_ts(struct pluto *pluto, int reenable) -{ - u32 val = pluto_readreg(pluto, REG_TSCR); - - if (val & TSCR_RSTN) { - val &= ~TSCR_RSTN; - pluto_write_tscr(pluto, val); - } - if (reenable) { - val |= TSCR_RSTN; - pluto_write_tscr(pluto, val); - } -} - -static void pluto_set_dma_addr(struct pluto *pluto) -{ - pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); -} - -static int __devinit pluto_dma_map(struct pluto *pluto) -{ - pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); - - return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); -} - -static void pluto_dma_unmap(struct pluto *pluto) -{ - pci_unmap_single(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); -} - -static int pluto_start_feed(struct dvb_demux_feed *f) -{ - struct pluto *pluto = feed_to_pluto(f); - - /* enable PID filtering */ - if (pluto->users++ == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); - - if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) - pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); - else if (pluto->full_ts_users++ == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); - - return 0; -} - -static int pluto_stop_feed(struct dvb_demux_feed *f) -{ - struct pluto *pluto = feed_to_pluto(f); - - /* disable PID filtering */ - if (--pluto->users == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); - - if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) - pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); - else if (--pluto->full_ts_users == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); - - return 0; -} - -static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) -{ - /* synchronize the DMA transfer with the CPU - * first so that we see updated contents. */ - pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); - - /* Workaround for broken hardware: - * [1] On startup NBPACKETS seems to contain an uninitialized value, - * but no packets have been transferred. - * [2] Sometimes (actually very often) NBPACKETS stays at zero - * although one packet has been transferred. - * [3] Sometimes (actually rarely), the card gets into an erroneous - * mode where it continuously generates interrupts, claiming it - * has received nbpackets>TS_DMA_PACKETS packets, but no packet - * has been transferred. Only a reset seems to solve this - */ - if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { - unsigned int i = 0; - while (pluto->dma_buf[i] == 0x47) - i += 188; - nbpackets = i / 188; - if (i == 0) { - pluto_reset_ts(pluto, 1); - dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n"); - } - } - - dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); - - /* clear the dma buffer. this is needed to be able to identify - * new valid ts packets above */ - memset(pluto->dma_buf, 0, nbpackets * 188); - - /* reset the dma address */ - pluto_set_dma_addr(pluto); - - /* sync the buffer and give it back to the card */ - pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); -} - -static irqreturn_t pluto_irq(int irq, void *dev_id) -{ - struct pluto *pluto = dev_id; - u32 tscr; - - /* check whether an interrupt occurred on this device */ - tscr = pluto_readreg(pluto, REG_TSCR); - if (!(tscr & (TSCR_DE | TSCR_OVR))) - return IRQ_NONE; - - if (tscr == 0xffffffff) { - if (pluto->dead == 0) - dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n"); - /* It's dead Jim */ - pluto->dead = 1; - return IRQ_HANDLED; - } - - /* dma end interrupt */ - if (tscr & TSCR_DE) { - pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); - /* overflow interrupt */ - if (tscr & TSCR_OVR) - pluto->overflow++; - if (pluto->overflow) { - dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", - pluto->overflow); - pluto_reset_ts(pluto, 1); - pluto->overflow = 0; - } - } else if (tscr & TSCR_OVR) { - pluto->overflow++; - } - - /* ACK the interrupt */ - pluto_write_tscr(pluto, tscr | TSCR_IACK); - - return IRQ_HANDLED; -} - -static void __devinit pluto_enable_irqs(struct pluto *pluto) -{ - u32 val = pluto_readreg(pluto, REG_TSCR); - - /* disable AFUL and LOCK interrupts */ - val |= (TSCR_MSKA | TSCR_MSKL); - /* enable DMA and OVERFLOW interrupts */ - val &= ~(TSCR_DEM | TSCR_MSKO); - /* clear pending interrupts */ - val |= TSCR_IACK; - - pluto_write_tscr(pluto, val); -} - -static void pluto_disable_irqs(struct pluto *pluto) -{ - u32 val = pluto_readreg(pluto, REG_TSCR); - - /* disable all interrupts */ - val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); - /* clear pending interrupts */ - val |= TSCR_IACK; - - pluto_write_tscr(pluto, val); -} - -static int __devinit pluto_hw_init(struct pluto *pluto) -{ - pluto_reset_frontend(pluto, 1); - - /* set automatic LED control by FPGA */ - pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); - - /* set data endianess */ -#ifdef __LITTLE_ENDIAN - pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); -#else - pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); -#endif - /* map DMA and set address */ - pluto_dma_map(pluto); - pluto_set_dma_addr(pluto); - - /* enable interrupts */ - pluto_enable_irqs(pluto); - - /* reset TS logic */ - pluto_reset_ts(pluto, 1); - - return 0; -} - -static void pluto_hw_exit(struct pluto *pluto) -{ - /* disable interrupts */ - pluto_disable_irqs(pluto); - - pluto_reset_ts(pluto, 0); - - /* LED: disable automatic control, enable yellow, disable green */ - pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); - - /* unmap DMA */ - pluto_dma_unmap(pluto); - - pluto_reset_frontend(pluto, 0); -} - -static inline u32 divide(u32 numerator, u32 denominator) -{ - if (denominator == 0) - return ~0; - - return DIV_ROUND_CLOSEST(numerator, denominator); -} - -/* LG Innotek TDTE-E001P (Infineon TUA6034) */ -static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct pluto *pluto = frontend_to_pluto(fe); - struct i2c_msg msg; - int ret; - u8 buf[4]; - u32 div; - - // Fref = 166.667 Hz - // Fref * 3 = 500.000 Hz - // IF = 36166667 - // IF / Fref = 217 - //div = divide(p->frequency + 36166667, 166667); - div = divide(p->frequency * 3, 500000) + 217; - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - - if (p->frequency < 611000000) - buf[2] = 0xb4; - else if (p->frequency < 811000000) - buf[2] = 0xbc; - else - buf[2] = 0xf4; - - // VHF: 174-230 MHz - // center: 350 MHz - // UHF: 470-862 MHz - if (p->frequency < 350000000) - buf[3] = 0x02; - else - buf[3] = 0x04; - - if (p->bandwidth_hz == 8000000) - buf[3] |= 0x08; - - msg.addr = I2C_ADDR_TUA6034 >> 1; - msg.flags = 0; - msg.buf = buf; - msg.len = sizeof(buf); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); - if (ret < 0) - return ret; - else if (ret == 0) - return -EREMOTEIO; - - return 0; -} - -static int pluto2_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct pluto *pluto = frontend_to_pluto(fe); - - return request_firmware(fw, name, &pluto->pdev->dev); -} - -static struct tda1004x_config pluto2_fe_config __devinitdata = { - .demod_address = I2C_ADDR_TDA10046 >> 1, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = pluto2_request_firmware, -}; - -static int __devinit frontend_init(struct pluto *pluto) -{ - int ret; - - pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); - if (!pluto->fe) { - dev_err(&pluto->pdev->dev, "could not attach frontend\n"); - return -ENODEV; - } - pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; - - ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); - if (ret < 0) { - if (pluto->fe->ops.release) - pluto->fe->ops.release(pluto->fe); - return ret; - } - - return 0; -} - -static void __devinit pluto_read_rev(struct pluto *pluto) -{ - u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; - dev_info(&pluto->pdev->dev, "board revision %d.%d\n", - (val >> 12) & 0x0f, (val >> 4) & 0xff); -} - -static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) -{ - u32 val = pluto_readreg(pluto, REG_MMAC); - mac[0] = (val >> 8) & 0xff; - mac[1] = (val >> 0) & 0xff; - - val = pluto_readreg(pluto, REG_IMAC); - mac[2] = (val >> 8) & 0xff; - mac[3] = (val >> 0) & 0xff; - - val = pluto_readreg(pluto, REG_LMAC); - mac[4] = (val >> 8) & 0xff; - mac[5] = (val >> 0) & 0xff; - - dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); -} - -static int __devinit pluto_read_serial(struct pluto *pluto) -{ - struct pci_dev *pdev = pluto->pdev; - unsigned int i, j; - u8 __iomem *cis; - - cis = pci_iomap(pdev, 1, 0); - if (!cis) - return -EIO; - - dev_info(&pdev->dev, "S/N "); - - for (i = 0xe0; i < 0x100; i += 4) { - u32 val = readl(&cis[i]); - for (j = 0; j < 32; j += 8) { - if ((val & 0xff) == 0xff) - goto out; - printk("%c", val & 0xff); - val >>= 8; - } - } -out: - printk("\n"); - pci_iounmap(pdev, cis); - - return 0; -} - -static int __devinit pluto2_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct pluto *pluto; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret = -ENOMEM; - - pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); - if (!pluto) - goto out; - - pluto->pdev = pdev; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_kfree; - - /* enable interrupts */ - pci_write_config_dword(pdev, 0x6c, 0x8000); - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - 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; - - pluto->io_mem = pci_iomap(pdev, 0, 0x40); - if (!pluto->io_mem) { - ret = -EIO; - goto err_pci_release_regions; - } - - pci_set_drvdata(pdev, pluto); - - ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto); - if (ret < 0) - goto err_pci_iounmap; - - ret = pluto_hw_init(pluto); - if (ret < 0) - goto err_free_irq; - - /* i2c */ - i2c_set_adapdata(&pluto->i2c_adap, pluto); - strcpy(pluto->i2c_adap.name, DRIVER_NAME); - pluto->i2c_adap.owner = THIS_MODULE; - pluto->i2c_adap.dev.parent = &pdev->dev; - pluto->i2c_adap.algo_data = &pluto->i2c_bit; - pluto->i2c_bit.data = pluto; - pluto->i2c_bit.setsda = pluto_setsda; - pluto->i2c_bit.setscl = pluto_setscl; - pluto->i2c_bit.getsda = pluto_getsda; - pluto->i2c_bit.getscl = pluto_getscl; - pluto->i2c_bit.udelay = 10; - pluto->i2c_bit.timeout = 10; - - /* Raise SCL and SDA */ - pluto_setsda(pluto, 1); - pluto_setscl(pluto, 1); - - ret = i2c_bit_add_bus(&pluto->i2c_adap); - if (ret < 0) - goto err_pluto_hw_exit; - - /* dvb */ - ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, - THIS_MODULE, &pdev->dev, adapter_nr); - if (ret < 0) - goto err_i2c_del_adapter; - - dvb_adapter = &pluto->dvb_adapter; - - pluto_read_rev(pluto); - pluto_read_serial(pluto); - pluto_read_mac(pluto, dvb_adapter->proposed_mac); - - dvbdemux = &pluto->demux; - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = pluto_start_feed; - dvbdemux->stop_feed = pluto_stop_feed; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto err_dvb_unregister_adapter; - - dmx = &dvbdemux->dmx; - - pluto->hw_frontend.source = DMX_FRONTEND_0; - pluto->mem_frontend.source = DMX_MEMORY_FE; - pluto->dmxdev.filternum = NHWFILTERS; - pluto->dmxdev.demux = dmx; - - ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); - if (ret < 0) - goto err_dvb_dmx_release; - - ret = dmx->add_frontend(dmx, &pluto->hw_frontend); - if (ret < 0) - goto err_dvb_dmxdev_release; - - ret = dmx->add_frontend(dmx, &pluto->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - ret = frontend_init(pluto); - if (ret < 0) - goto err_disconnect_frontend; - - dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); -out: - return ret; - -err_disconnect_frontend: - dmx->disconnect_frontend(dmx); -err_remove_mem_frontend: - dmx->remove_frontend(dmx, &pluto->mem_frontend); -err_remove_hw_frontend: - dmx->remove_frontend(dmx, &pluto->hw_frontend); -err_dvb_dmxdev_release: - dvb_dmxdev_release(&pluto->dmxdev); -err_dvb_dmx_release: - dvb_dmx_release(dvbdemux); -err_dvb_unregister_adapter: - dvb_unregister_adapter(dvb_adapter); -err_i2c_del_adapter: - i2c_del_adapter(&pluto->i2c_adap); -err_pluto_hw_exit: - pluto_hw_exit(pluto); -err_free_irq: - free_irq(pdev->irq, pluto); -err_pci_iounmap: - pci_iounmap(pdev, pluto->io_mem); -err_pci_release_regions: - pci_release_regions(pdev); -err_pci_disable_device: - pci_disable_device(pdev); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(pluto); - goto out; -} - -static void __devexit pluto2_remove(struct pci_dev *pdev) -{ - struct pluto *pluto = pci_get_drvdata(pdev); - struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; - struct dvb_demux *dvbdemux = &pluto->demux; - struct dmx_demux *dmx = &dvbdemux->dmx; - - dmx->close(dmx); - dvb_net_release(&pluto->dvbnet); - if (pluto->fe) - dvb_unregister_frontend(pluto->fe); - - dmx->disconnect_frontend(dmx); - dmx->remove_frontend(dmx, &pluto->mem_frontend); - dmx->remove_frontend(dmx, &pluto->hw_frontend); - dvb_dmxdev_release(&pluto->dmxdev); - dvb_dmx_release(dvbdemux); - dvb_unregister_adapter(dvb_adapter); - i2c_del_adapter(&pluto->i2c_adap); - pluto_hw_exit(pluto); - free_irq(pdev->irq, pluto); - pci_iounmap(pdev, pluto->io_mem); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - kfree(pluto); -} - -#ifndef PCI_VENDOR_ID_SCM -#define PCI_VENDOR_ID_SCM 0x0432 -#endif -#ifndef PCI_DEVICE_ID_PLUTO2 -#define PCI_DEVICE_ID_PLUTO2 0x0001 -#endif - -static struct pci_device_id pluto2_id_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_SCM, - .device = PCI_DEVICE_ID_PLUTO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* empty */ - }, -}; - -MODULE_DEVICE_TABLE(pci, pluto2_id_table); - -static struct pci_driver pluto2_driver = { - .name = DRIVER_NAME, - .id_table = pluto2_id_table, - .probe = pluto2_probe, - .remove = __devexit_p(pluto2_remove), -}; - -static int __init pluto2_init(void) -{ - return pci_register_driver(&pluto2_driver); -} - -static void __exit pluto2_exit(void) -{ - pci_unregister_driver(&pluto2_driver); -} - -module_init(pluto2_init); -module_exit(pluto2_exit); - -MODULE_AUTHOR("Andreas Oberritter "); -MODULE_DESCRIPTION("Pluto2 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/pt1/Kconfig b/drivers/media/dvb/pt1/Kconfig deleted file mode 100644 index 24501d5bf70..00000000000 --- a/drivers/media/dvb/pt1/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -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/drivers/media/dvb/pt1/Makefile b/drivers/media/dvb/pt1/Makefile deleted file mode 100644 index 98e391295af..00000000000 --- a/drivers/media/dvb/pt1/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o - -obj-$(CONFIG_DVB_PT1) += earth-pt1.o - -ccflags-y += -Idrivers/media/dvb-core -Idrivers/media/dvb-frontends diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c deleted file mode 100644 index 15b35c4725f..00000000000 --- a/drivers/media/dvb/pt1/pt1.c +++ /dev/null @@ -1,1246 +0,0 @@ -/* - * driver for Earthsoft PT1/PT2 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#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; - int table_index; - int buf_index; - - struct mutex lock; - int power; - int reset; -}; - -struct pt1_adapter { - struct pt1 *pt1; - int index; - - u8 *buf; - int upacket_count; - int packet_count; - int st_count; - - struct dvb_adapter adap; - struct dvb_demux demux; - int users; - struct dmxdev dmxdev; - struct dvb_frontend *fe; - int (*orig_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); - int (*orig_sleep)(struct dvb_frontend *fe); - int (*orig_init)(struct dvb_frontend *fe); - - fe_sec_voltage_t voltage; - int sleep; -}; - -#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 = 8; -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; - int phase; - schedule_timeout_uninterruptible((HZ + 999) / 1000); - phase = pt1->pdev->device == 0x211a ? 128 : 166; - for (i = 0; i < phase; 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; - int sc; - - 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; - - if (upacket >> 24 & 1) - printk_ratelimited(KERN_INFO "earth-pt1: device " - "buffer overflowing. table[%d] buf[%d]\n", - pt1->table_index, pt1->buf_index); - sc = upacket >> 26 & 0x7; - if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) - printk_ratelimited(KERN_INFO "earth-pt1: data loss" - " in streamID(adapter)[%d]\n", index); - adap->st_count = sc; - - 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; - struct pt1_buffer_page *page; - - pt1 = data; - set_freezable(); - - while (!kthread_should_stop()) { - try_to_freeze(); - - page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; - if (!pt1_filter(pt1, page)) { - schedule_timeout_interruptible((HZ + 999) / 1000); - continue; - } - - if (++pt1->buf_index >= PT1_NR_BUFS) { - pt1_increment_table_count(pt1); - pt1->buf_index = 0; - if (++pt1->table_index >= pt1_nr_tables) - pt1->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_polling(struct pt1 *pt1) -{ - int ret = 0; - - mutex_lock(&pt1->lock); - if (!pt1->kthread) { - pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); - if (IS_ERR(pt1->kthread)) { - ret = PTR_ERR(pt1->kthread); - pt1->kthread = NULL; - } - } - mutex_unlock(&pt1->lock); - 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++) { - int ret; - - ret = pt1_start_polling(adap->pt1); - if (ret) - return ret; - pt1_set_stream(adap->pt1, adap->index, 1); - } - return 0; -} - -static void pt1_stop_polling(struct pt1 *pt1) -{ - int i, count; - - mutex_lock(&pt1->lock); - for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) - count += pt1->adaps[i]->users; - - if (count == 0 && pt1->kthread) { - kthread_stop(pt1->kthread); - pt1->kthread = NULL; - } - mutex_unlock(&pt1->lock); -} - -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); - pt1_stop_polling(adap->pt1); - } - return 0; -} - -static void -pt1_update_power(struct pt1 *pt1) -{ - int bits; - int i; - struct pt1_adapter *adap; - static const int sleep_bits[] = { - 1 << 4, - 1 << 6 | 1 << 7, - 1 << 5, - 1 << 6 | 1 << 8, - }; - - bits = pt1->power | !pt1->reset << 3; - mutex_lock(&pt1->lock); - for (i = 0; i < PT1_NR_ADAPS; i++) { - adap = pt1->adaps[i]; - switch (adap->voltage) { - case SEC_VOLTAGE_13: /* actually 11V */ - bits |= 1 << 1; - break; - case SEC_VOLTAGE_18: /* actually 15V */ - bits |= 1 << 1 | 1 << 2; - break; - default: - break; - } - - /* XXX: The bits should be changed depending on adap->sleep. */ - bits |= sleep_bits[i]; - } - pt1_write_reg(pt1, 1, bits); - mutex_unlock(&pt1->lock); -} - -static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct pt1_adapter *adap; - - adap = container_of(fe->dvb, struct pt1_adapter, adap); - adap->voltage = voltage; - pt1_update_power(adap->pt1); - - if (adap->orig_set_voltage) - return adap->orig_set_voltage(fe, voltage); - else - return 0; -} - -static int pt1_sleep(struct dvb_frontend *fe) -{ - struct pt1_adapter *adap; - - adap = container_of(fe->dvb, struct pt1_adapter, adap); - adap->sleep = 1; - pt1_update_power(adap->pt1); - - if (adap->orig_sleep) - return adap->orig_sleep(fe); - else - return 0; -} - -static int pt1_wakeup(struct dvb_frontend *fe) -{ - struct pt1_adapter *adap; - - adap = container_of(fe->dvb, struct pt1_adapter, adap); - adap->sleep = 0; - pt1_update_power(adap->pt1); - schedule_timeout_uninterruptible((HZ + 999) / 1000); - - if (adap->orig_init) - return adap->orig_init(fe); - else - return 0; -} - -static void pt1_free_adapter(struct pt1_adapter *adap) -{ - 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 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->voltage = SEC_VOLTAGE_OFF; - adap->sleep = 1; - - 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; - adap->st_count = -1; - - 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; - - return adap; - -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]); -} - -static int pt1_init_adapters(struct pt1 *pt1) -{ - int i; - struct pt1_adapter *adap; - int ret; - - for (i = 0; i < PT1_NR_ADAPS; i++) { - adap = pt1_alloc_adapter(pt1); - if (IS_ERR(adap)) { - ret = PTR_ERR(adap); - goto err; - } - - adap->index = i; - pt1->adaps[i] = adap; - } - return 0; - -err: - while (i--) - pt1_free_adapter(pt1->adaps[i]); - - return ret; -} - -static void pt1_cleanup_frontend(struct pt1_adapter *adap) -{ - dvb_unregister_frontend(adap->fe); -} - -static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) -{ - int ret; - - adap->orig_set_voltage = fe->ops.set_voltage; - adap->orig_sleep = fe->ops.sleep; - adap->orig_init = fe->ops.init; - fe->ops.set_voltage = pt1_set_voltage; - fe->ops.sleep = pt1_sleep; - fe->ops.init = pt1_wakeup; - - ret = dvb_register_frontend(&adap->adap, fe); - if (ret < 0) - return ret; - - adap->fe = fe; - return 0; -} - -static void pt1_cleanup_frontends(struct pt1 *pt1) -{ - int i; - for (i = 0; i < PT1_NR_ADAPS; i++) - pt1_cleanup_frontend(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, - .frequency = VA1J5JF8007S_20MHZ, - }, - { - .demod_address = 0x1a, - .frequency = VA1J5JF8007T_20MHZ, - }, - }, { - { - .demod_address = 0x19, - .frequency = VA1J5JF8007S_20MHZ, - }, - { - .demod_address = 0x18, - .frequency = VA1J5JF8007T_20MHZ, - }, - }, -}; - -static const struct pt1_config pt2_configs[2] = { - { - { - .demod_address = 0x1b, - .frequency = VA1J5JF8007S_25MHZ, - }, - { - .demod_address = 0x1a, - .frequency = VA1J5JF8007T_25MHZ, - }, - }, { - { - .demod_address = 0x19, - .frequency = VA1J5JF8007S_25MHZ, - }, - { - .demod_address = 0x18, - .frequency = VA1J5JF8007T_25MHZ, - }, - }, -}; - -static int pt1_init_frontends(struct pt1 *pt1) -{ - int i, j; - struct i2c_adapter *i2c_adap; - const struct pt1_config *configs, *config; - struct dvb_frontend *fe[4]; - int ret; - - i = 0; - j = 0; - - i2c_adap = &pt1->i2c_adap; - configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs; - do { - config = &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 { - ret = pt1_init_frontend(pt1->adaps[j], fe[j]); - if (ret < 0) - goto err; - } while (++j < 4); - - return 0; - -err: - while (i-- > j) - fe[i]->ops.release(fe[i]); - - while (j--) - dvb_unregister_frontend(fe[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; - - if (pt1->kthread) - kthread_stop(pt1->kthread); - pt1_cleanup_tables(pt1); - pt1_cleanup_frontends(pt1); - pt1_disable_ram(pt1); - pt1->power = 0; - pt1->reset = 1; - pt1_update_power(pt1); - pt1_cleanup_adapters(pt1); - 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; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err; - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - 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; - } - - mutex_init(&pt1->lock); - pt1->pdev = pdev; - pt1->regs = regs; - pci_set_drvdata(pdev, pt1); - - ret = pt1_init_adapters(pt1); - if (ret < 0) - goto err_kfree; - - mutex_init(&pt1->lock); - - pt1->power = 0; - pt1->reset = 1; - pt1_update_power(pt1); - - i2c_adap = &pt1->i2c_adap; - i2c_adap->algo = &pt1_i2c_algo; - i2c_adap->algo_data = NULL; - i2c_adap->dev.parent = &pdev->dev; - strcpy(i2c_adap->name, DRIVER_NAME); - i2c_set_adapdata(i2c_adap, pt1); - ret = i2c_add_adapter(i2c_adap); - if (ret < 0) - goto err_pt1_cleanup_adapters; - - 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->power = 1; - pt1_update_power(pt1); - schedule_timeout_uninterruptible((HZ + 49) / 50); - - pt1->reset = 0; - pt1_update_power(pt1); - schedule_timeout_uninterruptible((HZ + 999) / 1000); - - ret = pt1_init_frontends(pt1); - if (ret < 0) - goto err_pt1_disable_ram; - - ret = pt1_init_tables(pt1); - if (ret < 0) - goto err_pt1_cleanup_frontends; - - return 0; - -err_pt1_cleanup_frontends: - pt1_cleanup_frontends(pt1); -err_pt1_disable_ram: - pt1_disable_ram(pt1); - pt1->power = 0; - pt1->reset = 1; - pt1_update_power(pt1); -err_i2c_del_adapter: - i2c_del_adapter(i2c_adap); -err_pt1_cleanup_adapters: - pt1_cleanup_adapters(pt1); -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) }, - { PCI_DEVICE(0x10ee, 0x222a) }, - { }, -}; -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 "); -MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c deleted file mode 100644 index d980dfb21e5..00000000000 --- a/drivers/media/dvb/pt1/va1j5jf8007s.c +++ /dev/null @@ -1,735 +0,0 @@ -/* - * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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 -#include -#include -#include -#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_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct va1j5jf8007s_state *state; - u8 addr; - int i; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - s32 word, x1, x2, x3, x4, x5, y; - - state = fe->demodulator_priv; - addr = state->config->demod_address; - - word = 0; - for (i = 0; i < 2; i++) { - write_buf[0] = 0xbc + i; - - 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; - - word <<= 8; - word |= read_buf[0]; - } - - word -= 3000; - if (word < 0) - word = 0; - - x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000); - x2 = (s64)x1 * x1 >> 31; - x3 = (s64)x2 * x1 >> 31; - x4 = (s64)x2 * x2 >> 31; - x5 = (s64)x4 * x1 >> 31; - - y = (58857ll << 23) / 1000; - y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30; - y += (s64)x2 * ((88977ll << 24) / 1000) >> 28; - y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27; - y += (s64)x4 * ((14341ll << 27) / 1000) >> 27; - y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28; - - *snr = y < 0 ? 0 : y >> 15; - return 0; -} - -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, - bool re_tune, - unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) -{ - struct va1j5jf8007s_state *state; - int ret; - int lock = 0; - - state = fe->demodulator_priv; - - if (re_tune) - 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 = { - .delsys = { SYS_ISDBS }, - .info = { - .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", - .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, - }, - - .read_snr = va1j5jf8007s_read_snr, - .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_20mhz_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 const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = { - {0x04, 0x02}, {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, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, -}; - -static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) -{ - const u8 (*bufs)[2]; - int size; - u8 addr; - u8 buf[2]; - struct i2c_msg msg; - int i; - - switch (state->config->frequency) { - case VA1J5JF8007S_20MHZ: - bufs = va1j5jf8007s_20mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs); - break; - case VA1J5JF8007S_25MHZ: - bufs = va1j5jf8007s_25mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs); - break; - default: - return -EINVAL; - } - - addr = state->config->demod_address; - - msg.addr = addr; - msg.flags = 0; - msg.len = 2; - msg.buf = buf; - for (i = 0; i < size; i++) { - memcpy(buf, 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/drivers/media/dvb/pt1/va1j5jf8007s.h b/drivers/media/dvb/pt1/va1j5jf8007s.h deleted file mode 100644 index b7d6f05a0e0..00000000000 --- a/drivers/media/dvb/pt1/va1j5jf8007s.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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 - -enum va1j5jf8007s_frequency { - VA1J5JF8007S_20MHZ, - VA1J5JF8007S_25MHZ, -}; - -struct va1j5jf8007s_config { - u8 demod_address; - enum va1j5jf8007s_frequency frequency; -}; - -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/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c deleted file mode 100644 index 2db15159d51..00000000000 --- a/drivers/media/dvb/pt1/va1j5jf8007t.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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 -#include -#include -#include -#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_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct va1j5jf8007t_state *state; - u8 addr; - int i; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - s32 word, x, y; - - state = fe->demodulator_priv; - addr = state->config->demod_address; - - word = 0; - for (i = 0; i < 3; i++) { - write_buf[0] = 0x8b + i; - - 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; - - word <<= 8; - word |= read_buf[0]; - } - - if (!word) - return -EIO; - - x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24)); - y = (24ll << 46) / 1000000; - y = ((s64)y * x >> 30) - (16ll << 40) / 10000; - y = ((s64)y * x >> 29) + (398ll << 35) / 10000; - y = ((s64)y * x >> 30) + (5491ll << 29) / 10000; - y = ((s64)y * x >> 30) + (30965ll << 23) / 10000; - *snr = y >> 15; - return 0; -} - -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, - bool re_tune, - unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) -{ - struct va1j5jf8007t_state *state; - int ret; - int lock = 0, retry = 0; - - state = fe->demodulator_priv; - - if (re_tune) - 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 = { - .delsys = { SYS_ISDBT }, - .info = { - .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", - .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, - }, - - .read_snr = va1j5jf8007t_read_snr, - .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_20mhz_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} -}; - -static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = { - {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, - {0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c}, - {0x77, 0x03}, {0xef, 0x01} -}; - -int va1j5jf8007t_prepare(struct dvb_frontend *fe) -{ - struct va1j5jf8007t_state *state; - const u8 (*bufs)[2]; - int size; - u8 buf[2]; - struct i2c_msg msg; - int i; - - state = fe->demodulator_priv; - - switch (state->config->frequency) { - case VA1J5JF8007T_20MHZ: - bufs = va1j5jf8007t_20mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs); - break; - case VA1J5JF8007T_25MHZ: - bufs = va1j5jf8007t_25mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs); - break; - default: - return -EINVAL; - } - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - for (i = 0; i < size; i++) { - memcpy(buf, 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/drivers/media/dvb/pt1/va1j5jf8007t.h b/drivers/media/dvb/pt1/va1j5jf8007t.h deleted file mode 100644 index 2903be519ef..00000000000 --- a/drivers/media/dvb/pt1/va1j5jf8007t.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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 - -enum va1j5jf8007t_frequency { - VA1J5JF8007T_20MHZ, - VA1J5JF8007T_25MHZ, -}; - -struct va1j5jf8007t_config { - u8 demod_address; - enum va1j5jf8007t_frequency frequency; -}; - -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/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig deleted file mode 100644 index 9d83ced69dd..00000000000 --- a/drivers/media/dvb/ttpci/Kconfig +++ /dev/null @@ -1,159 +0,0 @@ -config TTPCI_EEPROM - tristate - depends on I2C - default n - -config DVB_AV7110 - tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C - select TTPCI_EEPROM - select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_SP8870 if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_L64781 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - help - Support for SAA7146 and AV7110 based DVB cards as produced - by Fujitsu-Siemens, Technotrend, Hauppauge and others. - - This driver only supports the fullfeatured cards with - onboard MPEG2 decoder. - - This driver needs an external firmware. Please use the script - "/Documentation/dvb/get_dvb_firmware av7110" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - - Alternatively, you can download the file and use the kernel's - EXTRA_FIRMWARE configuration option to build it into your - kernel image by adding the filename to the EXTRA_FIRMWARE - configuration option string. - - Say Y if you own such a card and want to use it. - -config DVB_AV7110_OSD - bool "AV7110 OSD support" - depends on DVB_AV7110 - default y if DVB_AV7110=y || DVB_AV7110=m - help - The AV7110 firmware provides some code to generate an OnScreenDisplay - on the video output. This is kind of nonstandard and not guaranteed to - be maintained. - - Anyway, some popular DVB software like VDR uses this OSD to render - its menus, so say Y if you want to use this software. - - All other people say N. - -config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" - depends on DVB_CORE && PCI && I2C - select VIDEO_SAA7146 - select TTPCI_EEPROM - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. - -config DVB_BUDGET - tristate "Budget cards" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_L64781 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_S5H1420 if !DVB_FE_CUSTOMISE - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_ISL6423 if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - help - Support for simple SAA7146 based DVB cards (so called Budget- - or Nova-PCI cards) without onboard MPEG2 decoder, and without - analog inputs or an onboard Common Interface connector. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget. - -config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - depends on RC_CORE - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with onboard Common Interface connector. - - Note: The Common Interface is not yet supported by this driver - due to lack of information from the vendor. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-ci. - -config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs" - depends on DVB_BUDGET_CORE && I2C - select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_TDA8261 if !DVB_FE_CUSTOMISE - select DVB_TUA6100 if !DVB_FE_CUSTOMISE - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with one or more analog video inputs. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-av. - -config DVB_BUDGET_PATCH - tristate "AV7110 cards with Budget Patch" - depends on DVB_BUDGET_CORE && I2C - depends on DVB_AV7110 - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - help - Support for Budget Patch (full TS) modification on - SAA7146+AV7110 based cards (DVB-S cards). This - driver doesn't use onboard MPEG2 decoder. The - card is driven in Budget-only mode. Card is - required to have loaded firmware to tune properly. - Firmware can be loaded by insertion and removal of - standard AV7110 driver prior to loading this - driver. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-patch. diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile deleted file mode 100644 index 22a235f3cc4..00000000000 --- a/drivers/media/dvb/ttpci/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Makefile for the kernel SAA7146 FULL TS DVB device driver -# and the AV7110 DVB device driver -# - -dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o - -ifdef CONFIG_INPUT_EVDEV -dvb-ttpci-objs += av7110_ir.o -endif - -obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o -obj-$(CONFIG_DVB_BUDGET) += budget.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c deleted file mode 100644 index 4bd8bd56bef..00000000000 --- a/drivers/media/dvb/ttpci/av7110.c +++ /dev/null @@ -1,2939 +0,0 @@ -/* - * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) - * av7110.c: initialization and demux stuff - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include - -#include "dvb_frontend.h" - -#include "ttpci-eeprom.h" -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_av.h" -#include "av7110_ca.h" -#include "av7110_ipack.h" - -#include "bsbe1.h" -#include "lnbp21.h" -#include "bsru6.h" - -#define TS_WIDTH 376 -#define TS_HEIGHT 512 -#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) -#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) - - -int av7110_debug; - -static int vidmode = CVBS_RGB_OUT; -static int pids_off; -static int adac = DVB_ADAC_TI; -static int hw_sections; -static int rgb_on; -static int volume = 255; -static int budgetpatch; -static int wss_cfg_4_3 = 0x4008; -static int wss_cfg_16_9 = 0x0007; -static int tv_standard; -static int full_ts; - -module_param_named(debug, av7110_debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); -module_param(vidmode, int, 0444); -MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC"); -module_param(pids_off, int, 0444); -MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed"); -module_param(adac, int, 0444); -MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)"); -module_param(hw_sections, int, 0444); -MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); -module_param(rgb_on, int, 0444); -MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control" - " signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); -module_param(volume, int, 0444); -MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); -module_param(budgetpatch, int, 0444); -MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); -module_param(full_ts, int, 0444); -MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); -module_param(wss_cfg_4_3, int, 0444); -MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); -module_param(wss_cfg_16_9, int, 0444); -MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); -module_param(tv_standard, int, 0444); -MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static void restart_feeds(struct av7110 *av7110); -static int budget_start_feed(struct dvb_demux_feed *feed); -static int budget_stop_feed(struct dvb_demux_feed *feed); - -static int av7110_num; - -#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ -{\ - if (fe_func != NULL) { \ - av7110_copy = fe_func; \ - fe_func = av7110_func; \ - } \ -} - - -static void init_av7110_av(struct av7110 *av7110) -{ - int ret; - struct saa7146_dev *dev = av7110->dev; - - /* set internal volume control to maximum */ - av7110->adac_type = DVB_ADAC_TI; - ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret < 0) - printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); - - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, - 1, (u16) av7110->display_ar); - if (ret < 0) - printk("dvb-ttpci: unable to set aspect ratio\n"); - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, - 1, av7110->display_panscan); - if (ret < 0) - printk("dvb-ttpci: unable to set pan scan\n"); - - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3); - if (ret < 0) - printk("dvb-ttpci: unable to configure 4:3 wss\n"); - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9); - if (ret < 0) - printk("dvb-ttpci: unable to configure 16:9 wss\n"); - - ret = av7710_set_video_mode(av7110, vidmode); - if (ret < 0) - printk("dvb-ttpci:cannot set video mode:%d\n",ret); - - /* handle different card types */ - /* remaining inits according to card and frontend type */ - av7110->analog_tuner_flags = 0; - av7110->current_input = 0; - if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on - if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { - printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_CRYSTAL; - i2c_writereg(av7110, 0x20, 0x01, 0xd2); - i2c_writereg(av7110, 0x20, 0x02, 0x49); - i2c_writereg(av7110, 0x20, 0x03, 0x00); - i2c_writereg(av7110, 0x20, 0x04, 0x00); - - /** - * some special handling for the Siemens DVB-C cards... - */ - } else if (0 == av7110_init_analog_module(av7110)) { - /* done. */ - } - else if (dev->pci->subsystem_vendor == 0x110a) { - printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_NONE; - } - else { - av7110->adac_type = adac; - printk("dvb-ttpci: adac type set to %d @ card %d\n", - av7110->adac_type, av7110->dvb_adapter.num); - } - - if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { - // switch DVB SCART on - ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); - if (ret < 0) - printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); - ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); - if (ret < 0) - printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); - if (rgb_on && - ((av7110->dev->pci->subsystem_vendor == 0x110a) || - (av7110->dev->pci->subsystem_vendor == 0x13c2)) && - (av7110->dev->pci->subsystem_device == 0x0000)) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 - //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 - } - } - - if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e) - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on - - ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret < 0) - printk("dvb-ttpci:cannot set volume :%d\n",ret); -} - -static void recover_arm(struct av7110 *av7110) -{ - dprintk(4, "%p\n",av7110); - - av7110_bootarm(av7110); - msleep(100); - - init_av7110_av(av7110); - - /* card-specific recovery */ - if (av7110->recover) - av7110->recover(av7110); - - restart_feeds(av7110); - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_check_ir_config(av7110, true); -#endif -} - -static void av7110_arm_sync(struct av7110 *av7110) -{ - if (av7110->arm_thread) - kthread_stop(av7110->arm_thread); - - av7110->arm_thread = NULL; -} - -static int arm_thread(void *data) -{ - struct av7110 *av7110 = data; - u16 newloops = 0; - int timeout; - - dprintk(4, "%p\n",av7110); - - for (;;) { - timeout = wait_event_interruptible_timeout(av7110->arm_wait, - kthread_should_stop(), 5 * HZ); - - if (-ERESTARTSYS == timeout || kthread_should_stop()) { - /* got signal or told to quit*/ - break; - } - - if (!av7110->arm_ready) - continue; - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_check_ir_config(av7110, false); -#endif - - if (mutex_lock_interruptible(&av7110->dcomlock)) - break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); - mutex_unlock(&av7110->dcomlock); - - if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { - printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", - av7110->dvb_adapter.num); - - recover_arm(av7110); - - if (mutex_lock_interruptible(&av7110->dcomlock)) - break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; - mutex_unlock(&av7110->dcomlock); - } - av7110->arm_loops = newloops; - av7110->arm_errors = 0; - } - - return 0; -} - - -/**************************************************************************** - * IRQ handling - ****************************************************************************/ - -static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, - u8 *buffer2, size_t buffer2_len, - struct dvb_demux_filter *dvbdmxfilter, - enum dmx_success success, - struct av7110 *av7110) -{ - if (!dvbdmxfilter->feed->demux->dmx.frontend) - return 0; - if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE) - return 0; - - switch (dvbdmxfilter->type) { - case DMX_TYPE_SEC: - if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len) - return 0; - if (dvbdmxfilter->doneq) { - struct dmx_section_filter *filter = &dvbdmxfilter->filter; - int i; - u8 xor, neq = 0; - - for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { - xor = filter->filter_value[i] ^ buffer1[i]; - neq |= dvbdmxfilter->maskandnotmode[i] & xor; - } - if (!neq) - return 0; - } - return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, - buffer2, buffer2_len, - &dvbdmxfilter->filter, - DMX_OK); - case DMX_TYPE_TS: - if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) - return 0; - if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) - return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, - buffer2, buffer2_len, - &dvbdmxfilter->feed->feed.ts, - DMX_OK); - else - av7110_p2t_write(buffer1, buffer1_len, - dvbdmxfilter->feed->pid, - &av7110->p2t_filter[dvbdmxfilter->index]); - default: - return 0; - } -} - - -//#define DEBUG_TIMING -static inline void print_time(char *s) -{ -#ifdef DEBUG_TIMING - struct timeval tv; - do_gettimeofday(&tv); - printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec); -#endif -} - -#define DEBI_READ 0 -#define DEBI_WRITE 1 -static inline void start_debi_dma(struct av7110 *av7110, int dir, - unsigned long addr, unsigned int len) -{ - dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); - if (saa7146_wait_for_debi_done(av7110->dev, 0)) { - printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); - return; - } - - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ - SAA7146_IER_ENABLE(av7110->dev, MASK_19); - if (len < 5) - len = 5; /* we want a real DEBI DMA */ - if (dir == DEBI_WRITE) - iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); - else - irdebi(av7110, DEBISWAB, addr, 0, len); -} - -static void debiirq(unsigned long cookie) -{ - struct av7110 *av7110 = (struct av7110 *)cookie; - int type = av7110->debitype; - int handle = (type >> 8) & 0x1f; - unsigned int xfer = 0; - - print_time("debi"); - dprintk(4, "type 0x%04x\n", type); - - if (type == -1) { - printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", - jiffies, saa7146_read(av7110->dev, PSR), - saa7146_read(av7110->dev, SSR)); - goto debi_done; - } - av7110->debitype = -1; - - switch (type & 0xff) { - - case DATA_TS_RECORD: - dvb_dmx_swfilter_packets(&av7110->demux, - (const u8 *) av7110->debi_virt, - av7110->debilen / 188); - xfer = RX_BUFF; - break; - - case DATA_PES_RECORD: - if (av7110->demux.recording) - av7110_record_cb(&av7110->p2t[handle], - (u8 *) av7110->debi_virt, - av7110->debilen); - xfer = RX_BUFF; - break; - - case DATA_IPMPE: - case DATA_FSECTION: - case DATA_PIPING: - if (av7110->handle2filter[handle]) - DvbDmxFilterCallback((u8 *)av7110->debi_virt, - av7110->debilen, NULL, 0, - av7110->handle2filter[handle], - DMX_OK, av7110); - xfer = RX_BUFF; - break; - - case DATA_CI_GET: - { - u8 *data = av7110->debi_virt; - - if ((data[0] < 2) && data[2] == 0xff) { - int flags = 0; - if (data[5] > 0) - flags |= CA_CI_MODULE_PRESENT; - if (data[5] > 5) - flags |= CA_CI_MODULE_READY; - av7110->ci_slot[data[0]].flags = flags; - } else - ci_get_data(&av7110->ci_rbuffer, - av7110->debi_virt, - av7110->debilen); - xfer = RX_BUFF; - break; - } - - case DATA_COMMON_INTERFACE: - CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen); -#if 0 - { - int i; - - printk("av7110%d: ", av7110->num); - printk("%02x ", *(u8 *)av7110->debi_virt); - printk("%02x ", *(1+(u8 *)av7110->debi_virt)); - for (i = 2; i < av7110->debilen; i++) - printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt))); - for (i = 2; i < av7110->debilen; i++) - printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt))); - - printk("\n"); - } -#endif - xfer = RX_BUFF; - break; - - case DATA_DEBUG_MESSAGE: - ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0; - printk("%s\n", (s8 *) av7110->debi_virt); - xfer = RX_BUFF; - break; - - case DATA_CI_PUT: - dprintk(4, "debi DATA_CI_PUT\n"); - case DATA_MPEG_PLAY: - dprintk(4, "debi DATA_MPEG_PLAY\n"); - case DATA_BMP_LOAD: - dprintk(4, "debi DATA_BMP_LOAD\n"); - xfer = TX_BUFF; - break; - default: - break; - } -debi_done: - spin_lock(&av7110->debilock); - if (xfer) - iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); -} - -/* irq from av7110 firmware writing the mailbox register in the DPRAM */ -static void gpioirq(unsigned long cookie) -{ - struct av7110 *av7110 = (struct av7110 *)cookie; - u32 rxbuf, txbuf; - int len; - - if (av7110->debitype != -1) - /* we shouldn't get any irq while a debi xfer is running */ - printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", - jiffies, saa7146_read(av7110->dev, PSR), - saa7146_read(av7110->dev, SSR)); - - if (saa7146_wait_for_debi_done(av7110->dev, 0)) { - printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); - BUG(); /* maybe we should try resetting the debi? */ - } - - spin_lock(&av7110->debilock); - ARM_ClearIrq(av7110); - - /* see what the av7110 wants */ - av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); - av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - len = (av7110->debilen + 3) & ~3; - - print_time("gpio"); - dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); - - switch (av7110->debitype & 0xff) { - - case DATA_TS_PLAY: - case DATA_PES_PLAY: - break; - - case DATA_MPEG_VIDEO_EVENT: - { - u32 h_ar; - struct video_event event; - - av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2); - h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2); - - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - - av7110->video_size.h = h_ar & 0xfff; - - event.type = VIDEO_EVENT_SIZE_CHANGED; - event.u.size.w = av7110->video_size.w; - event.u.size.h = av7110->video_size.h; - switch ((h_ar >> 12) & 0xf) - { - case 3: - av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9; - event.u.size.aspect_ratio = VIDEO_FORMAT_16_9; - av7110->videostate.video_format = VIDEO_FORMAT_16_9; - break; - case 4: - av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1; - event.u.size.aspect_ratio = VIDEO_FORMAT_221_1; - av7110->videostate.video_format = VIDEO_FORMAT_221_1; - break; - default: - av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3; - event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; - av7110->videostate.video_format = VIDEO_FORMAT_4_3; - } - - dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", - av7110->video_size.w, av7110->video_size.h, - av7110->video_size.aspect_ratio); - - dvb_video_add_event(av7110, &event); - break; - } - - case DATA_CI_PUT: - { - int avail; - struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer; - - avail = dvb_ringbuffer_avail(cibuf); - if (avail <= 2) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; - len |= DVB_RINGBUFFER_PEEK(cibuf, 1); - if (avail < len + 2) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - DVB_RINGBUFFER_SKIP(cibuf, 2); - - dvb_ringbuffer_read(cibuf, av7110->debi_virt, len); - - iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - dprintk(8, "DMA: CI\n"); - start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); - spin_unlock(&av7110->debilock); - wake_up(&cibuf->queue); - return; - } - - case DATA_MPEG_PLAY: - if (!av7110->playing) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - len = 0; - if (av7110->debitype & 0x100) { - spin_lock(&av7110->aout.lock); - len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048); - spin_unlock(&av7110->aout.lock); - } - if (len <= 0 && (av7110->debitype & 0x200) - &&av7110->videostate.play_state != VIDEO_FREEZED) { - spin_lock(&av7110->avout.lock); - len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048); - spin_unlock(&av7110->avout.lock); - } - if (len <= 0) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); - iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - dprintk(8, "DMA: MPEG_PLAY\n"); - start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_BMP_LOAD: - len = av7110->debilen; - dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); - if (!len) { - av7110->bmp_state = BMP_LOADED; - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - wake_up(&av7110->bmpq); - dprintk(8, "gpio DATA_BMP_LOAD done\n"); - break; - } - if (len > av7110->bmplen) - len = av7110->bmplen; - if (len > 2 * 1024) - len = 2 * 1024; - iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); - av7110->bmpp += len; - av7110->bmplen -= len; - dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); - start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_CI_GET: - case DATA_COMMON_INTERFACE: - case DATA_FSECTION: - case DATA_IPMPE: - case DATA_PIPING: - if (!len || len > 4 * 1024) { - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - break; - } - /* fall through */ - - case DATA_TS_RECORD: - case DATA_PES_RECORD: - dprintk(8, "DMA: TS_REC etc.\n"); - start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_DEBUG_MESSAGE: - if (!len || len > 0xff) { - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - break; - } - start_debi_dma(av7110, DEBI_READ, Reserved, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_IRCOMMAND: - if (av7110->ir.ir_handler) - av7110->ir.ir_handler(av7110, - swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - break; - - default: - printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n", - av7110->debitype, av7110->debilen); - break; - } - av7110->debitype = -1; - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); -} - - -#ifdef CONFIG_DVB_AV7110_OSD -static int dvb_osd_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(4, "%p\n", av7110); - - if (cmd == OSD_SEND_CMD) - return av7110_osd_cmd(av7110, (osd_cmd_t *) parg); - if (cmd == OSD_GET_CAPABILITY) - return av7110_osd_capability(av7110, (osd_cap_t *) parg); - - return -EINVAL; -} - - -static const struct file_operations dvb_osd_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_generic_open, - .release = dvb_generic_release, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_osd = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_osd_fops, - .kernel_ioctl = dvb_osd_ioctl, -}; -#endif /* CONFIG_DVB_AV7110_OSD */ - - -static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, - u16 subpid, u16 pcrpid) -{ - u16 aflags = 0; - - dprintk(4, "%p\n", av7110); - - if (vpid == 0x1fff || apid == 0x1fff || - ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) { - vpid = apid = ttpid = subpid = pcrpid = 0; - av7110->pids[DMX_PES_VIDEO] = 0; - av7110->pids[DMX_PES_AUDIO] = 0; - av7110->pids[DMX_PES_TELETEXT] = 0; - av7110->pids[DMX_PES_PCR] = 0; - } - - if (av7110->audiostate.bypass_mode) - aflags |= 0x8000; - - return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, - pcrpid, vpid, apid, ttpid, subpid, aflags); -} - -int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, - u16 subpid, u16 pcrpid) -{ - int ret = 0; - dprintk(4, "%p\n", av7110); - - if (mutex_lock_interruptible(&av7110->pid_mutex)) - return -ERESTARTSYS; - - if (!(vpid & 0x8000)) - av7110->pids[DMX_PES_VIDEO] = vpid; - if (!(apid & 0x8000)) - av7110->pids[DMX_PES_AUDIO] = apid; - if (!(ttpid & 0x8000)) - av7110->pids[DMX_PES_TELETEXT] = ttpid; - if (!(pcrpid & 0x8000)) - av7110->pids[DMX_PES_PCR] = pcrpid; - - av7110->pids[DMX_PES_SUBTITLE] = 0; - - if (av7110->fe_synced) { - pcrpid = av7110->pids[DMX_PES_PCR]; - ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); - } - - mutex_unlock(&av7110->pid_mutex); - return ret; -} - - -/****************************************************************************** - * hardware filter functions - ******************************************************************************/ - -static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) -{ - struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed; - struct av7110 *av7110 = dvbdmxfeed->demux->priv; - u16 buf[20]; - int ret, i; - u16 handle; -// u16 mode = 0x0320; - u16 mode = 0xb96a; - - dprintk(4, "%p\n", av7110); - - if (av7110->full_ts) - return 0; - - if (dvbdmxfilter->type == DMX_TYPE_SEC) { - if (hw_sections) { - buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | - dvbdmxfilter->maskandmode[0]; - for (i = 3; i < 18; i++) - buf[i + 4 - 2] = - (dvbdmxfilter->filter.filter_value[i] << 8) | - dvbdmxfilter->maskandmode[i]; - mode = 4; - } - } else if ((dvbdmxfeed->ts_type & TS_PACKET) && - !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) { - av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed); - } - - buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter; - buf[1] = 16; - buf[2] = dvbdmxfeed->pid; - buf[3] = mode; - - ret = av7110_fw_request(av7110, buf, 20, &handle, 1); - if (ret != 0 || handle >= 32) { - printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " - "ret %d handle %04x\n", - __func__, buf[0], buf[1], buf[2], buf[3], - ret, handle); - dvbdmxfilter->hw_handle = 0xffff; - if (!ret) - ret = -1; - return ret; - } - - av7110->handle2filter[handle] = dvbdmxfilter; - dvbdmxfilter->hw_handle = handle; - - return ret; -} - -static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) -{ - struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv; - u16 buf[3]; - u16 answ[2]; - int ret; - u16 handle; - - dprintk(4, "%p\n", av7110); - - if (av7110->full_ts) - return 0; - - handle = dvbdmxfilter->hw_handle; - if (handle >= 32) { - printk("%s tried to stop invalid filter %04x, filter type = %x\n", - __func__, handle, dvbdmxfilter->type); - return -EINVAL; - } - - av7110->handle2filter[handle] = NULL; - - buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter; - buf[1] = 1; - buf[2] = handle; - ret = av7110_fw_request(av7110, buf, 3, answ, 2); - if (ret != 0 || answ[1] != handle) { - printk("dvb-ttpci: %s error cmd %04x %04x %04x ret %x " - "resp %04x %04x pid %d\n", - __func__, buf[0], buf[1], buf[2], ret, - answ[0], answ[1], dvbdmxfilter->feed->pid); - if (!ret) - ret = -1; - } - return ret; -} - - -static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct av7110 *av7110 = dvbdmx->priv; - u16 *pid = dvbdmx->pids, npids[5]; - int i; - int ret = 0; - - dprintk(4, "%p\n", av7110); - - npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; - i = dvbdmxfeed->pes_type; - npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; - if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { - npids[i] = 0; - ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - if (!ret) - ret = StartHWFilter(dvbdmxfeed->filter); - return ret; - } - if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { - ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - if (ret) - return ret; - } - - if (dvbdmxfeed->pes_type < 2 && npids[0]) - if (av7110->fe_synced) - { - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - if (ret) - return ret; - } - - if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { - if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) - ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); - if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) - ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); - } - return ret; -} - -static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct av7110 *av7110 = dvbdmx->priv; - u16 *pid = dvbdmx->pids, npids[5]; - int i; - - int ret = 0; - - dprintk(4, "%p\n", av7110); - - if (dvbdmxfeed->pes_type <= 1) { - ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); - if (ret) - return ret; - if (!av7110->rec_mode) - dvbdmx->recording = 0; - if (!av7110->playing) - dvbdmx->playing = 0; - } - npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; - i = dvbdmxfeed->pes_type; - switch (i) { - case 2: //teletext - if (dvbdmxfeed->ts_type & TS_PACKET) - ret = StopHWFilter(dvbdmxfeed->filter); - npids[2] = 0; - break; - case 0: - case 1: - case 4: - if (!pids_off) - return 0; - npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; - break; - } - if (!ret) - ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - return ret; -} - -static int av7110_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *av7110 = demux->priv; - int ret = 0; - - dprintk(4, "%p\n", av7110); - - if (!demux->dmx.frontend) - return -EINVAL; - - if (!av7110->full_ts && feed->pid > 0x1fff) - return -EINVAL; - - if (feed->type == DMX_TYPE_TS) { - if ((feed->ts_type & TS_DECODER) && - (feed->pes_type <= DMX_TS_PES_PCR)) { - switch (demux->dmx.frontend->source) { - case DMX_MEMORY_FE: - if (feed->ts_type & TS_DECODER) - if (feed->pes_type < 2 && - !(demux->pids[0] & 0x8000) && - !(demux->pids[1] & 0x8000)) { - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - ret = av7110_av_start_play(av7110,RP_AV); - if (!ret) - demux->playing = 1; - } - break; - default: - ret = dvb_feed_start_pid(feed); - break; - } - } else if ((feed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE)) { - ret = StartHWFilter(feed->filter); - } - } - - if (av7110->full_ts) { - budget_start_feed(feed); - return ret; - } - - if (feed->type == DMX_TYPE_SEC) { - int i; - - for (i = 0; i < demux->filternum; i++) { - if (demux->filter[i].state != DMX_STATE_READY) - continue; - if (demux->filter[i].type != DMX_TYPE_SEC) - continue; - if (demux->filter[i].filter.parent != &feed->feed.sec) - continue; - demux->filter[i].state = DMX_STATE_GO; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) { - ret = StartHWFilter(&demux->filter[i]); - if (ret) - break; - } - } - } - - return ret; -} - - -static int av7110_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *av7110 = demux->priv; - int i, rc, ret = 0; - dprintk(4, "%p\n", av7110); - - if (feed->type == DMX_TYPE_TS) { - if (feed->ts_type & TS_DECODER) { - if (feed->pes_type >= DMX_TS_PES_OTHER || - !demux->pesfilter[feed->pes_type]) - return -EINVAL; - demux->pids[feed->pes_type] |= 0x8000; - demux->pesfilter[feed->pes_type] = NULL; - } - if (feed->ts_type & TS_DECODER && - feed->pes_type < DMX_TS_PES_OTHER) { - ret = dvb_feed_stop_pid(feed); - } else - if ((feed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE)) - ret = StopHWFilter(feed->filter); - } - - if (av7110->full_ts) { - budget_stop_feed(feed); - return ret; - } - - if (feed->type == DMX_TYPE_SEC) { - for (i = 0; ifilternum; i++) { - if (demux->filter[i].state == DMX_STATE_GO && - demux->filter[i].filter.parent == &feed->feed.sec) { - demux->filter[i].state = DMX_STATE_READY; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) { - rc = StopHWFilter(&demux->filter[i]); - if (!ret) - ret = rc; - /* keep going, stop as many filters as possible */ - } - } - } - } - - return ret; -} - - -static void restart_feeds(struct av7110 *av7110) -{ - struct dvb_demux *dvbdmx = &av7110->demux; - struct dvb_demux_feed *feed; - int mode; - int feeding; - int i, j; - - dprintk(4, "%p\n", av7110); - - mode = av7110->playing; - av7110->playing = 0; - av7110->rec_mode = 0; - - feeding = av7110->feeding1; /* full_ts mod */ - - for (i = 0; i < dvbdmx->feednum; i++) { - feed = &dvbdmx->feed[i]; - if (feed->state == DMX_STATE_GO) { - if (feed->type == DMX_TYPE_SEC) { - for (j = 0; j < dvbdmx->filternum; j++) { - if (dvbdmx->filter[j].type != DMX_TYPE_SEC) - continue; - if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) - continue; - if (dvbdmx->filter[j].state == DMX_STATE_GO) - dvbdmx->filter[j].state = DMX_STATE_READY; - } - } - av7110_start_feed(feed); - } - } - - av7110->feeding1 = feeding; /* full_ts mod */ - - if (mode) - av7110_av_start_play(av7110, mode); -} - -static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, - uint64_t *stc, unsigned int *base) -{ - int ret; - u16 fwstc[4]; - u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC); - struct dvb_demux *dvbdemux; - struct av7110 *av7110; - - /* pointer casting paranoia... */ - BUG_ON(!demux); - dvbdemux = demux->priv; - BUG_ON(!dvbdemux); - av7110 = dvbdemux->priv; - - dprintk(4, "%p\n", av7110); - - if (num != 0) - return -EINVAL; - - ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); - if (ret) { - printk(KERN_ERR "%s: av7110_fw_request error\n", __func__); - return ret; - } - dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", - fwstc[0], fwstc[1], fwstc[2], fwstc[3]); - - *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) | - (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]); - *base = 1; - - dprintk(4, "stc = %lu\n", (unsigned long)*stc); - - return 0; -} - - -/****************************************************************************** - * SEC device file operations - ******************************************************************************/ - - -static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct av7110* av7110 = fe->dvb->priv; - - switch (tone) { - case SEC_TONE_ON: - return Set22K(av7110, 1); - - case SEC_TONE_OFF: - return Set22K(av7110, 0); - - default: - return -EINVAL; - } -} - -static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd* cmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); -} - -static int av7110_diseqc_send_burst(struct dvb_frontend* fe, - fe_sec_mini_cmd_t minicmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - return av7110_diseqc_send(av7110, 0, NULL, minicmd); -} - -/* simplified code from budget-core.c */ -static int stop_ts_capture(struct av7110 *budget) -{ - dprintk(2, "budget: %p\n", budget); - - if (--budget->feeding1) - return budget->feeding1; - saa7146_write(budget->dev, MC1, MASK_20); /* DMA3 off */ - SAA7146_IER_DISABLE(budget->dev, MASK_10); - SAA7146_ISR_CLEAR(budget->dev, MASK_10); - return 0; -} - -static int start_ts_capture(struct av7110 *budget) -{ - dprintk(2, "budget: %p\n", budget); - - if (budget->feeding1) - return ++budget->feeding1; - memset(budget->grabbing, 0x00, TS_BUFLEN); - budget->ttbp = 0; - SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ - SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ - saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ - return ++budget->feeding1; -} - -static int budget_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *budget = demux->priv; - int status; - - dprintk(2, "av7110: %p\n", budget); - - spin_lock(&budget->feedlock1); - feed->pusi_seen = 0; /* have a clean section start */ - status = start_ts_capture(budget); - spin_unlock(&budget->feedlock1); - return status; -} - -static int budget_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *budget = demux->priv; - int status; - - dprintk(2, "budget: %p\n", budget); - - spin_lock(&budget->feedlock1); - status = stop_ts_capture(budget); - spin_unlock(&budget->feedlock1); - return status; -} - -static void vpeirq(unsigned long cookie) -{ - struct av7110 *budget = (struct av7110 *)cookie; - u8 *mem = (u8 *) (budget->grabbing); - u32 olddma = budget->ttbp; - u32 newdma = saa7146_read(budget->dev, PCI_VDP3); - struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; - - /* nearest lower position divisible by 188 */ - newdma -= newdma % 188; - - if (newdma >= TS_BUFLEN) - return; - - budget->ttbp = newdma; - - if (!budget->feeding1 || (newdma == olddma)) - return; - - /* Ensure streamed PCI data is synced to CPU */ - pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); - -#if 0 - /* track rps1 activity */ - printk("vpeirq: %02x Event Counter 1 0x%04x\n", - mem[olddma], - saa7146_read(budget->dev, EC1R) & 0x3fff); -#endif - - if (newdma > olddma) - /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); - else { - /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); - dvb_dmx_swfilter_packets(demux, mem, newdma / 188); - } -} - -static int av7110_register(struct av7110 *av7110) -{ - int ret, i; - struct dvb_demux *dvbdemux = &av7110->demux; - struct dvb_demux *dvbdemux1 = &av7110->demux1; - - dprintk(4, "%p\n", av7110); - - if (av7110->registered) - return -1; - - av7110->registered = 1; - - dvbdemux->priv = (void *) av7110; - - for (i = 0; i < 32; i++) - av7110->handle2filter[i] = NULL; - - dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; - dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; - dvbdemux->start_feed = av7110_start_feed; - dvbdemux->stop_feed = av7110_stop_feed; - dvbdemux->write_to_decoder = av7110_write_to_decoder; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&av7110->demux); - av7110->demux.dmx.get_stc = dvb_get_stc; - - av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; - av7110->dmxdev.demux = &dvbdemux->dmx; - av7110->dmxdev.capabilities = 0; - - dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter); - - av7110->hw_frontend.source = DMX_FRONTEND_0; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend); - - if (ret < 0) - return ret; - - av7110->mem_frontend.source = DMX_MEMORY_FE; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend); - - if (ret < 0) - return ret; - - ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, - &av7110->hw_frontend); - if (ret < 0) - return ret; - - av7110_av_register(av7110); - av7110_ca_register(av7110); - -#ifdef CONFIG_DVB_AV7110_OSD - dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, - &dvbdev_osd, av7110, DVB_DEVICE_OSD); -#endif - - dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); - - if (budgetpatch) { - /* initialize software demux1 without its own frontend - * demux1 hardware is connected to frontend0 of demux0 - */ - dvbdemux1->priv = (void *) av7110; - - dvbdemux1->filternum = 256; - dvbdemux1->feednum = 256; - dvbdemux1->start_feed = budget_start_feed; - dvbdemux1->stop_feed = budget_stop_feed; - dvbdemux1->write_to_decoder = NULL; - - dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&av7110->demux1); - - av7110->dmxdev1.filternum = 256; - av7110->dmxdev1.demux = &dvbdemux1->dmx; - av7110->dmxdev1.capabilities = 0; - - dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter); - - dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); - printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); - } - return 0; -} - - -static void dvb_unregister(struct av7110 *av7110) -{ - struct dvb_demux *dvbdemux = &av7110->demux; - struct dvb_demux *dvbdemux1 = &av7110->demux1; - - dprintk(4, "%p\n", av7110); - - if (!av7110->registered) - return; - - if (budgetpatch) { - dvb_net_release(&av7110->dvb_net1); - dvbdemux->dmx.close(&dvbdemux1->dmx); - dvb_dmxdev_release(&av7110->dmxdev1); - dvb_dmx_release(&av7110->demux1); - } - - dvb_net_release(&av7110->dvb_net); - - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend); - - dvb_dmxdev_release(&av7110->dmxdev); - dvb_dmx_release(&av7110->demux); - - if (av7110->fe != NULL) { - dvb_unregister_frontend(av7110->fe); - dvb_frontend_detach(av7110->fe); - } - dvb_unregister_device(av7110->osd_dev); - av7110_av_unregister(av7110); - av7110_ca_unregister(av7110); -} - - -/**************************************************************************** - * I2C client commands - ****************************************************************************/ - -int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) -{ - u8 msg[2] = { reg, val }; - struct i2c_msg msgs; - - msgs.flags = 0; - msgs.addr = id / 2; - msgs.len = 2; - msgs.buf = msg; - return i2c_transfer(&av7110->i2c_adap, &msgs, 1); -} - -u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) -{ - u8 mm1[] = {0x00}; - u8 mm2[] = {0x00}; - struct i2c_msg msgs[2]; - - msgs[0].flags = 0; - msgs[1].flags = I2C_M_RD; - msgs[0].addr = msgs[1].addr = id / 2; - mm1[0] = reg; - msgs[0].len = 1; msgs[1].len = 1; - msgs[0].buf = mm1; msgs[1].buf = mm2; - i2c_transfer(&av7110->i2c_adap, msgs, 2); - - return mm2[0]; -} - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - - -static int check_firmware(struct av7110* av7110) -{ - u32 crc = 0, len = 0; - unsigned char *ptr; - - /* check for firmware magic */ - ptr = av7110->bin_fw; - if (ptr[0] != 'A' || ptr[1] != 'V' || - ptr[2] != 'F' || ptr[3] != 'W') { - printk("dvb-ttpci: this is not an av7110 firmware\n"); - return -EINVAL; - } - ptr += 4; - - /* check dpram file */ - crc = get_unaligned_be32(ptr); - ptr += 4; - len = get_unaligned_be32(ptr); - ptr += 4; - if (len >= 512) { - printk("dvb-ttpci: dpram file is way too big.\n"); - return -EINVAL; - } - if (crc != crc32_le(0, ptr, len)) { - printk("dvb-ttpci: crc32 of dpram file does not match.\n"); - return -EINVAL; - } - av7110->bin_dpram = ptr; - av7110->size_dpram = len; - ptr += len; - - /* check root file */ - crc = get_unaligned_be32(ptr); - ptr += 4; - len = get_unaligned_be32(ptr); - ptr += 4; - - if (len <= 200000 || len >= 300000 || - len > ((av7110->bin_fw + av7110->size_fw) - ptr)) { - printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len); - return -EINVAL; - } - if( crc != crc32_le(0, ptr, len)) { - printk("dvb-ttpci: crc32 of root file does not match.\n"); - return -EINVAL; - } - av7110->bin_root = ptr; - av7110->size_root = len; - return 0; -} - -static void put_firmware(struct av7110* av7110) -{ - vfree(av7110->bin_fw); -} - -static int get_firmware(struct av7110* av7110) -{ - int ret; - const struct firmware *fw; - - /* request the av7110 firmware, this will block until someone uploads it */ - ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev); - if (ret) { - if (ret == -ENOENT) { - printk(KERN_ERR "dvb-ttpci: could not load firmware," - " file not found: dvb-ttpci-01.fw\n"); - printk(KERN_ERR "dvb-ttpci: usually this should be in " - "/usr/lib/hotplug/firmware or /lib/firmware\n"); - printk(KERN_ERR "dvb-ttpci: and can be downloaded from" - " http://www.linuxtv.org/download/dvb/firmware/\n"); - } else - printk(KERN_ERR "dvb-ttpci: cannot request firmware" - " (error %i)\n", ret); - return -EINVAL; - } - - if (fw->size <= 200000) { - printk("dvb-ttpci: this firmware is way too small.\n"); - release_firmware(fw); - return -EINVAL; - } - - /* check if the firmware is available */ - av7110->bin_fw = vmalloc(fw->size); - if (NULL == av7110->bin_fw) { - dprintk(1, "out of memory\n"); - release_firmware(fw); - return -ENOMEM; - } - - memcpy(av7110->bin_fw, fw->data, fw->size); - av7110->size_fw = fw->size; - if ((ret = check_firmware(av7110))) - vfree(av7110->bin_fw); - - release_firmware(fw); - return ret; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (p->frequency + 479500) / 125; - - if (p->frequency > 2000000) - pwr = 3; - else if (p->frequency > 1800000) - pwr = 2; - else if (p->frequency > 1600000) - pwr = 1; - else if (p->frequency > 1200000) - pwr = 0; - else if (p->frequency >= 1100000) - pwr = 1; - else - pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = { - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (p->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - - - - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = p->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - - - -static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u32 f = p->frequency; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (f + 36125000 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1820_config philips_cd1516_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - - - -static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u32 div, pwr; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (p->frequency + 36200000) / 166666; - - if (p->frequency <= 782000000) - pwr = 1; - else - pwr = 2; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85; - data[3] = pwr << 6; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ -#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE) - struct av7110* av7110 = fe->dvb->priv; - - return request_firmware(fw, name, &av7110->dev->pci->dev); -#else - return -EINVAL; -#endif -} - -static struct sp8870_config alps_tdlb7_config = { - - .demod_address = 0x71, - .request_firmware = alps_tdlb7_request_firmware, -}; - - -static u8 nexusca_stv0297_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x00, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x00, - 0x4b, 0x7b, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x10, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x04, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x49, - 0x62, 0x0b, - 0x53, 0x08, - 0x59, 0x08, - 0xff, 0xff, -}; - -static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) }; - struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; - int i; - - div = (p->frequency + 36150000 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xce; - - if (p->frequency < 45000000) - return -EINVAL; - else if (p->frequency < 137000000) - data[3] = 0x01; - else if (p->frequency < 403000000) - data[3] = 0x02; - else if (p->frequency < 860000000) - data[3] = 0x04; - else - return -EINVAL; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) { - printk("nexusca: pll transfer failed!\n"); - return -EIO; - } - - // wait for PLL lock - for(i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1) - if (data[0] & 0x40) break; - msleep(10); - } - - return 0; -} - -static struct stv0297_config nexusca_stv0297_config = { - - .demod_address = 0x1C, - .inittab = nexusca_stv0297_inittab, - .invert = 1, - .stop_during_read = 1, -}; - - - -static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 cfg, cpump, band_select; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (36125000 + p->frequency) / 166666; - - cfg = 0x88; - - if (p->frequency < 175000000) - cpump = 2; - else if (p->frequency < 390000000) - cpump = 1; - else if (p->frequency < 470000000) - cpump = 2; - else if (p->frequency < 750000000) - cpump = 1; - else - cpump = 3; - - if (p->frequency < 175000000) - band_select = 0x0e; - else if (p->frequency < 470000000) - band_select = 0x05; - else - band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct l64781_config grundig_29504_401_config = { - .demod_address = 0x55, -}; - - - -static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) -{ - int ret = 0; - int synced = (status & FE_HAS_LOCK) ? 1 : 0; - - av7110->fe_status = status; - - if (av7110->fe_synced == synced) - return 0; - - if (av7110->playing) { - av7110->fe_synced = synced; - return 0; - } - - if (mutex_lock_interruptible(&av7110->pid_mutex)) - return -ERESTARTSYS; - - if (synced) { - ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], - av7110->pids[DMX_PES_AUDIO], - av7110->pids[DMX_PES_TELETEXT], 0, - av7110->pids[DMX_PES_PCR]); - if (!ret) - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - } else { - ret = SetPIDs(av7110, 0, 0, 0, 0, 0); - if (!ret) { - ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); - if (!ret) - ret = av7110_wait_msgstate(av7110, GPMQBusy); - } - } - - if (!ret) - av7110->fe_synced = synced; - - mutex_unlock(&av7110->pid_mutex); - return ret; -} - -static int av7110_fe_set_frontend(struct dvb_frontend *fe) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_set_frontend(fe); - - return ret; -} - -static int av7110_fe_init(struct dvb_frontend* fe) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_init(fe); - return ret; -} - -static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct av7110* av7110 = fe->dvb->priv; - - /* call the real implementation */ - int ret = av7110->fe_read_status(fe, status); - if (!ret) - if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) - ret = av7110_fe_lock_fix(av7110, *status); - return ret; -} - -static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_diseqc_reset_overload(fe); - return ret; -} - -static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd* cmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_master_cmd = *cmd; - ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); - } - return ret; -} - -static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_minicmd = minicmd; - ret = av7110->fe_diseqc_send_burst(fe, minicmd); - } - return ret; -} - -static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_tone = tone; - ret = av7110->fe_set_tone(fe, tone); - } - return ret; -} - -static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_voltage = voltage; - ret = av7110->fe_set_voltage(fe, voltage); - } - return ret; -} - -static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); - return ret; -} - -static void dvb_s_recover(struct av7110* av7110) -{ - av7110_fe_init(av7110->fe); - - av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); - if (av7110->saved_master_cmd.msg_len) { - msleep(20); - av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); - } - msleep(20); - av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); - msleep(20); - av7110_fe_set_tone(av7110->fe, av7110->saved_tone); - - av7110_fe_set_frontend(av7110->fe); -} - -static u8 read_pwm(struct av7110* av7110) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static int frontend_init(struct av7110 *av7110) -{ - int ret; - - if (av7110->dev->pci->subsystem_vendor == 0x110a) { - switch(av7110->dev->pci->subsystem_device) { - case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) - av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, - &av7110->i2c_adap, read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; - } - break; - } - - } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { - switch(av7110->dev->pci->subsystem_device) { - case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X - case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X - case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE - - // try the ALPS BSRV2 first of all - av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - break; - } - - // try the ALPS BSRU6 now - av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - av7110->fe->tuner_priv = &av7110->i2c_adap; - - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - break; - } - - // Try the grundig 29504-451 - av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - break; - } - - /* Try DVB-C cards */ - switch(av7110->dev->pci->subsystem_device) { - case 0x0000: - /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ - av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, - read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; - } - break; - case 0x0003: - /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ - av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, - read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - } - break; - } - break; - - case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X - // try ALPS TDLB7 first, then Grundig 29504-401 - av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; - break; - } - /* fall-thru */ - - case 0x0008: // Hauppauge/TT DVB-T - // Grundig 29504-401 - av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap); - if (av7110->fe) - av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - break; - - case 0x0002: // Hauppauge/TT DVB-C premium rev2.X - - av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - } - break; - - case 0x0004: // Galaxis DVB-S rev1.3 - /* ALPS BSRV2 */ - av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - } - break; - - case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ - /* Grundig 29504-451 */ - av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - } - break; - - case 0x000A: // Hauppauge/TT Nexus-CA rev1.X - - av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; - - /* set TDA9819 into DVB mode */ - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) - saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) - - /* tuner on this needs a slower i2c bus speed */ - av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - break; - } - break; - - case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ - /* ALPS BSBE1 */ - av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - av7110->fe->tuner_priv = &av7110->i2c_adap; - - if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) { - printk("dvb-ttpci: LNBP21 not found!\n"); - if (av7110->fe->ops.release) - av7110->fe->ops.release(av7110->fe); - av7110->fe = NULL; - } else { - av7110->fe->ops.dishnetwork_send_legacy_command = NULL; - av7110->recover = dvb_s_recover; - } - } - break; - } - } - - if (!av7110->fe) { - /* FIXME: propagate the failure code from the lower layers */ - ret = -ENOMEM; - printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - av7110->dev->pci->vendor, - av7110->dev->pci->device, - av7110->dev->pci->subsystem_vendor, - av7110->dev->pci->subsystem_device); - } else { - FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); - FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); - FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); - FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); - FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); - FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); - FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage); - FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); - FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); - - ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); - if (ret < 0) { - printk("av7110: Frontend registration failed!\n"); - dvb_frontend_detach(av7110->fe); - av7110->fe = NULL; - } - } - return ret; -} - -/* Budgetpatch note: - * Original hardware design by Roberto Deza: - * There is a DVB_Wiki at - * http://www.linuxtv.org/ - * - * New software triggering design by Emard that works on - * original Roberto Deza's hardware: - * - * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. - * GPIO3 is in budget-patch hardware connectd to port B VSYNC - * HS is an internal event of 7146, accessible with RPS - * and temporarily raised high every n lines - * (n in defined in the RPS_THRESH1 counter threshold) - * I think HS is raised high on the beginning of the n-th line - * and remains high until this n-th line that triggered - * it is completely received. When the receiption of n-th line - * ends, HS is lowered. - * - * To transmit data over DMA, 7146 needs changing state at - * port B VSYNC pin. Any changing of port B VSYNC will - * cause some DMA data transfer, with more or less packets loss. - * It depends on the phase and frequency of VSYNC and - * the way of 7146 is instructed to trigger on port B (defined - * in DD1_INIT register, 3rd nibble from the right valid - * numbers are 0-7, see datasheet) - * - * The correct triggering can minimize packet loss, - * dvbtraffic should give this stable bandwidths: - * 22k transponder = 33814 kbit/s - * 27.5k transponder = 38045 kbit/s - * by experiment it is found that the best results - * (stable bandwidths and almost no packet loss) - * are obtained using DD1_INIT triggering number 2 - * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) - * and a VSYNC phase that occurs in the middle of DMA transfer - * (about byte 188*512=96256 in the DMA window). - * - * Phase of HS is still not clear to me how to control, - * It just happens to be so. It can be seen if one enables - * RPS_IRQ and print Event Counter 1 in vpeirq(). Every - * time RPS_INTERRUPT is called, the Event Counter 1 will - * increment. That's how the 7146 is programmed to do event - * counting in this budget-patch.c - * I *think* HPS setting has something to do with the phase - * of HS but I can't be 100% sure in that. - * - * hardware debug note: a working budget card (including budget patch) - * with vpeirq() interrupt setup in mode "0x90" (every 64K) will - * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes - * and that means 3*25=75 Hz of interrupt freqency, as seen by - * watch cat /proc/interrupts - * - * If this frequency is 3x lower (and data received in the DMA - * buffer don't start with 0x47, but in the middle of packets, - * whose lengths appear to be like 188 292 188 104 etc. - * this means VSYNC line is not connected in the hardware. - * (check soldering pcb and pins) - * The same behaviour of missing VSYNC can be duplicated on budget - * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. - */ -static int __devinit av7110_attach(struct saa7146_dev* dev, - struct saa7146_pci_extension_data *pci_ext) -{ - const int length = TS_WIDTH * TS_HEIGHT; - struct pci_dev *pdev = dev->pci; - struct av7110 *av7110; - struct task_struct *thread; - int ret, count = 0; - - dprintk(4, "dev: %p\n", dev); - - /* Set RPS_IRQ to 1 to track rps1 activity. - * Enabling this won't send any interrupt to PC CPU. - */ -#define RPS_IRQ 0 - - if (budgetpatch == 1) { - budgetpatch = 0; - /* autodetect the presence of budget patch - * this only works if saa7146 has been recently - * reset with with MASK_31 to MC1 - * - * will wait for VBI_B event (vertical blank at port B) - * and will reset GPIO3 after VBI_B is detected. - * (GPIO3 should be raised high by CPU to - * test if GPIO3 will generate vertical blank signal - * in budget patch GPIO3 is connected to VSYNC_B - */ - - /* RESET SAA7146 */ - saa7146_write(dev, MC1, MASK_31); - /* autodetection success seems to be time-dependend after reset */ - - /* Fix VSYNC level */ - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - /* set vsync_b triggering */ - saa7146_write(dev, DD1_STREAM_B, 0); - /* port B VSYNC at rising edge */ - saa7146_write(dev, DD1_INIT, 0x00000200); - saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI - saa7146_write(dev, MC2, - 1 * (MASK_08 | MASK_24) | // BRS control - 0 * (MASK_09 | MASK_25) | // a - 1 * (MASK_10 | MASK_26) | // b - 0 * (MASK_06 | MASK_22) | // HPS_CTRL1 - 0 * (MASK_05 | MASK_21) | // HPS_CTRL2 - 0 * (MASK_01 | MASK_15) // DEBI - ); - - /* start writing RPS1 code from beginning */ - count = 0; - /* Disable RPS1 */ - saa7146_write(dev, MC1, MASK_29); - /* RPS1 timeout disable */ - saa7146_write(dev, RPS_TOV1, 0); - WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - /* issue RPS1 interrupt to increment counter */ - WRITE_RPS1(CMD_INTERRUPT); -#endif - WRITE_RPS1(CMD_STOP); - /* Jump to begin of RPS program as safety measure (p37) */ - WRITE_RPS1(CMD_JUMP); - WRITE_RPS1(dev->d_rps1.dma_handle); - -#if RPS_IRQ - /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) - * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled - * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called - */ - saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); - /* set event counter 1 threshold to maximum allowed value (rEC p55) */ - saa7146_write(dev, ECT1R, 0x3fff ); -#endif - /* Set RPS1 Address register to point to RPS code (r108 p42) */ - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - /* Enable RPS1, (rFC p33) */ - saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); - - mdelay(10); - /* now send VSYNC_B to rps1 by rising GPIO3 */ - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - mdelay(10); - /* if rps1 responded by lowering the GPIO3, - * then we have budgetpatch hardware - */ - if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) { - budgetpatch = 1; - printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n"); - } - /* Disable RPS1 */ - saa7146_write(dev, MC1, ( MASK_29 )); -#if RPS_IRQ - printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); -#endif - } - - /* prepare the av7110 device struct */ - av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL); - if (!av7110) { - dprintk(1, "out of memory\n"); - return -ENOMEM; - } - - av7110->card_name = (char*) pci_ext->ext_priv; - av7110->dev = dev; - dev->ext_priv = av7110; - - ret = get_firmware(av7110); - if (ret < 0) - goto err_kfree_0; - - ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, - THIS_MODULE, &dev->pci->dev, adapter_nr); - if (ret < 0) - goto err_put_firmware_1; - - /* the Siemens DVB needs this if you want to have the i2c chips - get recognized before the main driver is fully loaded */ - saa7146_write(dev, GPIO_CTRL, 0x500000); - - strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name)); - - saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ - - ret = i2c_add_adapter(&av7110->i2c_adap); - if (ret < 0) - goto err_dvb_unregister_adapter_2; - - ttpci_eeprom_parse_mac(&av7110->i2c_adap, - av7110->dvb_adapter.proposed_mac); - ret = -ENOMEM; - - /* full-ts mod? */ - if (full_ts) - av7110->full_ts = true; - - /* check for full-ts flag in eeprom */ - if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { - u8 flags = i2c_readreg(av7110, 0xaa, 2); - if (flags != 0xff && (flags & 0x01)) - av7110->full_ts = true; - } - - if (av7110->full_ts) { - printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); - spin_lock_init(&av7110->feedlock1); - av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, - &av7110->pt); - if (!av7110->grabbing) - goto err_i2c_del_3; - - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - - saa7146_write(dev, DD1_INIT, 0x00000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - saa7146_write(dev, BRS_CTRL, 0x60000000); - saa7146_write(dev, MC2, MASK_08 | MASK_24); - - /* dma3 */ - saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - saa7146_write(dev, BASE_ODD3, 0); - saa7146_write(dev, BASE_EVEN3, 0); - saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); - saa7146_write(dev, PITCH3, TS_WIDTH); - saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); - saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); - saa7146_write(dev, MC2, MASK_04 | MASK_20); - - tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); - - } else if (budgetpatch) { - spin_lock_init(&av7110->feedlock1); - av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, - &av7110->pt); - if (!av7110->grabbing) - goto err_i2c_del_3; - - saa7146_write(dev, PCI_BT_V1, 0x1c1f101f); - saa7146_write(dev, BCS_CTRL, 0x80400040); - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, DD1_INIT, 0x03000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - saa7146_write(dev, BASE_ODD3, 0); - saa7146_write(dev, BASE_EVEN3, 0); - saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); - saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); - - saa7146_write(dev, PITCH3, TS_WIDTH); - saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); - - /* upload all */ - saa7146_write(dev, MC2, 0x077c077c); - saa7146_write(dev, GPIO_CTRL, 0x000000); -#if RPS_IRQ - /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) - * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled - * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called - */ - saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); - /* set event counter 1 threshold to maximum allowed value (rEC p55) */ - saa7146_write(dev, ECT1R, 0x3fff ); -#endif - /* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */ - count = 0; - - /* Wait Source Line Counter Threshold (p36) */ - WRITE_RPS1(CMD_PAUSE | EVT_HS); - /* Set GPIO3=1 (p42) */ - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); -#if RPS_IRQ - /* issue RPS1 interrupt */ - WRITE_RPS1(CMD_INTERRUPT); -#endif - /* Wait reset Source Line Counter Threshold (p36) */ - WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); - /* Set GPIO3=0 (p42) */ - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - /* issue RPS1 interrupt */ - WRITE_RPS1(CMD_INTERRUPT); -#endif - /* Jump to begin of RPS program (p37) */ - WRITE_RPS1(CMD_JUMP); - WRITE_RPS1(dev->d_rps1.dma_handle); - - /* Fix VSYNC level */ - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - /* Set RPS1 Address register to point to RPS code (r108 p42) */ - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - /* Set Source Line Counter Threshold, using BRS (rCC p43) - * It generates HS event every TS_HEIGHT lines - * this is related to TS_WIDTH set in register - * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits - * are set to TS_WIDTH bytes (TS_WIDTH=2*188), - * then RPS_THRESH1 should be set to trigger - * every TS_HEIGHT (512) lines. - */ - saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); - - /* Enable RPS1 (rFC p33) */ - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - - /* end of budgetpatch register initialization */ - tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); - } else { - saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - saa7146_write(dev, BCS_CTRL, 0x80400040); - - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, DD1_INIT, 0x03000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - /* upload all */ - saa7146_write(dev, MC2, 0x077c077c); - saa7146_write(dev, GPIO_CTRL, 0x000000); - } - - tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110); - tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110); - - mutex_init(&av7110->pid_mutex); - - /* locks for data transfers from/to AV7110 */ - spin_lock_init(&av7110->debilock); - mutex_init(&av7110->dcomlock); - av7110->debitype = -1; - - /* default OSD window */ - av7110->osdwin = 1; - mutex_init(&av7110->osd_mutex); - - /* TV standard */ - av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC - : AV7110_VIDEO_MODE_PAL; - - /* ARM "watchdog" */ - init_waitqueue_head(&av7110->arm_wait); - av7110->arm_thread = NULL; - - /* allocate and init buffers */ - av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus); - if (!av7110->debi_virt) - goto err_saa71466_vfree_4; - - - av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS); - if (!av7110->iobuf) - goto err_pci_free_5; - - ret = av7110_av_init(av7110); - if (ret < 0) - goto err_iobuf_vfree_6; - - /* init BMP buffer */ - av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN; - init_waitqueue_head(&av7110->bmpq); - - ret = av7110_ca_init(av7110); - if (ret < 0) - goto err_av7110_av_exit_7; - - /* load firmware into AV7110 cards */ - ret = av7110_bootarm(av7110); - if (ret < 0) - goto err_av7110_ca_exit_8; - - ret = av7110_firmversion(av7110); - if (ret < 0) - goto err_stop_arm_9; - - if (FW_VERSION(av7110->arm_app)<0x2501) - printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. " - "System might be unstable!\n", FW_VERSION(av7110->arm_app)); - - thread = kthread_run(arm_thread, (void *) av7110, "arm_mon"); - if (IS_ERR(thread)) { - ret = PTR_ERR(thread); - goto err_stop_arm_9; - } - av7110->arm_thread = thread; - - /* set initial volume in mixer struct */ - av7110->mixer.volume_left = volume; - av7110->mixer.volume_right = volume; - - ret = av7110_register(av7110); - if (ret < 0) - goto err_arm_thread_stop_10; - - init_av7110_av(av7110); - - /* special case DVB-C: these cards have an analog tuner - plus need some special handling, so we have separate - saa7146_ext_vv data for these... */ - ret = av7110_init_v4l(av7110); - if (ret < 0) - goto err_av7110_unregister_11; - - av7110->dvb_adapter.priv = av7110; - ret = frontend_init(av7110); - if (ret < 0) - goto err_av7110_exit_v4l_12; - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_init(av7110); -#endif - printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); - av7110_num++; -out: - return ret; - -err_av7110_exit_v4l_12: - av7110_exit_v4l(av7110); -err_av7110_unregister_11: - dvb_unregister(av7110); -err_arm_thread_stop_10: - av7110_arm_sync(av7110); -err_stop_arm_9: - /* Nothing to do. Rejoice. */ -err_av7110_ca_exit_8: - av7110_ca_exit(av7110); -err_av7110_av_exit_7: - av7110_av_exit(av7110); -err_iobuf_vfree_6: - vfree(av7110->iobuf); -err_pci_free_5: - pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); -err_saa71466_vfree_4: - if (av7110->grabbing) - saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); -err_i2c_del_3: - i2c_del_adapter(&av7110->i2c_adap); -err_dvb_unregister_adapter_2: - dvb_unregister_adapter(&av7110->dvb_adapter); -err_put_firmware_1: - put_firmware(av7110); -err_kfree_0: - kfree(av7110); - goto out; -} - -static int __devexit av7110_detach(struct saa7146_dev* saa) -{ - struct av7110 *av7110 = saa->ext_priv; - dprintk(4, "%p\n", av7110); - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_exit(av7110); -#endif - if (budgetpatch || av7110->full_ts) { - if (budgetpatch) { - /* Disable RPS1 */ - saa7146_write(saa, MC1, MASK_29); - /* VSYNC LOW (inactive) */ - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - } - saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ - SAA7146_IER_DISABLE(saa, MASK_10); - SAA7146_ISR_CLEAR(saa, MASK_10); - msleep(50); - tasklet_kill(&av7110->vpe_tasklet); - saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt); - } - av7110_exit_v4l(av7110); - - av7110_arm_sync(av7110); - - tasklet_kill(&av7110->debi_tasklet); - tasklet_kill(&av7110->gpio_tasklet); - - dvb_unregister(av7110); - - SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03); - SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03); - - av7110_ca_exit(av7110); - av7110_av_exit(av7110); - - vfree(av7110->iobuf); - pci_free_consistent(saa->pci, 8192, av7110->debi_virt, - av7110->debi_bus); - - i2c_del_adapter(&av7110->i2c_adap); - - dvb_unregister_adapter (&av7110->dvb_adapter); - - av7110_num--; - - put_firmware(av7110); - - kfree(av7110); - - saa->ext_priv = NULL; - - return 0; -} - - -static void av7110_irq(struct saa7146_dev* dev, u32 *isr) -{ - struct av7110 *av7110 = dev->ext_priv; - - //print_time("av7110_irq"); - - /* Note: Don't try to handle the DEBI error irq (MASK_18), in - * intel mode the timeout is asserted all the time... - */ - - if (*isr & MASK_19) { - //printk("av7110_irq: DEBI\n"); - /* Note 1: The DEBI irq is level triggered: We must enable it - * only after we started a DMA xfer, and disable it here - * immediately, or it will be signalled all the time while - * DEBI is idle. - * Note 2: You would think that an irq which is masked is - * not signalled by the hardware. Not so for the SAA7146: - * An irq is signalled as long as the corresponding bit - * in the ISR is set, and disabling irqs just prevents the - * hardware from setting the ISR bit. This means a) that we - * must clear the ISR *after* disabling the irq (which is why - * we must do it here even though saa7146_core did it already), - * and b) that if we were to disable an edge triggered irq - * (like the gpio irqs sadly are) temporarily we would likely - * loose some. This sucks :-( - */ - SAA7146_IER_DISABLE(av7110->dev, MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); - tasklet_schedule(&av7110->debi_tasklet); - } - - if (*isr & MASK_03) { - //printk("av7110_irq: GPIO\n"); - tasklet_schedule(&av7110->gpio_tasklet); - } - - if (*isr & MASK_10) - tasklet_schedule(&av7110->vpe_tasklet); -} - - -static struct saa7146_extension av7110_extension_driver; - -#define MAKE_AV7110_INFO(x_var,x_name) \ -static struct saa7146_pci_extension_data x_var = { \ - .ext_priv = x_name, \ - .ext = &av7110_extension_driver } - -MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); -MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); -MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); -MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); -MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); -MAKE_AV7110_INFO(tts_2_3, "Technotrend/Hauppauge WinTV Nexus-S rev2.3"); -MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); -MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T"); -MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); -MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); -MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), - MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), - MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), - MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), - MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), - MAKE_EXTENSION_PCI(gxs_1_3, 0x13c2, 0x0004), - MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), - MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), - MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), - MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), - MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), - -/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 -/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? - - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - - -static struct saa7146_extension av7110_extension_driver = { - .name = "av7110", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = &pci_tbl[0], - .attach = av7110_attach, - .detach = __devexit_p(av7110_detach), - - .irq_mask = MASK_19 | MASK_03 | MASK_10, - .irq_func = av7110_irq, -}; - - -static int __init av7110_init(void) -{ - int retval; - retval = saa7146_register_extension(&av7110_extension_driver); - return retval; -} - - -static void __exit av7110_exit(void) -{ - saa7146_unregister_extension(&av7110_extension_driver); -} - -module_init(av7110_init); -module_exit(av7110_exit); - -MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by " - "Siemens, Technotrend, Hauppauge"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h deleted file mode 100644 index 88b3b2d6cc0..00000000000 --- a/drivers/media/dvb/ttpci/av7110.h +++ /dev/null @@ -1,314 +0,0 @@ -#ifndef _AV7110_H_ -#define _AV7110_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "dvbdev.h" -#include "demux.h" -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_filter.h" -#include "dvb_net.h" -#include "dvb_ringbuffer.h" -#include "dvb_frontend.h" -#include "ves1820.h" -#include "ves1x93.h" -#include "stv0299.h" -#include "tda8083.h" -#include "sp8870.h" -#include "stv0297.h" -#include "l64781.h" - -#include - - -#define ANALOG_TUNER_VES1820 1 -#define ANALOG_TUNER_STV0297 2 - -extern int av7110_debug; - -#define dprintk(level,args...) \ - do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0) - -#define MAXFILT 32 - -enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; - -enum av7110_video_mode { - AV7110_VIDEO_MODE_PAL = 0, - AV7110_VIDEO_MODE_NTSC = 1 -}; - -struct av7110_p2t { - u8 pes[TS_SIZE]; - u8 counter; - long int pos; - int frags; - struct dvb_demux_feed *feed; -}; - -/* video MPEG decoder events: */ -/* (code copied from dvb_frontend.c, should maybe be factored out...) */ -#define MAX_VIDEO_EVENT 8 -struct dvb_video_events { - struct video_event events[MAX_VIDEO_EVENT]; - int eventw; - int eventr; - int overflow; - wait_queue_head_t wait_queue; - spinlock_t lock; -}; - - -struct av7110; - -/* infrared remote control */ -struct infrared { - u16 key_map[256]; - struct input_dev *input_dev; - char input_phys[32]; - struct timer_list keyup_timer; - struct tasklet_struct ir_tasklet; - void (*ir_handler)(struct av7110 *av7110, u32 ircom); - u32 ir_command; - u32 ir_config; - u32 device_mask; - u8 protocol; - u8 inversion; - u16 last_key; - u16 last_toggle; - u8 delay_timer_finished; -}; - - -/* place to store all the necessary device information */ -struct av7110 { - - /* devices */ - - struct dvb_device dvb_dev; - struct dvb_net dvb_net; - - struct video_device *v4l_dev; - struct video_device *vbi_dev; - - struct saa7146_dev *dev; - - struct i2c_adapter i2c_adap; - - char *card_name; - - /* support for analog module of dvb-c */ - int analog_tuner_flags; - int current_input; - u32 current_freq; - - struct tasklet_struct debi_tasklet; - struct tasklet_struct gpio_tasklet; - - int adac_type; /* audio DAC type */ -#define DVB_ADAC_TI 0 -#define DVB_ADAC_CRYSTAL 1 -#define DVB_ADAC_MSP34x0 2 -#define DVB_ADAC_MSP34x5 3 -#define DVB_ADAC_NONE -1 - - - /* buffers */ - - void *iobuf; /* memory for all buffers */ - struct dvb_ringbuffer avout; /* buffer for video or A/V mux */ -#define AVOUTLEN (128*1024) - struct dvb_ringbuffer aout; /* buffer for audio */ -#define AOUTLEN (64*1024) - void *bmpbuf; -#define BMPLEN (8*32768+1024) - - /* bitmap buffers and states */ - - int bmpp; - int bmplen; - volatile int bmp_state; -#define BMP_NONE 0 -#define BMP_LOADING 1 -#define BMP_LOADED 2 - wait_queue_head_t bmpq; - - - /* DEBI and polled command interface */ - - spinlock_t debilock; - struct mutex dcomlock; - volatile int debitype; - volatile int debilen; - - - /* Recording and playback flags */ - - int rec_mode; - int playing; -#define RP_NONE 0 -#define RP_VIDEO 1 -#define RP_AUDIO 2 -#define RP_AV 3 - - - /* OSD */ - - int osdwin; /* currently active window */ - u16 osdbpp[8]; - struct mutex osd_mutex; - - /* CA */ - - ca_slot_info_t ci_slot[2]; - - enum av7110_video_mode vidmode; - struct dmxdev dmxdev; - struct dvb_demux demux; - - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - - /* for budget mode demux1 */ - struct dmxdev dmxdev1; - struct dvb_demux demux1; - struct dvb_net dvb_net1; - spinlock_t feedlock1; - int feeding1; - u32 ttbp; - unsigned char *grabbing; - struct saa7146_pgtable pt; - struct tasklet_struct vpe_tasklet; - bool full_ts; - - int fe_synced; - struct mutex pid_mutex; - - int video_blank; - struct video_status videostate; - u16 display_panscan; - int display_ar; - int trickmode; -#define TRICK_NONE 0 -#define TRICK_FAST 1 -#define TRICK_SLOW 2 -#define TRICK_FREEZE 3 - struct audio_status audiostate; - - struct dvb_demux_filter *handle2filter[32]; - struct av7110_p2t p2t_filter[MAXFILT]; - struct dvb_filter_pes2ts p2t[2]; - struct ipack ipack[2]; - u8 *kbuf[2]; - - int sinfo; - int feeding; - - int arm_errors; - int registered; - - - /* AV711X */ - - u32 arm_fw; - u32 arm_rtsl; - u32 arm_vid; - u32 arm_app; - u32 avtype; - int arm_ready; - struct task_struct *arm_thread; - wait_queue_head_t arm_wait; - u16 arm_loops; - - void *debi_virt; - dma_addr_t debi_bus; - - u16 pids[DMX_PES_OTHER]; - - struct dvb_ringbuffer ci_rbuffer; - struct dvb_ringbuffer ci_wbuffer; - - struct audio_mixer mixer; - - struct dvb_adapter dvb_adapter; - struct dvb_device *video_dev; - struct dvb_device *audio_dev; - struct dvb_device *ca_dev; - struct dvb_device *osd_dev; - - struct dvb_video_events video_events; - video_size_t video_size; - - u16 wssMode; - u16 wssData; - - struct infrared ir; - - /* firmware stuff */ - unsigned char *bin_fw; - unsigned long size_fw; - - unsigned char *bin_dpram; - unsigned long size_dpram; - - unsigned char *bin_root; - unsigned long size_root; - - struct dvb_frontend* fe; - fe_status_t fe_status; - - /* crash recovery */ - void (*recover)(struct av7110* av7110); - fe_sec_voltage_t saved_voltage; - fe_sec_tone_mode_t saved_tone; - struct dvb_diseqc_master_cmd saved_master_cmd; - fe_sec_mini_cmd_t saved_minicmd; - - int (*fe_init)(struct dvb_frontend* fe); - int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); - int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); - int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); - int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); - int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); - int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); - int (*fe_set_frontend)(struct dvb_frontend *fe); -}; - - -extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, - u16 subpid, u16 pcrpid); - -extern int av7110_check_ir_config(struct av7110 *av7110, int force); -extern int av7110_ir_init(struct av7110 *av7110); -extern void av7110_ir_exit(struct av7110 *av7110); - -/* msp3400 i2c subaddresses */ -#define MSP_WR_DEM 0x10 -#define MSP_RD_DEM 0x11 -#define MSP_WR_DSP 0x12 -#define MSP_RD_DSP 0x13 - -extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val); -extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg); -extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val); - - -extern int av7110_init_analog_module(struct av7110 *av7110); -extern int av7110_init_v4l(struct av7110 *av7110); -extern int av7110_exit_v4l(struct av7110 *av7110); - -#endif /* _AV7110_H_ */ diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c deleted file mode 100644 index 952b33dbac4..00000000000 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * av7110_av.c: audio and video MPEG decoder stuff - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_av.h" -#include "av7110_ipack.h" - -/* MPEG-2 (ISO 13818 / H.222.0) stream types */ -#define PROG_STREAM_MAP 0xBC -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define PTS_DTS_FLAGS 0xC0 - -//pts_dts flags -#define PTS_ONLY 0x80 -#define PTS_DTS 0xC0 -#define TS_SIZE 188 -#define TRANS_ERROR 0x80 -#define PAY_START 0x40 -#define TRANS_PRIO 0x20 -#define PID_MASK_HI 0x1F -//flags -#define TRANS_SCRMBL1 0x80 -#define TRANS_SCRMBL2 0x40 -#define ADAPT_FIELD 0x20 -#define PAYLOAD 0x10 -#define COUNT_MASK 0x0F - -// adaptation flags -#define DISCON_IND 0x80 -#define RAND_ACC_IND 0x40 -#define ES_PRI_IND 0x20 -#define PCR_FLAG 0x10 -#define OPCR_FLAG 0x08 -#define SPLICE_FLAG 0x04 -#define TRANS_PRIV 0x02 -#define ADAP_EXT_FLAG 0x01 - -// adaptation extension flags -#define LTW_FLAG 0x80 -#define PIECE_RATE 0x40 -#define SEAM_SPLICE 0x20 - - -static void p_to_t(u8 const *buf, long int length, u16 pid, - u8 *counter, struct dvb_demux_feed *feed); -static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); - - -int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv; - - if (!(dvbdmxfeed->ts_type & TS_PACKET)) - return 0; - if (buf[3] == 0xe0) // video PES do not have a length in TS - buf[4] = buf[5] = 0; - if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) - return dvbdmxfeed->cb.ts(buf, len, NULL, 0, - &dvbdmxfeed->feed.ts, DMX_OK); - else - return dvb_filter_pes2ts(p2t, buf, len, 1); -} - -static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; - - dvbdmxfeed->cb.ts(data, 188, NULL, 0, - &dvbdmxfeed->feed.ts, DMX_OK); - return 0; -} - -int av7110_av_start_record(struct av7110 *av7110, int av, - struct dvb_demux_feed *dvbdmxfeed) -{ - int ret = 0; - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - - dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); - - if (av7110->playing || (av7110->rec_mode & av)) - return -EBUSY; - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - dvbdmx->recording = 1; - av7110->rec_mode |= av; - - switch (av7110->rec_mode) { - case RP_AUDIO: - dvb_filter_pes2ts_init(&av7110->p2t[0], - dvbdmx->pesfilter[0]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[0]); - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); - break; - - case RP_VIDEO: - dvb_filter_pes2ts_init(&av7110->p2t[1], - dvbdmx->pesfilter[1]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[1]); - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); - break; - - case RP_AV: - dvb_filter_pes2ts_init(&av7110->p2t[0], - dvbdmx->pesfilter[0]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[0]); - dvb_filter_pes2ts_init(&av7110->p2t[1], - dvbdmx->pesfilter[1]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[1]); - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); - break; - } - return ret; -} - -int av7110_av_start_play(struct av7110 *av7110, int av) -{ - int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->rec_mode) - return -EBUSY; - if (av7110->playing & av) - return -EBUSY; - - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - - if (av7110->playing == RP_NONE) { - av7110_ipack_reset(&av7110->ipack[0]); - av7110_ipack_reset(&av7110->ipack[1]); - } - - av7110->playing |= av; - switch (av7110->playing) { - case RP_AUDIO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); - break; - case RP_VIDEO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); - av7110->sinfo = 0; - break; - case RP_AV: - av7110->sinfo = 0; - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); - break; - } - return ret; -} - -int av7110_av_stop(struct av7110 *av7110, int av) -{ - int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); - - if (!(av7110->playing & av) && !(av7110->rec_mode & av)) - return 0; - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - if (av7110->playing) { - av7110->playing &= ~av; - switch (av7110->playing) { - case RP_AUDIO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); - break; - case RP_VIDEO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); - break; - case RP_NONE: - ret = av7110_set_vidmode(av7110, av7110->vidmode); - break; - } - } else { - av7110->rec_mode &= ~av; - switch (av7110->rec_mode) { - case RP_AUDIO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); - break; - case RP_VIDEO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); - break; - case RP_NONE: - break; - } - } - return ret; -} - - -int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) -{ - int len; - u32 sync; - u16 blen; - - if (!dlen) { - wake_up(&buf->queue); - return -1; - } - while (1) { - len = dvb_ringbuffer_avail(buf); - if (len < 6) { - wake_up(&buf->queue); - return -1; - } - sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; - sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; - sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; - sync |= DVB_RINGBUFFER_PEEK(buf, 3); - - if (((sync &~ 0x0f) == 0x000001e0) || - ((sync &~ 0x1f) == 0x000001c0) || - (sync == 0x000001bd)) - break; - printk("resync\n"); - DVB_RINGBUFFER_SKIP(buf, 1); - } - blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; - blen |= DVB_RINGBUFFER_PEEK(buf, 5); - blen += 6; - if (len < blen || blen > dlen) { - //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); - wake_up(&buf->queue); - return -1; - } - - dvb_ringbuffer_read(buf, dest, (size_t) blen); - - dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", - (unsigned long) buf->pread, (unsigned long) buf->pwrite); - wake_up(&buf->queue); - return blen; -} - - -int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) -{ - int err, vol, val, balance = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - av7110->mixer.volume_left = volleft; - av7110->mixer.volume_right = volright; - - switch (av7110->adac_type) { - case DVB_ADAC_TI: - volleft = (volleft * 256) / 1036; - volright = (volright * 256) / 1036; - if (volleft > 0x3f) - volleft = 0x3f; - if (volright > 0x3f) - volright = 0x3f; - if ((err = SendDAC(av7110, 3, 0x80 + volleft))) - return err; - return SendDAC(av7110, 4, volright); - - case DVB_ADAC_CRYSTAL: - volleft = 127 - volleft / 2; - volright = 127 - volright / 2; - i2c_writereg(av7110, 0x20, 0x03, volleft); - i2c_writereg(av7110, 0x20, 0x04, volright); - return 0; - - case DVB_ADAC_MSP34x0: - vol = (volleft > volright) ? volleft : volright; - val = (vol * 0x73 / 255) << 8; - if (vol > 0) - balance = ((volright - volleft) * 127) / vol; - msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ - msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ - return 0; - - case DVB_ADAC_MSP34x5: - vol = (volleft > volright) ? volleft : volright; - val = (vol * 0x73 / 255) << 8; - if (vol > 0) - balance = ((volright - volleft) * 127) / vol; - msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ - return 0; - } - - return 0; -} - -int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) -{ - int ret; - dprintk(2, "av7110:%p, \n", av7110); - - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); - - if (!ret && !av7110->playing) { - ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], - av7110->pids[DMX_PES_AUDIO], - av7110->pids[DMX_PES_TELETEXT], - 0, av7110->pids[DMX_PES_PCR]); - if (!ret) - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - } - return ret; -} - - -static enum av7110_video_mode sw2mode[16] = { - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, -}; - -static int get_video_format(struct av7110 *av7110, u8 *buf, int count) -{ - int i; - int hsize, vsize; - int sw; - u8 *p; - int ret = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->sinfo) - return 0; - for (i = 7; i < count - 10; i++) { - p = buf + i; - if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) - continue; - p += 4; - hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); - vsize = ((p[1] &0x0F) << 8) | (p[2]); - sw = (p[3] & 0x0F); - ret = av7110_set_vidmode(av7110, sw2mode[sw]); - if (!ret) { - dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); - av7110->sinfo = 1; - } - break; - } - return ret; -} - - -/**************************************************************************** - * I/O buffer management and control - ****************************************************************************/ - -static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, - const u8 *buf, unsigned long count) -{ - unsigned long todo = count; - int free; - - while (todo > 0) { - if (dvb_ringbuffer_free(rbuf) < 2048) { - if (wait_event_interruptible(rbuf->queue, - (dvb_ringbuffer_free(rbuf) >= 2048))) - return count - todo; - } - free = dvb_ringbuffer_free(rbuf); - if (free > todo) - free = todo; - dvb_ringbuffer_write(rbuf, buf, free); - todo -= free; - buf += free; - } - - return count - todo; -} - -static void play_video_cb(u8 *buf, int count, void *priv) -{ - struct av7110 *av7110 = (struct av7110 *) priv; - dprintk(2, "av7110:%p, \n", av7110); - - if ((buf[3] & 0xe0) == 0xe0) { - get_video_format(av7110, buf, count); - aux_ring_buffer_write(&av7110->avout, buf, count); - } else - aux_ring_buffer_write(&av7110->aout, buf, count); -} - -static void play_audio_cb(u8 *buf, int count, void *priv) -{ - struct av7110 *av7110 = (struct av7110 *) priv; - dprintk(2, "av7110:%p, \n", av7110); - - aux_ring_buffer_write(&av7110->aout, buf, count); -} - - -#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) - -static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, - unsigned long count, int nonblock, int type) -{ - struct dvb_ringbuffer *rb; - u8 *kb; - unsigned long todo = count; - - dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); - - rb = (type) ? &av7110->avout : &av7110->aout; - kb = av7110->kbuf[type]; - - if (!kb) - return -ENOBUFS; - - if (nonblock && !FREE_COND_TS) - return -EWOULDBLOCK; - - while (todo >= TS_SIZE) { - if (!FREE_COND_TS) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(rb->queue, FREE_COND_TS)) - return count - todo; - } - if (copy_from_user(kb, buf, TS_SIZE)) - return -EFAULT; - write_ts_to_decoder(av7110, type, kb, TS_SIZE); - todo -= TS_SIZE; - buf += TS_SIZE; - } - - return count - todo; -} - - -#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ - dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) - -static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf, - unsigned long count, int nonblock, int type) -{ - unsigned long todo = count, n; - dprintk(2, "av7110:%p, \n", av7110); - - if (!av7110->kbuf[type]) - return -ENOBUFS; - - if (nonblock && !FREE_COND) - return -EWOULDBLOCK; - - while (todo > 0) { - if (!FREE_COND) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(av7110->avout.queue, - FREE_COND)) - return count - todo; - } - n = todo; - if (n > IPACKS * 2) - n = IPACKS * 2; - if (copy_from_user(av7110->kbuf[type], buf, n)) - return -EFAULT; - av7110_ipack_instant_repack(av7110->kbuf[type], n, - &av7110->ipack[type]); - todo -= n; - buf += n; - } - return count - todo; -} - -static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, - unsigned long count, int nonblock, int type) -{ - unsigned long todo = count, n; - dprintk(2, "av7110:%p, \n", av7110); - - if (!av7110->kbuf[type]) - return -ENOBUFS; - - if (nonblock && !FREE_COND) - return -EWOULDBLOCK; - - while (todo > 0) { - if (!FREE_COND) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(av7110->avout.queue, - FREE_COND)) - return count - todo; - } - n = todo; - if (n > IPACKS * 2) - n = IPACKS * 2; - av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); - todo -= n; - buf += n; - } - return count - todo; -} - -static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf, - unsigned long count, int nonblock, int type) -{ - unsigned long todo = count, n; - dprintk(2, "av7110:%p, \n", av7110); - - if (!av7110->kbuf[type]) - return -ENOBUFS; - if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) - return -EWOULDBLOCK; - - while (todo > 0) { - if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(av7110->aout.queue, - (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024))) - return count-todo; - } - n = todo; - if (n > IPACKS * 2) - n = IPACKS * 2; - if (copy_from_user(av7110->kbuf[type], buf, n)) - return -EFAULT; - av7110_ipack_instant_repack(av7110->kbuf[type], n, - &av7110->ipack[type]); - todo -= n; - buf += n; - } - return count - todo; -} - -void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed) -{ - memset(p->pes, 0, TS_SIZE); - p->counter = 0; - p->pos = 0; - p->frags = 0; - if (feed) - p->feed = feed; -} - -static void clear_p2t(struct av7110_p2t *p) -{ - memset(p->pes, 0, TS_SIZE); -// p->counter = 0; - p->pos = 0; - p->frags = 0; -} - - -static int find_pes_header(u8 const *buf, long int length, int *frags) -{ - int c = 0; - int found = 0; - - *frags = 0; - - while (c < length - 3 && !found) { - if (buf[c] == 0x00 && buf[c + 1] == 0x00 && - buf[c + 2] == 0x01) { - switch ( buf[c + 3] ) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - found = 1; - break; - - default: - c++; - break; - } - } else - c++; - } - if (c == length - 3 && !found) { - if (buf[length - 1] == 0x00) - *frags = 1; - if (buf[length - 2] == 0x00 && - buf[length - 1] == 0x00) - *frags = 2; - if (buf[length - 3] == 0x00 && - buf[length - 2] == 0x00 && - buf[length - 1] == 0x01) - *frags = 3; - return -1; - } - - return c; -} - -void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p) -{ - int c, c2, l, add; - int check, rest; - - c = 0; - c2 = 0; - if (p->frags){ - check = 0; - switch(p->frags) { - case 1: - if (buf[c] == 0x00 && buf[c + 1] == 0x01) { - check = 1; - c += 2; - } - break; - case 2: - if (buf[c] == 0x01) { - check = 1; - c++; - } - break; - case 3: - check = 1; - } - if (check) { - switch (buf[c]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - p->pes[0] = 0x00; - p->pes[1] = 0x00; - p->pes[2] = 0x01; - p->pes[3] = buf[c]; - p->pos = 4; - memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos); - c += (TS_SIZE - 4) - p->pos; - p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed); - clear_p2t(p); - break; - - default: - c = 0; - break; - } - } - p->frags = 0; - } - - if (p->pos) { - c2 = find_pes_header(buf + c, length - c, &p->frags); - if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos) - l = c2+c; - else - l = (TS_SIZE - 4) - p->pos; - memcpy(p->pes + p->pos, buf, l); - c += l; - p->pos += l; - p_to_t(p->pes, p->pos, pid, &p->counter, p->feed); - clear_p2t(p); - } - - add = 0; - while (c < length) { - c2 = find_pes_header(buf + c + add, length - c - add, &p->frags); - if (c2 >= 0) { - c2 += c + add; - if (c2 > c){ - p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed); - c = c2; - clear_p2t(p); - add = 0; - } else - add = 1; - } else { - l = length - c; - rest = l % (TS_SIZE - 4); - l -= rest; - p_to_t(buf + c, l, pid, &p->counter, p->feed); - memcpy(p->pes, buf + c + l, rest); - p->pos = rest; - c = length; - } - } -} - - -static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) -{ - int i; - int c = 0; - int fill; - u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 }; - - fill = (TS_SIZE - 4) - length; - if (pes_start) - tshead[1] = 0x40; - if (fill) - tshead[3] = 0x30; - tshead[1] |= (u8)((pid & 0x1F00) >> 8); - tshead[2] |= (u8)(pid & 0x00FF); - tshead[3] |= ((*counter)++ & 0x0F); - memcpy(buf, tshead, 4); - c += 4; - - if (fill) { - buf[4] = fill - 1; - c++; - if (fill > 1) { - buf[5] = 0x00; - c++; - } - for (i = 6; i < fill + 4; i++) { - buf[i] = 0xFF; - c++; - } - } - - return c; -} - - -static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, - struct dvb_demux_feed *feed) -{ - int l, pes_start; - u8 obuf[TS_SIZE]; - long c = 0; - - pes_start = 0; - if (length > 3 && - buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) - switch (buf[3]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - pes_start = 1; - break; - - default: - break; - } - - while (c < length) { - memset(obuf, 0, TS_SIZE); - if (length - c >= (TS_SIZE - 4)){ - l = write_ts_header2(pid, counter, pes_start, - obuf, (TS_SIZE - 4)); - memcpy(obuf + l, buf + c, TS_SIZE - l); - c += TS_SIZE - l; - } else { - l = write_ts_header2(pid, counter, pes_start, - obuf, length - c); - memcpy(obuf + l, buf + c, TS_SIZE - l); - c = length; - } - feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK); - pes_start = 0; - } -} - - -static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) -{ - struct ipack *ipack = &av7110->ipack[type]; - - if (buf[1] & TRANS_ERROR) { - av7110_ipack_reset(ipack); - return -1; - } - - if (!(buf[3] & PAYLOAD)) - return -1; - - if (buf[1] & PAY_START) - av7110_ipack_flush(ipack); - - if (buf[3] & ADAPT_FIELD) { - len -= buf[4] + 1; - buf += buf[4] + 1; - if (!len) - return 0; - } - - av7110_ipack_instant_repack(buf + 4, len - 4, ipack); - return 0; -} - - -int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *av7110 = (struct av7110 *) demux->priv; - - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) - return 0; - - switch (feed->pes_type) { - case 0: - if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - return -EINVAL; - break; - case 1: - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) - return -EINVAL; - break; - default: - return -1; - } - - return write_ts_to_decoder(av7110, feed->pes_type, buf, len); -} - - - -/****************************************************************************** - * Video MPEG decoder events - ******************************************************************************/ -void dvb_video_add_event(struct av7110 *av7110, struct video_event *event) -{ - struct dvb_video_events *events = &av7110->video_events; - int wp; - - spin_lock_bh(&events->lock); - - wp = (events->eventw + 1) % MAX_VIDEO_EVENT; - if (wp == events->eventr) { - events->overflow = 1; - events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; - } - - //FIXME: timestamp? - memcpy(&events->events[events->eventw], event, sizeof(struct video_event)); - events->eventw = wp; - - spin_unlock_bh(&events->lock); - - wake_up_interruptible(&events->wait_queue); -} - - -static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags) -{ - struct dvb_video_events *events = &av7110->video_events; - - if (events->overflow) { - events->overflow = 0; - return -EOVERFLOW; - } - if (events->eventw == events->eventr) { - int ret; - - if (flags & O_NONBLOCK) - return -EWOULDBLOCK; - - ret = wait_event_interruptible(events->wait_queue, - events->eventw != events->eventr); - if (ret < 0) - return ret; - } - - spin_lock_bh(&events->lock); - - memcpy(event, &events->events[events->eventr], - sizeof(struct video_event)); - events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; - - spin_unlock_bh(&events->lock); - - return 0; -} - - -/****************************************************************************** - * DVB device file operations - ******************************************************************************/ - -static unsigned int dvb_video_poll(struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned int mask = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) - poll_wait(file, &av7110->avout.queue, wait); - - poll_wait(file, &av7110->video_events.wait_queue, wait); - - if (av7110->video_events.eventw != av7110->video_events.eventr) - mask = POLLPRI; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - if (av7110->playing) { - if (FREE_COND) - mask |= (POLLOUT | POLLWRNORM); - } else /* if not playing: may play if asked for */ - mask |= (POLLOUT | POLLWRNORM); - } - - return mask; -} - -static ssize_t dvb_video_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned char c; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - return -EPERM; - - if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) - return -EPERM; - - if (get_user(c, buf)) - return -EFAULT; - if (c == 0x47 && count % TS_SIZE == 0) - return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); - else - return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); -} - -static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned int mask = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - poll_wait(file, &av7110->aout.queue, wait); - - if (av7110->playing) { - if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) - mask |= (POLLOUT | POLLWRNORM); - } else /* if not playing: may play if asked for */ - mask = (POLLOUT | POLLWRNORM); - - return mask; -} - -static ssize_t dvb_audio_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned char c; - - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) { - printk(KERN_ERR "not audio source memory\n"); - return -EPERM; - } - - if (get_user(c, buf)) - return -EFAULT; - if (c == 0x47 && count % TS_SIZE == 0) - return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); - else - return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); -} - -static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; - -#define MIN_IFRAME 400000 - -static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) -{ - unsigned i, n; - int progressive = 0; - int match = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - if (!(av7110->playing & RP_VIDEO)) { - if (av7110_av_start_play(av7110, RP_VIDEO) < 0) - return -EBUSY; - } - - /* search in buf for instances of 00 00 01 b5 1? */ - for (i = 0; i < len; i++) { - unsigned char c; - if (get_user(c, buf + i)) - return -EFAULT; - if (match == 5) { - progressive = c & 0x08; - match = 0; - } - if (c == 0x00) { - match = (match == 1 || match == 2) ? 2 : 1; - continue; - } - switch (match++) { - case 2: if (c == 0x01) - continue; - break; - case 3: if (c == 0xb5) - continue; - break; - case 4: if ((c & 0xf0) == 0x10) - continue; - break; - } - match = 0; - } - - /* setting n always > 1, fixes problems when playing stillframes - consisting of I- and P-Frames */ - n = MIN_IFRAME / len + 1; - - /* FIXME: nonblock? */ - dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); - - for (i = 0; i < n; i++) - dvb_play(av7110, buf, len, 0, 1); - - av7110_ipack_flush(&av7110->ipack[1]); - - if (progressive) - return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); - else - return 0; -} - - -static int dvb_video_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned long arg = (unsigned long) parg; - int ret = 0; - - dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && - cmd != VIDEO_GET_SIZE ) { - return -EPERM; - } - } - - switch (cmd) { - case VIDEO_STOP: - av7110->videostate.play_state = VIDEO_STOPPED; - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) - ret = av7110_av_stop(av7110, RP_VIDEO); - else - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, - av7110->videostate.video_blank ? 0 : 1); - if (!ret) - av7110->trickmode = TRICK_NONE; - break; - - case VIDEO_PLAY: - av7110->trickmode = TRICK_NONE; - if (av7110->videostate.play_state == VIDEO_FREEZED) { - av7110->videostate.play_state = VIDEO_PLAYING; - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (ret) - break; - } - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { - if (av7110->playing == RP_AV) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - if (ret) - break; - av7110->playing &= ~RP_VIDEO; - } - ret = av7110_av_start_play(av7110, RP_VIDEO); - } - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (!ret) - av7110->videostate.play_state = VIDEO_PLAYING; - break; - - case VIDEO_FREEZE: - av7110->videostate.play_state = VIDEO_FREEZED; - if (av7110->playing & RP_VIDEO) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); - else - ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); - if (!ret) - av7110->trickmode = TRICK_FREEZE; - break; - - case VIDEO_CONTINUE: - if (av7110->playing & RP_VIDEO) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (!ret) { - av7110->videostate.play_state = VIDEO_PLAYING; - av7110->trickmode = TRICK_NONE; - } - break; - - case VIDEO_SELECT_SOURCE: - av7110->videostate.stream_source = (video_stream_source_t) arg; - break; - - case VIDEO_SET_BLANK: - av7110->videostate.video_blank = (int) arg; - break; - - case VIDEO_GET_STATUS: - memcpy(parg, &av7110->videostate, sizeof(struct video_status)); - break; - - case VIDEO_GET_EVENT: - ret = dvb_video_get_event(av7110, parg, file->f_flags); - break; - - case VIDEO_GET_SIZE: - memcpy(parg, &av7110->video_size, sizeof(video_size_t)); - break; - - case VIDEO_SET_DISPLAY_FORMAT: - { - video_displayformat_t format = (video_displayformat_t) arg; - switch (format) { - case VIDEO_PAN_SCAN: - av7110->display_panscan = VID_PAN_SCAN_PREF; - break; - case VIDEO_LETTER_BOX: - av7110->display_panscan = VID_VC_AND_PS_PREF; - break; - case VIDEO_CENTER_CUT_OUT: - av7110->display_panscan = VID_CENTRE_CUT_PREF; - break; - default: - ret = -EINVAL; - } - if (ret < 0) - break; - av7110->videostate.display_format = format; - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, - 1, av7110->display_panscan); - break; - } - - case VIDEO_SET_FORMAT: - if (arg > 1) { - ret = -EINVAL; - break; - } - av7110->display_ar = arg; - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, - 1, (u16) arg); - break; - - case VIDEO_STILLPICTURE: - { - struct video_still_picture *pic = - (struct video_still_picture *) parg; - av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - ret = play_iframe(av7110, pic->iFrame, pic->size, - file->f_flags & O_NONBLOCK); - break; - } - - case VIDEO_FAST_FORWARD: - //note: arg is ignored by firmware - if (av7110->playing & RP_VIDEO) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); - else - ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); - if (!ret) { - av7110->trickmode = TRICK_FAST; - av7110->videostate.play_state = VIDEO_PLAYING; - } - break; - - case VIDEO_SLOWMOTION: - if (av7110->playing&RP_VIDEO) { - if (av7110->trickmode != TRICK_SLOW) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); - } else { - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); - } - if (!ret) { - av7110->trickmode = TRICK_SLOW; - av7110->videostate.play_state = VIDEO_PLAYING; - } - break; - - case VIDEO_GET_CAPABILITIES: - *(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 | - VIDEO_CAP_SYS | VIDEO_CAP_PROG; - break; - - case VIDEO_CLEAR_BUFFER: - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - av7110_ipack_reset(&av7110->ipack[1]); - if (av7110->playing == RP_AV) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); - if (ret) - break; - if (av7110->trickmode == TRICK_FAST) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); - if (av7110->trickmode == TRICK_SLOW) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Slow, 2, 0, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); - } - if (av7110->trickmode == TRICK_FREEZE) - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); - } - break; - - case VIDEO_SET_STREAMTYPE: - break; - - default: - ret = -ENOIOCTLCMD; - break; - } - - return ret; -} - -static int dvb_audio_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned long arg = (unsigned long) parg; - int ret = 0; - - dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); - - if (((file->f_flags & O_ACCMODE) == O_RDONLY) && - (cmd != AUDIO_GET_STATUS)) - return -EPERM; - - switch (cmd) { - case AUDIO_STOP: - if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - ret = av7110_av_stop(av7110, RP_AUDIO); - else - ret = audcom(av7110, AUDIO_CMD_MUTE); - if (!ret) - av7110->audiostate.play_state = AUDIO_STOPPED; - break; - - case AUDIO_PLAY: - if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - ret = av7110_av_start_play(av7110, RP_AUDIO); - if (!ret) - ret = audcom(av7110, AUDIO_CMD_UNMUTE); - if (!ret) - av7110->audiostate.play_state = AUDIO_PLAYING; - break; - - case AUDIO_PAUSE: - ret = audcom(av7110, AUDIO_CMD_MUTE); - if (!ret) - av7110->audiostate.play_state = AUDIO_PAUSED; - break; - - case AUDIO_CONTINUE: - if (av7110->audiostate.play_state == AUDIO_PAUSED) { - av7110->audiostate.play_state = AUDIO_PLAYING; - ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); - } - break; - - case AUDIO_SELECT_SOURCE: - av7110->audiostate.stream_source = (audio_stream_source_t) arg; - break; - - case AUDIO_SET_MUTE: - { - ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); - if (!ret) - av7110->audiostate.mute_state = (int) arg; - break; - } - - case AUDIO_SET_AV_SYNC: - av7110->audiostate.AV_sync_state = (int) arg; - ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); - break; - - case AUDIO_SET_BYPASS_MODE: - if (FW_VERSION(av7110->arm_app) < 0x2621) - ret = -EINVAL; - av7110->audiostate.bypass_mode = (int)arg; - break; - - case AUDIO_CHANNEL_SELECT: - av7110->audiostate.channel_select = (audio_channel_select_t) arg; - switch(av7110->audiostate.channel_select) { - case AUDIO_STEREO: - ret = audcom(av7110, AUDIO_CMD_STEREO); - if (!ret) { - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x49); - else if (av7110->adac_type == DVB_ADAC_MSP34x5) - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); - } - break; - case AUDIO_MONO_LEFT: - ret = audcom(av7110, AUDIO_CMD_MONO_L); - if (!ret) { - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x4a); - else if (av7110->adac_type == DVB_ADAC_MSP34x5) - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); - } - break; - case AUDIO_MONO_RIGHT: - ret = audcom(av7110, AUDIO_CMD_MONO_R); - if (!ret) { - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x45); - else if (av7110->adac_type == DVB_ADAC_MSP34x5) - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); - } - break; - default: - ret = -EINVAL; - break; - } - break; - - case AUDIO_GET_STATUS: - memcpy(parg, &av7110->audiostate, sizeof(struct audio_status)); - break; - - case AUDIO_GET_CAPABILITIES: - if (FW_VERSION(av7110->arm_app) < 0x2621) - *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; - else - *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | - AUDIO_CAP_MP1 | AUDIO_CAP_MP2; - break; - - case AUDIO_CLEAR_BUFFER: - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - av7110_ipack_reset(&av7110->ipack[0]); - if (av7110->playing == RP_AV) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); - break; - - case AUDIO_SET_ID: - break; - - case AUDIO_SET_MIXER: - { - struct audio_mixer *amix = (struct audio_mixer *)parg; - ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); - break; - } - - case AUDIO_SET_STREAMTYPE: - break; - - default: - ret = -ENOIOCTLCMD; - } - - return ret; -} - - -static int dvb_video_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - int err; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((err = dvb_generic_open(inode, file)) < 0) - return err; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - av7110->video_blank = 1; - av7110->audiostate.AV_sync_state = 1; - av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; - - /* empty event queue */ - av7110->video_events.eventr = av7110->video_events.eventw = 0; - } - - return 0; -} - -static int dvb_video_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - av7110_av_stop(av7110, RP_VIDEO); - } - - return dvb_generic_release(inode, file); -} - -static int dvb_audio_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - int err = dvb_generic_open(inode, file); - - dprintk(2, "av7110:%p, \n", av7110); - - if (err < 0) - return err; - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; - return 0; -} - -static int dvb_audio_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(2, "av7110:%p, \n", av7110); - - av7110_av_stop(av7110, RP_AUDIO); - return dvb_generic_release(inode, file); -} - - - -/****************************************************************************** - * driver registration - ******************************************************************************/ - -static const struct file_operations dvb_video_fops = { - .owner = THIS_MODULE, - .write = dvb_video_write, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_video_open, - .release = dvb_video_release, - .poll = dvb_video_poll, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_video = { - .priv = NULL, - .users = 6, - .readers = 5, /* arbitrary */ - .writers = 1, - .fops = &dvb_video_fops, - .kernel_ioctl = dvb_video_ioctl, -}; - -static const struct file_operations dvb_audio_fops = { - .owner = THIS_MODULE, - .write = dvb_audio_write, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_audio_open, - .release = dvb_audio_release, - .poll = dvb_audio_poll, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_audio = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_audio_fops, - .kernel_ioctl = dvb_audio_ioctl, -}; - - -int av7110_av_register(struct av7110 *av7110) -{ - av7110->audiostate.AV_sync_state = 0; - av7110->audiostate.mute_state = 0; - av7110->audiostate.play_state = AUDIO_STOPPED; - av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; - av7110->audiostate.channel_select = AUDIO_STEREO; - av7110->audiostate.bypass_mode = 0; - - av7110->videostate.video_blank = 0; - av7110->videostate.play_state = VIDEO_STOPPED; - av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; - av7110->videostate.video_format = VIDEO_FORMAT_4_3; - av7110->videostate.display_format = VIDEO_LETTER_BOX; - av7110->display_ar = VIDEO_FORMAT_4_3; - av7110->display_panscan = VID_VC_AND_PS_PREF; - - init_waitqueue_head(&av7110->video_events.wait_queue); - spin_lock_init(&av7110->video_events.lock); - av7110->video_events.eventw = av7110->video_events.eventr = 0; - av7110->video_events.overflow = 0; - memset(&av7110->video_size, 0, sizeof (video_size_t)); - - dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, - &dvbdev_video, av7110, DVB_DEVICE_VIDEO); - - dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, - &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); - - return 0; -} - -void av7110_av_unregister(struct av7110 *av7110) -{ - dvb_unregister_device(av7110->audio_dev); - dvb_unregister_device(av7110->video_dev); -} - -int av7110_av_init(struct av7110 *av7110) -{ - void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; - int i, ret; - - for (i = 0; i < 2; i++) { - struct ipack *ipack = av7110->ipack + i; - - ret = av7110_ipack_init(ipack, IPACKS, play[i]); - if (ret < 0) { - if (i) - av7110_ipack_free(--ipack); - goto out; - } - ipack->data = av7110; - } - - dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN); - dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN); - - av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN); - av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS; -out: - return ret; -} - -void av7110_av_exit(struct av7110 *av7110) -{ - av7110_ipack_free(&av7110->ipack[0]); - av7110_ipack_free(&av7110->ipack[1]); -} diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h deleted file mode 100644 index 5f02ef85e47..00000000000 --- a/drivers/media/dvb/ttpci/av7110_av.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _AV7110_AV_H_ -#define _AV7110_AV_H_ - -struct av7110; - -extern int av7110_set_vidmode(struct av7110 *av7110, - enum av7110_video_mode mode); - -extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); -extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); -extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); - -extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); -extern int av7110_av_stop(struct av7110 *av7110, int av); -extern int av7110_av_start_record(struct av7110 *av7110, int av, - struct dvb_demux_feed *dvbdmxfeed); -extern int av7110_av_start_play(struct av7110 *av7110, int av); - -extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event); - -extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed); -extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p); - -extern int av7110_av_register(struct av7110 *av7110); -extern void av7110_av_unregister(struct av7110 *av7110); -extern int av7110_av_init(struct av7110 *av7110); -extern void av7110_av_exit(struct av7110 *av7110); - - -#endif /* _AV7110_AV_H_ */ diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c deleted file mode 100644 index 9fc1dd0ba4c..00000000000 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * av7110_ca.c: CA and CI stuff - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_ca.h" - - -void CI_handle(struct av7110 *av7110, u8 *data, u16 len) -{ - dprintk(8, "av7110:%p\n",av7110); - - if (len < 3) - return; - switch (data[0]) { - case CI_MSG_CI_INFO: - if (data[2] != 1 && data[2] != 2) - break; - switch (data[1]) { - case 0: - av7110->ci_slot[data[2] - 1].flags = 0; - break; - case 1: - av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT; - break; - case 2: - av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY; - break; - } - break; - case CI_SWITCH_PRG_REPLY: - //av7110->ci_stat=data[1]; - break; - default: - break; - } -} - - -void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len) -{ - if (dvb_ringbuffer_free(cibuf) < len + 2) - return; - - DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8); - DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); - dvb_ringbuffer_write(cibuf, data, len); - wake_up_interruptible(&cibuf->queue); -} - - -/****************************************************************************** - * CI link layer file ops - ******************************************************************************/ - -static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) -{ - struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p; - void *data; - - for (p = tab; *p; p++) { - data = vmalloc(size); - if (!data) { - while (p-- != tab) { - vfree(p[0]->data); - p[0]->data = NULL; - } - return -ENOMEM; - } - dvb_ringbuffer_init(*p, data, size); - } - return 0; -} - -static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) -{ - dvb_ringbuffer_flush_spinlock_wakeup(cirbuf); - dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf); -} - -static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) -{ - vfree(cirbuf->data); - cirbuf->data = NULL; - vfree(ciwbuf->data); - ciwbuf->data = NULL; -} - -static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, - int slots, ca_slot_info_t *slot) -{ - int i; - int len = 0; - u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 }; - - for (i = 0; i < 2; i++) { - if (slots & (1 << i)) - len += 8; - } - - if (dvb_ringbuffer_free(cibuf) < len) - return -EBUSY; - - for (i = 0; i < 2; i++) { - if (slots & (1 << i)) { - msg[2] = i; - dvb_ringbuffer_write(cibuf, msg, 8); - slot[i].flags = 0; - } - } - - return 0; -} - -static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - int free; - int non_blocking = file->f_flags & O_NONBLOCK; - u8 *page = (u8 *)__get_free_page(GFP_USER); - int res; - - if (!page) - return -ENOMEM; - - res = -EINVAL; - if (count > 2048) - goto out; - - res = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out; - - free = dvb_ringbuffer_free(cibuf); - if (count + 2 > free) { - res = -EWOULDBLOCK; - if (non_blocking) - goto out; - res = -ERESTARTSYS; - if (wait_event_interruptible(cibuf->queue, - (dvb_ringbuffer_free(cibuf) >= count + 2))) - goto out; - } - - DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); - DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); - - res = dvb_ringbuffer_write(cibuf, page, count); -out: - free_page((unsigned long)page); - return res; -} - -static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, - char __user *buf, size_t count, loff_t *ppos) -{ - int avail; - int non_blocking = file->f_flags & O_NONBLOCK; - ssize_t len; - - if (!cibuf->data || !count) - return 0; - if (non_blocking && (dvb_ringbuffer_empty(cibuf))) - return -EWOULDBLOCK; - if (wait_event_interruptible(cibuf->queue, - !dvb_ringbuffer_empty(cibuf))) - return -ERESTARTSYS; - avail = dvb_ringbuffer_avail(cibuf); - if (avail < 4) - return 0; - len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; - len |= DVB_RINGBUFFER_PEEK(cibuf, 1); - if (avail < len + 2 || count < len) - return -EINVAL; - DVB_RINGBUFFER_SKIP(cibuf, 2); - - return dvb_ringbuffer_read_user(cibuf, buf, len); -} - -static int dvb_ca_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - int err = dvb_generic_open(inode, file); - - dprintk(8, "av7110:%p\n",av7110); - - if (err < 0) - return err; - ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer); - return 0; -} - -static unsigned int dvb_ca_poll (struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer; - struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer; - unsigned int mask = 0; - - dprintk(8, "av7110:%p\n",av7110); - - poll_wait(file, &rbuf->queue, wait); - poll_wait(file, &wbuf->queue, wait); - - if (!dvb_ringbuffer_empty(rbuf)) - mask |= (POLLIN | POLLRDNORM); - - if (dvb_ringbuffer_free(wbuf) > 1024) - mask |= (POLLOUT | POLLWRNORM); - - return mask; -} - -static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned long arg = (unsigned long) parg; - - dprintk(8, "av7110:%p\n",av7110); - - switch (cmd) { - case CA_RESET: - return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]); - break; - case CA_GET_CAP: - { - ca_caps_t cap; - - cap.slot_num = 2; - cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? - CA_CI_LINK : CA_CI) | CA_DESCR; - cap.descr_num = 16; - cap.descr_type = CA_ECD; - memcpy(parg, &cap, sizeof(cap)); - break; - } - - case CA_GET_SLOT_INFO: - { - ca_slot_info_t *info=(ca_slot_info_t *)parg; - - if (info->num < 0 || info->num > 1) - return -EINVAL; - av7110->ci_slot[info->num].num = info->num; - av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? - CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); - break; - } - - case CA_GET_MSG: - break; - - case CA_SEND_MSG: - break; - - case CA_GET_DESCR_INFO: - { - ca_descr_info_t info; - - info.num = 16; - info.type = CA_ECD; - memcpy(parg, &info, sizeof (info)); - break; - } - - case CA_SET_DESCR: - { - ca_descr_t *descr = (ca_descr_t*) parg; - - if (descr->index >= 16) - return -EINVAL; - if (descr->parity > 1) - return -EINVAL; - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5, - (descr->index<<8)|descr->parity, - (descr->cw[0]<<8)|descr->cw[1], - (descr->cw[2]<<8)|descr->cw[3], - (descr->cw[4]<<8)|descr->cw[5], - (descr->cw[6]<<8)|descr->cw[7]); - break; - } - - default: - return -EINVAL; - } - return 0; -} - -static ssize_t dvb_ca_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(8, "av7110:%p\n",av7110); - return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); -} - -static ssize_t dvb_ca_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(8, "av7110:%p\n",av7110); - return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos); -} - -static const struct file_operations dvb_ca_fops = { - .owner = THIS_MODULE, - .read = dvb_ca_read, - .write = dvb_ca_write, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_ca_open, - .release = dvb_generic_release, - .poll = dvb_ca_poll, - .llseek = default_llseek, -}; - -static struct dvb_device dvbdev_ca = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_ca_fops, - .kernel_ioctl = dvb_ca_ioctl, -}; - - -int av7110_ca_register(struct av7110 *av7110) -{ - return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, - &dvbdev_ca, av7110, DVB_DEVICE_CA); -} - -void av7110_ca_unregister(struct av7110 *av7110) -{ - dvb_unregister_device(av7110->ca_dev); -} - -int av7110_ca_init(struct av7110* av7110) -{ - return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192); -} - -void av7110_ca_exit(struct av7110* av7110) -{ - ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer); -} diff --git a/drivers/media/dvb/ttpci/av7110_ca.h b/drivers/media/dvb/ttpci/av7110_ca.h deleted file mode 100644 index 70ee855ece1..00000000000 --- a/drivers/media/dvb/ttpci/av7110_ca.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _AV7110_CA_H_ -#define _AV7110_CA_H_ - -struct av7110; - -extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len); -extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len); - -extern int av7110_ca_register(struct av7110 *av7110); -extern void av7110_ca_unregister(struct av7110 *av7110); -extern int av7110_ca_init(struct av7110* av7110); -extern void av7110_ca_exit(struct av7110* av7110); - -#endif /* _AV7110_CA_H_ */ diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c deleted file mode 100644 index f1cbfe52698..00000000000 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ /dev/null @@ -1,1208 +0,0 @@ -/* - * av7110_hw.c: av7110 low level hardware access and firmware interface - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * the project's page is at http://www.linuxtv.org/ - */ - -/* for debugging ARM communication: */ -//#define COM_DEBUG - -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" - -#define _NOHANDSHAKE - -/**************************************************************************** - * DEBI functions - ****************************************************************************/ - -/* This DEBI code is based on the Stradis driver - by Nathan Laredo */ - -int av7110_debiwrite(struct av7110 *av7110, u32 config, - int addr, u32 val, int count) -{ - struct saa7146_dev *dev = av7110->dev; - - if (count <= 0 || count > 32764) { - printk("%s: invalid count %d\n", __func__, count); - return -1; - } - if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { - printk("%s: wait_for_debi_done failed\n", __func__); - return -1; - } - saa7146_write(dev, DEBI_CONFIG, config); - if (count <= 4) /* immediate transfer */ - saa7146_write(dev, DEBI_AD, val); - else /* block transfer */ - saa7146_write(dev, DEBI_AD, av7110->debi_bus); - saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); - saa7146_write(dev, MC2, (2 << 16) | 2); - return 0; -} - -u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count) -{ - struct saa7146_dev *dev = av7110->dev; - u32 result = 0; - - if (count > 32764 || count <= 0) { - printk("%s: invalid count %d\n", __func__, count); - return 0; - } - if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { - printk("%s: wait_for_debi_done #1 failed\n", __func__); - return 0; - } - saa7146_write(dev, DEBI_AD, av7110->debi_bus); - saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); - - saa7146_write(dev, DEBI_CONFIG, config); - saa7146_write(dev, MC2, (2 << 16) | 2); - if (count > 4) - return count; - if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { - printk("%s: wait_for_debi_done #2 failed\n", __func__); - return 0; - } - - result = saa7146_read(dev, DEBI_AD); - result &= (0xffffffffUL >> ((4 - count) * 8)); - return result; -} - - - -/* av7110 ARM core boot stuff */ -#if 0 -void av7110_reset_arm(struct av7110 *av7110) -{ - saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); - - /* Disable DEBI and GPIO irq */ - SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - - saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI); - msleep(30); /* the firmware needs some time to initialize */ - - ARM_ResetMailBox(av7110); - - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - SAA7146_IER_ENABLE(av7110->dev, MASK_03); - - av7110->arm_ready = 1; - dprintk(1, "reset ARM\n"); -} -#endif /* 0 */ - -static int waitdebi(struct av7110 *av7110, int adr, int state) -{ - int k; - - dprintk(4, "%p\n", av7110); - - for (k = 0; k < 100; k++) { - if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state) - return 0; - udelay(5); - } - return -ETIMEDOUT; -} - -static int load_dram(struct av7110 *av7110, u32 *data, int len) -{ - int i; - int blocks, rest; - u32 base, bootblock = AV7110_BOOT_BLOCK; - - dprintk(4, "%p\n", av7110); - - blocks = len / AV7110_BOOT_MAX_SIZE; - rest = len % AV7110_BOOT_MAX_SIZE; - base = DRAM_START_CODE; - - for (i = 0; i < blocks; i++) { - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); - return -ETIMEDOUT; - } - dprintk(4, "writing DRAM block %d\n", i); - mwdebi(av7110, DEBISWAB, bootblock, - ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); - bootblock ^= 0x1400; - iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - base += AV7110_BOOT_MAX_SIZE; - } - - if (rest > 0) { - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); - return -ETIMEDOUT; - } - if (rest > 4) - mwdebi(av7110, DEBISWAB, bootblock, - ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); - else - mwdebi(av7110, DEBISWAB, bootblock, - ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); - - iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - } - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); - return -ETIMEDOUT; - } - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); - return -ETIMEDOUT; - } - return 0; -} - - -/* we cannot write av7110 DRAM directly, so load a bootloader into - * the DPRAM which implements a simple boot protocol */ -int av7110_bootarm(struct av7110 *av7110) -{ - const struct firmware *fw; - const char *fw_name = "av7110/bootcode.bin"; - struct saa7146_dev *dev = av7110->dev; - u32 ret; - int i; - - dprintk(4, "%p\n", av7110); - - av7110->arm_ready = 0; - - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); - - /* Disable DEBI and GPIO irq */ - SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - - /* enable DEBI */ - saa7146_write(av7110->dev, MC1, 0x08800880); - saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); - saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - /* test DEBI */ - iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); - /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */ - iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); - - if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { - printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: " - "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", - ret, 0x10325476); - return -1; - } - for (i = 0; i < 8192; i += 4) - iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4); - dprintk(2, "debi test OK\n"); - - /* boot */ - dprintk(1, "load boot code\n"); - saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO); - //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT); - //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); - - ret = request_firmware(&fw, fw_name, &dev->pci->dev); - if (ret) { - printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n", - fw_name); - return ret; - } - - mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size); - release_firmware(fw); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - - if (saa7146_wait_for_debi_done(av7110->dev, 1)) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "saa7146_wait_for_debi_done() timed out\n"); - return -ETIMEDOUT; - } - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); - mdelay(1); - - dprintk(1, "load dram code\n"); - if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "load_dram() failed\n"); - return -1; - } - - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); - mdelay(1); - - dprintk(1, "load dpram code\n"); - mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); - - if (saa7146_wait_for_debi_done(av7110->dev, 1)) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); - return -ETIMEDOUT; - } - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); - msleep(30); /* the firmware needs some time to initialize */ - - //ARM_ClearIrq(av7110); - ARM_ResetMailBox(av7110); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - SAA7146_IER_ENABLE(av7110->dev, MASK_03); - - av7110->arm_errors = 0; - av7110->arm_ready = 1; - return 0; -} -MODULE_FIRMWARE("av7110/bootcode.bin"); - -/**************************************************************************** - * DEBI command polling - ****************************************************************************/ - -int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) -{ - unsigned long start; - u32 stat; - int err; - - if (FW_VERSION(av7110->arm_app) <= 0x261c) { - /* not supported by old firmware */ - msleep(50); - return 0; - } - - /* new firmware */ - start = jiffies; - for (;;) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - mutex_unlock(&av7110->dcomlock); - if ((stat & flags) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", - __func__, stat & flags); - return -ETIMEDOUT; - } - msleep(1); - } - return 0; -} - -static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) -{ - int i; - unsigned long start; - char *type = NULL; - u16 flags[2] = {0, 0}; - u32 stat; - int err; - -// dprintk(4, "%p\n", av7110); - - if (!av7110->arm_ready) { - dprintk(1, "arm not ready.\n"); - return -ENXIO; - } - - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__); - av7110->arm_errors++; - return -ETIMEDOUT; - } - msleep(1); - } - - if (FW_VERSION(av7110->arm_app) <= 0x261f) - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); - -#ifndef _NOHANDSHAKE - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_SHAKE); - if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__); - return -ETIMEDOUT; - } - msleep(1); - } -#endif - - switch ((buf[0] >> 8) & 0xff) { - case COMTYPE_PIDFILTER: - case COMTYPE_ENCODER: - case COMTYPE_REC_PLAY: - case COMTYPE_MPEGDECODER: - type = "MSG"; - flags[0] = GPMQOver; - flags[1] = GPMQFull; - break; - case COMTYPE_OSD: - type = "OSD"; - flags[0] = OSDQOver; - flags[1] = OSDQFull; - break; - case COMTYPE_MISC: - if (FW_VERSION(av7110->arm_app) >= 0x261d) { - type = "MSG"; - flags[0] = GPMQOver; - flags[1] = GPMQBusy; - } - break; - default: - break; - } - - if (type != NULL) { - /* non-immediate COMMAND type */ - start = jiffies; - for (;;) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - if (stat & flags[0]) { - printk(KERN_ERR "%s: %s QUEUE overflow\n", - __func__, type); - return -1; - } - if ((stat & flags[1]) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", - __func__, type); - av7110->arm_errors++; - return -ETIMEDOUT; - } - msleep(1); - } - } - - for (i = 2; i < length; i++) - wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2); - - if (length) - wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); - else - wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); - - wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); - - if (FW_VERSION(av7110->arm_app) <= 0x261f) - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); - -#ifdef COM_DEBUG - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", - __func__, (buf[0] >> 8) & 0xff); - return -ETIMEDOUT; - } - msleep(1); - } - - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - if (stat & GPMQOver) { - printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__); - return -ENOSPC; - } - else if (stat & OSDQOver) { - printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__); - return -ENOSPC; - } -#endif - - return 0; -} - -static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) -{ - int ret; - -// dprintk(4, "%p\n", av7110); - - if (!av7110->arm_ready) { - dprintk(1, "arm not ready.\n"); - return -1; - } - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - - ret = __av7110_send_fw_cmd(av7110, buf, length); - mutex_unlock(&av7110->dcomlock); - if (ret && ret!=-ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", - __func__, ret); - return ret; -} - -int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) -{ - va_list args; - u16 buf[num + 2]; - int i, ret; - -// dprintk(4, "%p\n", av7110); - - buf[0] = ((type << 8) | com); - buf[1] = num; - - if (num) { - va_start(args, num); - for (i = 0; i < num; i++) - buf[i + 2] = va_arg(args, u32); - va_end(args); - } - - ret = av7110_send_fw_cmd(av7110, buf, num + 2); - if (ret && ret != -ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); - return ret; -} - -#if 0 -int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) -{ - int i, ret; - u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom), - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - dprintk(4, "%p\n", av7110); - - for(i = 0; i < len && i < 32; i++) - { - if(i % 2 == 0) - cmd[(i / 2) + 2] = (u16)(buf[i]) << 8; - else - cmd[(i / 2) + 2] |= buf[i]; - } - - ret = av7110_send_fw_cmd(av7110, cmd, 18); - if (ret && ret != -ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); - return ret; -} -#endif /* 0 */ - -int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, - int request_buf_len, u16 *reply_buf, int reply_buf_len) -{ - int err; - s16 i; - unsigned long start; -#ifdef COM_DEBUG - u32 stat; -#endif - - dprintk(4, "%p\n", av7110); - - if (!av7110->arm_ready) { - dprintk(1, "arm not ready.\n"); - return -1; - } - - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - - if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { - mutex_unlock(&av7110->dcomlock); - printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); - return err; - } - - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } -#ifdef _NOHANDSHAKE - msleep(1); -#endif - } - -#ifndef _NOHANDSHAKE - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_SHAKE); - if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } -#endif - -#ifdef COM_DEBUG - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - if (stat & GPMQOver) { - printk(KERN_ERR "%s: GPMQOver\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -1; - } - else if (stat & OSDQOver) { - printk(KERN_ERR "%s: OSDQOver\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -1; - } -#endif - - for (i = 0; i < reply_buf_len; i++) - reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2); - - mutex_unlock(&av7110->dcomlock); - return 0; -} - -static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) -{ - int ret; - ret = av7110_fw_request(av7110, &tag, 0, buf, length); - if (ret) - printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); - return ret; -} - - -/**************************************************************************** - * Firmware commands - ****************************************************************************/ - -/* get version of the firmware ROM, RTSL, video ucode and ARM application */ -int av7110_firmversion(struct av7110 *av7110) -{ - u16 buf[20]; - u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion); - - dprintk(4, "%p\n", av7110); - - if (av7110_fw_query(av7110, tag, buf, 16)) { - printk("dvb-ttpci: failed to boot firmware @ card %d\n", - av7110->dvb_adapter.num); - return -EIO; - } - - av7110->arm_fw = (buf[0] << 16) + buf[1]; - av7110->arm_rtsl = (buf[2] << 16) + buf[3]; - av7110->arm_vid = (buf[4] << 16) + buf[5]; - av7110->arm_app = (buf[6] << 16) + buf[7]; - av7110->avtype = (buf[8] << 16) + buf[9]; - - printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", - av7110->dvb_adapter.num, av7110->arm_fw, - av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); - - /* print firmware capabilities */ - if (FW_CI_LL_SUPPORT(av7110->arm_app)) - printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", - av7110->dvb_adapter.num); - else - printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", - av7110->dvb_adapter.num); - - return 0; -} - - -int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) -{ - int i, ret; - u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - dprintk(4, "%p\n", av7110); - - if (len > 10) - len = 10; - - buf[1] = len + 2; - buf[2] = len; - - if (burst != -1) - buf[3] = burst ? 0x01 : 0x00; - else - buf[3] = 0xffff; - - for (i = 0; i < len; i++) - buf[i + 4] = msg[i]; - - ret = av7110_send_fw_cmd(av7110, buf, 18); - if (ret && ret!=-ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); - return ret; -} - - -#ifdef CONFIG_DVB_AV7110_OSD - -static inline int SetColorBlend(struct av7110 *av7110, u8 windownr) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr); -} - -static inline int SetBlend_(struct av7110 *av7110, u8 windownr, - enum av7110_osd_palette_type colordepth, u16 index, u8 blending) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4, - windownr, colordepth, index, blending); -} - -static inline int SetColor_(struct av7110 *av7110, u8 windownr, - enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5, - windownr, colordepth, index, colorhi, colorlo); -} - -static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, - u16 colorfg, u16 colorbg) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4, - windownr, fontsize, colorfg, colorbg); -} - -static int FlushText(struct av7110 *av7110) -{ - unsigned long start; - int err; - - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_OSD); - if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", - __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } - mutex_unlock(&av7110->dcomlock); - return 0; -} - -static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) -{ - int i, ret; - unsigned long start; - int length = strlen(buf) + 1; - u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y }; - - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - - start = jiffies; - while (1) { - ret = time_after(jiffies, start + ARM_WAIT_OSD); - if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) - break; - if (ret) { - printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", - __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } -#ifndef _NOHANDSHAKE - start = jiffies; - while (1) { - ret = time_after(jiffies, start + ARM_WAIT_SHAKE); - if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) - break; - if (ret) { - printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", - __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } -#endif - for (i = 0; i < length / 2; i++) - wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, - swab16(*(u16 *)(buf + 2 * i)), 2); - if (length & 1) - wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); - ret = __av7110_send_fw_cmd(av7110, cbuf, 5); - mutex_unlock(&av7110->dcomlock); - if (ret && ret!=-ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); - return ret; -} - -static inline int DrawLine(struct av7110 *av7110, u8 windownr, - u16 x, u16 y, u16 dx, u16 dy, u16 color) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6, - windownr, x, y, dx, dy, color); -} - -static inline int DrawBlock(struct av7110 *av7110, u8 windownr, - u16 x, u16 y, u16 dx, u16 dy, u16 color) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6, - windownr, x, y, dx, dy, color); -} - -static inline int HideWindow(struct av7110 *av7110, u8 windownr) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr); -} - -static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y); -} - -static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y); -} - -static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr); -} - -static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr, - osd_raw_window_t disptype, - u16 width, u16 height) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4, - windownr, disptype, width, height); -} - - -static enum av7110_osd_palette_type bpp2pal[8] = { - Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit -}; -static osd_raw_window_t bpp2bit[8] = { - OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 -}; - -static inline int WaitUntilBmpLoaded(struct av7110 *av7110) -{ - int ret = wait_event_timeout(av7110->bmpq, - av7110->bmp_state != BMP_LOADING, 10*HZ); - if (ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", - ret, av7110->bmp_state); - av7110->bmp_state = BMP_NONE; - return -ETIMEDOUT; - } - return 0; -} - -static inline int LoadBitmap(struct av7110 *av7110, - u16 dx, u16 dy, int inc, u8 __user * data) -{ - u16 format; - int bpp; - int i; - int d, delta; - u8 c; - int ret; - - dprintk(4, "%p\n", av7110); - - format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; - - av7110->bmp_state = BMP_LOADING; - if (format == OSD_BITMAP8) { - bpp=8; delta = 1; - } else if (format == OSD_BITMAP4) { - bpp=4; delta = 2; - } else if (format == OSD_BITMAP2) { - bpp=2; delta = 4; - } else if (format == OSD_BITMAP1) { - bpp=1; delta = 8; - } else { - av7110->bmp_state = BMP_NONE; - return -EINVAL; - } - av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; - av7110->bmpp = 0; - if (av7110->bmplen > 32768) { - av7110->bmp_state = BMP_NONE; - return -EINVAL; - } - for (i = 0; i < dy; i++) { - if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { - av7110->bmp_state = BMP_NONE; - return -EINVAL; - } - } - if (format != OSD_BITMAP8) { - for (i = 0; i < dx * dy / delta; i++) { - c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1]; - for (d = delta - 2; d >= 0; d--) { - c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d] - << ((delta - d - 1) * bpp)); - ((u8 *)av7110->bmpbuf)[1024 + i] = c; - } - } - } - av7110->bmplen += 1024; - dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); - ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); - if (!ret) - ret = WaitUntilBmpLoaded(av7110); - return ret; -} - -static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) -{ - dprintk(4, "%p\n", av7110); - - return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); -} - -static inline int ReleaseBitmap(struct av7110 *av7110) -{ - dprintk(4, "%p\n", av7110); - - if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) - return -1; - if (av7110->bmp_state == BMP_LOADING) - dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); - av7110->bmp_state = BMP_NONE; - return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); -} - -static u32 RGB2YUV(u16 R, u16 G, u16 B) -{ - u16 y, u, v; - u16 Y, Cr, Cb; - - y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */ - u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */ - v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */ - - Y = y / 256; - Cb = u / 16; - Cr = v / 16; - - return Cr | (Cb << 16) | (Y << 8); -} - -static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) -{ - int ret; - - u16 ch, cl; - u32 yuv; - - yuv = blend ? RGB2YUV(r,g,b) : 0; - cl = (yuv & 0xffff); - ch = ((yuv >> 16) & 0xffff); - ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ch, cl); - if (!ret) - ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ((blend >> 4) & 0x0f)); - return ret; -} - -static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) -{ - int i; - int length = last - first + 1; - - if (length * 4 > DATA_BUFF3_SIZE) - return -EINVAL; - - for (i = 0; i < length; i++) { - u32 color, blend, yuv; - - if (get_user(color, colors + i)) - return -EFAULT; - blend = (color & 0xF0000000) >> 4; - yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, - (color >> 16) & 0xFF) | blend : 0; - yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); - wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); - } - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, - av7110->osdwin, - bpp2pal[av7110->osdbpp[av7110->osdwin]], - first, last); -} - -static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, - int x1, int y1, int inc, u8 __user * data) -{ - uint w, h, bpp, bpl, size, lpb, bnum, brest; - int i; - int rc,release_rc; - - w = x1 - x0 + 1; - h = y1 - y0 + 1; - if (inc <= 0) - inc = w; - if (w <= 0 || w > 720 || h <= 0 || h > 576) - return -EINVAL; - bpp = av7110->osdbpp[av7110->osdwin] + 1; - bpl = ((w * bpp + 7) & ~7) / 8; - size = h * bpl; - lpb = (32 * 1024) / bpl; - bnum = size / (lpb * bpl); - brest = size - bnum * lpb * bpl; - - if (av7110->bmp_state == BMP_LOADING) { - /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ - BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); - rc = WaitUntilBmpLoaded(av7110); - if (rc) - return rc; - /* just continue. This should work for all fw versions - * if bnum==1 && !brest && LoadBitmap was successful - */ - } - - rc = 0; - for (i = 0; i < bnum; i++) { - rc = LoadBitmap(av7110, w, lpb, inc, data); - if (rc) - break; - rc = BlitBitmap(av7110, x0, y0 + i * lpb); - if (rc) - break; - data += lpb * inc; - } - if (!rc && brest) { - rc = LoadBitmap(av7110, w, brest / bpl, inc, data); - if (!rc) - rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); - } - release_rc = ReleaseBitmap(av7110); - if (!rc) - rc = release_rc; - if (rc) - dprintk(1,"returns %d\n",rc); - return rc; -} - -int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) -{ - int ret; - - if (mutex_lock_interruptible(&av7110->osd_mutex)) - return -ERESTARTSYS; - - switch (dc->cmd) { - case OSD_Close: - ret = DestroyOSDWindow(av7110, av7110->osdwin); - break; - case OSD_Open: - av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; - ret = CreateOSDWindow(av7110, av7110->osdwin, - bpp2bit[av7110->osdbpp[av7110->osdwin]], - dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); - if (ret) - break; - if (!dc->data) { - ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - if (ret) - break; - ret = SetColorBlend(av7110, av7110->osdwin); - } - break; - case OSD_Show: - ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); - break; - case OSD_Hide: - ret = HideWindow(av7110, av7110->osdwin); - break; - case OSD_Clear: - ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); - break; - case OSD_Fill: - ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); - break; - case OSD_SetColor: - ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); - break; - case OSD_SetPalette: - if (FW_VERSION(av7110->arm_app) >= 0x2618) - ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); - else { - int i, len = dc->x0-dc->color+1; - u8 __user *colors = (u8 __user *)dc->data; - u8 r, g = 0, b = 0, blend = 0; - ret = 0; - for (i = 0; icolor + i, r, g, b, blend); - if (ret) - break; - } - } - break; - case OSD_SetPixel: - ret = DrawLine(av7110, av7110->osdwin, - dc->x0, dc->y0, 0, 0, dc->color); - break; - case OSD_SetRow: - dc->y1 = dc->y0; - /* fall through */ - case OSD_SetBlock: - ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); - break; - case OSD_FillRow: - ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, - dc->x1-dc->x0+1, dc->y1, dc->color); - break; - case OSD_FillBlock: - ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, - dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); - break; - case OSD_Line: - ret = DrawLine(av7110, av7110->osdwin, - dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); - break; - case OSD_Text: - { - char textbuf[240]; - - if (strncpy_from_user(textbuf, dc->data, 240) < 0) { - ret = -EFAULT; - break; - } - textbuf[239] = 0; - if (dc->x1 > 3) - dc->x1 = 3; - ret = SetFont(av7110, av7110->osdwin, dc->x1, - (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); - if (!ret) - ret = FlushText(av7110); - if (!ret) - ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); - break; - } - case OSD_SetWindow: - if (dc->x0 < 1 || dc->x0 > 7) - ret = -EINVAL; - else { - av7110->osdwin = dc->x0; - ret = 0; - } - break; - case OSD_MoveWindow: - ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - if (!ret) - ret = SetColorBlend(av7110, av7110->osdwin); - break; - case OSD_OpenRaw: - if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { - ret = -EINVAL; - break; - } - if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) - av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; - else - av7110->osdbpp[av7110->osdwin] = 0; - ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, - dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); - if (ret) - break; - if (!dc->data) { - ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - if (!ret) - ret = SetColorBlend(av7110, av7110->osdwin); - } - break; - default: - ret = -EINVAL; - break; - } - - mutex_unlock(&av7110->osd_mutex); - if (ret==-ERESTARTSYS) - dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); - else if (ret) - dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); - - return ret; -} - -int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) -{ - switch (cap->cmd) { - case OSD_CAP_MEMSIZE: - if (FW_4M_SDRAM(av7110->arm_app)) - cap->val = 1000000; - else - cap->val = 92000; - return 0; - default: - return -EINVAL; - } -} -#endif /* CONFIG_DVB_AV7110_OSD */ diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h deleted file mode 100644 index 1634aba5cb8..00000000000 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ /dev/null @@ -1,495 +0,0 @@ -#ifndef _AV7110_HW_H_ -#define _AV7110_HW_H_ - -#include "av7110.h" - -/* DEBI transfer mode defs */ - -#define DEBINOSWAP 0x000e0000 -#define DEBISWAB 0x001e0000 -#define DEBISWAP 0x002e0000 - -#define ARM_WAIT_FREE (HZ) -#define ARM_WAIT_SHAKE (HZ/5) -#define ARM_WAIT_OSD (HZ) - - -enum av7110_bootstate -{ - BOOTSTATE_BUFFER_EMPTY = 0, - BOOTSTATE_BUFFER_FULL = 1, - BOOTSTATE_AV7110_BOOT_COMPLETE = 2 -}; - -enum av7110_type_rec_play_format -{ RP_None, - AudioPES, - AudioMp2, - AudioPCM, - VideoPES, - AV_PES -}; - -enum av7110_osd_palette_type -{ - NoPalet = 0, /* No palette */ - Pal1Bit = 2, /* 2 colors for 1 Bit Palette */ - Pal2Bit = 4, /* 4 colors for 2 bit palette */ - Pal4Bit = 16, /* 16 colors for 4 bit palette */ - Pal8Bit = 256 /* 256 colors for 16 bit palette */ -}; - -/* switch defines */ -#define SB_GPIO 3 -#define SB_OFF SAA7146_GPIO_OUTLO /* SlowBlank off (TV-Mode) */ -#define SB_ON SAA7146_GPIO_INPUT /* SlowBlank on (AV-Mode) */ -#define SB_WIDE SAA7146_GPIO_OUTHI /* SlowBlank 6V (16/9-Mode) (not implemented) */ - -#define FB_GPIO 1 -#define FB_OFF SAA7146_GPIO_LO /* FastBlank off (CVBS-Mode) */ -#define FB_ON SAA7146_GPIO_OUTHI /* FastBlank on (RGB-Mode) */ -#define FB_LOOP SAA7146_GPIO_INPUT /* FastBlank loop-through (PC graphics ???) */ - -enum av7110_video_output_mode -{ - NO_OUT = 0, /* disable analog output */ - CVBS_RGB_OUT = 1, - CVBS_YC_OUT = 2, - YC_OUT = 3 -}; - -/* firmware internal msg q status: */ -#define GPMQFull 0x0001 /* Main Message Queue Full */ -#define GPMQOver 0x0002 /* Main Message Queue Overflow */ -#define HPQFull 0x0004 /* High Priority Msg Queue Full */ -#define HPQOver 0x0008 -#define OSDQFull 0x0010 /* OSD Queue Full */ -#define OSDQOver 0x0020 -#define GPMQBusy 0x0040 /* Queue not empty, FW >= 261d */ -#define HPQBusy 0x0080 -#define OSDQBusy 0x0100 - -/* hw section filter flags */ -#define SECTION_EIT 0x01 -#define SECTION_SINGLE 0x00 -#define SECTION_CYCLE 0x02 -#define SECTION_CONTINUOS 0x04 -#define SECTION_MODE 0x06 -#define SECTION_IPMPE 0x0C /* size up to 4k */ -#define SECTION_HIGH_SPEED 0x1C /* larger buffer */ -#define DATA_PIPING_FLAG 0x20 /* for Data Piping Filter */ - -#define PBUFSIZE_NONE 0x0000 -#define PBUFSIZE_1P 0x0100 -#define PBUFSIZE_2P 0x0200 -#define PBUFSIZE_1K 0x0300 -#define PBUFSIZE_2K 0x0400 -#define PBUFSIZE_4K 0x0500 -#define PBUFSIZE_8K 0x0600 -#define PBUFSIZE_16K 0x0700 -#define PBUFSIZE_32K 0x0800 - - -/* firmware command codes */ -enum av7110_osd_command { - WCreate, - WDestroy, - WMoveD, - WMoveA, - WHide, - WTop, - DBox, - DLine, - DText, - Set_Font, - SetColor, - SetBlend, - SetWBlend, - SetCBlend, - SetNonBlend, - LoadBmp, - BlitBmp, - ReleaseBmp, - SetWTrans, - SetWNoTrans, - Set_Palette -}; - -enum av7110_pid_command { - MultiPID, - VideoPID, - AudioPID, - InitFilt, - FiltError, - NewVersion, - CacheError, - AddPIDFilter, - DelPIDFilter, - Scan, - SetDescr, - SetIR, - FlushTSQueue -}; - -enum av7110_mpeg_command { - SelAudChannels -}; - -enum av7110_audio_command { - AudioDAC, - CabADAC, - ON22K, - OFF22K, - MainSwitch, - ADSwitch, - SendDiSEqC, - SetRegister, - SpdifSwitch -}; - -enum av7110_request_command { - AudioState, - AudioBuffState, - VideoState1, - VideoState2, - VideoState3, - CrashCounter, - ReqVersion, - ReqVCXO, - ReqRegister, - ReqSecFilterError, - ReqSTC -}; - -enum av7110_encoder_command { - SetVidMode, - SetTestMode, - LoadVidCode, - SetMonitorType, - SetPanScanType, - SetFreezeMode, - SetWSSConfig -}; - -enum av7110_rec_play_state { - __Record, - __Stop, - __Play, - __Pause, - __Slow, - __FF_IP, - __Scan_I, - __Continue -}; - -enum av7110_fw_cmd_misc { - AV7110_FW_VIDEO_ZOOM = 1, - AV7110_FW_VIDEO_COMMAND, - AV7110_FW_AUDIO_COMMAND -}; - -enum av7110_command_type { - COMTYPE_NOCOM, - COMTYPE_PIDFILTER, - COMTYPE_MPEGDECODER, - COMTYPE_OSD, - COMTYPE_BMP, - COMTYPE_ENCODER, - COMTYPE_AUDIODAC, - COMTYPE_REQUEST, - COMTYPE_SYSTEM, - COMTYPE_REC_PLAY, - COMTYPE_COMMON_IF, - COMTYPE_PID_FILTER, - COMTYPE_PES, - COMTYPE_TS, - COMTYPE_VIDEO, - COMTYPE_AUDIO, - COMTYPE_CI_LL, - COMTYPE_MISC = 0x80 -}; - -#define VID_NONE_PREF 0x00 /* No aspect ration processing preferred */ -#define VID_PAN_SCAN_PREF 0x01 /* Pan and Scan Display preferred */ -#define VID_VERT_COMP_PREF 0x02 /* Vertical compression display preferred */ -#define VID_VC_AND_PS_PREF 0x03 /* PanScan and vertical Compression if allowed */ -#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ - -/* MPEG video decoder commands */ -#define AV_VIDEO_CMD_STOP 0x000e -#define AV_VIDEO_CMD_PLAY 0x000d -#define AV_VIDEO_CMD_FREEZE 0x0102 -#define AV_VIDEO_CMD_FFWD 0x0016 -#define AV_VIDEO_CMD_SLOW 0x0022 - -/* MPEG audio decoder commands */ -#define AUDIO_CMD_MUTE 0x0001 -#define AUDIO_CMD_UNMUTE 0x0002 -#define AUDIO_CMD_PCM16 0x0010 -#define AUDIO_CMD_STEREO 0x0080 -#define AUDIO_CMD_MONO_L 0x0100 -#define AUDIO_CMD_MONO_R 0x0200 -#define AUDIO_CMD_SYNC_OFF 0x000e -#define AUDIO_CMD_SYNC_ON 0x000f - -/* firmware data interface codes */ -#define DATA_NONE 0x00 -#define DATA_FSECTION 0x01 -#define DATA_IPMPE 0x02 -#define DATA_MPEG_RECORD 0x03 -#define DATA_DEBUG_MESSAGE 0x04 -#define DATA_COMMON_INTERFACE 0x05 -#define DATA_MPEG_PLAY 0x06 -#define DATA_BMP_LOAD 0x07 -#define DATA_IRCOMMAND 0x08 -#define DATA_PIPING 0x09 -#define DATA_STREAMING 0x0a -#define DATA_CI_GET 0x0b -#define DATA_CI_PUT 0x0c -#define DATA_MPEG_VIDEO_EVENT 0x0d - -#define DATA_PES_RECORD 0x10 -#define DATA_PES_PLAY 0x11 -#define DATA_TS_RECORD 0x12 -#define DATA_TS_PLAY 0x13 - -/* ancient CI command codes, only two are actually still used - * by the link level CI firmware */ -#define CI_CMD_ERROR 0x00 -#define CI_CMD_ACK 0x01 -#define CI_CMD_SYSTEM_READY 0x02 -#define CI_CMD_KEYPRESS 0x03 -#define CI_CMD_ON_TUNED 0x04 -#define CI_CMD_ON_SWITCH_PROGRAM 0x05 -#define CI_CMD_SECTION_ARRIVED 0x06 -#define CI_CMD_SECTION_TIMEOUT 0x07 -#define CI_CMD_TIME 0x08 -#define CI_CMD_ENTER_MENU 0x09 -#define CI_CMD_FAST_PSI 0x0a -#define CI_CMD_GET_SLOT_INFO 0x0b - -#define CI_MSG_NONE 0x00 -#define CI_MSG_CI_INFO 0x01 -#define CI_MSG_MENU 0x02 -#define CI_MSG_LIST 0x03 -#define CI_MSG_TEXT 0x04 -#define CI_MSG_REQUEST_INPUT 0x05 -#define CI_MSG_INPUT_COMPLETE 0x06 -#define CI_MSG_LIST_MORE 0x07 -#define CI_MSG_MENU_MORE 0x08 -#define CI_MSG_CLOSE_MMI_IMM 0x09 -#define CI_MSG_SECTION_REQUEST 0x0a -#define CI_MSG_CLOSE_FILTER 0x0b -#define CI_PSI_COMPLETE 0x0c -#define CI_MODULE_READY 0x0d -#define CI_SWITCH_PRG_REPLY 0x0e -#define CI_MSG_TEXT_MORE 0x0f - -#define CI_MSG_CA_PMT 0xe0 -#define CI_MSG_ERROR 0xf0 - - -/* base address of the dual ported RAM which serves as communication - * area between PCI bus and av7110, - * as seen by the DEBI bus of the saa7146 */ -#define DPRAM_BASE 0x4000 - -/* boot protocol area */ -#define AV7110_BOOT_STATE (DPRAM_BASE + 0x3F8) -#define AV7110_BOOT_SIZE (DPRAM_BASE + 0x3FA) -#define AV7110_BOOT_BASE (DPRAM_BASE + 0x3FC) -#define AV7110_BOOT_BLOCK (DPRAM_BASE + 0x400) -#define AV7110_BOOT_MAX_SIZE 0xc00 - -/* firmware command protocol area */ -#define IRQ_STATE (DPRAM_BASE + 0x0F4) -#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) -#define MSGSTATE (DPRAM_BASE + 0x0F8) -#define COMMAND (DPRAM_BASE + 0x0FC) -#define COM_BUFF (DPRAM_BASE + 0x100) -#define COM_BUFF_SIZE 0x20 - -/* various data buffers */ -#define BUFF1_BASE (DPRAM_BASE + 0x120) -#define BUFF1_SIZE 0xE0 - -#define DATA_BUFF0_BASE (DPRAM_BASE + 0x200) -#define DATA_BUFF0_SIZE 0x0800 - -#define DATA_BUFF1_BASE (DATA_BUFF0_BASE+DATA_BUFF0_SIZE) -#define DATA_BUFF1_SIZE 0x0800 - -#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE) -#define DATA_BUFF2_SIZE 0x0800 - -#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE) -#define DATA_BUFF3_SIZE 0x0400 - -#define Reserved (DPRAM_BASE + 0x1E00) -#define Reserved_SIZE 0x1C0 - - -/* firmware status area */ -#define STATUS_BASE (DPRAM_BASE + 0x1FC0) -#define STATUS_LOOPS (STATUS_BASE + 0x08) - -#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) -/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */ -#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E) - -/* firmware data protocol area */ -#define RX_TYPE (DPRAM_BASE + 0x1FE8) -#define RX_LEN (DPRAM_BASE + 0x1FEA) -#define TX_TYPE (DPRAM_BASE + 0x1FEC) -#define TX_LEN (DPRAM_BASE + 0x1FEE) - -#define RX_BUFF (DPRAM_BASE + 0x1FF4) -#define TX_BUFF (DPRAM_BASE + 0x1FF6) - -#define HANDSHAKE_REG (DPRAM_BASE + 0x1FF8) -#define COM_IF_LOCK (DPRAM_BASE + 0x1FFA) - -#define IRQ_RX (DPRAM_BASE + 0x1FFC) -#define IRQ_TX (DPRAM_BASE + 0x1FFE) - -/* used by boot protocol to load firmware into av7110 DRAM */ -#define DRAM_START_CODE 0x2e000404 -#define DRAM_MAX_CODE_SIZE 0x00100000 - -/* saa7146 gpio lines */ -#define RESET_LINE 2 -#define DEBI_DONE_LINE 1 -#define ARM_IRQ_LINE 0 - - - -extern int av7110_bootarm(struct av7110 *av7110); -extern int av7110_firmversion(struct av7110 *av7110); -#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) -#define FW_4M_SDRAM(arm_app) ((arm_app) & 0x40000000) -#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF) - -extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags); -extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...); -extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, - int request_buf_len, u16 *reply_buf, int reply_buf_len); - - -/* DEBI (saa7146 data extension bus interface) access */ -extern int av7110_debiwrite(struct av7110 *av7110, u32 config, - int addr, u32 val, int count); -extern u32 av7110_debiread(struct av7110 *av7110, u32 config, - int addr, int count); - - -/* DEBI during interrupt */ -/* single word writes */ -static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - av7110_debiwrite(av7110, config, addr, val, count); -} - -/* buffer writes */ -static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, - const u8 *val, int count) -{ - memcpy(av7110->debi_virt, val, count); - av7110_debiwrite(av7110, config, addr, 0, count); -} - -static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - u32 res; - - res=av7110_debiread(av7110, config, addr, count); - if (count<=4) - memcpy(av7110->debi_virt, (char *) &res, count); - return res; -} - -/* DEBI outside interrupts, only for count <= 4! */ -static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - unsigned long flags; - - spin_lock_irqsave(&av7110->debilock, flags); - av7110_debiwrite(av7110, config, addr, val, count); - spin_unlock_irqrestore(&av7110->debilock, flags); -} - -static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - unsigned long flags; - u32 res; - - spin_lock_irqsave(&av7110->debilock, flags); - res=av7110_debiread(av7110, config, addr, count); - spin_unlock_irqrestore(&av7110->debilock, flags); - return res; -} - -/* handle mailbox registers of the dual ported RAM */ -static inline void ARM_ResetMailBox(struct av7110 *av7110) -{ - unsigned long flags; - - spin_lock_irqsave(&av7110->debilock, flags); - av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2); - av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2); - spin_unlock_irqrestore(&av7110->debilock, flags); -} - -static inline void ARM_ClearMailBox(struct av7110 *av7110) -{ - iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); -} - -static inline void ARM_ClearIrq(struct av7110 *av7110) -{ - irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); -} - -/**************************************************************************** - * Firmware commands - ****************************************************************************/ - -static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) -{ - return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); -} - -static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) -{ - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); -} - -static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) -{ - return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, - (com>>16), (com&0xffff), - (arg>>16), (arg&0xffff)); -} - -static inline int audcom(struct av7110 *av7110, u32 com) -{ - return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, - (com>>16), (com&0xffff)); -} - -static inline int Set22K(struct av7110 *av7110, int state) -{ - return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); -} - - -extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst); - - -#ifdef CONFIG_DVB_AV7110_OSD -extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc); -extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap); -#endif /* CONFIG_DVB_AV7110_OSD */ - - - -#endif /* _AV7110_HW_H_ */ diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c deleted file mode 100644 index 699ef8b5b99..00000000000 --- a/drivers/media/dvb/ttpci/av7110_ipack.c +++ /dev/null @@ -1,403 +0,0 @@ -#include "dvb_filter.h" -#include "av7110_ipack.h" -#include /* for memcpy() */ -#include - - -void av7110_ipack_reset(struct ipack *p) -{ - p->found = 0; - p->cid = 0; - p->plength = 0; - p->flag1 = 0; - p->flag2 = 0; - p->hlength = 0; - p->mpeg = 0; - p->check = 0; - p->which = 0; - p->done = 0; - p->count = 0; -} - - -int av7110_ipack_init(struct ipack *p, int size, - void (*func)(u8 *buf, int size, void *priv)) -{ - if (!(p->buf = vmalloc(size*sizeof(u8)))) { - printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); - return -ENOMEM; - } - p->size = size; - p->func = func; - p->repack_subids = 0; - av7110_ipack_reset(p); - return 0; -} - - -void av7110_ipack_free(struct ipack *p) -{ - vfree(p->buf); -} - - -static void send_ipack(struct ipack *p) -{ - int off; - struct dvb_audio_info ai; - int ac3_off = 0; - int streamid = 0; - int nframes = 0; - int f = 0; - - switch (p->mpeg) { - case 2: - if (p->count < 10) - return; - p->buf[3] = p->cid; - p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); - p->buf[5] = (u8)((p->count - 6) & 0x00ff); - if (p->repack_subids && p->cid == PRIVATE_STREAM1) { - off = 9 + p->buf[8]; - streamid = p->buf[off]; - if ((streamid & 0xf8) == 0x80) { - ai.off = 0; - ac3_off = ((p->buf[off + 2] << 8)| - p->buf[off + 3]); - if (ac3_off < p->count) - f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off, - p->count - ac3_off, &ai, 0); - if (!f) { - nframes = (p->count - off - 3 - ac3_off) / - ai.framesize + 1; - p->buf[off + 2] = (ac3_off >> 8) & 0xff; - p->buf[off + 3] = (ac3_off) & 0xff; - p->buf[off + 1] = nframes; - ac3_off += nframes * ai.framesize - p->count; - } - } - } - p->func(p->buf, p->count, p->data); - - p->buf[6] = 0x80; - p->buf[7] = 0x00; - p->buf[8] = 0x00; - p->count = 9; - if (p->repack_subids && p->cid == PRIVATE_STREAM1 - && (streamid & 0xf8) == 0x80) { - p->count += 4; - p->buf[9] = streamid; - p->buf[10] = (ac3_off >> 8) & 0xff; - p->buf[11] = (ac3_off) & 0xff; - p->buf[12] = 0; - } - break; - - case 1: - if (p->count < 8) - return; - p->buf[3] = p->cid; - p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); - p->buf[5] = (u8)((p->count - 6) & 0x00ff); - p->func(p->buf, p->count, p->data); - - p->buf[6] = 0x0f; - p->count = 7; - break; - } -} - - -void av7110_ipack_flush(struct ipack *p) -{ - if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6) - return; - p->plength = p->found - 6; - p->found = 0; - send_ipack(p); - av7110_ipack_reset(p); -} - - -static void write_ipack(struct ipack *p, const u8 *data, int count) -{ - u8 headr[3] = { 0x00, 0x00, 0x01 }; - - if (p->count < 6) { - memcpy(p->buf, headr, 3); - p->count = 6; - } - - if (p->count + count < p->size){ - memcpy(p->buf+p->count, data, count); - p->count += count; - } else { - int rest = p->size - p->count; - memcpy(p->buf+p->count, data, rest); - p->count += rest; - send_ipack(p); - if (count - rest > 0) - write_ipack(p, data + rest, count - rest); - } -} - - -int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p) -{ - int l; - int c = 0; - - while (c < count && (p->mpeg == 0 || - (p->mpeg == 1 && p->found < 7) || - (p->mpeg == 2 && p->found < 9)) - && (p->found < 5 || !p->done)) { - switch (p->found) { - case 0: - case 1: - if (buf[c] == 0x00) - p->found++; - else - p->found = 0; - c++; - break; - case 2: - if (buf[c] == 0x01) - p->found++; - else if (buf[c] == 0) - p->found = 2; - else - p->found = 0; - c++; - break; - case 3: - p->cid = 0; - switch (buf[c]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - p->done = 1; - /* fall through */ - case PRIVATE_STREAM1: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - p->found++; - p->cid = buf[c]; - c++; - break; - default: - p->found = 0; - break; - } - break; - - case 4: - if (count-c > 1) { - p->plen[0] = buf[c]; - c++; - p->plen[1] = buf[c]; - c++; - p->found += 2; - p->plength = (p->plen[0] << 8) | p->plen[1]; - } else { - p->plen[0] = buf[c]; - p->found++; - return count; - } - break; - case 5: - p->plen[1] = buf[c]; - c++; - p->found++; - p->plength = (p->plen[0] << 8) | p->plen[1]; - break; - case 6: - if (!p->done) { - p->flag1 = buf[c]; - c++; - p->found++; - if ((p->flag1 & 0xc0) == 0x80) - p->mpeg = 2; - else { - p->hlength = 0; - p->which = 0; - p->mpeg = 1; - p->flag2 = 0; - } - } - break; - - case 7: - if (!p->done && p->mpeg == 2) { - p->flag2 = buf[c]; - c++; - p->found++; - } - break; - - case 8: - if (!p->done && p->mpeg == 2) { - p->hlength = buf[c]; - c++; - p->found++; - } - break; - } - } - - if (c == count) - return count; - - if (!p->plength) - p->plength = MMAX_PLENGTH - 6; - - if (p->done || ((p->mpeg == 2 && p->found >= 9) || - (p->mpeg == 1 && p->found >= 7))) { - switch (p->cid) { - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - case PRIVATE_STREAM1: - if (p->mpeg == 2 && p->found == 9) { - write_ipack(p, &p->flag1, 1); - write_ipack(p, &p->flag2, 1); - write_ipack(p, &p->hlength, 1); - } - - if (p->mpeg == 1 && p->found == 7) - write_ipack(p, &p->flag1, 1); - - if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && - p->found < 14) { - while (c < count && p->found < 14) { - p->pts[p->found - 9] = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - } - if (c == count) - return count; - } - - if (p->mpeg == 1 && p->which < 2000) { - - if (p->found == 7) { - p->check = p->flag1; - p->hlength = 1; - } - - while (!p->which && c < count && - p->check == 0xff){ - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - } - - if (c == count) - return count; - - if ((p->check & 0xc0) == 0x40 && !p->which) { - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - - p->which = 1; - if (c == count) - return count; - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - p->which = 2; - if (c == count) - return count; - } - - if (p->which == 1) { - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - p->which = 2; - if (c == count) - return count; - } - - if ((p->check & 0x30) && p->check != 0xff) { - p->flag2 = (p->check & 0xf0) << 2; - p->pts[0] = p->check; - p->which = 3; - } - - if (c == count) - return count; - if (p->which > 2){ - if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) { - while (c < count && p->which < 7) { - p->pts[p->which - 2] = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->which++; - p->hlength++; - } - if (c == count) - return count; - } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) { - while (c < count && p->which < 12) { - if (p->which < 7) - p->pts[p->which - 2] = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->which++; - p->hlength++; - } - if (c == count) - return count; - } - p->which = 2000; - } - - } - - while (c < count && p->found < p->plength + 6) { - l = count - c; - if (l + p->found > p->plength + 6) - l = p->plength + 6 - p->found; - write_ipack(p, buf + c, l); - p->found += l; - c += l; - } - break; - } - - - if (p->done) { - if (p->found + count - c < p->plength + 6) { - p->found += count - c; - c = count; - } else { - c += p->plength + 6 - p->found; - p->found = p->plength + 6; - } - } - - if (p->plength && p->found == p->plength + 6) { - send_ipack(p); - av7110_ipack_reset(p); - if (c < count) - av7110_ipack_instant_repack(buf + c, count - c, p); - } - } - return count; -} diff --git a/drivers/media/dvb/ttpci/av7110_ipack.h b/drivers/media/dvb/ttpci/av7110_ipack.h deleted file mode 100644 index becf94d3fdf..00000000000 --- a/drivers/media/dvb/ttpci/av7110_ipack.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _AV7110_IPACK_H_ -#define _AV7110_IPACK_H_ - -extern int av7110_ipack_init(struct ipack *p, int size, - void (*func)(u8 *buf, int size, void *priv)); - -extern void av7110_ipack_reset(struct ipack *p); -extern int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p); -extern void av7110_ipack_free(struct ipack * p); -extern void av7110_ipack_flush(struct ipack *p); - -#endif diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c deleted file mode 100644 index 908f272fe26..00000000000 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Driver for the remote control of SAA7146 based AV7110 cards - * - * Copyright (C) 1999-2003 Holger Waechtler - * Copyright (C) 2003-2007 Oliver Endriss - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - */ - - -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" - - -#define AV_CNT 4 - -#define IR_RC5 0 -#define IR_RCMM 1 -#define IR_RC5_EXT 2 /* internal only */ - -#define IR_ALL 0xffffffff - -#define UP_TIMEOUT (HZ*7/25) - - -/* Note: enable ir debugging by or'ing debug with 16 */ - -static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; -module_param_array(ir_protocol, int, NULL, 0644); -MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); - -static int ir_inversion[AV_CNT]; -module_param_array(ir_inversion, int, NULL, 0644); -MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); - -static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; -module_param_array(ir_device_mask, uint, NULL, 0644); -MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); - - -static int av_cnt; -static struct av7110 *av_list[AV_CNT]; - -static u16 default_key_map [256] = { - KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, - KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, - KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0, - 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0, - KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, - KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW, - KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN, - 0, 0, 0, 0, KEY_EPG, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR -}; - - -/* key-up timer */ -static void av7110_emit_keyup(unsigned long parm) -{ - struct infrared *ir = (struct infrared *) parm; - - if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) - return; - - input_report_key(ir->input_dev, ir->last_key, 0); - input_sync(ir->input_dev); -} - - -/* tasklet */ -static void av7110_emit_key(unsigned long parm) -{ - struct infrared *ir = (struct infrared *) parm; - u32 ircom = ir->ir_command; - u8 data; - u8 addr; - u16 toggle; - u16 keycode; - - /* extract device address and data */ - switch (ir->protocol) { - case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - toggle = ircom & 0x0800; - break; - - case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ - data = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - toggle = ircom & 0x8000; - break; - - case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - /* invert 7th data bit for backward compatibility with RC5 keymaps */ - if (!(ircom & 0x1000)) - data |= 0x40; - toggle = ircom & 0x0800; - break; - - default: - printk("%s invalid protocol %x\n", __func__, ir->protocol); - return; - } - - input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); - input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); - - keycode = ir->key_map[data]; - - dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", - __func__, ircom, addr, data, keycode); - - /* check device address */ - if (!(ir->device_mask & (1 << addr))) - return; - - if (!keycode) { - printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", - __func__, ircom, addr, data); - return; - } - - if (timer_pending(&ir->keyup_timer)) { - del_timer(&ir->keyup_timer); - if (ir->last_key != keycode || toggle != ir->last_toggle) { - ir->delay_timer_finished = 0; - input_event(ir->input_dev, EV_KEY, ir->last_key, 0); - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - } else if (ir->delay_timer_finished) { - input_event(ir->input_dev, EV_KEY, keycode, 2); - input_sync(ir->input_dev); - } - } else { - ir->delay_timer_finished = 0; - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - } - - ir->last_key = keycode; - ir->last_toggle = toggle; - - ir->keyup_timer.expires = jiffies + UP_TIMEOUT; - add_timer(&ir->keyup_timer); - -} - - -/* register with input layer */ -static void input_register_keys(struct infrared *ir) -{ - int i; - - set_bit(EV_KEY, ir->input_dev->evbit); - set_bit(EV_REP, ir->input_dev->evbit); - set_bit(EV_MSC, ir->input_dev->evbit); - - set_bit(MSC_RAW, ir->input_dev->mscbit); - set_bit(MSC_SCAN, ir->input_dev->mscbit); - - memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); - - for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { - if (ir->key_map[i] > KEY_MAX) - ir->key_map[i] = 0; - else if (ir->key_map[i] > KEY_RESERVED) - set_bit(ir->key_map[i], ir->input_dev->keybit); - } - - ir->input_dev->keycode = ir->key_map; - ir->input_dev->keycodesize = sizeof(ir->key_map[0]); - ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); -} - - -/* called by the input driver after rep[REP_DELAY] ms */ -static void input_repeat_key(unsigned long parm) -{ - struct infrared *ir = (struct infrared *) parm; - - ir->delay_timer_finished = 1; -} - - -/* check for configuration changes */ -int av7110_check_ir_config(struct av7110 *av7110, int force) -{ - int i; - int modified = force; - int ret = -ENODEV; - - for (i = 0; i < av_cnt; i++) - if (av7110 == av_list[i]) - break; - - if (i < av_cnt && av7110) { - if ((av7110->ir.protocol & 1) != ir_protocol[i] || - av7110->ir.inversion != ir_inversion[i]) - modified = true; - - if (modified) { - /* protocol */ - if (ir_protocol[i]) { - ir_protocol[i] = 1; - av7110->ir.protocol = IR_RCMM; - av7110->ir.ir_config = 0x0001; - } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { - av7110->ir.protocol = IR_RC5_EXT; - av7110->ir.ir_config = 0x0002; - } else { - av7110->ir.protocol = IR_RC5; - av7110->ir.ir_config = 0x0000; - } - /* inversion */ - if (ir_inversion[i]) { - ir_inversion[i] = 1; - av7110->ir.ir_config |= 0x8000; - } - av7110->ir.inversion = ir_inversion[i]; - /* update ARM */ - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, - av7110->ir.ir_config); - } else - ret = 0; - - /* address */ - if (av7110->ir.device_mask != ir_device_mask[i]) - av7110->ir.device_mask = ir_device_mask[i]; - } - - return ret; -} - - -/* /proc/av7110_ir interface */ -static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - char *page; - u32 ir_config; - int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; - int i; - - if (count < size) - return -EINVAL; - - page = vmalloc(size); - if (!page) - return -ENOMEM; - - if (copy_from_user(page, buffer, size)) { - vfree(page); - return -EFAULT; - } - - memcpy(&ir_config, page, sizeof ir_config); - - for (i = 0; i < av_cnt; i++) { - /* keymap */ - memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, - sizeof(av_list[i]->ir.key_map)); - /* protocol, inversion, address */ - ir_protocol[i] = ir_config & 0x0001; - ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; - if (ir_config & 0x4000) - ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); - else - ir_device_mask[i] = IR_ALL; - /* update configuration */ - av7110_check_ir_config(av_list[i], false); - input_register_keys(&av_list[i]->ir); - } - vfree(page); - return count; -} - -static const struct file_operations av7110_ir_proc_fops = { - .owner = THIS_MODULE, - .write = av7110_ir_proc_write, - .llseek = noop_llseek, -}; - -/* interrupt handler */ -static void ir_handler(struct av7110 *av7110, u32 ircom) -{ - dprintk(4, "ir command = %08x\n", ircom); - av7110->ir.ir_command = ircom; - tasklet_schedule(&av7110->ir.ir_tasklet); -} - - -int __devinit av7110_ir_init(struct av7110 *av7110) -{ - struct input_dev *input_dev; - static struct proc_dir_entry *e; - int err; - - if (av_cnt >= ARRAY_SIZE(av_list)) - return -ENOSPC; - - av_list[av_cnt++] = av7110; - av7110_check_ir_config(av7110, true); - - init_timer(&av7110->ir.keyup_timer); - av7110->ir.keyup_timer.function = av7110_emit_keyup; - av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - av7110->ir.input_dev = input_dev; - snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), - "pci-%s/ir0", pci_name(av7110->dev->pci)); - - input_dev->name = "DVB on-card IR receiver"; - - input_dev->phys = av7110->ir.input_phys; - input_dev->id.bustype = BUS_PCI; - input_dev->id.version = 2; - if (av7110->dev->pci->subsystem_vendor) { - input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; - input_dev->id.product = av7110->dev->pci->subsystem_device; - } else { - input_dev->id.vendor = av7110->dev->pci->vendor; - input_dev->id.product = av7110->dev->pci->device; - } - input_dev->dev.parent = &av7110->dev->pci->dev; - /* initial keymap */ - memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); - input_register_keys(&av7110->ir); - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; - } - input_dev->timer.function = input_repeat_key; - input_dev->timer.data = (unsigned long) &av7110->ir; - - if (av_cnt == 1) { - e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); - if (e) - e->size = 4 + 256 * sizeof(u16); - } - - tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); - av7110->ir.ir_handler = ir_handler; - - return 0; -} - - -void __devexit av7110_ir_exit(struct av7110 *av7110) -{ - int i; - - if (av_cnt == 0) - return; - - del_timer_sync(&av7110->ir.keyup_timer); - av7110->ir.ir_handler = NULL; - tasklet_kill(&av7110->ir.ir_tasklet); - - for (i = 0; i < av_cnt; i++) - if (av_list[i] == av7110) { - av_list[i] = av_list[av_cnt-1]; - av_list[av_cnt-1] = NULL; - break; - } - - if (av_cnt == 1) - remove_proc_entry("av7110_ir", NULL); - - input_unregister_device(av7110->ir.input_dev); - - av_cnt--; -} - -//MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); -//MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c deleted file mode 100644 index 1b2d15140a1..00000000000 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ /dev/null @@ -1,966 +0,0 @@ -/* - * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * the project's page is at http://www.linuxtv.org/ - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_av.h" - -int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) -{ - u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; - struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; - - switch (av7110->adac_type) { - case DVB_ADAC_MSP34x0: - msgs.addr = 0x40; - break; - case DVB_ADAC_MSP34x5: - msgs.addr = 0x42; - break; - default: - return 0; - } - - if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { - dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", - av7110->dvb_adapter.num, reg, val); - return -EIO; - } - return 0; -} - -static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) -{ - u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; - u8 msg2[2]; - struct i2c_msg msgs[2] = { - { .flags = 0 , .len = 3, .buf = msg1 }, - { .flags = I2C_M_RD, .len = 2, .buf = msg2 } - }; - - switch (av7110->adac_type) { - case DVB_ADAC_MSP34x0: - msgs[0].addr = 0x40; - msgs[1].addr = 0x40; - break; - case DVB_ADAC_MSP34x5: - msgs[0].addr = 0x42; - msgs[1].addr = 0x42; - break; - default: - return 0; - } - - if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { - dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", - av7110->dvb_adapter.num, reg); - return -EIO; - } - *val = (msg2[0] << 8) | msg2[1]; - return 0; -} - -static struct v4l2_input inputs[4] = { - { - .index = 0, - .name = "DVB", - .type = V4L2_INPUT_TYPE_CAMERA, - .audioset = 1, - .tuner = 0, /* ignored */ - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - }, { - .index = 1, - .name = "Television", - .type = V4L2_INPUT_TYPE_TUNER, - .audioset = 1, - .tuner = 0, - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - }, { - .index = 2, - .name = "Video", - .type = V4L2_INPUT_TYPE_CAMERA, - .audioset = 0, - .tuner = 0, - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - }, { - .index = 3, - .name = "Y/C", - .type = V4L2_INPUT_TYPE_CAMERA, - .audioset = 0, - .tuner = 0, - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - } -}; - -static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) -{ - struct av7110 *av7110 = dev->ext_priv; - u8 buf[] = { 0x00, reg, data }; - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; - - dprintk(4, "dev: %p\n", dev); - - if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) - return -1; - return 0; -} - -static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) -{ - struct av7110 *av7110 = dev->ext_priv; - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; - - dprintk(4, "dev: %p\n", dev); - - if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) - return -1; - return 0; -} - -static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq) -{ - u32 div; - u8 config; - u8 buf[4]; - - dprintk(4, "freq: 0x%08x\n", freq); - - /* magic number: 614. tuning with the frequency given by v4l2 - is always off by 614*62.5 = 38375 kHz...*/ - div = freq + 614; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x8e; - - if (freq < (u32) (16 * 168.25)) - config = 0xa0; - else if (freq < (u32) (16 * 447.25)) - config = 0x90; - else - config = 0x30; - config &= ~0x02; - - buf[3] = config; - - return tuner_write(dev, 0x61, buf); -} - -static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq) -{ - struct av7110 *av7110 = (struct av7110*)dev->ext_priv; - u32 div; - u8 data[4]; - - div = (freq + 38900000 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xce; - - if (freq < 45000000) - return -EINVAL; - else if (freq < 137000000) - data[3] = 0x01; - else if (freq < 403000000) - data[3] = 0x02; - else if (freq < 860000000) - data[3] = 0x04; - else - return -EINVAL; - - if (av7110->fe->ops.i2c_gate_ctrl) - av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1); - return tuner_write(dev, 0x63, data); -} - - - -static struct saa7146_standard analog_standard[]; -static struct saa7146_standard dvb_standard[]; -static struct saa7146_standard standard[]; - -static struct v4l2_audio msp3400_v4l2_audio = { - .index = 0, - .name = "Television", - .capability = V4L2_AUDCAP_STEREO -}; - -static int av7110_dvb_c_switch(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct av7110 *av7110 = (struct av7110*)dev->ext_priv; - u16 adswitch; - int source, sync, err; - - dprintk(4, "%p\n", av7110); - - if ((vv->video_status & STATUS_OVERLAY) != 0) { - vv->ov_suspend = vv->video_fh; - err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ - if (err != 0) { - dprintk(2, "suspending video failed\n"); - vv->ov_suspend = NULL; - } - } - - if (0 != av7110->current_input) { - dprintk(1, "switching to analog TV:\n"); - adswitch = 1; - source = SAA7146_HPS_SOURCE_PORT_B; - sync = SAA7146_HPS_SYNC_PORT_B; - memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); - - switch (av7110->current_input) { - case 1: - dprintk(1, "switching SAA7113 to Analog Tuner Input\n"); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume - - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) - dprintk(1, "setting band in demodulator failed\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) - } - if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) - dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); - break; - case 2: - dprintk(1, "switching SAA7113 to Video AV CVBS Input\n"); - if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) - dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); - break; - case 3: - dprintk(1, "switching SAA7113 to Video AV Y/C Input\n"); - if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) - dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); - break; - default: - dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n"); - } - } else { - adswitch = 0; - source = SAA7146_HPS_SOURCE_PORT_A; - sync = SAA7146_HPS_SYNC_PORT_A; - memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); - dprintk(1, "switching DVB mode\n"); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume - - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) - dprintk(1, "setting band in demodulator failed\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) - } - } - - /* hmm, this does not do anything!? */ - if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch)) - dprintk(1, "ADSwitch error\n"); - - saa7146_set_hps_source_and_sync(dev, source, sync); - - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - u16 stereo_det; - s8 stereo; - - dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); - - if (!av7110->analog_tuner_flags || t->index != 0) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strcpy((char *)t->name, "Television"); - - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ - t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ - /* FIXME: add the real signal strength here */ - t->signal = 0xffff; - t->afc = 0; - - /* FIXME: standard / stereo detection is still broken */ - msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); - dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); - msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); - dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); - stereo = (s8)(stereo_det >> 8); - if (stereo > 0x10) { - /* stereo */ - t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - t->audmode = V4L2_TUNER_MODE_STEREO; - } else if (stereo < -0x10) { - /* bilingual */ - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - t->audmode = V4L2_TUNER_MODE_LANG1; - } else /* mono */ - t->rxsubchans = V4L2_TUNER_SUB_MONO; - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - u16 fm_matrix, src; - dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); - - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; - - switch (t->audmode) { - case V4L2_TUNER_MODE_STEREO: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); - fm_matrix = 0x3001; /* stereo */ - src = 0x0020; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); - fm_matrix = 0x3000; /* bilingual */ - src = 0x0020; - break; - case V4L2_TUNER_MODE_LANG1: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); - fm_matrix = 0x3000; /* mono */ - src = 0x0000; - break; - case V4L2_TUNER_MODE_LANG2: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); - fm_matrix = 0x3000; /* mono */ - src = 0x0010; - break; - default: /* case V4L2_TUNER_MODE_MONO: */ - dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); - fm_matrix = 0x3000; /* mono */ - src = 0x0030; - break; - } - msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); - msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); - msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency); - - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = av7110->current_freq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency); - - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; - - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); - - /* tune in desired frequency */ - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) - ves1820_set_tv_freq(dev, f->frequency); - else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) - stv0297_set_tv_freq(dev, f->frequency); - av7110->current_freq = f->frequency; - - msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ - msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); - - if (av7110->analog_tuner_flags) { - if (i->index >= 4) - return -EINVAL; - } else { - if (i->index != 0) - return -EINVAL; - } - - memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); - - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - *input = av7110->current_input; - dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_INPUT: %d\n", input); - - if (!av7110->analog_tuner_flags) - return input ? -EINVAL : 0; - - if (input >= 4) - return -EINVAL; - - av7110->current_input = input; - return av7110_dvb_c_switch(fh); -} - -static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) -{ - dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); - if (a->index != 0) - return -EINVAL; - *a = msp3400_v4l2_audio; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); - if (a->index != 0) - return -EINVAL; - if (av7110->current_input >= 2) - return -EINVAL; - *a = msp3400_v4l2_audio; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); - if (av7110->current_input >= 2) - return -EINVAL; - return a->index ? -EINVAL : 0; -} - -static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_sliced_vbi_cap *cap) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); - if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - return -EINVAL; - if (FW_VERSION(av7110->arm_app) >= 0x2623) { - cap->service_set = V4L2_SLICED_WSS_625; - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - } - return 0; -} - -static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_FMT:\n"); - if (FW_VERSION(av7110->arm_app) < 0x2623) - return -EINVAL; - memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); - if (av7110->wssMode) { - f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; - f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; - f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); - } - return 0; -} - -static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_FMT\n"); - if (FW_VERSION(av7110->arm_app) < 0x2623) - return -EINVAL; - if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && - f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { - memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); - /* WSS controlled by firmware */ - av7110->wssMode = 0; - av7110->wssData = 0; - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, - SetWSSConfig, 1, 0); - } else { - memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); - f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; - f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; - f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); - /* WSS controlled by userspace */ - av7110->wssMode = 1; - av7110->wssData = 0; - } - return 0; -} - -static int av7110_vbi_reset(struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - - dprintk(2, "%s\n", __func__); - av7110->wssMode = 0; - av7110->wssData = 0; - if (FW_VERSION(av7110->arm_app) < 0x2623) - return 0; - else - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); -} - -static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - struct v4l2_sliced_vbi_data d; - int rc; - - dprintk(2, "%s\n", __func__); - if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d) - return -EINVAL; - if (copy_from_user(&d, data, count)) - return -EFAULT; - if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23) - return -EINVAL; - if (d.id) - av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0]; - else - av7110->wssData = 0x8000; - rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData); - return (rc < 0) ? rc : count; -} - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - -static u8 saa7113_init_regs[] = { - 0x02, 0xd0, - 0x03, 0x23, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xe9, - 0x07, 0x0d, - 0x08, 0x98, - 0x09, 0x02, - 0x0a, 0x80, - 0x0b, 0x40, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x7c, - 0x10, 0x48, - 0x11, 0x0c, - 0x12, 0x8b, - 0x13, 0x1a, - 0x14, 0x00, - 0x15, 0x00, - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1b, 0x00, - 0x1c, 0x00, - 0x1d, 0x00, - 0x1e, 0x00, - - 0x41, 0x77, - 0x42, 0x77, - 0x43, 0x77, - 0x44, 0x77, - 0x45, 0x77, - 0x46, 0x77, - 0x47, 0x77, - 0x48, 0x77, - 0x49, 0x77, - 0x4a, 0x77, - 0x4b, 0x77, - 0x4c, 0x77, - 0x4d, 0x77, - 0x4e, 0x77, - 0x4f, 0x77, - 0x50, 0x77, - 0x51, 0x77, - 0x52, 0x77, - 0x53, 0x77, - 0x54, 0x77, - 0x55, 0x77, - 0x56, 0x77, - 0x57, 0xff, - - 0xff -}; - - -static struct saa7146_ext_vv av7110_vv_data_st; -static struct saa7146_ext_vv av7110_vv_data_c; - -int av7110_init_analog_module(struct av7110 *av7110) -{ - u16 version1, version2; - - if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && - i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { - pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP34x0; - } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && - i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { - pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP34x5; - } else - return -ENODEV; - - msleep(100); // the probing above resets the msp... - msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); - msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); - dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", - av7110->dvb_adapter.num, version1, version2); - msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume - msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART - - if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { - pr_info("saa7113 not accessible\n"); - } else { - u8 *i = saa7113_init_regs; - - if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { - /* Fujitsu/Siemens DVB-Cable */ - av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; - } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) { - /* Hauppauge/TT DVB-C premium */ - av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; - } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) { - /* Hauppauge/TT DVB-C premium */ - av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297; - } - - /* setup for DVB by default */ - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) - dprintk(1, "setting band in demodulator failed\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) - saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) - } - - /* init the saa7113 */ - while (*i != 0xff) { - if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { - dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num); - break; - } - i += 2; - } - /* setup msp for analog sound: B/G Dual-FM */ - msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG - msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz - msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI - msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz - msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI - msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2 - } - - memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); - /* set dd1 stream a & b */ - saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); - saa7146_write(av7110->dev, DD1_INIT, 0x03000700); - saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - return 0; -} - -int av7110_init_v4l(struct av7110 *av7110) -{ - struct saa7146_dev* dev = av7110->dev; - struct saa7146_ext_vv *vv_data; - int ret; - - /* special case DVB-C: these cards have an analog tuner - plus need some special handling, so we have separate - saa7146_ext_vv data for these... */ - if (av7110->analog_tuner_flags) - vv_data = &av7110_vv_data_c; - else - vv_data = &av7110_vv_data_st; - ret = saa7146_vv_init(dev, vv_data); - - if (ret) { - ERR("cannot init capture device. skipping\n"); - return -ENODEV; - } - vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input; - vv_data->vid_ops.vidioc_g_input = vidioc_g_input; - vv_data->vid_ops.vidioc_s_input = vidioc_s_input; - vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner; - vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner; - vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency; - vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency; - vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio; - vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio; - vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio; - vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL; - - vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner; - vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner; - vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency; - vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency; - vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL; - vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; - vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; - vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; - - if (FW_VERSION(av7110->arm_app) < 0x2623) - vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT; - - if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { - ERR("cannot register capture device. skipping\n"); - saa7146_vv_release(dev); - return -ENODEV; - } - if (FW_VERSION(av7110->arm_app) >= 0x2623) { - if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) - ERR("cannot register vbi v4l2 device. skipping\n"); - } - return 0; -} - -int av7110_exit_v4l(struct av7110 *av7110) -{ - struct saa7146_dev* dev = av7110->dev; - - saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); - saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); - - saa7146_vv_release(dev); - - return 0; -} - - - -/* FIXME: these values are experimental values that look better than the - values from the latest "official" driver -- at least for me... (MiHu) */ -static struct saa7146_standard standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL_BG, - .v_offset = 0x15, .v_field = 288, - .h_offset = 0x48, .h_pixels = 708, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x10, .v_field = 244, - .h_offset = 0x40, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } -}; - -static struct saa7146_standard analog_standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL_BG, - .v_offset = 0x1b, .v_field = 288, - .h_offset = 0x08, .h_pixels = 708, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x10, .v_field = 244, - .h_offset = 0x40, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } -}; - -static struct saa7146_standard dvb_standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL_BG, - .v_offset = 0x14, .v_field = 288, - .h_offset = 0x48, .h_pixels = 708, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x10, .v_field = 244, - .h_offset = 0x40, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } -}; - -static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) -{ - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - - if (std->id & V4L2_STD_PAL) { - av7110->vidmode = AV7110_VIDEO_MODE_PAL; - av7110_set_vidmode(av7110, av7110->vidmode); - } - else if (std->id & V4L2_STD_NTSC) { - av7110->vidmode = AV7110_VIDEO_MODE_NTSC; - av7110_set_vidmode(av7110, av7110->vidmode); - } - else - return -1; - - return 0; -} - - -static struct saa7146_ext_vv av7110_vv_data_st = { - .inputs = 1, - .audios = 1, - .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, - .flags = 0, - - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), - .std_callback = &std_callback, - - .vbi_fops.open = av7110_vbi_reset, - .vbi_fops.release = av7110_vbi_reset, - .vbi_fops.write = av7110_vbi_write, -}; - -static struct saa7146_ext_vv av7110_vv_data_c = { - .inputs = 1, - .audios = 1, - .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, - .flags = SAA7146_USE_PORT_B_FOR_VBI, - - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), - .std_callback = &std_callback, - - .vbi_fops.open = av7110_vbi_reset, - .vbi_fops.release = av7110_vbi_reset, - .vbi_fops.write = av7110_vbi_write, -}; - diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c deleted file mode 100644 index 12ddb53c58d..00000000000 --- a/drivers/media/dvb/ttpci/budget-av.c +++ /dev/null @@ -1,1640 +0,0 @@ -/* - * budget-av.c: driver for the SAA7146 based Budget DVB cards - * with analog video in - * - * Compiled from various sources by Michael Hunold - * - * CI interface support (c) 2004 Olivier Gournet & - * Andrew de Quincey - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "budget.h" -#include "stv0299.h" -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -#include "tda8261.h" -#include "tda8261_cfg.h" -#include "tda1002x.h" -#include "tda1004x.h" -#include "tua6100.h" -#include "dvb-pll.h" -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_ca_en50221.h" - -#define DEBICICAM 0x02420000 - -#define SLOTSTATUS_NONE 1 -#define SLOTSTATUS_PRESENT 2 -#define SLOTSTATUS_RESET 4 -#define SLOTSTATUS_READY 8 -#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct budget_av { - struct budget budget; - struct video_device *vd; - int cur_input; - int has_saa7113; - struct tasklet_struct ciintf_irq_tasklet; - int slot_status; - struct dvb_ca_en50221 ca; - u8 reinitialise_demod:1; -}; - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); - - -/* GPIO Connections: - * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! - * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory - * 2 - CI Card Enable (Active Low) - * 3 - CI Card Detect - */ - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - -static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg) -{ - u8 mm1[] = { 0x00 }; - u8 mm2[] = { 0x00 }; - struct i2c_msg msgs[2]; - - msgs[0].flags = 0; - msgs[1].flags = I2C_M_RD; - msgs[0].addr = msgs[1].addr = id / 2; - mm1[0] = reg; - msgs[0].len = 1; - msgs[1].len = 1; - msgs[0].buf = mm1; - msgs[1].buf = mm2; - - i2c_transfer(i2c, msgs, 2); - - return mm2[0]; -} - -static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len) -{ - u8 mm1[] = { reg }; - struct i2c_msg msgs[2] = { - {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, - {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} - }; - - if (i2c_transfer(i2c, msgs, 2) != 2) - return -EIO; - - return 0; -} - -static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val) -{ - u8 msg[2] = { reg, val }; - struct i2c_msg msgs; - - msgs.flags = 0; - msgs.addr = id / 2; - msgs.len = 2; - msgs.buf = msg; - return i2c_transfer(i2c, &msgs, 1); -} - -static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); - udelay(1); - - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 1\n"); - } - return result; -} - -static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); - udelay(1); - - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 2\n"); - } - return result; -} - -static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - udelay(1); - - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 3\n"); - return -ETIMEDOUT; - } - return result; -} - -static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - udelay(1); - - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 5\n"); - } - return result; -} - -static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_reset\n"); - budget_av->slot_status = SLOTSTATUS_RESET; - - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ - msleep(2); - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ - msleep(20); /* 20 ms Vcc settling time */ - - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - msleep(20); - - /* reinitialise the frontend if necessary */ - if (budget_av->reinitialise_demod) - dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); - - return 0; -} - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_shutdown\n"); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - budget_av->slot_status = SLOTSTATUS_NONE; - - return 0; -} - -static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); - - return 0; -} - -static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - int result; - - if (slot != 0) - return -EINVAL; - - /* test the card detect line - needs to be done carefully - * since it never goes high for some CAMs on this interface (e.g. topuptv) */ - if (budget_av->slot_status == SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - udelay(1); - if (saa7146_read(saa, PSR) & MASK_06) { - if (budget_av->slot_status == SLOTSTATUS_NONE) { - budget_av->slot_status = SLOTSTATUS_PRESENT; - pr_info("cam inserted A\n"); - } - } - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - } - - /* We also try and read from IO memory to work round the above detection bug. If - * there is no CAM, we will get a timeout. Only done if there is no cam - * present, since this test actually breaks some cams :( - * - * if the CI interface is not open, we also do the above test since we - * don't care if the cam has problems - we'll be resetting it on open() anyway */ - if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); - if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { - budget_av->slot_status = SLOTSTATUS_PRESENT; - pr_info("cam inserted B\n"); - } else if (result < 0) { - if (budget_av->slot_status != SLOTSTATUS_NONE) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 5\n"); - return 0; - } - } - } - - /* read from attribute memory in reset/ready state to know when the CAM is ready */ - if (budget_av->slot_status == SLOTSTATUS_RESET) { - result = ciintf_read_attribute_mem(ca, slot, 0); - if (result == 0x1d) { - budget_av->slot_status = SLOTSTATUS_READY; - } - } - - /* work out correct return code */ - if (budget_av->slot_status != SLOTSTATUS_NONE) { - if (budget_av->slot_status & SLOTSTATUS_READY) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } - return DVB_CA_EN50221_POLL_CAM_PRESENT; - } - return 0; -} - -static int ciintf_init(struct budget_av *budget_av) -{ - struct saa7146_dev *saa = budget_av->budget.dev; - int result; - - memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - - /* Enable DEBI pins */ - saa7146_write(saa, MC1, MASK_27 | MASK_11); - - /* register CI interface */ - budget_av->ca.owner = THIS_MODULE; - budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; - budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; - budget_av->ca.read_cam_control = ciintf_read_cam_control; - budget_av->ca.write_cam_control = ciintf_write_cam_control; - budget_av->ca.slot_reset = ciintf_slot_reset; - budget_av->ca.slot_shutdown = ciintf_slot_shutdown; - budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; - budget_av->ca.poll_slot_status = ciintf_poll_slot_status; - budget_av->ca.data = budget_av; - budget_av->budget.ci_present = 1; - budget_av->slot_status = SLOTSTATUS_NONE; - - if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, - &budget_av->ca, 0, 1)) != 0) { - pr_err("ci initialisation failed\n"); - goto error; - } - - pr_info("ci interface initialised\n"); - return 0; - -error: - saa7146_write(saa, MC1, MASK_27); - return result; -} - -static void ciintf_deinit(struct budget_av *budget_av) -{ - struct saa7146_dev *saa = budget_av->budget.dev; - - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - - /* release the CA device */ - dvb_ca_en50221_release(&budget_av->ca); - - /* disable DEBI pins */ - saa7146_write(saa, MC1, MASK_27); -} - - -static const u8 saa7113_tab[] = { - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x33, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xeb, - 0x07, 0xe0, - 0x08, 0x28, - 0x09, 0x00, - 0x0a, 0x80, - 0x0b, 0x47, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x44, - - 0x10, 0x08, - 0x11, 0x0c, - 0x12, 0x7b, - 0x13, 0x00, - 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, - - 0x57, 0xff, - 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, - 0x5b, 0x83, 0x5e, 0x00, - 0xff -}; - -static int saa7113_init(struct budget_av *budget_av) -{ - struct budget *budget = &budget_av->budget; - struct saa7146_dev *saa = budget->dev; - const u8 *data = saa7113_tab; - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); - msleep(200); - - if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { - dprintk(1, "saa7113 not found on KNC card\n"); - return -ENODEV; - } - - dprintk(1, "saa7113 detected and initializing\n"); - - while (*data != 0xff) { - i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); - data += 2; - } - - dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); - - return 0; -} - -static int saa7113_setinput(struct budget_av *budget_av, int input) -{ - struct budget *budget = &budget_av->budget; - - if (1 != budget_av->has_saa7113) - return -ENODEV; - - if (input == 1) { - i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); - i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); - } else if (input == 0) { - i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); - i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); - } else - return -EINVAL; - - budget_av->cur_input = input; - return 0; -} - - -static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - - aclk = 0xb5; - if (srate < 2000000) - bclk = 0x86; - else if (srate < 5000000) - bclk = 0x89; - else if (srate < 15000000) - bclk = 0x8f; - else if (srate < 45000000) - bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) - m1 = 0x10; - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - stv0299_writereg(fe, 0x0f, 0x80 | m1); - - return 0; -} - -static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 div; - u8 buf[4]; - struct budget *budget = (struct budget *) fe->dvb->priv; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((c->frequency < 950000) || (c->frequency > 2150000)) - return -EINVAL; - - div = (c->frequency + (125 - 1)) / 125; /* round correctly */ - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; - buf[3] = 0x20; - - if (c->symbol_rate < 4000000) - buf[3] |= 1; - - if (c->frequency < 1250000) - buf[3] |= 0; - else if (c->frequency < 1550000) - buf[3] |= 0x40; - else if (c->frequency < 2050000) - buf[3] |= 0x80; - else if (c->frequency < 2150000) - buf[3] |= 0xC0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static u8 typhoon_cinergy1200s_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x92, - 0xff, 0xff -}; - -static struct stv0299_config typhoon_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - - -static struct stv0299_config cinergy_1200s_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - -static struct stv0299_config cinergy_1200s_1894_0010_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - -static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget *budget = (struct budget *) fe->dvb->priv; - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (c->frequency < 150000000 ? 0x01 : - c->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct tda1002x_config philips_cu1216_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static struct tda1002x_config philips_cu1216_config_altaddress = { - .demod_address = 0x0d, - .invert = 0, -}; - -static struct tda10023_config philips_cu1216_tda10023_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static int philips_tu1216_tuner_init(struct dvb_frontend *fe) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - return 0; -} - -static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget *budget = (struct budget *) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = - sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = c->frequency + 36166000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (c->frequency < 49000000) - return -EINVAL; - else if (c->frequency < 161000000) - band = 1; - else if (c->frequency < 444000000) - band = 2; - else if (c->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter - switch (c->bandwidth_hz) { - case 6000000: - filter = 0; - break; - - case 7000000: - filter = 0; - break; - - case 8000000: - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; - - // setup tuner buffer - tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tu1216_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - - return request_firmware(fw, name, &budget->dev->pci->dev); -} - -static struct tda1004x_config philips_tu1216_config = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 1, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tu1216_request_firmware, -}; - -static u8 philips_sd1878_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, - 0x05, 0x35, - 0x06, 0x40, - 0x07, 0x00, - 0x08, 0x43, - 0x09, 0x02, - 0x0C, 0x51, - 0x0D, 0x82, - 0x0E, 0x23, - 0x10, 0x3f, - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x93, - 0xff, 0xff -}; - -static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - - aclk = 0xb5; - if (srate < 2000000) - bclk = 0x86; - else if (srate < 5000000) - bclk = 0x89; - else if (srate < 15000000) - bclk = 0x8f; - else if (srate < 45000000) - bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) - m1 = 0x10; - - stv0299_writereg(fe, 0x0e, 0x23); - stv0299_writereg(fe, 0x0f, 0x94); - stv0299_writereg(fe, 0x10, 0x39); - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x15, 0xc9); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - stv0299_writereg(fe, 0x0f, 0x80 | m1); - - return 0; -} - -static struct stv0299_config philips_sd1878_config = { - .demod_address = 0x68, - .inittab = philips_sd1878_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, -}; - -/* KNC1 DVB-S (STB0899) Inittab */ -static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { - - { STB0899_DEV_ID , 0x81 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x8c }, - { STB0899_DISF22RX , 0x9a }, - { STB0899_SYSREG , 0x0b }, - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0x30 }, - { STB0899_IRQSTATUS_2 , 0x00 }, - { STB0899_IRQSTATUS_1 , 0x00 }, - { STB0899_IRQSTATUS_0 , 0x00 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x20 }, - { STB0899_IOPVALUE3 , 0xc9 }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x40 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x00 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x41 }, - { STB0899_AGC1REF , 0x08 }, - { STB0899_RTC , 0x7a }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x33 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xee }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xdd }, - { STB0899_LDT2 , 0xc9 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfb }, - { STB0899_QDCCOMP , 0x03 }, - { STB0899_POWERI , 0x3b }, - { STB0899_POWERQ , 0x3d }, - { STB0899_RCOMP , 0x81 }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x04 }, - { STB0899_AGC2I2 , 0xf5 }, - { STB0899_TLIR , 0x25 }, - { STB0899_RTF , 0x80 }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xca }, - { STB0899_CFRM , 0xf1 }, - { STB0899_CFRL , 0xf3 }, - { STB0899_NIRM , 0x2a }, - { STB0899_NIRL , 0x05 }, - { STB0899_ISYMB , 0x17 }, - { STB0899_QSYMB , 0xfa }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0xfd }, - { STB0899_EQUAQ1 , 0x04 }, - { STB0899_EQUAI2 , 0x0f }, - { STB0899_EQUAQ2 , 0xff }, - { STB0899_EQUAI3 , 0xdf }, - { STB0899_EQUAQ3 , 0xfa }, - { STB0899_EQUAI4 , 0x37 }, - { STB0899_EQUAQ4 , 0x0d }, - { STB0899_EQUAI5 , 0xbd }, - { STB0899_EQUAQ5 , 0xf7 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0xff }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x00 }, - { STB0899_ECNT3L , 0x00 }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xf0 }, - { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, - { STB0899_VTH56 , 0x4e }, - { STB0899_VTH67 , 0x48 }, - { STB0899_VTH78 , 0x38 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x0c }, - { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x00 }, - { STB0899_TSLLSTKL , 0x00 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0xab }, - { STB0899_PCKLENUL , 0x00 }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xcc }, - { STB0899_TSSTATUS , 0x80 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x96 }, - { STB0899_ERRCTRL3 , 0x89 }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x1f }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0x00 }, - { STB0899_MATSTRL , 0x00 }, - { STB0899_UPLSTRM , 0x00 }, - { STB0899_UPLSTRL , 0x00 }, - { STB0899_DFLSTRM , 0x00 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x00 }, - { STB0899_SYNCDSTRM , 0x00 }, - { STB0899_SYNCDSTRL , 0x00 }, - { STB0899_CFGPDELSTATUS1 , 0x10 }, - { STB0899_CFGPDELSTATUS2 , 0x00 }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x00 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -/* STB0899 demodulator config for the KNC1 and clones */ -static struct stb0899_config knc1_dvbs2_config = { - .init_dev = knc1_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = knc1_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .postproc = NULL, - - .demod_address = 0x68, -// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ - .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ -// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_OFF, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 90000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = tda8261_get_frequency, - .tuner_set_frequency = tda8261_set_frequency, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = tda8261_get_bandwidth, - .tuner_set_rfsiggain = NULL -}; - -/* - * SD1878/SHA tuner config - * 1F, Single I/P, Horizontal mount, High Sensitivity - */ -static const struct tda8261_config sd1878c_config = { -// .name = "SD1878/SHA", - .addr = 0x60, - .step_size = TDA8261_STEP_1000 /* kHz */ -}; - -static u8 read_pwm(struct budget_av *budget_av) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, - {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} - }; - - if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -#define SUBID_DVBS_KNC1 0x0010 -#define SUBID_DVBS_KNC1_PLUS 0x0011 -#define SUBID_DVBS_TYPHOON 0x4f56 -#define SUBID_DVBS_CINERGY1200 0x1154 -#define SUBID_DVBS_CYNERGY1200N 0x1155 -#define SUBID_DVBS_TV_STAR 0x0014 -#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 -#define SUBID_DVBS_TV_STAR_CI 0x0016 -#define SUBID_DVBS2_KNC1 0x0018 -#define SUBID_DVBS2_KNC1_OEM 0x0019 -#define SUBID_DVBS_EASYWATCH_1 0x001a -#define SUBID_DVBS_EASYWATCH_2 0x001b -#define SUBID_DVBS2_EASYWATCH 0x001d -#define SUBID_DVBS_EASYWATCH 0x001e - -#define SUBID_DVBC_EASYWATCH 0x002a -#define SUBID_DVBC_EASYWATCH_MK3 0x002c -#define SUBID_DVBC_KNC1 0x0020 -#define SUBID_DVBC_KNC1_PLUS 0x0021 -#define SUBID_DVBC_KNC1_MK3 0x0022 -#define SUBID_DVBC_KNC1_TDA10024 0x0028 -#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 -#define SUBID_DVBC_CINERGY1200 0x1156 -#define SUBID_DVBC_CINERGY1200_MK3 0x1176 - -#define SUBID_DVBT_EASYWATCH 0x003a -#define SUBID_DVBT_KNC1_PLUS 0x0031 -#define SUBID_DVBT_KNC1 0x0030 -#define SUBID_DVBT_CINERGY1200 0x1157 - -static void frontend_init(struct budget_av *budget_av) -{ - struct saa7146_dev * saa = budget_av->budget.dev; - struct dvb_frontend * fe = NULL; - - /* Enable / PowerON Frontend */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - - /* Wait for PowerON */ - msleep(100); - - /* additional setup necessary for the PLUS cards */ - switch (saa->pci->subsystem_device) { - case SUBID_DVBS_KNC1_PLUS: - case SUBID_DVBC_KNC1_PLUS: - case SUBID_DVBT_KNC1_PLUS: - case SUBID_DVBC_EASYWATCH: - case SUBID_DVBC_KNC1_PLUS_MK3: - case SUBID_DVBS2_KNC1: - case SUBID_DVBS2_KNC1_OEM: - case SUBID_DVBS2_EASYWATCH: - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); - break; - } - - switch (saa->pci->subsystem_device) { - - case SUBID_DVBS_KNC1: - /* - * maybe that setting is needed for other dvb-s cards as well, - * but so far it has been only confirmed for this type - */ - budget_av->reinitialise_demod = 1; - /* fall through */ - case SUBID_DVBS_KNC1_PLUS: - case SUBID_DVBS_EASYWATCH_1: - if (saa->pci->subsystem_vendor == 0x1894) { - fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config, - &budget_av->budget.i2c_adap); - if (fe) { - dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap); - } - } else { - fe = dvb_attach(stv0299_attach, &typhoon_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - } - break; - - case SUBID_DVBS_TV_STAR: - case SUBID_DVBS_TV_STAR_PLUS_X4: - case SUBID_DVBS_TV_STAR_CI: - case SUBID_DVBS_CYNERGY1200N: - case SUBID_DVBS_EASYWATCH: - case SUBID_DVBS_EASYWATCH_2: - fe = dvb_attach(stv0299_attach, &philips_sd1878_config, - &budget_av->budget.i2c_adap); - if (fe) { - dvb_attach(dvb_pll_attach, fe, 0x60, - &budget_av->budget.i2c_adap, - DVB_PLL_PHILIPS_SD1878_TDA8261); - } - break; - - case SUBID_DVBS_TYPHOON: - fe = dvb_attach(stv0299_attach, &typhoon_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - break; - case SUBID_DVBS2_KNC1: - case SUBID_DVBS2_KNC1_OEM: - case SUBID_DVBS2_EASYWATCH: - budget_av->reinitialise_demod = 1; - if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) - dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); - - break; - case SUBID_DVBS_CINERGY1200: - fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - break; - - case SUBID_DVBC_KNC1: - case SUBID_DVBC_KNC1_PLUS: - case SUBID_DVBC_CINERGY1200: - case SUBID_DVBC_EASYWATCH: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10021_attach, &philips_cu1216_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe == NULL) - fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBC_EASYWATCH_MK3: - case SUBID_DVBC_CINERGY1200_MK3: - case SUBID_DVBC_KNC1_MK3: - case SUBID_DVBC_KNC1_TDA10024: - case SUBID_DVBC_KNC1_PLUS_MK3: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10023_attach, - &philips_cu1216_tda10023_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBT_EASYWATCH: - case SUBID_DVBT_KNC1: - case SUBID_DVBT_KNC1_PLUS: - case SUBID_DVBT_CINERGY1200: - budget_av->reinitialise_demod = 1; - fe = dvb_attach(tda10046_attach, &philips_tu1216_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.init = philips_tu1216_tuner_init; - fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; - } - break; - } - - if (fe == NULL) { - pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - saa->pci->vendor, - saa->pci->device, - saa->pci->subsystem_vendor, - saa->pci->subsystem_device); - return; - } - - budget_av->budget.dvb_frontend = fe; - - if (dvb_register_frontend(&budget_av->budget.dvb_adapter, - budget_av->budget.dvb_frontend)) { - pr_err("Frontend registration failed!\n"); - dvb_frontend_detach(budget_av->budget.dvb_frontend); - budget_av->budget.dvb_frontend = NULL; - } -} - - -static void budget_av_irq(struct saa7146_dev *dev, u32 * isr) -{ - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - - dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); - - if (*isr & MASK_10) - ttpci_budget_irq10_handler(dev, isr); -} - -static int budget_av_detach(struct saa7146_dev *dev) -{ - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - int err; - - dprintk(2, "dev: %p\n", dev); - - if (1 == budget_av->has_saa7113) { - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); - - msleep(200); - - saa7146_unregister_device(&budget_av->vd, dev); - - saa7146_vv_release(dev); - } - - if (budget_av->budget.ci_present) - ciintf_deinit(budget_av); - - if (budget_av->budget.dvb_frontend != NULL) { - dvb_unregister_frontend(budget_av->budget.dvb_frontend); - dvb_frontend_detach(budget_av->budget.dvb_frontend); - } - err = ttpci_budget_deinit(&budget_av->budget); - - kfree(budget_av); - - return err; -} - -#define KNC1_INPUTS 2 -static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { - { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, - V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, - V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, -}; - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index); - if (i->index >= KNC1_INPUTS) - return -EINVAL; - memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - - *i = budget_av->cur_input; - - dprintk(1, "VIDIOC_G_INPUT %d\n", *i); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - - dprintk(1, "VIDIOC_S_INPUT %d\n", input); - return saa7113_setinput(budget_av, input); -} - -static struct saa7146_ext_vv vv_data; - -static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct budget_av *budget_av; - u8 *mac; - int err; - - dprintk(2, "dev: %p\n", dev); - - if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) - return -ENOMEM; - - budget_av->has_saa7113 = 0; - budget_av->budget.ci_present = 0; - - dev->ext_priv = budget_av; - - err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, - adapter_nr); - if (err) { - kfree(budget_av); - return err; - } - - /* knc1 initialization */ - saa7146_write(dev, DD1_STREAM_B, 0x04000000); - saa7146_write(dev, DD1_INIT, 0x07000600); - saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); - - if (saa7113_init(budget_av) == 0) { - budget_av->has_saa7113 = 1; - - if (0 != saa7146_vv_init(dev, &vv_data)) { - /* fixme: proper cleanup here */ - ERR("cannot init vv subsystem\n"); - return err; - } - vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; - vv_data.vid_ops.vidioc_g_input = vidioc_g_input; - vv_data.vid_ops.vidioc_s_input = vidioc_s_input; - - if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { - /* fixme: proper cleanup here */ - ERR("cannot register capture v4l2 device\n"); - saa7146_vv_release(dev); - return err; - } - - /* beware: this modifies dev->vv ... */ - saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, - SAA7146_HPS_SYNC_PORT_A); - - saa7113_setinput(budget_av, 0); - } - - /* fixme: find some sane values here... */ - saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - - mac = budget_av->budget.dvb_adapter.proposed_mac; - if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { - pr_err("KNC1-%d: Could not read MAC from KNC1 card\n", - budget_av->budget.dvb_adapter.num); - memset(mac, 0, 6); - } else { - pr_info("KNC1-%d: MAC addr = %pM\n", - budget_av->budget.dvb_adapter.num, mac); - } - - budget_av->budget.dvb_adapter.priv = budget_av; - frontend_init(budget_av); - ciintf_init(budget_av); - - ttpci_budget_init_hooks(&budget_av->budget); - - return 0; -} - -static struct saa7146_standard standard[] = { - {.name = "PAL",.id = V4L2_STD_PAL, - .v_offset = 0x17,.v_field = 288, - .h_offset = 0x14,.h_pixels = 680, - .v_max_out = 576,.h_max_out = 768 }, - - {.name = "NTSC",.id = V4L2_STD_NTSC, - .v_offset = 0x16,.v_field = 240, - .h_offset = 0x06,.h_pixels = 708, - .v_max_out = 480,.h_max_out = 640, }, -}; - -static struct saa7146_ext_vv vv_data = { - .inputs = 2, - .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 - .flags = 0, - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), -}; - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); -MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); -MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); -MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); -MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); -MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); -MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); -MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); -MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); -MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); -MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); -MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); -MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024); -MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); -MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); -MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); -MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); -MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); -MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); -MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), - MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), - MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), - MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), - MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), - MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), - MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), - MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), - MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), - MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), - MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), - MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), - MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), - MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), - MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), - MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), - MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), - MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), - MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), - MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), - MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028), - MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), - MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), - MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), - MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), - MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), - MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), - MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), - MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget_av", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = pci_tbl, - - .module = THIS_MODULE, - .attach = budget_av_attach, - .detach = budget_av_detach, - - .irq_mask = MASK_10, - .irq_func = budget_av_irq, -}; - -static int __init budget_av_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_av_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_av_init); -module_exit(budget_av_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c deleted file mode 100644 index 98e52417876..00000000000 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ /dev/null @@ -1,1591 +0,0 @@ -/* - * budget-ci.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold - * - * msp430 IR support contributed by Jack Thomasson - * partially based on the Siemens DVB driver by Ralph+Marcus Metzler - * - * CI interface support (c) 2004 Andrew de Quincey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include -#include - -#include "budget.h" - -#include "dvb_ca_en50221.h" -#include "stv0299.h" -#include "stv0297.h" -#include "tda1004x.h" -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -#include "stb6100.h" -#include "stb6100_cfg.h" -#include "lnbp21.h" -#include "bsbe1.h" -#include "bsru6.h" -#include "tda1002x.h" -#include "tda827x.h" -#include "bsbe1-d01a.h" - -#define MODULE_NAME "budget_ci" - -/* - * Regarding DEBIADDR_IR: - * Some CI modules hang if random addresses are read. - * Using address 0x4000 for the IR read means that we - * use the same address as for CI version, which should - * be a safe default. - */ -#define DEBIADDR_IR 0x4000 -#define DEBIADDR_CICONTROL 0x0000 -#define DEBIADDR_CIVERSION 0x4000 -#define DEBIADDR_IO 0x1000 -#define DEBIADDR_ATTR 0x3000 - -#define CICONTROL_RESET 0x01 -#define CICONTROL_ENABLETS 0x02 -#define CICONTROL_CAMDETECT 0x08 - -#define DEBICICTL 0x00420000 -#define DEBICICAM 0x02420000 - -#define SLOTSTATUS_NONE 1 -#define SLOTSTATUS_PRESENT 2 -#define SLOTSTATUS_RESET 4 -#define SLOTSTATUS_READY 8 -#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) - -/* RC5 device wildcard */ -#define IR_DEVICE_ANY 255 - -static int rc5_device = -1; -module_param(rc5_device, int, 0644); -MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); - -static int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct budget_ci_ir { - struct rc_dev *dev; - struct tasklet_struct msp430_irq_tasklet; - char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ - char phys[32]; - int rc5_device; - u32 ir_key; - bool have_command; - bool full_rc5; /* Outputs a full RC5 code */ -}; - -struct budget_ci { - struct budget budget; - struct tasklet_struct ciintf_irq_tasklet; - int slot_status; - int ci_irq; - struct dvb_ca_en50221 ca; - struct budget_ci_ir ir; - u8 tuner_pll_address; /* used for philips_tdm1316l configs */ -}; - -static void msp430_ir_interrupt(unsigned long data) -{ - struct budget_ci *budget_ci = (struct budget_ci *) data; - struct rc_dev *dev = budget_ci->ir.dev; - u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; - - /* - * The msp430 chip can generate two different bytes, command and device - * - * type1: X1CCCCCC, C = command bits (0 - 63) - * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit - * - * Each signal from the remote control can generate one or more command - * bytes and one or more device bytes. For the repeated bytes, the - * highest bit (X) is set. The first command byte is always generated - * before the first device byte. Other than that, no specific order - * seems to apply. To make life interesting, bytes can also be lost. - * - * Only when we have a command and device byte, a keypress is - * generated. - */ - - if (ir_debug) - printk("budget_ci: received byte 0x%02x\n", command); - - /* Remove repeat bit, we use every command */ - command = command & 0x7f; - - /* Is this a RC5 command byte? */ - if (command & 0x40) { - budget_ci->ir.have_command = true; - budget_ci->ir.ir_key = command & 0x3f; - return; - } - - /* It's a RC5 device byte */ - if (!budget_ci->ir.have_command) - return; - budget_ci->ir.have_command = false; - - if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && - budget_ci->ir.rc5_device != (command & 0x1f)) - return; - - if (budget_ci->ir.full_rc5) { - rc_keydown(dev, - budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key, - (command & 0x20) ? 1 : 0); - return; - } - - /* FIXME: We should generate complete scancodes for all devices */ - rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0); -} - -static int msp430_ir_init(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - struct rc_dev *dev; - int error; - - dev = rc_allocate_device(); - if (!dev) { - printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); - return -ENOMEM; - } - - snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), - "Budget-CI dvb ir receiver %s", saa->name); - snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys), - "pci-%s/ir0", pci_name(saa->pci)); - - dev->driver_name = MODULE_NAME; - dev->input_name = budget_ci->ir.name; - dev->input_phys = budget_ci->ir.phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.version = 1; - if (saa->pci->subsystem_vendor) { - dev->input_id.vendor = saa->pci->subsystem_vendor; - dev->input_id.product = saa->pci->subsystem_device; - } else { - dev->input_id.vendor = saa->pci->vendor; - dev->input_id.product = saa->pci->device; - } - dev->dev.parent = &saa->pci->dev; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; - - /* Select keymap and address */ - switch (budget_ci->budget.dev->pci->subsystem_device) { - case 0x100c: - case 0x100f: - case 0x1011: - case 0x1012: - /* The hauppauge keymap is a superset of these remotes */ - dev->map_name = RC_MAP_HAUPPAUGE; - budget_ci->ir.full_rc5 = true; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = 0x1f; - break; - case 0x1010: - case 0x1017: - case 0x1019: - case 0x101a: - case 0x101b: - /* for the Technotrend 1500 bundled remote */ - dev->map_name = RC_MAP_TT_1500; - break; - default: - /* unknown remote */ - dev->map_name = RC_MAP_BUDGET_CI_OLD; - break; - } - if (!budget_ci->ir.full_rc5) - dev->scanmask = 0xff; - - error = rc_register_device(dev); - if (error) { - printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); - rc_free_device(dev); - return error; - } - - budget_ci->ir.dev = dev; - - tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, - (unsigned long) budget_ci); - - SAA7146_IER_ENABLE(saa, MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); - - return 0; -} - -static void msp430_ir_deinit(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - - SAA7146_IER_DISABLE(saa, MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); - - rc_unregister_device(budget_ci->ir.dev); -} - -static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, - DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); -} - -static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, - DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); -} - -static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, - DEBIADDR_IO | (address & 3), 1, 1, 0); -} - -static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, - DEBIADDR_IO | (address & 3), 1, value, 1, 0); -} - -static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - - if (slot != 0) - return -EINVAL; - - if (budget_ci->ci_irq) { - // trigger on RISING edge during reset so we know when READY is re-asserted - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - } - budget_ci->slot_status = SLOTSTATUS_RESET; - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); - msleep(1); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - return 0; -} - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - return 0; -} - -static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - int tmp; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - - tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - tmp | CICONTROL_ENABLETS, 1, 0); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); - return 0; -} - -static void ciintf_interrupt(unsigned long data) -{ - struct budget_ci *budget_ci = (struct budget_ci *) data; - struct saa7146_dev *saa = budget_ci->budget.dev; - unsigned int flags; - - // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) - return; - - // read the CAM status - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - if (flags & CICONTROL_CAMDETECT) { - - // GPIO should be set to trigger on falling edge if a CAM is present - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - - if (budget_ci->slot_status & SLOTSTATUS_NONE) { - // CAM insertion IRQ - budget_ci->slot_status = SLOTSTATUS_PRESENT; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - - } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { - // CAM ready (reset completed) - budget_ci->slot_status = SLOTSTATUS_READY; - dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); - - } else if (budget_ci->slot_status & SLOTSTATUS_READY) { - // FR/DA IRQ - dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); - } - } else { - - // trigger on rising edge if a CAM is not present - when a CAM is inserted, we - // only want to get the IRQ when it sets READY. If we trigger on the falling edge, - // the CAM might not actually be ready yet. - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - - // generate a CAM removal IRQ if we haven't already - if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { - // CAM removal IRQ - budget_ci->slot_status = SLOTSTATUS_NONE; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - } -} - -static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - unsigned int flags; - - // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) - return -EINVAL; - - // read the CAM status - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - if (flags & CICONTROL_CAMDETECT) { - // mark it as present if it wasn't before - if (budget_ci->slot_status & SLOTSTATUS_NONE) { - budget_ci->slot_status = SLOTSTATUS_PRESENT; - } - - // during a RESET, we check if we can read from IO memory to see when CAM is ready - if (budget_ci->slot_status & SLOTSTATUS_RESET) { - if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { - budget_ci->slot_status = SLOTSTATUS_READY; - } - } - } else { - budget_ci->slot_status = SLOTSTATUS_NONE; - } - - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - if (budget_ci->slot_status & SLOTSTATUS_READY) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } - return DVB_CA_EN50221_POLL_CAM_PRESENT; - } - - return 0; -} - -static int ciintf_init(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - int flags; - int result; - int ci_version; - int ca_flags; - - memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); - - // enable DEBI pins - saa7146_write(saa, MC1, MASK_27 | MASK_11); - - // test if it is there - ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); - if ((ci_version & 0xa0) != 0xa0) { - result = -ENODEV; - goto error; - } - - // determine whether a CAM is present or not - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - budget_ci->slot_status = SLOTSTATUS_NONE; - if (flags & CICONTROL_CAMDETECT) - budget_ci->slot_status = SLOTSTATUS_PRESENT; - - // version 0xa2 of the CI firmware doesn't generate interrupts - if (ci_version == 0xa2) { - ca_flags = 0; - budget_ci->ci_irq = 0; - } else { - ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | - DVB_CA_EN50221_FLAG_IRQ_FR | - DVB_CA_EN50221_FLAG_IRQ_DA; - budget_ci->ci_irq = 1; - } - - // register CI interface - budget_ci->ca.owner = THIS_MODULE; - budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; - budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; - budget_ci->ca.read_cam_control = ciintf_read_cam_control; - budget_ci->ca.write_cam_control = ciintf_write_cam_control; - budget_ci->ca.slot_reset = ciintf_slot_reset; - budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; - budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; - budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; - budget_ci->ca.data = budget_ci; - if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, - &budget_ci->ca, - ca_flags, 1)) != 0) { - printk("budget_ci: CI interface detected, but initialisation failed.\n"); - goto error; - } - - // Setup CI slot IRQ - if (budget_ci->ci_irq) { - tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - } else { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - } - SAA7146_IER_ENABLE(saa, MASK_03); - } - - // enable interface - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - // success! - printk("budget_ci: CI interface initialised\n"); - budget_ci->budget.ci_present = 1; - - // forge a fake CI IRQ so the CAM state is setup correctly - if (budget_ci->ci_irq) { - flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; - if (budget_ci->slot_status != SLOTSTATUS_NONE) - flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); - } - - return 0; - -error: - saa7146_write(saa, MC1, MASK_27); - return result; -} - -static void ciintf_deinit(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - - // disable CI interrupts - if (budget_ci->ci_irq) { - SAA7146_IER_DISABLE(saa, MASK_03); - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ciintf_irq_tasklet); - } - - // reset interface - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); - msleep(1); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - // disable TS data stream to CI interface - saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); - - // release the CA device - dvb_ca_en50221_release(&budget_ci->ca); - - // disable DEBI pins - saa7146_write(saa, MC1, MASK_27); -} - -static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) -{ - struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; - - dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); - - if (*isr & MASK_06) - tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); - - if (*isr & MASK_10) - ttpci_budget_irq10_handler(dev, isr); - - if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) - tasklet_schedule(&budget_ci->ciintf_irq_tasklet); -} - -static u8 philips_su1278_tt_inittab[] = { - 0x01, 0x0f, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x5b, - 0x05, 0x85, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x02, - 0x09, 0x00, - 0x0C, 0x01, - 0x0D, 0x81, - 0x0E, 0x44, - 0x0f, 0x14, - 0x10, 0x3c, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x97, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x93, - 0xff, 0xff -}; - -static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - stv0299_writereg(fe, 0x0e, 0x44); - if (srate >= 10000000) { - stv0299_writereg(fe, 0x13, 0x97); - stv0299_writereg(fe, 0x14, 0x95); - stv0299_writereg(fe, 0x15, 0xc9); - stv0299_writereg(fe, 0x17, 0x8c); - stv0299_writereg(fe, 0x1a, 0xfe); - stv0299_writereg(fe, 0x1c, 0x7f); - stv0299_writereg(fe, 0x2d, 0x09); - } else { - stv0299_writereg(fe, 0x13, 0x99); - stv0299_writereg(fe, 0x14, 0x8d); - stv0299_writereg(fe, 0x15, 0xce); - stv0299_writereg(fe, 0x17, 0x43); - stv0299_writereg(fe, 0x1a, 0x1d); - stv0299_writereg(fe, 0x1c, 0x12); - stv0299_writereg(fe, 0x2d, 0x05); - } - stv0299_writereg(fe, 0x0e, 0x23); - stv0299_writereg(fe, 0x0f, 0x94); - stv0299_writereg(fe, 0x10, 0x39); - stv0299_writereg(fe, 0x15, 0xc9); - - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - - return 0; -} - -static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u32 div; - u8 buf[4]; - struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((p->frequency < 950000) || (p->frequency > 2150000)) - return -EINVAL; - - div = (p->frequency + (500 - 1)) / 500; /* round correctly */ - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; - buf[3] = 0x20; - - if (p->symbol_rate < 4000000) - buf[3] |= 1; - - if (p->frequency < 1250000) - buf[3] |= 0; - else if (p->frequency < 1550000) - buf[3] |= 0x40; - else if (p->frequency < 2050000) - buf[3] |= 0x80; - else if (p->frequency < 2150000) - buf[3] |= 0xC0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct stv0299_config philips_su1278_tt_config = { - - .demod_address = 0x68, - .inittab = philips_su1278_tt_inittab, - .mclk = 64000000UL, - .invert = 0, - .skip_reinit = 1, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 50, - .set_symbol_rate = philips_su1278_tt_set_symbol_rate, -}; - - - -static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = - sizeof(td1316_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - // disable the mc44BC374c (do not check for errors) - tuner_msg.addr = 0x65; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); - } - - return 0; -} - -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = p->frequency + 36130000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (p->frequency < 49000000) - return -EINVAL; - else if (p->frequency < 159000000) - band = 1; - else if (p->frequency < 444000000) - band = 2; - else if (p->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter and TDA9889 - switch (p->bandwidth_hz) { - case 6000000: - tda1004x_writereg(fe, 0x0C, 0x14); - filter = 0; - break; - - case 7000000: - tda1004x_writereg(fe, 0x0C, 0x80); - filter = 0; - break; - - case 8000000: - tda1004x_writereg(fe, 0x0C, 0x14); - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - - return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); -} - -static struct tda1004x_config philips_tdm1316l_config = { - - .demod_address = 0x8, - .invert = 0, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static struct tda1004x_config philips_tdm1316l_config_invert = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u8 tuner_buf[5]; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, - .flags = 0, - .buf = tuner_buf, - .len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = p->frequency + 36125000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) { - cp = 3; - band = 1; - } else if (tuner_frequency < 160000000) { - cp = 5; - band = 1; - } else if (tuner_frequency < 200000000) { - cp = 6; - band = 1; - } else if (tuner_frequency < 290000000) { - cp = 3; - band = 2; - } else if (tuner_frequency < 420000000) { - cp = 5; - band = 2; - } else if (tuner_frequency < 480000000) { - cp = 6; - band = 2; - } else if (tuner_frequency < 620000000) { - cp = 3; - band = 4; - } else if (tuner_frequency < 830000000) { - cp = 5; - band = 4; - } else if (tuner_frequency < 895000000) { - cp = 7; - band = 4; - } else - return -EINVAL; - - // assume PLL filter should always be 8MHz for the moment. - filter = 1; - - // calculate divisor - tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xc8; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - tuner_buf[4] = 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(50); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - - return 0; -} - -static u8 dvbc_philips_tdm1316l_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x20, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x00, - 0x4b, 0x7b, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x10, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x04, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x38, - 0x62, 0x0a, - 0x53, 0x13, - 0x59, 0x08, - 0xff, 0xff, -}; - -static struct stv0297_config dvbc_philips_tdm1316l_config = { - .demod_address = 0x1c, - .inittab = dvbc_philips_tdm1316l_inittab, - .invert = 0, - .stop_during_read = 1, -}; - -static struct tda10023_config tda10023_config = { - .demod_address = 0xc, - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .deltaf = 0xa511, -}; - -static struct tda827x_config tda827x_config = { - .config = 0, -}; - -/* TT S2-3200 DVB-S (STB0899) Inittab */ -static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { - - { STB0899_DEV_ID , 0x81 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x8c }, - { STB0899_DISF22RX , 0x9a }, - { STB0899_SYSREG , 0x0b }, - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0x30 }, - { STB0899_IRQSTATUS_2 , 0x00 }, - { STB0899_IRQSTATUS_1 , 0x00 }, - { STB0899_IRQSTATUS_0 , 0x00 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x20 }, - { STB0899_IOPVALUE3 , 0xc9 }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x40 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x00 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x41 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x7a }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xc7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xdd }, - { STB0899_LDT2 , 0xc9 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfb }, - { STB0899_QDCCOMP , 0x03 }, - { STB0899_POWERI , 0x3b }, - { STB0899_POWERQ , 0x3d }, - { STB0899_RCOMP , 0x81 }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x04 }, - { STB0899_AGC2I2 , 0xf5 }, - { STB0899_TLIR , 0x25 }, - { STB0899_RTF , 0x80 }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xca }, - { STB0899_CFRM , 0xf1 }, - { STB0899_CFRL , 0xf3 }, - { STB0899_NIRM , 0x2a }, - { STB0899_NIRL , 0x05 }, - { STB0899_ISYMB , 0x17 }, - { STB0899_QSYMB , 0xfa }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0xfd }, - { STB0899_EQUAQ1 , 0x04 }, - { STB0899_EQUAI2 , 0x0f }, - { STB0899_EQUAQ2 , 0xff }, - { STB0899_EQUAI3 , 0xdf }, - { STB0899_EQUAQ3 , 0xfa }, - { STB0899_EQUAI4 , 0x37 }, - { STB0899_EQUAQ4 , 0x0d }, - { STB0899_EQUAI5 , 0xbd }, - { STB0899_EQUAQ5 , 0xf7 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0xff }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x00 }, - { STB0899_ECNT3L , 0x00 }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xf0 }, - { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, - { STB0899_VTH56 , 0x4e }, - { STB0899_VTH67 , 0x48 }, - { STB0899_VTH78 , 0x38 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x0c }, - { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x00 }, - { STB0899_TSLLSTKL , 0x00 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0xab }, - { STB0899_PCKLENUL , 0x00 }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xcc }, - { STB0899_TSSTATUS , 0x80 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x96 }, - { STB0899_ERRCTRL3 , 0x89 }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x1f }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0x00 }, - { STB0899_MATSTRL , 0x00 }, - { STB0899_UPLSTRM , 0x00 }, - { STB0899_UPLSTRL , 0x00 }, - { STB0899_DFLSTRM , 0x00 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x00 }, - { STB0899_SYNCDSTRM , 0x00 }, - { STB0899_SYNCDSTRL , 0x00 }, - { STB0899_CFGPDELSTATUS1 , 0x10 }, - { STB0899_CFGPDELSTATUS2 , 0x00 }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x00 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -static struct stb0899_config tt3200_config = { - .init_dev = tt3200_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = tt3200_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .postproc = NULL, - - .demod_address = 0x68, - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL -}; - -static struct stb6100_config tt3200_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static void frontend_init(struct budget_ci *budget_ci) -{ - switch (budget_ci->budget.dev->pci->subsystem_device) { - case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) - budget_ci->budget.dvb_frontend = - dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; - break; - } - break; - - case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) - budget_ci->budget.dvb_frontend = - dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; - break; - } - break; - - case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) - budget_ci->tuner_pll_address = 0x61; - budget_ci->budget.dvb_frontend = - dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) - budget_ci->tuner_pll_address = 0x63; - budget_ci->budget.dvb_frontend = - dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) - budget_ci->tuner_pll_address = 0x60; - budget_ci->budget.dvb_frontend = - dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1017: // TT S-1500 PCI - budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; - - budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ - budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { - printk(KERN_ERR "%s: No tda827x found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */ - budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) { - if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { - printk(KERN_ERR "%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } else { - printk(KERN_ERR "%s: No STB6000 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x1019: // TT S2-3200 PCI - /* - * NOTE! on some STB0899 versions, the internal PLL takes a longer time - * to settle, aka LOCK. On the older revisions of the chip, we don't see - * this, as a result on the newer chips the entire clock tree, will not - * be stable after a freshly POWER 'ed up situation. - * In this case, we should RESET the STB0899 (Active LOW) and wait for - * PLL stabilization. - * - * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is - * connected to the SAA7146 GPIO, GPIO2, Pin 142 - */ - /* Reset Demodulator */ - saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); - /* Wait for everything to die */ - msleep(50); - /* Pull it up out of Reset state */ - saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); - /* Wait for PLL to stabilize */ - msleep(250); - /* - * PLL state should be stable now. Ideally, we should check - * for PLL LOCK status. But well, never mind! - */ - budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { - if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { - printk("%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } else { - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - } - - if (budget_ci->budget.dvb_frontend == NULL) { - printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget_ci->budget.dev->pci->vendor, - budget_ci->budget.dev->pci->device, - budget_ci->budget.dev->pci->subsystem_vendor, - budget_ci->budget.dev->pci->subsystem_device); - } else { - if (dvb_register_frontend - (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { - printk("budget-ci: Frontend registration failed!\n"); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } -} - -static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct budget_ci *budget_ci; - int err; - - budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL); - if (!budget_ci) { - err = -ENOMEM; - goto out1; - } - - dprintk(2, "budget_ci: %p\n", budget_ci); - - dev->ext_priv = budget_ci; - - err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, - adapter_nr); - if (err) - goto out2; - - err = msp430_ir_init(budget_ci); - if (err) - goto out3; - - ciintf_init(budget_ci); - - budget_ci->budget.dvb_adapter.priv = budget_ci; - frontend_init(budget_ci); - - ttpci_budget_init_hooks(&budget_ci->budget); - - return 0; - -out3: - ttpci_budget_deinit(&budget_ci->budget); -out2: - kfree(budget_ci); -out1: - return err; -} - -static int budget_ci_detach(struct saa7146_dev *dev) -{ - struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; - struct saa7146_dev *saa = budget_ci->budget.dev; - int err; - - if (budget_ci->budget.ci_present) - ciintf_deinit(budget_ci); - msp430_ir_deinit(budget_ci); - if (budget_ci->budget.dvb_frontend) { - dvb_unregister_frontend(budget_ci->budget.dvb_frontend); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - } - err = ttpci_budget_deinit(&budget_ci->budget); - - // disable frontend and CI interface - saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); - - kfree(budget_ci); - - return err; -} - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); -MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), - MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), - MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), - MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), - MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), - MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), - MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), - MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), - MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget_ci dvb", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = &pci_tbl[0], - .attach = budget_ci_attach, - .detach = budget_ci_detach, - - .irq_mask = MASK_03 | MASK_06 | MASK_10, - .irq_func = budget_ci_irq, -}; - -static int __init budget_ci_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_ci_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_ci_init); -module_exit(budget_ci_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB cards w/ CI-module produced by " - "Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c deleted file mode 100644 index 37d02fe0913..00000000000 --- a/drivers/media/dvb/ttpci/budget-core.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * budget-core.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 26feb2004 Support for FS Activy Card (Grundig tuner) by - * Michael Dreher , - * Oliver Endriss , - * Andreas 'randy' Weinberger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - - -#include "budget.h" -#include "ttpci-eeprom.h" - -#define TS_WIDTH (2 * TS_SIZE) -#define TS_WIDTH_ACTIVY TS_SIZE -#define TS_WIDTH_DVBC TS_SIZE -#define TS_HEIGHT_MASK 0xf00 -#define TS_HEIGHT_MASK_ACTIVY 0xc00 -#define TS_HEIGHT_MASK_DVBC 0xe00 -#define TS_MIN_BUFSIZE_K 188 -#define TS_MAX_BUFSIZE_K 1410 -#define TS_MAX_BUFSIZE_K_ACTIVY 564 -#define TS_MAX_BUFSIZE_K_DVBC 1316 -#define BUFFER_WARNING_WAIT (30*HZ) - -int budget_debug; -static int dma_buffer_size = TS_MIN_BUFSIZE_K; -module_param_named(debug, budget_debug, int, 0644); -module_param_named(bufsize, dma_buffer_size, int, 0444); -MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); -MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); - -/**************************************************************************** - * TT budget / WinTV Nova - ****************************************************************************/ - -static int stop_ts_capture(struct budget *budget) -{ - dprintk(2, "budget: %p\n", budget); - - saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off - SAA7146_IER_DISABLE(budget->dev, MASK_10); - return 0; -} - -static int start_ts_capture(struct budget *budget) -{ - struct saa7146_dev *dev = budget->dev; - - dprintk(2, "budget: %p\n", budget); - - if (!budget->feeding || !budget->fe_synced) - return 0; - - saa7146_write(dev, MC1, MASK_20); // DMA3 off - - memset(budget->grabbing, 0x00, budget->buffer_size); - - saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - - budget->ttbp = 0; - - /* - * Signal path on the Activy: - * - * tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory - * - * Since the tuner feeds 204 bytes packets into the SAA7146, - * DMA3 is configured to strip the trailing 16 FEC bytes: - * Pitch: 188, NumBytes3: 188, NumLines3: 1024 - */ - - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: - saa7146_write(dev, DD1_INIT, 0x04000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - break; - case BUDGET_PATCH: - saa7146_write(dev, DD1_INIT, 0x00000200); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - break; - case BUDGET_CIN1200C_MK3: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1C_TDA10024: - case BUDGET_KNC1CP_MK3: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x00000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - break; - default: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x02000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - } - - saa7146_write(dev, MC2, (MASK_08 | MASK_24)); - mdelay(10); - - saa7146_write(dev, BASE_ODD3, 0); - if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { - // using odd/even buffers - saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); - } else { - // using a single buffer - saa7146_write(dev, BASE_EVEN3, 0); - } - saa7146_write(dev, PROT_ADDR3, budget->buffer_size); - saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); - - saa7146_write(dev, PITCH3, budget->buffer_width); - saa7146_write(dev, NUM_LINE_BYTE3, - (budget->buffer_height << 16) | budget->buffer_width); - - saa7146_write(dev, MC2, (MASK_04 | MASK_20)); - - SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ - SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ - saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ - - return 0; -} - -static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - int synced; - int ret; - - if (budget->read_fe_status) - ret = budget->read_fe_status(fe, status); - else - ret = -EINVAL; - - if (!ret) { - synced = (*status & FE_HAS_LOCK); - if (synced != budget->fe_synced) { - budget->fe_synced = synced; - spin_lock(&budget->feedlock); - if (synced) - start_ts_capture(budget); - else - stop_ts_capture(budget); - spin_unlock(&budget->feedlock); - } - } - return ret; -} - -static void vpeirq(unsigned long data) -{ - struct budget *budget = (struct budget *) data; - u8 *mem = (u8 *) (budget->grabbing); - u32 olddma = budget->ttbp; - u32 newdma = saa7146_read(budget->dev, PCI_VDP3); - u32 count; - - /* Ensure streamed PCI data is synced to CPU */ - pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); - - /* nearest lower position divisible by 188 */ - newdma -= newdma % 188; - - if (newdma >= budget->buffer_size) - return; - - budget->ttbp = newdma; - - if (budget->feeding == 0 || newdma == olddma) - return; - - if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ - count = newdma - olddma; - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); - } else { /* wraparound, dump olddma..buflen and 0..newdma */ - count = budget->buffer_size - olddma; - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); - count += newdma; - dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); - } - - if (count > budget->buffer_warning_threshold) - budget->buffer_warnings++; - - if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { - printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", - budget->dev->name, __func__, budget->buffer_warnings, count); - budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; - budget->buffer_warnings = 0; - } -} - - -int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop) -{ - struct saa7146_dev *saa = budget->dev; - int result = 0; - unsigned long flags = 0; - - if (count > 4 || count <= 0) - return 0; - - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, MC2, (2 << 16) | 2); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - result = saa7146_read(saa, DEBI_AD); - result &= (0xffffffffUL >> ((4 - count) * 8)); - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - - return result; -} - -int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, - int count, u32 value, int uselocks, int nobusyloop) -{ - struct saa7146_dev *saa = budget->dev; - unsigned long flags = 0; - int result; - - if (count > 4 || count <= 0) - return 0; - - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, DEBI_AD, value); - saa7146_write(saa, MC2, (2 << 16) | 2); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return 0; -} - - -/**************************************************************************** - * DVB API SECTION - ****************************************************************************/ - -static int budget_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct budget *budget = (struct budget *) demux->priv; - int status = 0; - - dprintk(2, "budget: %p\n", budget); - - if (!demux->dmx.frontend) - return -EINVAL; - - spin_lock(&budget->feedlock); - feed->pusi_seen = 0; /* have a clean section start */ - if (budget->feeding++ == 0) - status = start_ts_capture(budget); - spin_unlock(&budget->feedlock); - return status; -} - -static int budget_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct budget *budget = (struct budget *) demux->priv; - int status = 0; - - dprintk(2, "budget: %p\n", budget); - - spin_lock(&budget->feedlock); - if (--budget->feeding == 0) - status = stop_ts_capture(budget); - spin_unlock(&budget->feedlock); - return status; -} - -static int budget_register(struct budget *budget) -{ - struct dvb_demux *dvbdemux = &budget->demux; - int ret; - - dprintk(2, "budget: %p\n", budget); - - dvbdemux->priv = (void *) budget; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = budget_start_feed; - dvbdemux->stop_feed = budget_stop_feed; - dvbdemux->write_to_decoder = NULL; - - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&budget->demux); - - budget->dmxdev.filternum = 256; - budget->dmxdev.demux = &dvbdemux->dmx; - budget->dmxdev.capabilities = 0; - - dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter); - - budget->hw_frontend.source = DMX_FRONTEND_0; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); - - if (ret < 0) - return ret; - - budget->mem_frontend.source = DMX_MEMORY_FE; - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); - if (ret < 0) - return ret; - - ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); - if (ret < 0) - return ret; - - dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); - - return 0; -} - -static void budget_unregister(struct budget *budget) -{ - struct dvb_demux *dvbdemux = &budget->demux; - - dprintk(2, "budget: %p\n", budget); - - dvb_net_release(&budget->dvb_net); - - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend); - - dvb_dmxdev_release(&budget->dmxdev); - dvb_dmx_release(&budget->demux); -} - -int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, - struct saa7146_pci_extension_data *info, - struct module *owner, short *adapter_nums) -{ - int ret = 0; - struct budget_info *bi = info->ext_priv; - int max_bufsize; - int height_mask; - - memset(budget, 0, sizeof(struct budget)); - - dprintk(2, "dev: %p, budget: %p\n", dev, budget); - - budget->card = bi; - budget->dev = (struct saa7146_dev *) dev; - - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: - budget->buffer_width = TS_WIDTH_ACTIVY; - max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; - height_mask = TS_HEIGHT_MASK_ACTIVY; - break; - - case BUDGET_KNC1C: - case BUDGET_KNC1CP: - case BUDGET_CIN1200C: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1C_TDA10024: - case BUDGET_KNC1CP_MK3: - case BUDGET_CIN1200C_MK3: - budget->buffer_width = TS_WIDTH_DVBC; - max_bufsize = TS_MAX_BUFSIZE_K_DVBC; - height_mask = TS_HEIGHT_MASK_DVBC; - break; - - default: - budget->buffer_width = TS_WIDTH; - max_bufsize = TS_MAX_BUFSIZE_K; - height_mask = TS_HEIGHT_MASK; - } - - if (dma_buffer_size < TS_MIN_BUFSIZE_K) - dma_buffer_size = TS_MIN_BUFSIZE_K; - else if (dma_buffer_size > max_bufsize) - dma_buffer_size = max_bufsize; - - budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; - if (budget->buffer_height > 0xfff) { - budget->buffer_height /= 2; - budget->buffer_height &= height_mask; - budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; - } else { - budget->buffer_height &= height_mask; - budget->buffer_size = budget->buffer_height * budget->buffer_width; - } - budget->buffer_warning_threshold = budget->buffer_size * 80/100; - budget->buffer_warnings = 0; - budget->buffer_warning_time = jiffies; - - dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", - budget->dev->name, - budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", - budget->buffer_width, budget->buffer_height); - printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); - - ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, - owner, &budget->dev->pci->dev, adapter_nums); - if (ret < 0) - return ret; - - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25)); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - saa7146_write(dev, DD1_INIT, 0x02000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - if (bi->type != BUDGET_FS_ACTIVY) - budget->video_port = BUDGET_VIDEO_PORTB; - else - budget->video_port = BUDGET_VIDEO_PORTA; - spin_lock_init(&budget->feedlock); - spin_lock_init(&budget->debilock); - - /* the Siemens DVB needs this if you want to have the i2c chips - get recognized before the main driver is loaded */ - if (bi->type != BUDGET_FS_ACTIVY) - saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ - - strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name)); - - saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); - strcpy(budget->i2c_adap.name, budget->card->name); - - if (i2c_add_adapter(&budget->i2c_adap) < 0) { - ret = -ENOMEM; - goto err_dvb_unregister; - } - - ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); - - budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt); - if (NULL == budget->grabbing) { - ret = -ENOMEM; - goto err_del_i2c; - } - - saa7146_write(dev, PCI_BT_V1, 0x001c0000); - /* upload all */ - saa7146_write(dev, GPIO_CTRL, 0x000000); - - tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); - - /* frontend power on */ - if (bi->type != BUDGET_FS_ACTIVY) - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - if ((ret = budget_register(budget)) == 0) - return 0; /* Everything OK */ - - /* An error occurred, cleanup resources */ - saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); - -err_del_i2c: - i2c_del_adapter(&budget->i2c_adap); - -err_dvb_unregister: - dvb_unregister_adapter(&budget->dvb_adapter); - - return ret; -} - -void ttpci_budget_init_hooks(struct budget *budget) -{ - if (budget->dvb_frontend && !budget->read_fe_status) { - budget->read_fe_status = budget->dvb_frontend->ops.read_status; - budget->dvb_frontend->ops.read_status = budget_read_fe_status; - } -} - -int ttpci_budget_deinit(struct budget *budget) -{ - struct saa7146_dev *dev = budget->dev; - - dprintk(2, "budget: %p\n", budget); - - budget_unregister(budget); - - tasklet_kill(&budget->vpe_tasklet); - - saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); - - i2c_del_adapter(&budget->i2c_adap); - - dvb_unregister_adapter(&budget->dvb_adapter); - - return 0; -} - -void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr) -{ - struct budget *budget = (struct budget *) dev->ext_priv; - - dprintk(8, "dev: %p, budget: %p\n", dev, budget); - - if (*isr & MASK_10) - tasklet_schedule(&budget->vpe_tasklet); -} - -void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) -{ - struct budget *budget = (struct budget *) dev->ext_priv; - - spin_lock(&budget->feedlock); - budget->video_port = video_port; - if (budget->feeding) { - stop_ts_capture(budget); - start_ts_capture(budget); - } - spin_unlock(&budget->feedlock); -} - -EXPORT_SYMBOL_GPL(ttpci_budget_debiread); -EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); -EXPORT_SYMBOL_GPL(ttpci_budget_init); -EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks); -EXPORT_SYMBOL_GPL(ttpci_budget_deinit); -EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); -EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); -EXPORT_SYMBOL_GPL(budget_debug); - -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c deleted file mode 100644 index 2cb35c23d2a..00000000000 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - * budget-patch.c: driver for Budget Patch, - * hardware modification of DVB-S cards enabling full TS - * - * Written by Emard - * - * Original idea by Roberto Deza - * - * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic - * and Metzlerbros - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include "av7110.h" -#include "av7110_hw.h" -#include "budget.h" -#include "stv0299.h" -#include "ves1x93.h" -#include "tda8083.h" - -#include "bsru6.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define budget_patch budget - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); -//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), -// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), - { - .vendor = 0, - } -}; - -/* those lines are for budget-patch to be tried -** on a true budget card and observe the -** behaviour of VSYNC generated by rps1. -** this code was shamelessly copy/pasted from budget.c -*/ -static void gpio_Set22K (struct budget *budget, int state) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); -} - -/* Diseqc functions only for TT Budget card */ -/* taken from the Skyvision DVB driver by - Ralph Metzler */ - -static void DiseqcSendBit (struct budget *budget, int data) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(data ? 500 : 1000); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - udelay(data ? 1000 : 500); -} - -static void DiseqcSendByte (struct budget *budget, int data) -{ - int i, par=1, d; - - dprintk(2, "budget: %p\n", budget); - - for (i=7; i>=0; i--) { - d = (data>>i)&1; - par ^= d; - DiseqcSendBit(budget, d); - } - - DiseqcSendBit(budget, par); -} - -static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) -{ - struct saa7146_dev *dev=budget->dev; - int i; - - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - mdelay(16); - - for (i=0; idvb->priv; - - switch (tone) { - case SEC_TONE_ON: - gpio_Set22K (budget, 1); - break; - - case SEC_TONE_OFF: - gpio_Set22K (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, 0, NULL, minicmd); - - return 0; -} - -static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) -{ - int i; - - dprintk(2, "budget: %p\n", budget); - - for (i = 2; i < length; i++) - { - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); - msleep(5); - } - if (length) - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); - else - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); - msleep(5); - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); - msleep(5); - return 0; -} - -static void av7110_set22k(struct budget_patch *budget, int state) -{ - u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; - - dprintk(2, "budget: %p\n", budget); - budget_av7110_send_fw_cmd(budget, buf, 2); -} - -static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) -{ - int i; - u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - dprintk(2, "budget: %p\n", budget); - - if (len>10) - len=10; - - buf[1] = len+2; - buf[2] = len; - - if (burst != -1) - buf[3]=burst ? 0x01 : 0x00; - else - buf[3]=0xffff; - - for (i=0; idvb->priv; - - switch (tone) { - case SEC_TONE_ON: - av7110_set22k (budget, 1); - break; - - case SEC_TONE_OFF: - av7110_set22k (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - - av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - - av7110_send_diseqc_msg (budget, 0, NULL, minicmd); - - return 0; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (p->frequency + 479500) / 125; - - if (p->frequency > 2000000) - pwr = 3; - else if (p->frequency > 1800000) - pwr = 2; - else if (p->frequency > 1600000) - pwr = 1; - else if (p->frequency > 1200000) - pwr = 0; - else if (p->frequency >= 1100000) - pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = { - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = p->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - -static void frontend_init(struct budget_patch* budget) -{ - switch(budget->dev->pci->subsystem_device) { - case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X - case 0x1013: // SATELCO Multimedia PCI - - // try the ALPS BSRV2 first of all - budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; - break; - } - - // try the ALPS BSRU6 now - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - - // Try the grundig 29504-451 - budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - break; - } - - if (budget->dvb_frontend == NULL) { - printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget->dev->pci->vendor, - budget->dev->pci->device, - budget->dev->pci->subsystem_vendor, - budget->dev->pci->subsystem_device); - } else { - if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { - printk("budget-av: Frontend registration failed!\n"); - dvb_frontend_detach(budget->dvb_frontend); - budget->dvb_frontend = NULL; - } - } -} - -/* written by Emard */ -static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) -{ - struct budget_patch *budget; - int err; - int count = 0; - int detected = 0; - -#define PATCH_RESET 0 -#define RPS_IRQ 0 -#define HPS_SETUP 0 -#if PATCH_RESET - saa7146_write(dev, MC1, MASK_31); - msleep(40); -#endif -#if HPS_SETUP - // initialize registers. Better to have it like this - // than leaving something unconfigured - saa7146_write(dev, DD1_STREAM_B, 0); - // port B VSYNC at rising edge - saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! - saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI - - // debi config - // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); - - // zero all HPS registers - saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 - saa7146_write(dev, HPS_H_SCALE, 0); // r6c - saa7146_write(dev, BCS_CTRL, 0); // r70 - saa7146_write(dev, HPS_V_SCALE, 0); // r60 - saa7146_write(dev, HPS_V_GAIN, 0); // r64 - saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 - saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 - // Set HPS prescaler for port B input - saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); - saa7146_write(dev, MC2, - 0 * (MASK_08 | MASK_24) | // BRS control - 0 * (MASK_09 | MASK_25) | // a - 0 * (MASK_10 | MASK_26) | // b - 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 - 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 - 0 * (MASK_01 | MASK_15) // DEBI - ); -#endif - // Disable RPS1 and RPS0 - saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); - // RPS1 timeout disable - saa7146_write(dev, RPS_TOV1, 0); - - // code for autodetection - // will wait for VBI_B event (vertical blank at port B) - // and will reset GPIO3 after VBI_B is detected. - // (GPIO3 should be raised high by CPU to - // test if GPIO3 will generate vertical blank signal - // in budget patch GPIO3 is connected to VSYNC_B - count = 0; -#if 0 - WRITE_RPS1(CMD_UPLOAD | - MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); -#endif - WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - // issue RPS1 interrupt to increment counter - WRITE_RPS1(CMD_INTERRUPT); - // at least a NOP is neede between two interrupts - WRITE_RPS1(CMD_NOP); - // interrupt again - WRITE_RPS1(CMD_INTERRUPT); -#endif - WRITE_RPS1(CMD_STOP); - -#if RPS_IRQ - // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) - // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled - // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called - saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); - // set event counter 1 threshold to maximum allowed value (rEC p55) - saa7146_write(dev, ECT1R, 0x3fff ); -#endif - // Fix VSYNC level - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - // Set RPS1 Address register to point to RPS code (r108 p42) - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - // Enable RPS1, (rFC p33) - saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); - - - mdelay(50); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - mdelay(150); - - - if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) - detected = 1; - -#if RPS_IRQ - printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); -#endif - // Disable RPS1 - saa7146_write(dev, MC1, ( MASK_29 )); - - if(detected == 0) - printk("budget-patch not detected or saa7146 in non-default state.\n" - "try enabling ressetting of 7146 with MASK_31 in MC1 register\n"); - - else - printk("BUDGET-PATCH DETECTED.\n"); - - -/* OLD (Original design by Roberto Deza): -** This code will setup the SAA7146_RPS1 to generate a square -** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of -** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; -** then, this GPIO3 output which is connected to the D1B_VSYNC -** input, will trigger the acquisition of the alternate field -** and so on. -** Currently, the TT_budget / WinTV_Nova cards have two ICs -** (74HCT4040, LVC74) for the generation of this VSYNC signal, -** which seems that can be done perfectly without this :-)). -*/ - -/* New design (By Emard) -** this rps1 code will copy internal HS event to GPIO3 pin. -** GPIO3 is in budget-patch hardware connected to port B VSYNC - -** HS is an internal event of 7146, accessible with RPS -** and temporarily raised high every n lines -** (n in defined in the RPS_THRESH1 counter threshold) -** I think HS is raised high on the beginning of the n-th line -** and remains high until this n-th line that triggered -** it is completely received. When the reception of n-th line -** ends, HS is lowered. - -** To transmit data over DMA, 7146 needs changing state at -** port B VSYNC pin. Any changing of port B VSYNC will -** cause some DMA data transfer, with more or less packets loss. -** It depends on the phase and frequency of VSYNC and -** the way of 7146 is instructed to trigger on port B (defined -** in DD1_INIT register, 3rd nibble from the right valid -** numbers are 0-7, see datasheet) -** -** The correct triggering can minimize packet loss, -** dvbtraffic should give this stable bandwidths: -** 22k transponder = 33814 kbit/s -** 27.5k transponder = 38045 kbit/s -** by experiment it is found that the best results -** (stable bandwidths and almost no packet loss) -** are obtained using DD1_INIT triggering number 2 -** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) -** and a VSYNC phase that occurs in the middle of DMA transfer -** (about byte 188*512=96256 in the DMA window). -** -** Phase of HS is still not clear to me how to control, -** It just happens to be so. It can be seen if one enables -** RPS_IRQ and print Event Counter 1 in vpeirq(). Every -** time RPS_INTERRUPT is called, the Event Counter 1 will -** increment. That's how the 7146 is programmed to do event -** counting in this budget-patch.c -** I *think* HPS setting has something to do with the phase -** of HS but I can't be 100% sure in that. - -** hardware debug note: a working budget card (including budget patch) -** with vpeirq() interrupt setup in mode "0x90" (every 64K) will -** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes -** and that means 3*25=75 Hz of interrupt frequency, as seen by -** watch cat /proc/interrupts -** -** If this frequency is 3x lower (and data received in the DMA -** buffer don't start with 0x47, but in the middle of packets, -** whose lengths appear to be like 188 292 188 104 etc. -** this means VSYNC line is not connected in the hardware. -** (check soldering pcb and pins) -** The same behaviour of missing VSYNC can be duplicated on budget -** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. -*/ - - // Setup RPS1 "program" (p35) - count = 0; - - - // Wait Source Line Counter Threshold (p36) - WRITE_RPS1(CMD_PAUSE | EVT_HS); - // Set GPIO3=1 (p42) - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); -#if RPS_IRQ - // issue RPS1 interrupt - WRITE_RPS1(CMD_INTERRUPT); -#endif - // Wait reset Source Line Counter Threshold (p36) - WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); - // Set GPIO3=0 (p42) - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - // issue RPS1 interrupt - WRITE_RPS1(CMD_INTERRUPT); -#endif - // Jump to begin of RPS program (p37) - WRITE_RPS1(CMD_JUMP); - WRITE_RPS1(dev->d_rps1.dma_handle); - - // Fix VSYNC level - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - // Set RPS1 Address register to point to RPS code (r108 p42) - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - - if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) - return -ENOMEM; - - dprintk(2, "budget: %p\n", budget); - - err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); - if (err) { - kfree(budget); - return err; - } - - // Set Source Line Counter Threshold, using BRS (rCC p43) - // It generates HS event every TS_HEIGHT lines - // this is related to TS_WIDTH set in register - // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE - // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 - //,then RPS_THRESH1 - // should be set to trigger every TS_HEIGHT (512) lines. - // - saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); - - // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); - // Enable RPS1 (rFC p33) - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - - - dev->ext_priv = budget; - - budget->dvb_adapter.priv = budget; - frontend_init(budget); - - ttpci_budget_init_hooks(budget); - - return 0; -} - -static int budget_patch_detach (struct saa7146_dev* dev) -{ - struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; - int err; - - if (budget->dvb_frontend) { - dvb_unregister_frontend(budget->dvb_frontend); - dvb_frontend_detach(budget->dvb_frontend); - } - err = ttpci_budget_deinit (budget); - - kfree (budget); - - return err; -} - -static int __init budget_patch_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_patch_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -static struct saa7146_extension budget_extension = { - .name = "budget_patch dvb", - .flags = 0, - - .module = THIS_MODULE, - .pci_tbl = pci_tbl, - .attach = budget_patch_attach, - .detach = budget_patch_detach, - - .irq_mask = MASK_10, - .irq_func = ttpci_budget_irq10_handler, -}; - -module_init(budget_patch_init); -module_exit(budget_patch_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); -MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 " - "based so-called Budget Patch cards"); diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c deleted file mode 100644 index 7e6e43ae5c5..00000000000 --- a/drivers/media/dvb/ttpci/budget.c +++ /dev/null @@ -1,871 +0,0 @@ -/* - * budget.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 26feb2004 Support for FS Activy Card (Grundig tuner) by - * Michael Dreher , - * Oliver Endriss and - * Andreas 'randy' Weinberger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include "budget.h" -#include "stv0299.h" -#include "ves1x93.h" -#include "ves1820.h" -#include "l64781.h" -#include "tda8083.h" -#include "s5h1420.h" -#include "tda10086.h" -#include "tda826x.h" -#include "lnbp21.h" -#include "bsru6.h" -#include "bsbe1.h" -#include "tdhd1.h" -#include "stv6110x.h" -#include "stv090x.h" -#include "isl6423.h" -#include "lnbh24.h" - - -static int diseqc_method; -module_param(diseqc_method, int, 0444); -MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static void Set22K (struct budget *budget, int state) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); -} - -/* Diseqc functions only for TT Budget card */ -/* taken from the Skyvision DVB driver by - Ralph Metzler */ - -static void DiseqcSendBit (struct budget *budget, int data) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(data ? 500 : 1000); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - udelay(data ? 1000 : 500); -} - -static void DiseqcSendByte (struct budget *budget, int data) -{ - int i, par=1, d; - - dprintk(2, "budget: %p\n", budget); - - for (i=7; i>=0; i--) { - d = (data>>i)&1; - par ^= d; - DiseqcSendBit(budget, d); - } - - DiseqcSendBit(budget, par); -} - -static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) -{ - struct saa7146_dev *dev=budget->dev; - int i; - - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - mdelay(16); - - for (i=0; idev; - - dprintk(2, "budget: %p\n", budget); - - switch (voltage) { - case SEC_VOLTAGE_13: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); - break; - case SEC_VOLTAGE_18: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - break; - case SEC_VOLTAGE_OFF: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - return SetVoltage_Activy (budget, voltage); -} - -static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - switch (tone) { - case SEC_TONE_ON: - Set22K (budget, 1); - break; - - case SEC_TONE_OFF: - Set22K (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, 0, NULL, minicmd); - - return 0; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (c->frequency + 479500) / 125; - - if (c->frequency > 2000000) - pwr = 3; - else if (c->frequency > 1800000) - pwr = 2; - else if (c->frequency > 1600000) - pwr = 1; - else if (c->frequency > 1200000) - pwr = 0; - else if (c->frequency >= 1100000) - pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = -{ - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (c->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - -static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget *budget = fe->dvb->priv; - u8 *tuner_addr = fe->tuner_priv; - u32 div; - u8 cfg, cpump, band_select; - u8 data[4]; - struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) }; - - if (tuner_addr) - msg.addr = *tuner_addr; - else - msg.addr = 0x61; - - div = (36125000 + c->frequency) / 166666; - - cfg = 0x88; - - if (c->frequency < 175000000) - cpump = 2; - else if (c->frequency < 390000000) - cpump = 1; - else if (c->frequency < 470000000) - cpump = 2; - else if (c->frequency < 750000000) - cpump = 1; - else - cpump = 3; - - if (c->frequency < 175000000) - band_select = 0x0e; - else if (c->frequency < 470000000) - band_select = 0x05; - else - band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct l64781_config grundig_29504_401_config = { - .demod_address = 0x55, -}; - -static struct l64781_config grundig_29504_401_config_activy = { - .demod_address = 0x54, -}; - -static u8 tuner_address_grundig_29504_401_activy = 0x60; - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = c->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - -static int s5h1420_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = c->frequency / 1000; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xc2; - - if (div < 1450) - data[3] = 0x00; - else if (div < 1850) - data[3] = 0x40; - else if (div < 2000) - data[3] = 0x80; - else - data[3] = 0xc0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - - return 0; -} - -static struct s5h1420_config s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .cdclk_polarity = 1, -}; - -static struct tda10086_config tda10086_config = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct stv0299_config alps_bsru6_config_activy = { - .demod_address = 0x68, - .inittab = alps_bsru6_inittab, - .mclk = 88000000UL, - .invert = 1, - .op0_off = 1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsru6_set_symbol_rate, -}; - -static struct stv0299_config alps_bsbe1_config_activy = { - .demod_address = 0x68, - .inittab = alps_bsbe1_inittab, - .mclk = 88000000UL, - .invert = 1, - .op0_off = 1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsbe1_set_symbol_rate, -}; - -static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) -{ - struct budget *budget = (struct budget *)fe->dvb->priv; - - return request_firmware(fw, name, &budget->dev->pci->dev); -} - - -static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) -{ - u8 val; - struct i2c_msg msg[] = { - { .addr = adr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 } - }; - - return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val; -} - -static u8 read_pwm(struct budget* budget) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static struct stv090x_config tt1600_stv090x_config = { - .device = STV0903, - .demod_mode = STV090x_SINGLE, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 13500000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_DVBCI, - .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, - - .repeater_level = STV090x_RPTLEVEL_16, - - .tuner_init = NULL, - .tuner_sleep = NULL, - .tuner_set_mode = NULL, - .tuner_set_frequency = NULL, - .tuner_get_frequency = NULL, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = NULL, - .tuner_set_bbgain = NULL, - .tuner_get_bbgain = NULL, - .tuner_set_refclk = NULL, - .tuner_get_status = NULL, -}; - -static struct stv6110x_config tt1600_stv6110x_config = { - .addr = 0x60, - .refclk = 27000000, - .clk_div = 2, -}; - -static struct isl6423_config tt1600_isl6423_config = { - .current_max = SEC_CURRENT_515m, - .curlim = SEC_CURRENT_LIM_ON, - .mod_extern = 1, - .addr = 0x08, -}; - -static void frontend_init(struct budget *budget) -{ - (void)alps_bsbe1_config; /* avoid warning */ - - switch(budget->dev->pci->subsystem_device) { - case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) - case 0x1013: - // try the ALPS BSRV2 first of all - budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - - // try the ALPS BSRU6 now - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) { - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - } - break; - } - break; - - case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) - - budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - break; - } - break; - - case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) - - budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - budget->dvb_frontend->tuner_priv = NULL; - break; - } - break; - - case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ - { - int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); - - if (subtype < 0) - break; - /* fixme: find a better way to identify the card */ - if (subtype < 0x36) { - /* assume ALPS BSRU6 */ - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - break; - } - } else { - /* assume ALPS BSBE1 */ - /* reset tuner */ - saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI); - msleep(250); - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - break; - } - } - break; - } - - case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) - budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - } - break; - - case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ - budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - } - break; - - case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ - budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy; - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - } - break; - - case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) - budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params; - if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - goto error_out; - } - break; - } - - case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262) - // gpio2 is connected to CLB - reset it + leave it high - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(1); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(1); - - budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL) - printk("%s: No tda826x found!\n", __func__); - if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - goto error_out; - } - break; - } - - case 0x101c: { /* TT S2-1600 */ - struct stv6110x_devctl *ctl; - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(250); - - budget->dvb_frontend = dvb_attach(stv090x_attach, - &tt1600_stv090x_config, - &budget->i2c_adap, - STV090x_DEMODULATOR_0); - - if (budget->dvb_frontend) { - - ctl = dvb_attach(stv6110x_attach, - budget->dvb_frontend, - &tt1600_stv6110x_config, - &budget->i2c_adap); - - if (ctl) { - tt1600_stv090x_config.tuner_init = ctl->tuner_init; - tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; - tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (budget->dvb_frontend->ops.init) - budget->dvb_frontend->ops.init(budget->dvb_frontend); - - if (dvb_attach(isl6423_attach, - budget->dvb_frontend, - &budget->i2c_adap, - &tt1600_isl6423_config) == NULL) { - printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__); - goto error_out; - } - } else { - printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); - goto error_out; - } - } - } - break; - - case 0x1020: { /* Omicom S2 */ - struct stv6110x_devctl *ctl; - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(250); - - budget->dvb_frontend = dvb_attach(stv090x_attach, - &tt1600_stv090x_config, - &budget->i2c_adap, - STV090x_DEMODULATOR_0); - - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: Omicom S2 detected\n"); - - ctl = dvb_attach(stv6110x_attach, - budget->dvb_frontend, - &tt1600_stv6110x_config, - &budget->i2c_adap); - - if (ctl) { - tt1600_stv090x_config.tuner_init = ctl->tuner_init; - tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; - tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (budget->dvb_frontend->ops.init) - budget->dvb_frontend->ops.init(budget->dvb_frontend); - - if (dvb_attach(lnbh24_attach, - budget->dvb_frontend, - &budget->i2c_adap, - LNBH24_PCL | LNBH24_TTX, - LNBH24_TEN, 0x14>>1) == NULL) { - printk(KERN_ERR - "No LNBH24 found!\n"); - goto error_out; - } - } else { - printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); - goto error_out; - } - } - } - break; - } - - if (budget->dvb_frontend == NULL) { - printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget->dev->pci->vendor, - budget->dev->pci->device, - budget->dev->pci->subsystem_vendor, - budget->dev->pci->subsystem_device); - } else { - if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) - goto error_out; - } - return; - -error_out: - printk("budget: Frontend registration failed!\n"); - dvb_frontend_detach(budget->dvb_frontend); - budget->dvb_frontend = NULL; - return; -} - -static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) -{ - struct budget *budget = NULL; - int err; - - budget = kmalloc(sizeof(struct budget), GFP_KERNEL); - if( NULL == budget ) { - return -ENOMEM; - } - - dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget); - - dev->ext_priv = budget; - - err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); - if (err) { - printk("==> failed\n"); - kfree (budget); - return err; - } - - budget->dvb_adapter.priv = budget; - frontend_init(budget); - - ttpci_budget_init_hooks(budget); - - return 0; -} - -static int budget_detach (struct saa7146_dev* dev) -{ - struct budget *budget = (struct budget*) dev->ext_priv; - int err; - - if (budget->dvb_frontend) { - dvb_unregister_frontend(budget->dvb_frontend); - dvb_frontend_detach(budget->dvb_frontend); - } - - err = ttpci_budget_deinit (budget); - - kfree (budget); - dev->ext_priv = NULL; - - return err; -} - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); -MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), - MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), - MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), - MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), - MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), - MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), - MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), - MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), - MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), - MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), - MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), - MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget dvb", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = pci_tbl, - .attach = budget_attach, - .detach = budget_detach, - - .irq_mask = MASK_10, - .irq_func = ttpci_budget_irq10_handler, -}; - -static int __init budget_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_init); -module_exit(budget_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h deleted file mode 100644 index 3d8a806c20b..00000000000 --- a/drivers/media/dvb/ttpci/budget.h +++ /dev/null @@ -1,124 +0,0 @@ - -#ifndef __BUDGET_DVB__ -#define __BUDGET_DVB__ - -#include "dvb_frontend.h" -#include "dvbdev.h" -#include "demux.h" -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_filter.h" -#include "dvb_net.h" - -#include -#include - -#include - -extern int budget_debug; - -#ifdef dprintk -#undef dprintk -#endif - -#define dprintk(level,args...) \ - do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0) - -struct budget_info { - char *name; - int type; -}; - -/* place to store all the necessary device information */ -struct budget { - - /* devices */ - struct dvb_device dvb_dev; - struct dvb_net dvb_net; - - struct saa7146_dev *dev; - - struct i2c_adapter i2c_adap; - struct budget_info *card; - - unsigned char *grabbing; - struct saa7146_pgtable pt; - - struct tasklet_struct fidb_tasklet; - struct tasklet_struct vpe_tasklet; - - struct dmxdev dmxdev; - struct dvb_demux demux; - - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - - int ci_present; - int video_port; - - u32 buffer_width; - u32 buffer_height; - u32 buffer_size; - u32 buffer_warning_threshold; - u32 buffer_warnings; - unsigned long buffer_warning_time; - - u32 ttbp; - int feeding; - - spinlock_t feedlock; - - spinlock_t debilock; - - struct dvb_adapter dvb_adapter; - struct dvb_frontend *dvb_frontend; - int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); - int fe_synced; - - void *priv; -}; - -#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \ -static struct budget_info x_var ## _info = { \ - .name=x_name, \ - .type=x_type }; \ -static struct saa7146_pci_extension_data x_var = { \ - .ext_priv = &x_var ## _info, \ - .ext = &budget_extension }; - -#define BUDGET_TT 0 -#define BUDGET_TT_HW_DISEQC 1 -#define BUDGET_PATCH 3 -#define BUDGET_FS_ACTIVY 4 -#define BUDGET_CIN1200S 5 -#define BUDGET_CIN1200C 6 -#define BUDGET_CIN1200T 7 -#define BUDGET_KNC1S 8 -#define BUDGET_KNC1C 9 -#define BUDGET_KNC1T 10 -#define BUDGET_KNC1SP 11 -#define BUDGET_KNC1CP 12 -#define BUDGET_KNC1TP 13 -#define BUDGET_TVSTAR 14 -#define BUDGET_CIN1200C_MK3 15 -#define BUDGET_KNC1C_MK3 16 -#define BUDGET_KNC1CP_MK3 17 -#define BUDGET_KNC1S2 18 -#define BUDGET_KNC1C_TDA10024 19 - -#define BUDGET_VIDEO_PORTA 0 -#define BUDGET_VIDEO_PORTB 1 - -extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, - struct saa7146_pci_extension_data *info, - struct module *owner, short *adapter_nums); -extern void ttpci_budget_init_hooks(struct budget *budget); -extern int ttpci_budget_deinit(struct budget *budget); -extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); -extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port); -extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop); -extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value, - int uselocks, int nobusyloop); - -#endif diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c deleted file mode 100644 index 32d43156c54..00000000000 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, - decode it and store it in the associated adapter struct for - use by dvb_net.c - - This card appear to have the 24C16 write protect held to ground, - thus permitting normal read/write operation. Theoretically it - would be possible to write routines to burn a different (encoded) - MAC address into the EEPROM. - - Robert Schlabbach GMX - Michael Glaum KVH Industries - Holger Waechtler Convergence - - Copyright (C) 2002-2003 Ralph Metzler - Metzler Brothers Systementwicklung GbR - - 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 -#include -#include -#include -#include - -#include "ttpci-eeprom.h" - -#if 1 -#define dprintk(x...) do { printk(x); } while (0) -#else -#define dprintk(x...) do { } while (0) -#endif - - -static int check_mac_tt(u8 *buf) -{ - int i; - u16 tmp = 0xffff; - - for (i = 0; i < 8; i++) { - tmp = (tmp << 8) | ((tmp >> 8) ^ buf[i]); - tmp ^= (tmp >> 4) & 0x0f; - tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5); - } - tmp ^= 0xffff; - return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9])); -} - -static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) -{ - u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, - 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, - 0x1d, 0x36, 0x64, 0x78}; - u8 data[20]; - int i; - - /* In case there is a sig check failure have the orig contents available */ - memcpy(data, encodedMAC, 20); - - for (i = 0; i < 20; i++) - data[i] ^= xor[i]; - for (i = 0; i < 10; i++) - data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) - >> ((data[2 * i + 1] >> 6) & 3); - - if (check_mac_tt(data)) - return -ENODEV; - - decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0]; - decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4]; - return 0; -} - -int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC) -{ - u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, - 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, - 0x1d, 0x36, 0x64, 0x78}; - u8 data[20]; - int i; - - memcpy(data, encodedMAC, 20); - - for (i = 0; i < 20; i++) - data[i] ^= xor[i]; - for (i = 0; i < 10; i++) - data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) - >> ((data[2 * i + 1] >> 6) & 3); - - if (check_mac_tt(data)) - return -ENODEV; - - decodedMAC[0] = data[2]; - decodedMAC[1] = data[1]; - decodedMAC[2] = data[0]; - decodedMAC[3] = data[6]; - decodedMAC[4] = data[5]; - decodedMAC[5] = data[4]; - return 0; -} -EXPORT_SYMBOL(ttpci_eeprom_decode_mac); - -static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) -{ - int ret; - u8 b0[] = { 0xcc }; - - struct i2c_msg msg[] = { - { .addr = 0x50, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 } - }; - - /* dprintk("%s\n", __func__); */ - - ret = i2c_transfer(adapter, msg, 2); - - if (ret != 2) /* Assume EEPROM isn't there */ - return (-ENODEV); - - return 0; -} - - -int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) -{ - int ret, i; - u8 encodedMAC[20]; - u8 decodedMAC[6]; - - ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC); - - if (ret != 0) { /* Will only be -ENODEV */ - dprintk("Couldn't read from EEPROM: not there?\n"); - memset(proposed_mac, 0, 6); - return ret; - } - - ret = getmac_tt(decodedMAC, encodedMAC); - if( ret != 0 ) { - dprintk("adapter failed MAC signature check\n"); - dprintk("encoded MAC from EEPROM was " ); - for(i=0; i<19; i++) { - dprintk( "%.2x:", encodedMAC[i]); - } - dprintk("%.2x\n", encodedMAC[19]); - memset(proposed_mac, 0, 6); - return ret; - } - - memcpy(proposed_mac, decodedMAC, 6); - dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - decodedMAC[0], decodedMAC[1], decodedMAC[2], - decodedMAC[3], decodedMAC[4], decodedMAC[5]); - return 0; -} - -EXPORT_SYMBOL(ttpci_eeprom_parse_mac); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); -MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards " - "made by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h deleted file mode 100644 index dcc33d5a5cb..00000000000 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM, - decode it and store it in associated adapter net device - - Robert Schlabbach GMX - Michael Glaum KVH Industries - Holger Waechtler Convergence - - 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 __TTPCI_EEPROM_H__ -#define __TTPCI_EEPROM_H__ - -#include -#include - -extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC); -extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac); - -#endif diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig new file mode 100644 index 00000000000..3b9164af6ec --- /dev/null +++ b/drivers/media/pci/Kconfig @@ -0,0 +1,50 @@ +# +# DVB device configuration +# + +menuconfig DVB_CAPTURE_DRIVERS + bool "DVB/ATSC adapters" + depends on DVB_CORE + default y + ---help--- + Say Y to select Digital TV adapters + +if DVB_CAPTURE_DRIVERS && DVB_CORE + +comment "Supported SAA7146 based PCI Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/pci/ttpci/Kconfig" + +comment "Supported FlexCopII (B2C2) Adapters" + depends on DVB_CORE && (PCI || USB) && I2C +source "drivers/media/pci/b2c2/Kconfig" + +comment "Supported BT878 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/pci/bt8xx/Kconfig" + +comment "Supported Pluto2 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/pci/pluto2/Kconfig" + +comment "Supported SDMC DM1105 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/pci/dm1105/Kconfig" + +comment "Supported Earthsoft PT1 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/pci/pt1/Kconfig" + +comment "Supported Mantis Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/pci/mantis/Kconfig" + +comment "Supported nGene Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/pci/ngene/Kconfig" + +comment "Supported ddbridge ('Octopus') Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/pci/ddbridge/Kconfig" + +endif # DVB_CAPTURE_DRIVERS diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile new file mode 100644 index 00000000000..c5fa43a275a --- /dev/null +++ b/drivers/media/pci/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the kernel multimedia device drivers. +# + +obj-y := ttpci/ \ + b2c2/ \ + bt8xx/ \ + pluto2/ \ + dm1105/ \ + pt1/ \ + mantis/ \ + ngene/ \ + ddbridge/ diff --git a/drivers/media/pci/b2c2/Kconfig b/drivers/media/pci/b2c2/Kconfig new file mode 100644 index 00000000000..9e578140074 --- /dev/null +++ b/drivers/media/pci/b2c2/Kconfig @@ -0,0 +1,45 @@ +config DVB_B2C2_FLEXCOP + tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" + depends on DVB_CORE && I2C + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_MT312 if !DVB_FE_CUSTOMISE + select DVB_NXT200X if !DVB_FE_CUSTOMISE + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_BCM3510 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_S5H1420 if !DVB_FE_CUSTOMISE + select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE + select DVB_ISL6421 if !DVB_FE_CUSTOMISE + select DVB_CX24123 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE + help + Support for the digital TV receiver chip made by B2C2 Inc. included in + Technisats PCI cards and USB boxes. + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_PCI + tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" + depends on DVB_B2C2_FLEXCOP && PCI && I2C + help + Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_USB + tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" + depends on DVB_B2C2_FLEXCOP && USB && I2C + help + Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_DEBUG + bool "Enable debug for the B2C2 FlexCop drivers" + depends on DVB_B2C2_FLEXCOP + help + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. diff --git a/drivers/media/pci/b2c2/Makefile b/drivers/media/pci/b2c2/Makefile new file mode 100644 index 00000000000..7a1f5ce6d32 --- /dev/null +++ b/drivers/media/pci/b2c2/Makefile @@ -0,0 +1,16 @@ +b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \ + flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o + +ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),) +b2c2-flexcop-objs += flexcop-dma.o +endif + +b2c2-flexcop-pci-objs = flexcop-pci.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o + +b2c2-flexcop-usb-objs = flexcop-usb.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ +ccflags-y += -Idrivers/media/common/tuners/ diff --git a/drivers/media/pci/b2c2/flexcop-common.h b/drivers/media/pci/b2c2/flexcop-common.h new file mode 100644 index 00000000000..437912e4982 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-common.h @@ -0,0 +1,185 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-common.h - common header file for device-specific source files + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_COMMON_H__ +#define __FLEXCOP_COMMON_H__ + +#include +#include +#include + +#include "flexcop-reg.h" + +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "dvb_frontend.h" + +#define FC_MAX_FEED 256 + +#ifndef FC_LOG_PREFIX +#warning please define a log prefix for your file, using a default one +#define FC_LOG_PREFIX "b2c2-undef" +#endif + +/* Steal from usb.h */ +#undef err +#define err(format, arg...) \ + printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) \ + printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) \ + printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg) + +struct flexcop_dma { + struct pci_dev *pdev; + + u8 *cpu_addr0; + dma_addr_t dma_addr0; + u8 *cpu_addr1; + dma_addr_t dma_addr1; + u32 size; /* size of each address in bytes */ +}; + +struct flexcop_i2c_adapter { + struct flexcop_device *fc; + struct i2c_adapter i2c_adap; + + u8 no_base_addr; + flexcop_i2c_port_t port; +}; + +/* Control structure for data definitions that are common to + * the B2C2-based PCI and USB devices. + */ +struct flexcop_device { + /* general */ + struct device *dev; /* for firmware_class */ + +#define FC_STATE_DVB_INIT 0x01 +#define FC_STATE_I2C_INIT 0x02 +#define FC_STATE_FE_INIT 0x04 + int init_state; + + /* device information */ + int has_32_hw_pid_filter; + flexcop_revision_t rev; + flexcop_device_type_t dev_type; + flexcop_bus_t bus_type; + + /* dvb stuff */ + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int (*fe_sleep) (struct dvb_frontend *); + + struct flexcop_i2c_adapter fc_i2c_adap[3]; + struct mutex i2c_mutex; + struct module *owner; + + /* options and status */ + int extra_feedcount; + int feedcount; + int pid_filtering; + int fullts_streaming_state; + + /* bus specific callbacks */ + flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *, + flexcop_ibi_register); + int (*write_ibi_reg) (struct flexcop_device *, + flexcop_ibi_register, flexcop_ibi_value); + int (*i2c_request) (struct flexcop_i2c_adapter *, + flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); + int (*stream_control) (struct flexcop_device *, int); + int (*get_mac_addr) (struct flexcop_device *fc, int extended); + void *bus_specific; +}; + +/* exported prototypes */ + +/* from flexcop.c */ +void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len); +void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no); + +struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len); +void flexcop_device_kfree(struct flexcop_device *); + +int flexcop_device_initialize(struct flexcop_device *); +void flexcop_device_exit(struct flexcop_device *fc); +void flexcop_reset_block_300(struct flexcop_device *fc); + +/* from flexcop-dma.c */ +int flexcop_dma_allocate(struct pci_dev *pdev, + struct flexcop_dma *dma, u32 size); +void flexcop_dma_free(struct flexcop_dma *dma); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, int onoff); +int flexcop_dma_control_size_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, int onoff); +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, + flexcop_dma_index_t dma_idx); +int flexcop_dma_xfer_control(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, + int onoff); +int flexcop_dma_config_timer(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, u8 cycles); + +/* from flexcop-eeprom.c */ +/* the PCI part uses this call to get the MAC address, the USB part has its own */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); + +/* from flexcop-i2c.c */ +/* the PCI part uses this a i2c_request callback, whereas the usb part has its own + * one. We have it in flexcop-i2c.c, because it is going via the actual + * I2C-channel of the flexcop. + */ +int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t, + u8 chipaddr, u8 addr, u8 *buf, u16 len); + +/* from flexcop-sram.c */ +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, + flexcop_sram_dest_target_t target); +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s); +void flexcop_sram_ctrl(struct flexcop_device *fc, + int usb_wan, int sramdma, int maximumfill); + +/* global prototypes for the flexcop-chip */ +/* from flexcop-fe-tuner.c */ +int flexcop_frontend_init(struct flexcop_device *fc); +void flexcop_frontend_exit(struct flexcop_device *fc); + +/* from flexcop-i2c.c */ +int flexcop_i2c_init(struct flexcop_device *fc); +void flexcop_i2c_exit(struct flexcop_device *fc); + +/* from flexcop-sram.c */ +int flexcop_sram_init(struct flexcop_device *fc); + +/* from flexcop-misc.c */ +void flexcop_determine_revision(struct flexcop_device *fc); +void flexcop_device_name(struct flexcop_device *fc, + const char *prefix, const char *suffix); +void flexcop_dump_reg(struct flexcop_device *fc, + flexcop_ibi_register reg, int num); + +/* from flexcop-hw-filter.c */ +int flexcop_pid_feed_control(struct flexcop_device *fc, + struct dvb_demux_feed *dvbdmxfeed, int onoff); +void flexcop_hw_filter_init(struct flexcop_device *fc); + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff); + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]); +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff); + +#endif diff --git a/drivers/media/pci/b2c2/flexcop-dma.c b/drivers/media/pci/b2c2/flexcop-dma.c new file mode 100644 index 00000000000..2881e0d956a --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-dma.c @@ -0,0 +1,172 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-dma.c - configuring and controlling the DMA of the FlexCop + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +int flexcop_dma_allocate(struct pci_dev *pdev, + struct flexcop_dma *dma, u32 size) +{ + u8 *tcpu; + dma_addr_t tdma = 0; + + if (size % 2) { + err("dma buffersize has to be even."); + return -EINVAL; + } + + if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { + dma->pdev = pdev; + dma->cpu_addr0 = tcpu; + dma->dma_addr0 = tdma; + dma->cpu_addr1 = tcpu + size/2; + dma->dma_addr1 = tdma + size/2; + dma->size = size/2; + return 0; + } + return -ENOMEM; +} +EXPORT_SYMBOL(flexcop_dma_allocate); + +void flexcop_dma_free(struct flexcop_dma *dma) +{ + pci_free_consistent(dma->pdev, dma->size*2, + dma->cpu_addr0, dma->dma_addr0); + memset(dma,0,sizeof(struct flexcop_dma)); +} +EXPORT_SYMBOL(flexcop_dma_free); + +int flexcop_dma_config(struct flexcop_device *fc, + struct flexcop_dma *dma, + flexcop_dma_index_t dma_idx) +{ + flexcop_ibi_value v0x0,v0x4,v0xc; + v0x0.raw = v0x4.raw = v0xc.raw = 0; + + v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; + v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; + v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; + + if ((dma_idx & FC_DMA_1) == dma_idx) { + fc->write_ibi_reg(fc,dma1_000,v0x0); + fc->write_ibi_reg(fc,dma1_004,v0x4); + fc->write_ibi_reg(fc,dma1_00c,v0xc); + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + fc->write_ibi_reg(fc,dma2_010,v0x0); + fc->write_ibi_reg(fc,dma2_014,v0x4); + fc->write_ibi_reg(fc,dma2_01c,v0xc); + } else { + err("either DMA1 or DMA2 can be configured within one " + "flexcop_dma_config call."); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config); + +/* start the DMA transfers, but not the DMA IRQs */ +int flexcop_dma_xfer_control(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + flexcop_dma_addr_index_t index, + int onoff) +{ + flexcop_ibi_value v0x0,v0xc; + flexcop_ibi_register r0x0,r0xc; + + if ((dma_idx & FC_DMA_1) == dma_idx) { + r0x0 = dma1_000; + r0xc = dma1_00c; + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + r0x0 = dma2_010; + r0xc = dma2_01c; + } else { + err("either transfer DMA1 or DMA2 can be started within one " + "flexcop_dma_xfer_control call."); + return -EINVAL; + } + + v0x0 = fc->read_ibi_reg(fc,r0x0); + v0xc = fc->read_ibi_reg(fc,r0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + + if (index & FC_DMA_SUBADDR_0) + v0x0.dma_0x0.dma_0start = onoff; + + if (index & FC_DMA_SUBADDR_1) + v0xc.dma_0xc.dma_1start = onoff; + + fc->write_ibi_reg(fc,r0x0,v0x0); + fc->write_ibi_reg(fc,r0xc,v0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_xfer_control); + +static int flexcop_dma_remap(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + int onoff) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + deb_info("%s\n",__func__); + v.dma_0xc.remap_enable = onoff; + fc->write_ibi_reg(fc,r,v); + return 0; +} + +int flexcop_dma_control_size_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_size_irq); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Timer_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Timer_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_timer_irq); + +/* 1 cycles = 1.97 msec */ +int flexcop_dma_config_timer(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, u8 cycles) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + + flexcop_dma_remap(fc,dma_idx,0); + + deb_info("%s\n",__func__); + v.dma_0x4_write.dmatimer = cycles; + fc->write_ibi_reg(fc,r,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config_timer); + diff --git a/drivers/media/pci/b2c2/flexcop-eeprom.c b/drivers/media/pci/b2c2/flexcop-eeprom.c new file mode 100644 index 00000000000..a25373a9bd8 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-eeprom.c @@ -0,0 +1,147 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading) + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +#if 0 +/*EEPROM (Skystar2 has one "24LC08B" chip on board) */ +static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) +{ + return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); +} + +static int eeprom_lrc_write(struct adapter *adapter, u32 addr, + u32 len, u8 *wbuf, u8 *rbuf, int retries) +{ +int i; + +for (i = 0; i < retries; i++) { + if (eeprom_write(adapter, addr, wbuf, len) == len) { + if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) + return 1; + } + } + return 0; +} + +/* These functions could be used to unlock SkyStar2 cards. */ + +static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 rbuf[20]; + u8 wbuf[20]; + + if (len != 16) + return 0; + + memcpy(wbuf, key, len); + wbuf[16] = 0; + wbuf[17] = 0; + wbuf[18] = 0; + wbuf[19] = calc_lrc(wbuf, 19); + return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); +} + +static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 buf[20]; + + if (len != 16) + return 0; + + if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) + return 0; + + memcpy(key, buf, len); + return 1; +} + +static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) +{ + u8 tmp[8]; + + if (type != 0) { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[5]; + tmp[4] = mac[6]; + tmp[5] = mac[7]; + } else { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[3]; + tmp[4] = mac[4]; + tmp[5] = mac[5]; + } + + tmp[6] = 0; + tmp[7] = calc_lrc(tmp, 7); + + if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) + return 1; + return 0; +} + +static int flexcop_eeprom_read(struct flexcop_device *fc, + u16 addr, u8 *buf, u16 len) +{ + return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); +} + +#endif + +static u8 calc_lrc(u8 *buf, int len) +{ + int i; + u8 sum = 0; + for (i = 0; i < len; i++) + sum = sum ^ buf[i]; + return sum; +} + +static int flexcop_eeprom_request(struct flexcop_device *fc, + flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) +{ + int i,ret = 0; + u8 chipaddr = 0x50 | ((addr >> 8) & 3); + for (i = 0; i < retries; i++) { + ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr, + addr & 0xff, buf, len); + if (ret == 0) + break; + } + return ret; +} + +static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, + u8 *buf, u16 len, int retries) +{ + int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries); + if (ret == 0) + if (calc_lrc(buf, len - 1) != buf[len - 1]) + ret = -EINVAL; + return ret; +} + +/* JJ's comment about extended == 1: it is not presently used anywhere but was + * added to the low-level functions for possible support of EUI64 */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) +{ + u8 buf[8]; + int ret = 0; + + if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { + if (extended != 0) { + err("TODO: extended (EUI64) MAC addresses aren't " + "completely supported yet"); + ret = -EINVAL; + } else + memcpy(fc->dvb_adapter.proposed_mac,buf,6); + } + return ret; +} +EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); diff --git a/drivers/media/pci/b2c2/flexcop-fe-tuner.c b/drivers/media/pci/b2c2/flexcop-fe-tuner.c new file mode 100644 index 00000000000..850a6c60675 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-fe-tuner.c @@ -0,0 +1,678 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling + * see flexcop.c for copyright information + */ +#include +#include "flexcop.h" +#include "mt312.h" +#include "stv0299.h" +#include "s5h1420.h" +#include "itd1000.h" +#include "cx24113.h" +#include "cx24123.h" +#include "isl6421.h" +#include "mt352.h" +#include "bcm3510.h" +#include "nxt200x.h" +#include "dvb-pll.h" +#include "lgdt330x.h" +#include "tuner-simple.h" +#include "stv0297.h" + + +/* Can we use the specified front-end? Remember that if we are compiled + * into the kernel we can't call code that's in modules. */ +#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \ + (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE))) + +/* lnb control */ +#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299) +static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct flexcop_device *fc = fe->dvb->priv; + flexcop_ibi_value v; + deb_tuner("polarity/voltage = %u\n", voltage); + + v = fc->read_ibi_reg(fc, misc_204); + switch (voltage) { + case SEC_VOLTAGE_OFF: + v.misc_204.ACPI1_sig = 1; + break; + case SEC_VOLTAGE_13: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 0; + break; + case SEC_VOLTAGE_18: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 1; + break; + default: + err("unknown SEC_VOLTAGE value"); + return -EINVAL; + } + return fc->write_ibi_reg(fc, misc_204, v); +} +#endif + +#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312) +static int flexcop_sleep(struct dvb_frontend* fe) +{ + struct flexcop_device *fc = fe->dvb->priv; + if (fc->fe_sleep) + return fc->fe_sleep(fe); + return 0; +} +#endif + +/* SkyStar2 DVB-S rev 2.3 */ +#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL) +static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ +/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ + struct flexcop_device *fc = fe->dvb->priv; + flexcop_ibi_value v; + u16 ax; + v.raw = 0; + deb_tuner("tone = %u\n",tone); + + switch (tone) { + case SEC_TONE_ON: + ax = 0x01ff; + break; + case SEC_TONE_OFF: + ax = 0; + break; + default: + err("unknown SEC_TONE value"); + return -EINVAL; + } + + v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ + v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; + v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; + return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); +} + +static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) +{ + flexcop_set_tone(fe, SEC_TONE_ON); + udelay(data ? 500 : 1000); + flexcop_set_tone(fe, SEC_TONE_OFF); + udelay(data ? 1000 : 500); +} + +static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) +{ + int i, par = 1, d; + for (i = 7; i >= 0; i--) { + d = (data >> i) & 1; + par ^= d; + flexcop_diseqc_send_bit(fe, d); + } + flexcop_diseqc_send_bit(fe, par); +} + +static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, + int len, u8 *msg, unsigned long burst) +{ + int i; + + flexcop_set_tone(fe, SEC_TONE_OFF); + mdelay(16); + + for (i = 0; i < len; i++) + flexcop_diseqc_send_byte(fe,msg[i]); + mdelay(16); + + if (burst != -1) { + if (burst) + flexcop_diseqc_send_byte(fe, 0xff); + else { + flexcop_set_tone(fe, SEC_TONE_ON); + mdelay(12); + udelay(500); + flexcop_set_tone(fe, SEC_TONE_OFF); + } + msleep(20); + } + return 0; +} + +static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); +} + +static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) +{ + return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); +} + +static struct mt312_config skystar23_samsung_tbdu18132_config = { + .demod_address = 0x0e, +}; + +static int skystar2_rev23_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + struct dvb_frontend_ops *ops; + + fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); + if (!fc->fe) + return 0; + + if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, + DVB_PLL_SAMSUNG_TBDU18132)) + return 0; + + ops = &fc->fe->ops; + ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + ops->diseqc_send_burst = flexcop_diseqc_send_burst; + ops->set_tone = flexcop_set_tone; + ops->set_voltage = flexcop_set_voltage; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + return 1; +} +#else +#define skystar2_rev23_attach NULL +#endif + +/* SkyStar2 DVB-S rev 2.6 */ +#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL) +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + return 0; +} + +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, +}; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, +}; + +static int skystar2_rev26_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); + if (!fc->fe) + return 0; + + if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, + DVB_PLL_SAMSUNG_TBMU24112)) + return 0; + + fc->fe->ops.set_voltage = flexcop_set_voltage; + fc->fe_sleep = fc->fe->ops.sleep; + fc->fe->ops.sleep = flexcop_sleep; + return 1; + +} +#else +#define skystar2_rev26_attach NULL +#endif + +/* SkyStar2 DVB-S rev 2.7 */ +#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000) +static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { + .demod_address = 0x53, + .invert = 1, + .repeated_start_workaround = 1, + .serial_mpeg = 1, +}; + +static struct itd1000_config skystar2_rev2_7_itd1000_config = { + .i2c_address = 0x61, +}; + +static int skystar2_rev27_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + flexcop_ibi_value r108; + struct i2c_adapter *i2c_tuner; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[0].no_base_addr = 1; + fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, + i2c); + if (!fc->fe) + goto fail; + + i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); + if (!i2c_tuner) + goto fail; + + fc->fe_sleep = fc->fe->ops.sleep; + fc->fe->ops.sleep = flexcop_sleep; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 1, 1)) { + err("ISL6421 could NOT be attached"); + goto fail_isl; + } + info("ISL6421 successfully attached"); + + /* the ITD1000 requires a lower i2c clock - is it a problem ? */ + r108.raw = 0x00000506; + fc->write_ibi_reg(fc, tw_sm_c_108, r108); + if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner, + &skystar2_rev2_7_itd1000_config)) { + err("ITD1000 could NOT be attached"); + /* Should i2c clock be restored? */ + goto fail_isl; + } + info("ITD1000 successfully attached"); + + return 1; + +fail_isl: + fc->fc_i2c_adap[2].no_base_addr = 0; +fail: + /* for the next devices we need it again */ + fc->fc_i2c_adap[0].no_base_addr = 0; + return 0; +} +#else +#define skystar2_rev27_attach NULL +#endif + +/* SkyStar2 rev 2.8 */ +#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113) +static struct cx24123_config skystar2_rev2_8_cx24123_config = { + .demod_address = 0x55, + .dont_use_pll = 1, + .agc_callback = cx24113_agc_callback, +}; + +static const struct cx24113_config skystar2_rev2_8_cx24113_config = { + .i2c_addr = 0x54, + .xtal_khz = 10111, +}; + +static int skystar2_rev28_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + struct i2c_adapter *i2c_tuner; + + fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config, + i2c); + if (!fc->fe) + return 0; + + i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); + if (!i2c_tuner) + return 0; + + if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config, + i2c_tuner)) { + err("CX24113 could NOT be attached"); + return 0; + } + info("CX24113 successfully attached"); + + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 0, 0)) { + err("ISL6421 could NOT be attached"); + fc->fc_i2c_adap[2].no_base_addr = 0; + return 0; + } + info("ISL6421 successfully attached"); + /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an + * IR-receiver (PIC16F818) - but the card has no input for that ??? */ + return 1; +} +#else +#define skystar2_rev28_attach NULL +#endif + +/* AirStar DVB-T */ +#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL) +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + return 0; +} + +static struct mt352_config samsung_tdtc9251dh0_config = { + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, +}; + +static int airstar_dvbt_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, + DVB_PLL_SAMSUNG_TDTC9251DH0); +} +#else +#define airstar_dvbt_attach NULL +#endif + +/* AirStar ATSC 1st generation */ +#if FE_SUPPORTED(BCM3510) +static int flexcop_fe_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char* name) +{ + struct flexcop_device *fc = fe->dvb->priv; + return request_firmware(fw, name, fc->dev); +} + +static struct bcm3510_config air2pc_atsc_first_gen_config = { + .demod_address = 0x0f, + .request_firmware = flexcop_fe_request_firmware, +}; + +static int airstar_atsc1_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); + return fc->fe != NULL; +} +#else +#define airstar_atsc1_attach NULL +#endif + +/* AirStar ATSC 2nd generation */ +#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) +static struct nxt200x_config samsung_tbmv_config = { + .demod_address = 0x0a, +}; + +static int airstar_atsc2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, + DVB_PLL_SAMSUNG_TBMV); +} +#else +#define airstar_atsc2_attach NULL +#endif + +/* AirStar ATSC 3rd generation */ +#if FE_SUPPORTED(LGDT330X) +static struct lgdt330x_config air2pc_atsc_hd5000_config = { + .demod_address = 0x59, + .demod_chip = LGDT3303, + .serial_mpeg = 0x04, + .clock_polarity_flip = 1, +}; + +static int airstar_atsc3_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, + TUNER_LG_TDVS_H06XF); +} +#else +#define airstar_atsc3_attach NULL +#endif + +/* CableStar2 DVB-C */ +#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL) +static u8 alps_tdee4_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x48, + 0x01, 0x58, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x30, 0xff, + 0x31, 0x9d, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x29, + 0x35, 0x55, + 0x36, 0x80, + 0x37, 0x6e, + 0x38, 0x9c, + 0x40, 0x1a, + 0x41, 0xfe, + 0x42, 0x33, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x51, + 0x4b, 0xf8, + 0x52, 0x30, + 0x53, 0x06, + 0x59, 0x06, + 0x5a, 0x5e, + 0x5b, 0x04, + 0x61, 0x49, + 0x62, 0x0a, + 0x70, 0xff, + 0x71, 0x04, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x20, + 0x81, 0x00, + 0x82, 0x30, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x22, + 0x86, 0x08, + 0x87, 0x1b, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x00, + 0x91, 0x04, + 0xa0, 0x86, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x5b, + 0xc1, 0x10, + 0xc2, 0x12, + 0xd0, 0x02, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x02, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x01, + 0xff, 0xff, +}; + +static struct stv0297_config alps_tdee4_stv0297_config = { + .demod_address = 0x1c, + .inittab = alps_tdee4_stv0297_inittab, +}; + +static int cablestar2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fc_i2c_adap[0].no_base_addr = 1; + fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); + if (!fc->fe) + goto fail; + + /* This tuner doesn't use the stv0297's I2C gate, but instead the + * tuner is connected to a different flexcop I2C adapter. */ + if (fc->fe->ops.i2c_gate_ctrl) + fc->fe->ops.i2c_gate_ctrl(fc->fe, 0); + fc->fe->ops.i2c_gate_ctrl = NULL; + + if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, + &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4)) + goto fail; + + return 1; + +fail: + /* Reset for next frontend to try */ + fc->fc_i2c_adap[0].no_base_addr = 0; + return 0; +} +#else +#define cablestar2_attach NULL +#endif + +static struct { + flexcop_device_type_t type; + int (*attach)(struct flexcop_device *, struct i2c_adapter *); +} flexcop_frontends[] = { + { FC_SKY_REV27, skystar2_rev27_attach }, + { FC_SKY_REV28, skystar2_rev28_attach }, + { FC_SKY_REV26, skystar2_rev26_attach }, + { FC_AIR_DVBT, airstar_dvbt_attach }, + { FC_AIR_ATSC2, airstar_atsc2_attach }, + { FC_AIR_ATSC3, airstar_atsc3_attach }, + { FC_AIR_ATSC1, airstar_atsc1_attach }, + { FC_CABLE, cablestar2_attach }, + { FC_SKY_REV23, skystar2_rev23_attach }, +}; + +/* try to figure out the frontend */ +int flexcop_frontend_init(struct flexcop_device *fc) +{ + int i; + for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { + if (!flexcop_frontends[i].attach) + continue; + /* type needs to be set before, because of some workarounds + * done based on the probed card type */ + fc->dev_type = flexcop_frontends[i].type; + if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap)) + goto fe_found; + /* Clean up partially attached frontend */ + if (fc->fe) { + dvb_frontend_detach(fc->fe); + fc->fe = NULL; + } + } + fc->dev_type = FC_UNK; + err("no frontend driver found for this B2C2/FlexCop adapter"); + return -ENODEV; + +fe_found: + info("found '%s' .", fc->fe->ops.info.name); + if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { + err("frontend registration failed!"); + dvb_frontend_detach(fc->fe); + fc->fe = NULL; + return -EINVAL; + } + fc->init_state |= FC_STATE_FE_INIT; + return 0; +} + +void flexcop_frontend_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_FE_INIT) { + dvb_unregister_frontend(fc->fe); + dvb_frontend_detach(fc->fe); + } + fc->init_state &= ~FC_STATE_FE_INIT; +} diff --git a/drivers/media/pci/b2c2/flexcop-hw-filter.c b/drivers/media/pci/b2c2/flexcop-hw-filter.c new file mode 100644 index 00000000000..77e45475f4c --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-hw-filter.c @@ -0,0 +1,232 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-hw-filter.c - pid and mac address filtering and control functions + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff); + deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off"); +} + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff); +} + +static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff); +} + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) +{ + flexcop_ibi_value v418, v41c; + v41c = fc->read_ibi_reg(fc, mac_address_41c); + + v418.mac_address_418.MAC1 = mac[0]; + v418.mac_address_418.MAC2 = mac[1]; + v418.mac_address_418.MAC3 = mac[2]; + v418.mac_address_418.MAC6 = mac[3]; + v41c.mac_address_41c.MAC7 = mac[4]; + v41c.mac_address_41c.MAC8 = mac[5]; + + fc->write_ibi_reg(fc, mac_address_418, v418); + fc->write_ibi_reg(fc, mac_address_41c, v41c); +} + +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff); +} + +static void flexcop_pid_group_filter(struct flexcop_device *fc, + u16 pid, u16 mask) +{ + /* index_reg_310.extra_index_reg need to 0 or 7 to work */ + flexcop_ibi_value v30c; + v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; + v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; + fc->write_ibi_reg(fc, pid_filter_30c, v30c); +} + +static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff); +} + +/* this fancy define reduces the code size of the quite similar PID controlling of + * the first 6 PIDs + */ + +#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ + flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ +v208 = fc->read_ibi_reg(fc, ctrl_208); \ +vpid.vregname.field = onoff ? pid : 0x1fff; \ +vpid.vregname.trans_field = transval; \ +v208.ctrl_208.enablefield = onoff; \ +fc->write_ibi_reg(fc, vregname, vpid); \ +fc->write_ibi_reg(fc, ctrl_208, v208); + +static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig, + Stream1_trans, 0); +} + +static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig, + Stream2_trans, 0); +} + +static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0); +} + +static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0); +} + +static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0); +} + +static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0); +} + +static void flexcop_pid_control(struct flexcop_device *fc, + int index, u16 pid, int onoff) +{ + if (pid == 0x2000) + return; + + deb_ts("setting pid: %5d %04x at index %d '%s'\n", + pid, pid, index, onoff ? "on" : "off"); + + /* We could use bit magic here to reduce source code size. + * I decided against it, but to use the real register names */ + switch (index) { + case 0: + flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff); + break; + case 1: + flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff); + break; + case 2: + flexcop_pid_PCR_PID_ctrl(fc, pid, onoff); + break; + case 3: + flexcop_pid_PMT_PID_ctrl(fc, pid, onoff); + break; + case 4: + flexcop_pid_EMM_PID_ctrl(fc, pid, onoff); + break; + case 5: + flexcop_pid_ECM_PID_ctrl(fc, pid, onoff); + break; + default: + if (fc->has_32_hw_pid_filter && index < 38) { + flexcop_ibi_value vpid, vid; + + /* set the index */ + vid = fc->read_ibi_reg(fc, index_reg_310); + vid.index_reg_310.index_reg = index - 6; + fc->write_ibi_reg(fc, index_reg_310, vid); + + vpid = fc->read_ibi_reg(fc, pid_n_reg_314); + vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; + vpid.pid_n_reg_314.PID_enable_bit = onoff; + fc->write_ibi_reg(fc, pid_n_reg_314, vpid); + } + break; + } +} + +static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff) +{ + if (fc->fullts_streaming_state != onoff) { + deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); + flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); + flexcop_pid_group_filter_ctrl(fc, onoff); + fc->fullts_streaming_state = onoff; + } + return 0; +} + +int flexcop_pid_feed_control(struct flexcop_device *fc, + struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; + + fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ + if (dvbdmxfeed->index >= max_pid_filter) + fc->extra_feedcount += onoff ? 1 : -1; + + /* toggle complete-TS-streaming when: + * - pid_filtering is not enabled and it is the first or last feed requested + * - pid_filtering is enabled, + * - but the number of requested feeds is exceeded + * - or the requested pid is 0x2000 */ + + if (!fc->pid_filtering && fc->feedcount == onoff) + flexcop_toggle_fullts_streaming(fc, onoff); + + if (fc->pid_filtering) { + flexcop_pid_control \ + (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); + + if (fc->extra_feedcount > 0) + flexcop_toggle_fullts_streaming(fc, 1); + else if (dvbdmxfeed->pid == 0x2000) + flexcop_toggle_fullts_streaming(fc, onoff); + else + flexcop_toggle_fullts_streaming(fc, 0); + } + + /* if it was the first or last feed request change the stream-status */ + if (fc->feedcount == onoff) { + flexcop_rcv_data_ctrl(fc, onoff); + if (fc->stream_control) /* device specific stream control */ + fc->stream_control(fc, onoff); + + /* feeding stopped -> reset the flexcop filter*/ + if (onoff == 0) { + flexcop_reset_block_300(fc); + flexcop_hw_filter_init(fc); + } + } + return 0; +} +EXPORT_SYMBOL(flexcop_pid_feed_control); + +void flexcop_hw_filter_init(struct flexcop_device *fc) +{ + int i; + flexcop_ibi_value v; + for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) + flexcop_pid_control(fc, i, 0x1fff, 0); + + flexcop_pid_group_filter(fc, 0, 0x1fe0); + flexcop_pid_group_filter_ctrl(fc, 0); + + v = fc->read_ibi_reg(fc, pid_filter_308); + v.pid_filter_308.EMM_filter_4 = 1; + v.pid_filter_308.EMM_filter_6 = 0; + fc->write_ibi_reg(fc, pid_filter_308, v); + + flexcop_null_filter_ctrl(fc, 1); +} diff --git a/drivers/media/pci/b2c2/flexcop-i2c.c b/drivers/media/pci/b2c2/flexcop-i2c.c new file mode 100644 index 00000000000..965d5eb3375 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-i2c.c @@ -0,0 +1,288 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +#define FC_MAX_I2C_RETRIES 100000 + +static int flexcop_i2c_operation(struct flexcop_device *fc, + flexcop_ibi_value *r100) +{ + int i; + flexcop_ibi_value r; + + r100->tw_sm_c_100.working_start = 1; + deb_i2c("r100 before: %08x\n",r100->raw); + + fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); + fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */ + + for (i = 0; i < FC_MAX_I2C_RETRIES; i++) { + r = fc->read_ibi_reg(fc, tw_sm_c_100); + + if (!r.tw_sm_c_100.no_base_addr_ack_error) { + if (r.tw_sm_c_100.st_done) { + *r100 = r; + deb_i2c("i2c success\n"); + return 0; + } + } else { + deb_i2c("suffering from an i2c ack_error\n"); + return -EREMOTEIO; + } + } + deb_i2c("tried %d times i2c operation, " + "never finished or too many ack errors.\n", i); + return -EREMOTEIO; +} + +static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, + flexcop_ibi_value r100, u8 *buf) +{ + flexcop_ibi_value r104; + int len = r100.tw_sm_c_100.total_bytes, + /* remember total_bytes is buflen-1 */ + ret; + + /* work-around to have CableStar2 and SkyStar2 rev 2.7 work + * correctly: + * + * the ITD1000 is behind an i2c-gate which closes automatically + * after an i2c-transaction the STV0297 needs 2 consecutive reads + * one with no_base_addr = 0 and one with 1 + * + * those two work-arounds are conflictin: we check for the card + * type, it is set when probing the ITD1000 */ + if (i2c->fc->dev_type == FC_SKY_REV27) + r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; + + ret = flexcop_i2c_operation(i2c->fc, &r100); + if (ret != 0) { + deb_i2c("Retrying operation\n"); + r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; + ret = flexcop_i2c_operation(i2c->fc, &r100); + } + if (ret != 0) { + deb_i2c("read failed. %d\n", ret); + return ret; + } + + buf[0] = r100.tw_sm_c_100.data1_reg; + + if (len > 0) { + r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104); + deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw); + + /* there is at least one more byte, otherwise we wouldn't be here */ + buf[1] = r104.tw_sm_c_104.data2_reg; + if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; + if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; + } + return 0; +} + +static int flexcop_i2c_write4(struct flexcop_device *fc, + flexcop_ibi_value r100, u8 *buf) +{ + flexcop_ibi_value r104; + int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */ + r104.raw = 0; + + /* there is at least one byte, otherwise we wouldn't be here */ + r100.tw_sm_c_100.data1_reg = buf[0]; + r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0; + r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; + r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; + + deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw); + + /* write the additional i2c data before doing the actual i2c operation */ + fc->write_ibi_reg(fc, tw_sm_c_104, r104); + return flexcop_i2c_operation(fc, &r100); +} + +int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, + flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + int ret; + +#ifdef DUMP_I2C_MESSAGES + int i; +#endif + + u16 bytes_to_transfer; + flexcop_ibi_value r100; + + deb_i2c("op = %d\n",op); + r100.raw = 0; + r100.tw_sm_c_100.chipaddr = chipaddr; + r100.tw_sm_c_100.twoWS_rw = op; + r100.tw_sm_c_100.twoWS_port_reg = i2c->port; + +#ifdef DUMP_I2C_MESSAGES + printk(KERN_DEBUG "%d ", i2c->port); + if (op == FC_READ) + printk("rd("); + else + printk("wr("); + printk("%02x): %02x ", chipaddr, addr); +#endif + + /* in that case addr is the only value -> + * we write it twice as baseaddr and val0 + * BBTI is doing it like that for ISL6421 at least */ + if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { + buf = &addr; + len = 1; + } + + while (len != 0) { + bytes_to_transfer = len > 4 ? 4 : len; + + r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; + r100.tw_sm_c_100.baseaddr = addr; + + if (op == FC_READ) + ret = flexcop_i2c_read4(i2c, r100, buf); + else + ret = flexcop_i2c_write4(i2c->fc, r100, buf); + +#ifdef DUMP_I2C_MESSAGES + for (i = 0; i < bytes_to_transfer; i++) + printk("%02x ", buf[i]); +#endif + + if (ret < 0) + return ret; + + buf += bytes_to_transfer; + addr += bytes_to_transfer; + len -= bytes_to_transfer; + } + +#ifdef DUMP_I2C_MESSAGES + printk("\n"); +#endif + + return 0; +} +/* exported for PCI i2c */ +EXPORT_SYMBOL(flexcop_i2c_request); + +/* master xfer callback for demodulator */ +static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); + int i, ret = 0; + + /* Some drivers use 1 byte or 0 byte reads as probes, which this + * driver doesn't support. These probes will always fail, so this + * hack makes them always succeed. If one knew how, it would of + * course be better to actually do the read. */ + if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) + return 1; + + if (mutex_lock_interruptible(&i2c->fc->i2c_mutex)) + return -ERESTARTSYS; + + for (i = 0; i < num; i++) { + /* reading */ + if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) { + ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr, + msgs[i].buf[0], msgs[i+1].buf, + msgs[i+1].len); + i++; /* skip the following message */ + } else /* writing */ + ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr, + msgs[i].buf[0], &msgs[i].buf[1], + msgs[i].len - 1); + if (ret < 0) { + deb_i2c("i2c master_xfer failed"); + break; + } + } + + mutex_unlock(&i2c->fc->i2c_mutex); + + if (ret == 0) + ret = num; + return ret; +} + +static u32 flexcop_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm flexcop_algo = { + .master_xfer = flexcop_master_xfer, + .functionality = flexcop_i2c_func, +}; + +int flexcop_i2c_init(struct flexcop_device *fc) +{ + int ret; + mutex_init(&fc->i2c_mutex); + + fc->fc_i2c_adap[0].fc = fc; + fc->fc_i2c_adap[1].fc = fc; + fc->fc_i2c_adap[2].fc = fc; + fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD; + fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; + fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; + + strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", + sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", + sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", + sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); + + i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); + i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); + i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]); + + fc->fc_i2c_adap[0].i2c_adap.algo = + fc->fc_i2c_adap[1].i2c_adap.algo = + fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo; + fc->fc_i2c_adap[0].i2c_adap.algo_data = + fc->fc_i2c_adap[1].i2c_adap.algo_data = + fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL; + fc->fc_i2c_adap[0].i2c_adap.dev.parent = + fc->fc_i2c_adap[1].i2c_adap.dev.parent = + fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev; + + ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap); + if (ret < 0) + return ret; + + ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap); + if (ret < 0) + goto adap_1_failed; + + ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap); + if (ret < 0) + goto adap_2_failed; + + fc->init_state |= FC_STATE_I2C_INIT; + return 0; + +adap_2_failed: + i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); +adap_1_failed: + i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); + return ret; +} + +void flexcop_i2c_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_I2C_INIT) { + i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap); + i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); + i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); + } + fc->init_state &= ~FC_STATE_I2C_INIT; +} diff --git a/drivers/media/pci/b2c2/flexcop-misc.c b/drivers/media/pci/b2c2/flexcop-misc.c new file mode 100644 index 00000000000..f06f3a9070f --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-misc.c @@ -0,0 +1,86 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-misc.c - miscellaneous functions + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +void flexcop_determine_revision(struct flexcop_device *fc) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); + + switch (v.misc_204.Rev_N_sig_revision_hi) { + case 0x2: + deb_info("found a FlexCopII.\n"); + fc->rev = FLEXCOP_II; + break; + case 0x3: + deb_info("found a FlexCopIIb.\n"); + fc->rev = FLEXCOP_IIB; + break; + case 0x0: + deb_info("found a FlexCopIII.\n"); + fc->rev = FLEXCOP_III; + break; + default: + err("unknown FlexCop Revision: %x. Please report this to " + "linux-dvb@linuxtv.org.", + v.misc_204.Rev_N_sig_revision_hi); + break; + } + + if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) + deb_info("this FlexCop has " + "the additional 32 hardware pid filter.\n"); + else + deb_info("this FlexCop has " + "the 6 basic main hardware pid filter.\n"); + /* bus parts have to decide if hw pid filtering is used or not. */ +} + +static const char *flexcop_revision_names[] = { + "Unknown chip", + "FlexCopII", + "FlexCopIIb", + "FlexCopIII", +}; + +static const char *flexcop_device_names[] = { + [FC_UNK] = "Unknown device", + [FC_CABLE] = "Cable2PC/CableStar 2 DVB-C", + [FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T", + [FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation", + [FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation", + [FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", + [FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)", + [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6", + [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", + [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8", +}; + +static const char *flexcop_bus_names[] = { + "USB", + "PCI", +}; + +void flexcop_device_name(struct flexcop_device *fc, + const char *prefix, const char *suffix) +{ + info("%s '%s' at the '%s' bus controlled by a '%s' %s", + prefix, flexcop_device_names[fc->dev_type], + flexcop_bus_names[fc->bus_type], + flexcop_revision_names[fc->rev], suffix); +} + +void flexcop_dump_reg(struct flexcop_device *fc, + flexcop_ibi_register reg, int num) +{ + flexcop_ibi_value v; + int i; + for (i = 0; i < num; i++) { + v = fc->read_ibi_reg(fc, reg+4*i); + deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw); + } + deb_rdump("\n"); +} +EXPORT_SYMBOL(flexcop_dump_reg); diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c new file mode 100644 index 00000000000..44f8fb5f17f --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -0,0 +1,450 @@ +/* + * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-pci.c - covers the PCI part including DMA transfers + * see flexcop.c for copyright information + */ + +#define FC_LOG_PREFIX "flexcop-pci" +#include "flexcop-common.h" + +static int enable_pid_filtering = 1; +module_param(enable_pid_filtering, int, 0444); +MODULE_PARM_DESC(enable_pid_filtering, + "enable hardware pid filtering: supported values: 0 (fullts), 1"); + +static int irq_chk_intv = 100; +module_param(irq_chk_intv, int, 0644); +MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); + +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) printk(args); } while (0) +#define DEBSTATUS "" +#else +#define dprintk(level,args...) +#define DEBSTATUS " (debugging is not enabled)" +#endif + +#define deb_info(args...) dprintk(0x01, args) +#define deb_reg(args...) dprintk(0x02, args) +#define deb_ts(args...) dprintk(0x04, args) +#define deb_irq(args...) dprintk(0x08, args) +#define deb_chk(args...) dprintk(0x10, args) + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." + DEBSTATUS); + +#define DRIVER_VERSION "0.1" +#define DRIVER_NAME "flexcop-pci" +#define DRIVER_AUTHOR "Patrick Boettcher " + +struct flexcop_pci { + struct pci_dev *pdev; + +#define FC_PCI_INIT 0x01 +#define FC_PCI_DMA_INIT 0x02 + int init_state; + + void __iomem *io_mem; + u32 irq; + /* buffersize (at least for DMA1, need to be % 188 == 0, + * this logic is required */ +#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) +#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) + struct flexcop_dma dma[2]; + + int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ + u32 last_dma1_cur_pos; + /* position of the pointer last time the timer/packet irq occurred */ + int count; + int count_prev; + int stream_problem; + + spinlock_t irq_lock; + unsigned long last_irq; + + struct delayed_work irq_check_work; + struct flexcop_device *fc_dev; +}; + +static int lastwreg, lastwval, lastrreg, lastrval; + +static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register r) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + flexcop_ibi_value v; + v.raw = readl(fc_pci->io_mem + r); + + if (lastrreg != r || lastrval != v.raw) { + lastrreg = r; lastrval = v.raw; + deb_reg("new rd: %3x: %08x\n", r, v.raw); + } + + return v; +} + +static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register r, flexcop_ibi_value v) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + + if (lastwreg != r || lastwval != v.raw) { + lastwreg = r; lastwval = v.raw; + deb_reg("new wr: %3x: %08x\n", r, v.raw); + } + + writel(v.raw, fc_pci->io_mem + r); + return 0; +} + +static void flexcop_pci_irq_check_work(struct work_struct *work) +{ + struct flexcop_pci *fc_pci = + container_of(work, struct flexcop_pci, irq_check_work.work); + struct flexcop_device *fc = fc_pci->fc_dev; + + if (fc->feedcount) { + + if (fc_pci->count == fc_pci->count_prev) { + deb_chk("no IRQ since the last check\n"); + if (fc_pci->stream_problem++ == 3) { + struct dvb_demux_feed *feed; + deb_info("flexcop-pci: stream problem, resetting pid filter\n"); + + spin_lock_irq(&fc->demux.lock); + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 0); + } + + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 1); + } + spin_unlock_irq(&fc->demux.lock); + + fc_pci->stream_problem = 0; + } + } else { + fc_pci->stream_problem = 0; + fc_pci->count_prev = fc_pci->count; + } + } + + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); +} + +/* When PID filtering is turned on, we use the timer IRQ, because small amounts + * of data need to be passed to the user space instantly as well. When PID + * filtering is turned off, we use the page-change-IRQ */ +static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) +{ + struct flexcop_pci *fc_pci = dev_id; + struct flexcop_device *fc = fc_pci->fc_dev; + unsigned long flags; + flexcop_ibi_value v; + irqreturn_t ret = IRQ_HANDLED; + + spin_lock_irqsave(&fc_pci->irq_lock, flags); + v = fc->read_ibi_reg(fc, irq_20c); + + /* errors */ + if (v.irq_20c.Data_receiver_error) + deb_chk("data receiver error\n"); + if (v.irq_20c.Continuity_error_flag) + deb_chk("Contunuity error flag is set\n"); + if (v.irq_20c.LLC_SNAP_FLAG_set) + deb_chk("LLC_SNAP_FLAG_set is set\n"); + if (v.irq_20c.Transport_Error) + deb_chk("Transport error\n"); + + if ((fc_pci->count % 1000) == 0) + deb_chk("%d valid irq took place so far\n", fc_pci->count); + + if (v.irq_20c.DMA1_IRQ_Status == 1) { + if (fc_pci->active_dma1_addr == 0) + flexcop_pass_dmx_packets(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0, + fc_pci->dma[0].size / 188); + else + flexcop_pass_dmx_packets(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr1, + fc_pci->dma[0].size / 188); + + deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr); + fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; + /* for the timer IRQ we only can use buffer dmx feeding, because we don't have + * complete TS packets when reading from the DMA memory */ + } else if (v.irq_20c.DMA1_Timer_Status == 1) { + dma_addr_t cur_addr = + fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; + u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; + + deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, " + "last_cur_pos: %08x ", + jiffies_to_usecs(jiffies - fc_pci->last_irq), + v.raw, (unsigned long long)cur_addr, cur_pos, + fc_pci->last_dma1_cur_pos); + fc_pci->last_irq = jiffies; + + /* buffer end was reached, restarted from the beginning + * pass the data from last_cur_pos to the buffer end to the demux + */ + if (cur_pos < fc_pci->last_dma1_cur_pos) { + deb_irq(" end was reached: passing %d bytes ", + (fc_pci->dma[0].size*2 - 1) - + fc_pci->last_dma1_cur_pos); + flexcop_pass_dmx_data(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0 + + fc_pci->last_dma1_cur_pos, + (fc_pci->dma[0].size*2) - + fc_pci->last_dma1_cur_pos); + fc_pci->last_dma1_cur_pos = 0; + } + + if (cur_pos > fc_pci->last_dma1_cur_pos) { + deb_irq(" passing %d bytes ", + cur_pos - fc_pci->last_dma1_cur_pos); + flexcop_pass_dmx_data(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0 + + fc_pci->last_dma1_cur_pos, + cur_pos - fc_pci->last_dma1_cur_pos); + } + deb_irq("\n"); + + fc_pci->last_dma1_cur_pos = cur_pos; + fc_pci->count++; + } else { + deb_irq("isr for flexcop called, " + "apparently without reason (%08x)\n", v.raw); + ret = IRQ_NONE; + } + + spin_unlock_irqrestore(&fc_pci->irq_lock, flags); + return ret; +} + +static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + if (onoff) { + flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1); + flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2); + flexcop_dma_config_timer(fc, FC_DMA_1, 0); + flexcop_dma_xfer_control(fc, FC_DMA_1, + FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1); + deb_irq("DMA xfer enabled\n"); + + fc_pci->last_dma1_cur_pos = 0; + flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1); + deb_irq("IRQ enabled\n"); + fc_pci->count_prev = fc_pci->count; + } else { + flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0); + deb_irq("IRQ disabled\n"); + + flexcop_dma_xfer_control(fc, FC_DMA_1, + FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0); + deb_irq("DMA xfer disabled\n"); + } + return 0; +} + +static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) +{ + int ret; + ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0], + FC_DEFAULT_DMA1_BUFSIZE); + if (ret != 0) + return ret; + + ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1], + FC_DEFAULT_DMA2_BUFSIZE); + if (ret != 0) { + flexcop_dma_free(&fc_pci->dma[0]); + return ret; + } + + flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA | + FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); + flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO | + FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); + fc_pci->init_state |= FC_PCI_DMA_INIT; + return ret; +} + +static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci) +{ + if (fc_pci->init_state & FC_PCI_DMA_INIT) { + flexcop_dma_free(&fc_pci->dma[0]); + flexcop_dma_free(&fc_pci->dma[1]); + } + fc_pci->init_state &= ~FC_PCI_DMA_INIT; +} + +static int flexcop_pci_init(struct flexcop_pci *fc_pci) +{ + int ret; + + info("card revision %x", fc_pci->pdev->revision); + + if ((ret = pci_enable_device(fc_pci->pdev)) != 0) + return ret; + pci_set_master(fc_pci->pdev); + + if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) + goto err_pci_disable_device; + + fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); + + if (!fc_pci->io_mem) { + err("cannot map io memory\n"); + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(fc_pci->pdev, fc_pci); + spin_lock_init(&fc_pci->irq_lock); + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, + IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) + goto err_pci_iounmap; + + fc_pci->init_state |= FC_PCI_INIT; + return ret; + +err_pci_iounmap: + pci_iounmap(fc_pci->pdev, fc_pci->io_mem); + pci_set_drvdata(fc_pci->pdev, NULL); +err_pci_release_regions: + pci_release_regions(fc_pci->pdev); +err_pci_disable_device: + pci_disable_device(fc_pci->pdev); + return ret; +} + +static void flexcop_pci_exit(struct flexcop_pci *fc_pci) +{ + if (fc_pci->init_state & FC_PCI_INIT) { + free_irq(fc_pci->pdev->irq, fc_pci); + pci_iounmap(fc_pci->pdev, fc_pci->io_mem); + pci_set_drvdata(fc_pci->pdev, NULL); + pci_release_regions(fc_pci->pdev); + pci_disable_device(fc_pci->pdev); + } + fc_pci->init_state &= ~FC_PCI_INIT; +} + +static int flexcop_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct flexcop_device *fc; + struct flexcop_pci *fc_pci; + int ret = -ENOMEM; + + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) { + err("out of memory\n"); + return -ENOMEM; + } + + /* general flexcop init */ + fc_pci = fc->bus_specific; + fc_pci->fc_dev = fc; + + fc->read_ibi_reg = flexcop_pci_read_ibi_reg; + fc->write_ibi_reg = flexcop_pci_write_ibi_reg; + fc->i2c_request = flexcop_i2c_request; + fc->get_mac_addr = flexcop_eeprom_check_mac_addr; + fc->stream_control = flexcop_pci_stream_control; + + if (enable_pid_filtering) + info("will use the HW PID filter."); + else + info("will pass the complete TS to the demuxer."); + + fc->pid_filtering = enable_pid_filtering; + fc->bus_type = FC_PCI; + fc->dev = &pdev->dev; + fc->owner = THIS_MODULE; + + /* bus specific part */ + fc_pci->pdev = pdev; + if ((ret = flexcop_pci_init(fc_pci)) != 0) + goto err_kfree; + + /* init flexcop */ + if ((ret = flexcop_device_initialize(fc)) != 0) + goto err_pci_exit; + + /* init dma */ + if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) + goto err_fc_exit; + + INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); + + if (irq_chk_intv > 0) + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? + 100 : + irq_chk_intv)); + return ret; + +err_fc_exit: + flexcop_device_exit(fc); +err_pci_exit: + flexcop_pci_exit(fc_pci); +err_kfree: + flexcop_device_kfree(fc); + return ret; +} + +/* in theory every _exit function should be called exactly two times, + * here and in the bail-out-part of the _init-function + */ +static void flexcop_pci_remove(struct pci_dev *pdev) +{ + struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); + + if (irq_chk_intv > 0) + cancel_delayed_work(&fc_pci->irq_check_work); + + flexcop_pci_dma_exit(fc_pci); + flexcop_device_exit(fc_pci->fc_dev); + flexcop_pci_exit(fc_pci); + flexcop_device_kfree(fc_pci->fc_dev); +} + +static struct pci_device_id flexcop_pci_tbl[] = { + { PCI_DEVICE(0x13d0, 0x2103) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); + +static struct pci_driver flexcop_pci_driver = { + .name = "b2c2_flexcop_pci", + .id_table = flexcop_pci_tbl, + .probe = flexcop_pci_probe, + .remove = flexcop_pci_remove, +}; + +static int __init flexcop_pci_module_init(void) +{ + return pci_register_driver(&flexcop_pci_driver); +} + +static void __exit flexcop_pci_module_exit(void) +{ + pci_unregister_driver(&flexcop_pci_driver); +} + +module_init(flexcop_pci_module_init); +module_exit(flexcop_pci_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/b2c2/flexcop-reg.h b/drivers/media/pci/b2c2/flexcop-reg.h new file mode 100644 index 00000000000..dc4528dcbb9 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-reg.h @@ -0,0 +1,166 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_REG_H__ +#define __FLEXCOP_REG_H__ + +typedef enum { + FLEXCOP_UNK = 0, + FLEXCOP_II, + FLEXCOP_IIB, + FLEXCOP_III, +} flexcop_revision_t; + +typedef enum { + FC_UNK = 0, + FC_CABLE, + FC_AIR_DVBT, + FC_AIR_ATSC1, + FC_AIR_ATSC2, + FC_AIR_ATSC3, + FC_SKY_REV23, + FC_SKY_REV26, + FC_SKY_REV27, + FC_SKY_REV28, +} flexcop_device_type_t; + +typedef enum { + FC_USB = 0, + FC_PCI, +} flexcop_bus_t; + +/* FlexCop IBI Registers */ +#if defined(__LITTLE_ENDIAN) +#include "flexcop_ibi_value_le.h" +#else +#if defined(__BIG_ENDIAN) +#include "flexcop_ibi_value_be.h" +#else +#error no endian defined +#endif +#endif + +#define fc_data_Tag_ID_DVB 0x3e +#define fc_data_Tag_ID_ATSC 0x3f +#define fc_data_Tag_ID_IDSB 0x8b + +#define fc_key_code_default 0x1 +#define fc_key_code_even 0x2 +#define fc_key_code_odd 0x3 + +extern flexcop_ibi_value ibi_zero; + +typedef enum { + FC_I2C_PORT_DEMOD = 1, + FC_I2C_PORT_EEPROM = 2, + FC_I2C_PORT_TUNER = 3, +} flexcop_i2c_port_t; + +typedef enum { + FC_WRITE = 0, + FC_READ = 1, +} flexcop_access_op_t; + +typedef enum { + FC_SRAM_DEST_NET = 1, + FC_SRAM_DEST_CAI = 2, + FC_SRAM_DEST_CAO = 4, + FC_SRAM_DEST_MEDIA = 8 +} flexcop_sram_dest_t; + +typedef enum { + FC_SRAM_DEST_TARGET_WAN_USB = 0, + FC_SRAM_DEST_TARGET_DMA1 = 1, + FC_SRAM_DEST_TARGET_DMA2 = 2, + FC_SRAM_DEST_TARGET_FC3_CA = 3 +} flexcop_sram_dest_target_t; + +typedef enum { + FC_SRAM_2_32KB = 0, /* 64KB */ + FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ + FC_SRAM_1_128KB = 2, /* 128KB */ + FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ +} flexcop_sram_type_t; + +typedef enum { + FC_WAN_SPEED_4MBITS = 0, + FC_WAN_SPEED_8MBITS = 1, + FC_WAN_SPEED_12MBITS = 2, + FC_WAN_SPEED_16MBITS = 3, +} flexcop_wan_speed_t; + +typedef enum { + FC_DMA_1 = 1, + FC_DMA_2 = 2, +} flexcop_dma_index_t; + +typedef enum { + FC_DMA_SUBADDR_0 = 1, + FC_DMA_SUBADDR_1 = 2, +} flexcop_dma_addr_index_t; + +/* names of the particular registers */ +typedef enum { + dma1_000 = 0x000, + dma1_004 = 0x004, + dma1_008 = 0x008, + dma1_00c = 0x00c, + dma2_010 = 0x010, + dma2_014 = 0x014, + dma2_018 = 0x018, + dma2_01c = 0x01c, + + tw_sm_c_100 = 0x100, + tw_sm_c_104 = 0x104, + tw_sm_c_108 = 0x108, + tw_sm_c_10c = 0x10c, + tw_sm_c_110 = 0x110, + + lnb_switch_freq_200 = 0x200, + misc_204 = 0x204, + ctrl_208 = 0x208, + irq_20c = 0x20c, + sw_reset_210 = 0x210, + misc_214 = 0x214, + mbox_v8_to_host_218 = 0x218, + mbox_host_to_v8_21c = 0x21c, + + pid_filter_300 = 0x300, + pid_filter_304 = 0x304, + pid_filter_308 = 0x308, + pid_filter_30c = 0x30c, + index_reg_310 = 0x310, + pid_n_reg_314 = 0x314, + mac_low_reg_318 = 0x318, + mac_high_reg_31c = 0x31c, + + data_tag_400 = 0x400, + card_id_408 = 0x408, + card_id_40c = 0x40c, + mac_address_418 = 0x418, + mac_address_41c = 0x41c, + + ci_600 = 0x600, + pi_604 = 0x604, + pi_608 = 0x608, + dvb_reg_60c = 0x60c, + + sram_ctrl_reg_700 = 0x700, + net_buf_reg_704 = 0x704, + cai_buf_reg_708 = 0x708, + cao_buf_reg_70c = 0x70c, + media_buf_reg_710 = 0x710, + sram_dest_reg_714 = 0x714, + net_buf_reg_718 = 0x718, + wan_ctrl_reg_71c = 0x71c, +} flexcop_ibi_register; + +#define flexcop_set_ibi_value(reg,attr,val) { \ + flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ + v.reg.attr = val; \ + fc->write_ibi_reg(fc,reg,v); \ +} + +#endif diff --git a/drivers/media/pci/b2c2/flexcop-sram.c b/drivers/media/pci/b2c2/flexcop-sram.c new file mode 100644 index 00000000000..f2199e43e80 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-sram.c @@ -0,0 +1,363 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-sram.c - functions for controlling the SRAM + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +static void flexcop_sram_set_chip(struct flexcop_device *fc, + flexcop_sram_type_t type) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type); +} + +int flexcop_sram_init(struct flexcop_device *fc) +{ + switch (fc->rev) { + case FLEXCOP_II: + case FLEXCOP_IIB: + flexcop_sram_set_chip(fc, FC_SRAM_1_32KB); + break; + case FLEXCOP_III: + flexcop_sram_set_chip(fc, FC_SRAM_1_48KB); + break; + default: + return -EINVAL; + } + return 0; +} + +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, + flexcop_sram_dest_target_t target) +{ + flexcop_ibi_value v; + v = fc->read_ibi_reg(fc, sram_dest_reg_714); + + if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { + err("SRAM destination target to available on FlexCopII(b)\n"); + return -EINVAL; + } + deb_sram("sram dest: %x target: %x\n", dest, target); + + if (dest & FC_SRAM_DEST_NET) + v.sram_dest_reg_714.NET_Dest = target; + if (dest & FC_SRAM_DEST_CAI) + v.sram_dest_reg_714.CAI_Dest = target; + if (dest & FC_SRAM_DEST_CAO) + v.sram_dest_reg_714.CAO_Dest = target; + if (dest & FC_SRAM_DEST_MEDIA) + v.sram_dest_reg_714.MEDIA_Dest = target; + + fc->write_ibi_reg(fc,sram_dest_reg_714,v); + udelay(1000); /* TODO delay really necessary */ + + return 0; +} +EXPORT_SYMBOL(flexcop_sram_set_dest); + +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); +} +EXPORT_SYMBOL(flexcop_wan_set_speed); + +void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); + v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; + v.sram_dest_reg_714.ctrl_sramdma = sramdma; + v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; + fc->write_ibi_reg(fc,sram_dest_reg_714,v); +} +EXPORT_SYMBOL(flexcop_sram_ctrl); + +#if 0 +static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04000000 | (*buf << 0x10); + + retries = 2; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __func__); + + write_reg_dw(adapter, 0x700, command); + + buf++; + addr++; + } +} + +static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command, value; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04008000; + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __func__); + + write_reg_dw(adapter, 0x700, command); + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __func__); + + value = read_reg_dw(adapter, 0x700) >> 0x10; + + *buf = (value & 0xff); + + addr++; + buf++; + } +} + +static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + while (len != 0) { + length = len; + /* check if the address range belongs to the same + * 32K memory chip. If not, the data is read + * from one chip at a time */ + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_read_chunk(adapter, addr, buf, length); + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + while (len != 0) { + length = len; + + /* check if the address range belongs to the same + * 32K memory chip. If not, the data is + * written to one chip at a time */ + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_write_chunk(adapter, addr, buf, length); + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_set_size(struct adapter *adapter, u32 mask) +{ + write_reg_dw(adapter, 0x71c, + (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); +} + +static void sram_init(struct adapter *adapter) +{ + u32 tmp; + tmp = read_reg_dw(adapter, 0x71c); + write_reg_dw(adapter, 0x71c, 1); + + if (read_reg_dw(adapter, 0x71c) != 0) { + write_reg_dw(adapter, 0x71c, tmp); + adapter->dw_sram_type = tmp & 0x30000; + ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); + } else { + adapter->dw_sram_type = 0x10000; + ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); + } +} + +static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) +{ + u8 tmp1, tmp2; + dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr); + + sram_set_size(adapter, mask); + sram_init(adapter); + + tmp2 = 0xa5; + tmp1 = 0x4f; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2); + + if (tmp2 != 0xa5) + return 0; + + tmp2 = 0x5a; + tmp1 = 0xf4; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2); + + if (tmp2 != 0x5a) + return 0; + return 1; +} + +static u32 sram_length(struct adapter *adapter) +{ + if (adapter->dw_sram_type == 0x10000) + return 32768; /* 32K */ + if (adapter->dw_sram_type == 0x00000) + return 65536; /* 64K */ + if (adapter->dw_sram_type == 0x20000) + return 131072; /* 128K */ + return 32768; /* 32K */ +} + +/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. + - for 128K there are 4x32K chips at bank 0,1,2,3. + - for 64K there are 2x32K chips at bank 1,2. + - for 32K there is one 32K chip at bank 0. + + FlexCop works only with one bank at a time. The bank is selected + by bits 28-29 of the 0x700 register. + + bank 0 covers addresses 0x00000-0x07fff + bank 1 covers addresses 0x08000-0x0ffff + bank 2 covers addresses 0x10000-0x17fff + bank 3 covers addresses 0x18000-0x1ffff */ + +static int flexcop_sram_detect(struct flexcop_device *fc) +{ + flexcop_ibi_value r208, r71c_0, vr71c_1; + r208 = fc->read_ibi_reg(fc, ctrl_208); + fc->write_ibi_reg(fc, ctrl_208, ibi_zero); + + r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); + write_reg_dw(adapter, 0x71c, 1); + tmp3 = read_reg_dw(adapter, 0x71c); + dprintk("%s: tmp3 = %x\n", __func__, tmp3); + write_reg_dw(adapter, 0x71c, tmp2); + + // check for internal SRAM ??? + tmp3--; + if (tmp3 != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 32K\n", __func__); + return 32; + } + + if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { + sram_set_size(adapter, 0x20000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 128K\n", __func__); + return 128; + } + + if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { + sram_set_size(adapter, 0x00000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 64K\n", __func__); + return 64; + } + + if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 32K\n", __func__); + return 32; + } + + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: SRAM detection failed. Set to 32K \n", __func__); + return 0; +} + +static void sll_detect_sram_size(struct adapter *adapter) +{ + sram_detect_for_flex2(adapter); +} + +#endif diff --git a/drivers/media/pci/b2c2/flexcop-usb.c b/drivers/media/pci/b2c2/flexcop-usb.c new file mode 100644 index 00000000000..8b6275f8590 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-usb.c @@ -0,0 +1,587 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-usb.c - covers the USB part + * see flexcop.c for copyright information + */ +#define FC_LOG_PREFIX "flexcop_usb" +#include "flexcop-usb.h" +#include "flexcop-common.h" + +/* Version information */ +#define DRIVER_VERSION "0.1" +#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver" +#define DRIVER_AUTHOR "Patrick Boettcher " + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) printk(args); } while (0) + +#define debug_dump(b, l, method) do {\ + int i; \ + for (i = 0; i < l; i++) \ + method("%02x ", b[i]); \ + method("\n"); \ +} while (0) + +#define DEBSTATUS "" +#else +#define dprintk(level, args...) +#define debug_dump(b, l, method) +#define DEBSTATUS " (debugging is not enabled)" +#endif + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2," + "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); +#undef DEBSTATUS + +#define deb_info(args...) dprintk(0x01, args) +#define deb_ts(args...) dprintk(0x02, args) +#define deb_ctrl(args...) dprintk(0x04, args) +#define deb_i2c(args...) dprintk(0x08, args) +#define deb_v8(args...) dprintk(0x10, args) + +/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits + * in the IBI address, to make the V8 code simpler. + * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used) + * in general: 0000 0HHH 000L LL00 + * IBI ADDRESS FORMAT: RHHH BLLL + * + * where R is the read(1)/write(0) bit, B is the busy bit + * and HHH and LLL are the two sets of three bits from the PCI address. + */ +#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \ + (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) +#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \ + (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) + +/* + * DKT 020228 + * - forget about this VENDOR_BUFFER_SIZE, read and write register + * deal with DWORD or 4 bytes, that should be should from now on + * - from now on, we don't support anything older than firm 1.00 + * I eliminated the write register as a 2 trip of writing hi word and lo word + * and force this to write only 4 bytes at a time. + * NOTE: this should work with all the firmware from 1.00 and newer + */ +static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read) +{ + struct flexcop_usb *fc_usb = fc->bus_specific; + u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; + u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; + u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | + (read ? 0x80 : 0); + + int len = usb_control_msg(fc_usb->udev, + read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, + request, + request_type, /* 0xc0 read or 0x40 write */ + wAddress, + 0, + val, + sizeof(u32), + B2C2_WAIT_FOR_OPERATION_RDW * HZ); + + if (len != sizeof(u32)) { + err("error while %s dword from %d (%d).", read ? "reading" : + "writing", wAddress, wRegOffsPCI); + return -EIO; + } + return 0; +} +/* + * DKT 010817 - add support for V8 memory read/write and flash update + */ +static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, + flexcop_usb_request_t req, u8 page, u16 wAddress, + u8 *pbBuffer, u32 buflen) +{ + u8 request_type = USB_TYPE_VENDOR; + u16 wIndex; + int nWaitTime, pipe, len; + wIndex = page << 8; + + switch (req) { + case B2C2_USB_READ_V8_MEM: + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; + request_type |= USB_DIR_IN; + pipe = B2C2_USB_CTRL_PIPE_IN; + break; + case B2C2_USB_WRITE_V8_MEM: + wIndex |= pbBuffer[0]; + request_type |= USB_DIR_OUT; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + case B2C2_USB_FLASH_BLOCK: + request_type |= USB_DIR_OUT; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + default: + deb_info("unsupported request for v8_mem_req %x.\n", req); + return -EINVAL; + } + deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req, + wAddress, wIndex, buflen); + + len = usb_control_msg(fc_usb->udev, pipe, + req, + request_type, + wAddress, + wIndex, + pbBuffer, + buflen, + nWaitTime * HZ); + + debug_dump(pbBuffer, len, deb_v8); + return len == buflen ? 0 : -EIO; +} + +#define bytes_left_to_read_on_page(paddr,buflen) \ + ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ + ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) + +static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, + flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, + u32 addr, int extended, u8 *buf, u32 len) +{ + int i,ret = 0; + u16 wMax; + u32 pagechunk = 0; + + switch(req) { + case B2C2_USB_READ_V8_MEM: + wMax = USB_MEM_READ_MAX; + break; + case B2C2_USB_WRITE_V8_MEM: + wMax = USB_MEM_WRITE_MAX; + break; + case B2C2_USB_FLASH_BLOCK: + wMax = USB_FLASH_MAX; + break; + default: + return -EINVAL; + break; + } + for (i = 0; i < len;) { + pagechunk = + wMax < bytes_left_to_read_on_page(addr, len) ? + wMax : + bytes_left_to_read_on_page(addr, len); + deb_info("%x\n", + (addr & V8_MEMORY_PAGE_MASK) | + (V8_MEMORY_EXTENDED*extended)); + + ret = flexcop_usb_v8_memory_req(fc_usb, req, + page_start + (addr / V8_MEMORY_PAGE_SIZE), + (addr & V8_MEMORY_PAGE_MASK) | + (V8_MEMORY_EXTENDED*extended), + &buf[i], pagechunk); + + if (ret < 0) + return ret; + addr += pagechunk; + len -= pagechunk; + } + return 0; +} + +static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) +{ + return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM, + V8_MEMORY_PAGE_FLASH, 0x1f010, 1, + fc->dvb_adapter.proposed_mac, 6); +} + +#if 0 +static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, + flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, + u16 buflen, u8 *pvBuffer) +{ + u16 wValue; + u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR; + int nWaitTime = 2, + pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len; + wValue = (func << 8) | extra; + + len = usb_control_msg(fc_usb->udev,pipe, + B2C2_USB_UTILITY, + request_type, + wValue, + wIndex, + pvBuffer, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EIO; +} +#endif + +/* usb i2c stuff */ +static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, + flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, + u8 chipaddr, u8 addr, u8 *buf, u8 buflen) +{ + struct flexcop_usb *fc_usb = i2c->fc->bus_specific; + u16 wValue, wIndex; + int nWaitTime,pipe,len; + u8 request_type = USB_TYPE_VENDOR; + + switch (func) { + case USB_FUNC_I2C_WRITE: + case USB_FUNC_I2C_MULTIWRITE: + case USB_FUNC_I2C_REPEATWRITE: + /* DKT 020208 - add this to support special case of DiSEqC */ + case USB_FUNC_I2C_CHECKWRITE: + pipe = B2C2_USB_CTRL_PIPE_OUT; + nWaitTime = 2; + request_type |= USB_DIR_OUT; + break; + case USB_FUNC_I2C_READ: + case USB_FUNC_I2C_REPEATREAD: + pipe = B2C2_USB_CTRL_PIPE_IN; + nWaitTime = 2; + request_type |= USB_DIR_IN; + break; + default: + deb_info("unsupported function for i2c_req %x\n", func); + return -EINVAL; + } + wValue = (func << 8) | (i2c->port << 4); + wIndex = (chipaddr << 8 ) | addr; + + deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n", + func, request_type, req, + wValue & 0xff, wValue >> 8, + wIndex & 0xff, wIndex >> 8); + + len = usb_control_msg(fc_usb->udev,pipe, + req, + request_type, + wValue, + wIndex, + buf, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EREMOTEIO; +} + +/* actual bus specific access functions, + make sure prototype are/will be equal to pci */ +static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register reg) +{ + flexcop_ibi_value val; + val.raw = 0; + flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1); + return val; +} + +static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register reg, flexcop_ibi_value val) +{ + return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0); +} + +static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c, + flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + if (op == FC_READ) + return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, + USB_FUNC_I2C_READ, chipaddr, addr, buf, len); + else + return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, + USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len); +} + +static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, + u8 *buffer, int buffer_length) +{ + u8 *b; + int l; + + deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", + fc_usb->tmp_buffer_length, buffer_length); + + if (fc_usb->tmp_buffer_length > 0) { + memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, + buffer_length); + fc_usb->tmp_buffer_length += buffer_length; + b = fc_usb->tmp_buffer; + l = fc_usb->tmp_buffer_length; + } else { + b=buffer; + l=buffer_length; + } + + while (l >= 190) { + if (*b == 0xff) { + switch (*(b+1) & 0x03) { + case 0x01: /* media packet */ + if (*(b+2) == 0x47) + flexcop_pass_dmx_packets( + fc_usb->fc_dev, b+2, 1); + else + deb_ts("not ts packet %*ph\n", 4, b+2); + b += 190; + l -= 190; + break; + default: + deb_ts("wrong packet type\n"); + l = 0; + break; + } + } else { + deb_ts("wrong header\n"); + l = 0; + } + } + + if (l>0) + memcpy(fc_usb->tmp_buffer, b, l); + fc_usb->tmp_buffer_length = l; +} + +static void flexcop_usb_urb_complete(struct urb *urb) +{ + struct flexcop_usb *fc_usb = urb->context; + int i; + + if (urb->actual_length > 0) + deb_ts("urb completed, bufsize: %d actlen; %d\n", + urb->transfer_buffer_length, urb->actual_length); + + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status < 0) { + err("iso frame descriptor %d has an error: %d\n", i, + urb->iso_frame_desc[i].status); + } else + if (urb->iso_frame_desc[i].actual_length > 0) { + deb_ts("passed %d bytes to the demux\n", + urb->iso_frame_desc[i].actual_length); + + flexcop_usb_process_frame(fc_usb, + urb->transfer_buffer + + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + usb_submit_urb(urb,GFP_ATOMIC); +} + +static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) +{ + /* submit/kill iso packets */ + return 0; +} + +static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) +{ + int i; + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) + if (fc_usb->iso_urb[i] != NULL) { + deb_ts("unlinking/killing urb no. %d\n",i); + usb_kill_urb(fc_usb->iso_urb[i]); + usb_free_urb(fc_usb->iso_urb[i]); + } + + if (fc_usb->iso_buffer != NULL) + pci_free_consistent(NULL, + fc_usb->buffer_size, fc_usb->iso_buffer, + fc_usb->dma_addr); +} + +static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) +{ + u16 frame_size = le16_to_cpu( + fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); + int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * + frame_size, i, j, ret; + int buffer_offset = 0; + + deb_ts("creating %d iso-urbs with %d frames " + "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, + B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); + + fc_usb->iso_buffer = pci_alloc_consistent(NULL, + bufsize, &fc_usb->dma_addr); + if (fc_usb->iso_buffer == NULL) + return -ENOMEM; + + memset(fc_usb->iso_buffer, 0, bufsize); + fc_usb->buffer_size = bufsize; + + /* creating iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { + fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, + GFP_ATOMIC); + if (fc_usb->iso_urb[i] == NULL) { + ret = -ENOMEM; + goto urb_error; + } + } + + /* initialising and submitting iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { + int frame_offset = 0; + struct urb *urb = fc_usb->iso_urb[i]; + deb_ts("initializing and submitting urb no. %d " + "(buf_offset: %d).\n", i, buffer_offset); + + urb->dev = fc_usb->udev; + urb->context = fc_usb; + urb->complete = flexcop_usb_urb_complete; + urb->pipe = B2C2_USB_DATA_PIPE; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; + + buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; + for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { + deb_ts("urb no: %d, frame: %d, frame_offset: %d\n", + i, j, frame_offset); + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = frame_size; + frame_offset += frame_size; + } + + if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { + err("submitting urb %d failed with %d.", i, ret); + goto urb_error; + } + deb_ts("submitted urb no. %d.\n",i); + } + + /* SRAM */ + flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA | + FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, + FC_SRAM_DEST_TARGET_WAN_USB); + flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS); + flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1); + return 0; + +urb_error: + flexcop_usb_transfer_exit(fc_usb); + return ret; +} + +static int flexcop_usb_init(struct flexcop_usb *fc_usb) +{ + /* use the alternate setting with the larges buffer */ + usb_set_interface(fc_usb->udev,0,1); + switch (fc_usb->udev->speed) { + case USB_SPEED_LOW: + err("cannot handle USB speed because it is too slow."); + return -ENODEV; + break; + case USB_SPEED_FULL: + info("running at FULL speed."); + break; + case USB_SPEED_HIGH: + info("running at HIGH speed."); + break; + case USB_SPEED_UNKNOWN: /* fall through */ + default: + err("cannot handle USB speed because it is unknown."); + return -ENODEV; + } + usb_set_intfdata(fc_usb->uintf, fc_usb); + return 0; +} + +static void flexcop_usb_exit(struct flexcop_usb *fc_usb) +{ + usb_set_intfdata(fc_usb->uintf, NULL); +} + +static int flexcop_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct flexcop_usb *fc_usb = NULL; + struct flexcop_device *fc = NULL; + int ret; + + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { + err("out of memory\n"); + return -ENOMEM; + } + + /* general flexcop init */ + fc_usb = fc->bus_specific; + fc_usb->fc_dev = fc; + + fc->read_ibi_reg = flexcop_usb_read_ibi_reg; + fc->write_ibi_reg = flexcop_usb_write_ibi_reg; + fc->i2c_request = flexcop_usb_i2c_request; + fc->get_mac_addr = flexcop_usb_get_mac_addr; + + fc->stream_control = flexcop_usb_stream_control; + + fc->pid_filtering = 1; + fc->bus_type = FC_USB; + + fc->dev = &udev->dev; + fc->owner = THIS_MODULE; + + /* bus specific part */ + fc_usb->udev = udev; + fc_usb->uintf = intf; + if ((ret = flexcop_usb_init(fc_usb)) != 0) + goto err_kfree; + + /* init flexcop */ + if ((ret = flexcop_device_initialize(fc)) != 0) + goto err_usb_exit; + + /* xfer init */ + if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) + goto err_fc_exit; + + info("%s successfully initialized and connected.", DRIVER_NAME); + return 0; + +err_fc_exit: + flexcop_device_exit(fc); +err_usb_exit: + flexcop_usb_exit(fc_usb); +err_kfree: + flexcop_device_kfree(fc); + return ret; +} + +static void flexcop_usb_disconnect(struct usb_interface *intf) +{ + struct flexcop_usb *fc_usb = usb_get_intfdata(intf); + flexcop_usb_transfer_exit(fc_usb); + flexcop_device_exit(fc_usb->fc_dev); + flexcop_usb_exit(fc_usb); + flexcop_device_kfree(fc_usb->fc_dev); + info("%s successfully deinitialized and disconnected.", DRIVER_NAME); +} + +static struct usb_device_id flexcop_usb_table [] = { + { USB_DEVICE(0x0af7, 0x0101) }, + { } +}; +MODULE_DEVICE_TABLE (usb, flexcop_usb_table); + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver flexcop_usb_driver = { + .name = "b2c2_flexcop_usb", + .probe = flexcop_usb_probe, + .disconnect = flexcop_usb_disconnect, + .id_table = flexcop_usb_table, +}; + +module_usb_driver(flexcop_usb_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/b2c2/flexcop-usb.h b/drivers/media/pci/b2c2/flexcop-usb.h new file mode 100644 index 00000000000..92529a9c447 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop-usb.h @@ -0,0 +1,111 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-usb.h - header file for the USB part + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_USB_H_INCLUDED__ +#define __FLEXCOP_USB_H_INCLUDED__ + +#include + +/* transfer parameters */ +#define B2C2_USB_FRAMES_PER_ISO 4 +#define B2C2_USB_NUM_ISO_URB 4 + +#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0) +#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0) +#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81) + +struct flexcop_usb { + struct usb_device *udev; + struct usb_interface *uintf; + + u8 *iso_buffer; + int buffer_size; + dma_addr_t dma_addr; + + struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; + struct flexcop_device *fc_dev; + + u8 tmp_buffer[1023+190]; + int tmp_buffer_length; +}; + +#if 0 +/* request types TODO What is its use?*/ +typedef enum { + +} flexcop_usb_request_type_t; +#endif + +/* request */ +typedef enum { + B2C2_USB_WRITE_V8_MEM = 0x04, + B2C2_USB_READ_V8_MEM = 0x05, + B2C2_USB_READ_REG = 0x08, + B2C2_USB_WRITE_REG = 0x0A, + B2C2_USB_WRITEREGHI = 0x0B, + B2C2_USB_FLASH_BLOCK = 0x10, + B2C2_USB_I2C_REQUEST = 0x11, + B2C2_USB_UTILITY = 0x12, +} flexcop_usb_request_t; + +/* function definition for I2C_REQUEST */ +typedef enum { + USB_FUNC_I2C_WRITE = 0x01, + USB_FUNC_I2C_MULTIWRITE = 0x02, + USB_FUNC_I2C_READ = 0x03, + USB_FUNC_I2C_REPEATWRITE = 0x04, + USB_FUNC_GET_DESCRIPTOR = 0x05, + USB_FUNC_I2C_REPEATREAD = 0x06, + /* DKT 020208 - add this to support special case of DiSEqC */ + USB_FUNC_I2C_CHECKWRITE = 0x07, + USB_FUNC_I2C_CHECKRESULT = 0x08, +} flexcop_usb_i2c_function_t; + +/* function definition for UTILITY request 0x12 + * DKT 020304 - new utility function */ +typedef enum { + UTILITY_SET_FILTER = 0x01, + UTILITY_DATA_ENABLE = 0x02, + UTILITY_FLEX_MULTIWRITE = 0x03, + UTILITY_SET_BUFFER_SIZE = 0x04, + UTILITY_FLEX_OPERATOR = 0x05, + UTILITY_FLEX_RESET300_START = 0x06, + UTILITY_FLEX_RESET300_STOP = 0x07, + UTILITY_FLEX_RESET300 = 0x08, + UTILITY_SET_ISO_SIZE = 0x09, + UTILITY_DATA_RESET = 0x0A, + UTILITY_GET_DATA_STATUS = 0x10, + UTILITY_GET_V8_REG = 0x11, + /* DKT 020326 - add function for v1.14 */ + UTILITY_SRAM_WRITE = 0x12, + UTILITY_SRAM_READ = 0x13, + UTILITY_SRAM_TESTFILL = 0x14, + UTILITY_SRAM_TESTSET = 0x15, + UTILITY_SRAM_TESTVERIFY = 0x16, +} flexcop_usb_utility_function_t; + +#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ) +#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ) + +#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ) + +typedef enum { + V8_MEMORY_PAGE_DVB_CI = 0x20, + V8_MEMORY_PAGE_DVB_DS = 0x40, + V8_MEMORY_PAGE_MULTI2 = 0x60, + V8_MEMORY_PAGE_FLASH = 0x80 +} flexcop_usb_mem_page_t; + +#define V8_MEMORY_EXTENDED (1 << 15) +#define USB_MEM_READ_MAX 32 +#define USB_MEM_WRITE_MAX 1 +#define USB_FLASH_MAX 8 +#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */ +#define V8_MEMORY_PAGE_MASK 0x7FFF + +#endif diff --git a/drivers/media/pci/b2c2/flexcop.c b/drivers/media/pci/b2c2/flexcop.c new file mode 100644 index 00000000000..b1e8c99f469 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop.c @@ -0,0 +1,324 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop.c - main module part + * Copyright (C) 2004-9 Patrick Boettcher + * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc + * + * Acknowledgements: + * John Jurrius from BBTI, Inc. for extensive support + * with code examples and data books + * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) + * + * Contributions to the skystar2-driver have been done by + * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) + * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) + * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu) + * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac + * filtering) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "flexcop.h" + +#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" +#define DRIVER_AUTHOR "Patrick Boettcher demux->priv; + return flexcop_pid_feed_control(fc, dvbdmxfeed, 1); +} + +static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct flexcop_device *fc = dvbdmxfeed->demux->priv; + return flexcop_pid_feed_control(fc, dvbdmxfeed, 0); +} + +static int flexcop_dvb_init(struct flexcop_device *fc) +{ + int ret = dvb_register_adapter(&fc->dvb_adapter, + "FlexCop Digital TV device", fc->owner, + fc->dev, adapter_nr); + if (ret < 0) { + err("error registering DVB adapter"); + return ret; + } + fc->dvb_adapter.priv = fc; + + fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING + | DMX_MEMORY_BASED_FILTERING); + fc->demux.priv = fc; + fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; + fc->demux.start_feed = flexcop_dvb_start_feed; + fc->demux.stop_feed = flexcop_dvb_stop_feed; + fc->demux.write_to_decoder = NULL; + + ret = dvb_dmx_init(&fc->demux); + if (ret < 0) { + err("dvb_dmx failed: error %d", ret); + goto err_dmx; + } + + fc->hw_frontend.source = DMX_FRONTEND_0; + + fc->dmxdev.filternum = fc->demux.feednum; + fc->dmxdev.demux = &fc->demux.dmx; + fc->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter); + if (ret < 0) { + err("dvb_dmxdev_init failed: error %d", ret); + goto err_dmx_dev; + } + + ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend); + if (ret < 0) { + err("adding hw_frontend to dmx failed: error %d", ret); + goto err_dmx_add_hw_frontend; + } + + fc->mem_frontend.source = DMX_MEMORY_FE; + ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend); + if (ret < 0) { + err("adding mem_frontend to dmx failed: error %d", ret); + goto err_dmx_add_mem_frontend; + } + + ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend); + if (ret < 0) { + err("connect frontend failed: error %d", ret); + goto err_connect_frontend; + } + + ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + if (ret < 0) { + err("dvb_net_init failed: error %d", ret); + goto err_net; + } + + fc->init_state |= FC_STATE_DVB_INIT; + return 0; + +err_net: + fc->demux.dmx.disconnect_frontend(&fc->demux.dmx); +err_connect_frontend: + fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend); +err_dmx_add_mem_frontend: + fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend); +err_dmx_add_hw_frontend: + dvb_dmxdev_release(&fc->dmxdev); +err_dmx_dev: + dvb_dmx_release(&fc->demux); +err_dmx: + dvb_unregister_adapter(&fc->dvb_adapter); + return ret; +} + +static void flexcop_dvb_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_DVB_INIT) { + dvb_net_release(&fc->dvbnet); + + fc->demux.dmx.close(&fc->demux.dmx); + fc->demux.dmx.remove_frontend(&fc->demux.dmx, + &fc->mem_frontend); + fc->demux.dmx.remove_frontend(&fc->demux.dmx, + &fc->hw_frontend); + dvb_dmxdev_release(&fc->dmxdev); + dvb_dmx_release(&fc->demux); + dvb_unregister_adapter(&fc->dvb_adapter); + deb_info("deinitialized dvb stuff\n"); + } + fc->init_state &= ~FC_STATE_DVB_INIT; +} + +/* these methods are necessary to achieve the long-term-goal of hiding the + * struct flexcop_device from the bus-parts */ +void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) +{ + dvb_dmx_swfilter(&fc->demux, buf, len); +} +EXPORT_SYMBOL(flexcop_pass_dmx_data); + +void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) +{ + dvb_dmx_swfilter_packets(&fc->demux, buf, no); +} +EXPORT_SYMBOL(flexcop_pass_dmx_packets); + +static void flexcop_reset(struct flexcop_device *fc) +{ + flexcop_ibi_value v210, v204; + + /* reset the flexcop itself */ + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.raw = 0; + v210.sw_reset_210.reset_block_000 = 1; + v210.sw_reset_210.reset_block_100 = 1; + v210.sw_reset_210.reset_block_200 = 1; + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.reset_block_400 = 1; + v210.sw_reset_210.reset_block_500 = 1; + v210.sw_reset_210.reset_block_600 = 1; + v210.sw_reset_210.reset_block_700 = 1; + v210.sw_reset_210.Block_reset_enable = 0xb2; + v210.sw_reset_210.Special_controls = 0xc259; + fc->write_ibi_reg(fc,sw_reset_210,v210); + msleep(1); + + /* reset the periphical devices */ + + v204 = fc->read_ibi_reg(fc,misc_204); + v204.misc_204.Per_reset_sig = 0; + fc->write_ibi_reg(fc,misc_204,v204); + msleep(1); + v204.misc_204.Per_reset_sig = 1; + fc->write_ibi_reg(fc,misc_204,v204); +} + +void flexcop_reset_block_300(struct flexcop_device *fc) +{ + flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208), + v210 = fc->read_ibi_reg(fc, sw_reset_210); + + deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw); + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.Block_reset_enable = 0xb2; + + fc->write_ibi_reg(fc,sw_reset_210,v210); + fc->write_ibi_reg(fc,ctrl_208,v208_save); +} + +struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) +{ + void *bus; + struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), + GFP_KERNEL); + if (!fc) { + err("no memory"); + return NULL; + } + + bus = kzalloc(bus_specific_len, GFP_KERNEL); + if (!bus) { + err("no memory"); + kfree(fc); + return NULL; + } + + fc->bus_specific = bus; + + return fc; +} +EXPORT_SYMBOL(flexcop_device_kmalloc); + +void flexcop_device_kfree(struct flexcop_device *fc) +{ + kfree(fc->bus_specific); + kfree(fc); +} +EXPORT_SYMBOL(flexcop_device_kfree); + +int flexcop_device_initialize(struct flexcop_device *fc) +{ + int ret; + ibi_zero.raw = 0; + + flexcop_reset(fc); + flexcop_determine_revision(fc); + flexcop_sram_init(fc); + flexcop_hw_filter_init(fc); + flexcop_smc_ctrl(fc, 0); + + ret = flexcop_dvb_init(fc); + if (ret) + goto error; + + /* i2c has to be done before doing EEProm stuff - + * because the EEProm is accessed via i2c */ + ret = flexcop_i2c_init(fc); + if (ret) + goto error; + + /* do the MAC address reading after initializing the dvb_adapter */ + if (fc->get_mac_addr(fc, 0) == 0) { + u8 *b = fc->dvb_adapter.proposed_mac; + info("MAC address = %pM", b); + flexcop_set_mac_filter(fc,b); + flexcop_mac_filter_ctrl(fc,1); + } else + warn("reading of MAC address failed.\n"); + + ret = flexcop_frontend_init(fc); + if (ret) + goto error; + + flexcop_device_name(fc,"initialization of","complete"); + return 0; + +error: + flexcop_device_exit(fc); + return ret; +} +EXPORT_SYMBOL(flexcop_device_initialize); + +void flexcop_device_exit(struct flexcop_device *fc) +{ + flexcop_frontend_exit(fc); + flexcop_i2c_exit(fc); + flexcop_dvb_exit(fc); +} +EXPORT_SYMBOL(flexcop_device_exit); + +static int flexcop_module_init(void) +{ + info(DRIVER_NAME " loaded successfully"); + return 0; +} + +static void flexcop_module_cleanup(void) +{ + info(DRIVER_NAME " unloaded successfully"); +} + +module_init(flexcop_module_init); +module_exit(flexcop_module_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/b2c2/flexcop.h b/drivers/media/pci/b2c2/flexcop.h new file mode 100644 index 00000000000..897b10c85ad --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop.h @@ -0,0 +1,29 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop.h - private header file for all flexcop-chip-source files + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_H__ +#define __FLEXCOP_H___ + +#define FC_LOG_PREFIX "b2c2-flexcop" +#include "flexcop-common.h" + +extern int b2c2_flexcop_debug; + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) +#else +#define dprintk(level,args...) +#endif + +#define deb_info(args...) dprintk(0x01, args) +#define deb_tuner(args...) dprintk(0x02, args) +#define deb_i2c(args...) dprintk(0x04, args) +#define deb_ts(args...) dprintk(0x08, args) +#define deb_sram(args...) dprintk(0x10, args) +#define deb_rdump(args...) dprintk(0x20, args) + +#endif diff --git a/drivers/media/pci/b2c2/flexcop_ibi_value_be.h b/drivers/media/pci/b2c2/flexcop_ibi_value_be.h new file mode 100644 index 00000000000..8f64bdbd72b --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop_ibi_value_be.h @@ -0,0 +1,455 @@ +/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * register descriptions + * see flexcop.c for copyright information + */ +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_address0 :30; + u32 dma_0No_update : 1; + u32 dma_0start : 1; + } dma_0x0; + + struct { + u32 dma_addr_size :24; + u32 DMA_maxpackets : 8; + } dma_0x4_remap; + + struct { + u32 dma_addr_size :24; + u32 unused : 1; + u32 dma1timer : 7; + } dma_0x4_read; + + struct { + u32 dma_addr_size :24; + u32 dmatimer : 7; + u32 unused : 1; + } dma_0x4_write; + + struct { + u32 dma_cur_addr :30; + u32 unused : 2; + } dma_0x8; + + struct { + u32 dma_address1 :30; + u32 remap_enable : 1; + u32 dma_1start : 1; + } dma_0xc; + + struct { + u32 st_done : 1; + u32 no_base_addr_ack_error : 1; + u32 twoWS_port_reg : 2; + u32 total_bytes : 2; + u32 twoWS_rw : 1; + u32 working_start : 1; + u32 data1_reg : 8; + u32 baseaddr : 8; + u32 reserved1 : 1; + u32 chipaddr : 7; + } tw_sm_c_100; + + struct { + u32 unused : 6; + u32 force_stop : 1; + u32 exlicit_stops : 1; + u32 data4_reg : 8; + u32 data3_reg : 8; + u32 data2_reg : 8; + } tw_sm_c_104; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_108; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_10c; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_110; + + struct { + u32 LNB_CTLPrescaler_sig : 2; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLHighCount_sig :15; + } lnb_switch_freq_200; + + struct { + u32 Rev_N_sig_reserved2 : 1; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_revision_hi : 4; + u32 reserved :20; + u32 Per_reset_sig : 1; + u32 LNB_L_H_sig : 1; + u32 ACPI3_sig : 1; + u32 ACPI1_sig : 1; + } misc_204; + + struct { + u32 unused : 9; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 Rcv_Data_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 WAN_Enable_sig : 1; + u32 Mask_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 Stream1_filter_sig : 1; + } ctrl_208; + + struct { + u32 reserved :21; + u32 Transport_Error : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Continuity_error_flag : 1; + u32 Data_receiver_error : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA1_IRQ_Status : 1; + } irq_20c; + + struct { + u32 Special_controls :16; + u32 Block_reset_enable : 8; + u32 reset_block_700 : 1; + u32 reset_block_600 : 1; + u32 reset_block_500 : 1; + u32 reset_block_400 : 1; + u32 reset_block_300 : 1; + u32 reset_block_200 : 1; + u32 reset_block_100 : 1; + u32 reset_block_000 : 1; + } sw_reset_210; + + struct { + u32 unused2 :20; + u32 polarity_PS_ERR_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_CLK_sig : 1; + u32 unused1 : 3; + u32 s2p_sel_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 halt_V8_sig : 1; + u32 v2WS_oe_sig : 1; + u32 vuart_oe_sig : 1; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_busmuster : 1; + u32 sysramaccess_write : 1; + u32 unused : 7; + u32 sysramaccess_addr :15; + u32 sysramaccess_data : 8; + } mbox_host_to_v8_21c; + + struct { + u32 debug_fifo_problem : 1; + u32 debug_flag_write_status00 : 1; + u32 Stream2_trans : 1; + u32 Stream2_PID :13; + u32 debug_flag_pid_saved : 1; + u32 MAC_Multicast_filter : 1; + u32 Stream1_trans : 1; + u32 Stream1_PID :13; + } pid_filter_300; + + struct { + u32 reserved : 2; + u32 PMT_trans : 1; + u32 PMT_PID :13; + u32 debug_overrun2 : 1; + u32 debug_overrun3 : 1; + u32 PCR_trans : 1; + u32 PCR_PID :13; + } pid_filter_304; + + struct { + u32 reserved : 2; + u32 ECM_trans : 1; + u32 ECM_PID :13; + u32 EMM_filter_6 : 1; + u32 EMM_filter_4 : 1; + u32 EMM_trans : 1; + u32 EMM_PID :13; + } pid_filter_308; + + struct { + u32 unused2 : 3; + u32 Group_mask :13; + u32 unused1 : 2; + u32 Group_trans : 1; + u32 Group_PID :13; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 unused :15; + u32 net_master_read :17; + } pid_filter_30c_ext_ind_1; + + struct { + u32 unused :15; + u32 net_master_write :17; + } pid_filter_30c_ext_ind_2; + + struct { + u32 unused :15; + u32 next_net_master_write :17; + } pid_filter_30c_ext_ind_3; + + struct { + u32 reserved2 : 5; + u32 stack_read :10; + u32 reserved1 : 6; + u32 state_write :10; + u32 unused1 : 1; + } pid_filter_30c_ext_ind_4; + + struct { + u32 unused :22; + u32 stack_cnt :10; + } pid_filter_30c_ext_ind_5; + + struct { + u32 unused : 4; + u32 data_size_reg :12; + u32 write_status4 : 2; + u32 write_status1 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg0 : 2; + } pid_filter_30c_ext_ind_6; + + struct { + u32 unused :22; + u32 pass_alltables : 1; + u32 AB_select : 1; + u32 extra_index_reg : 3; + u32 index_reg : 5; + } index_reg_310; + + struct { + u32 reserved :17; + u32 PID_enable_bit : 1; + u32 PID_trans : 1; + u32 PID :13; + } pid_n_reg_314; + + struct { + u32 reserved : 6; + u32 HighAB_bit : 1; + u32 Enable_bit : 1; + u32 A6_byte : 8; + u32 A5_byte : 8; + u32 A4_byte : 8; + } mac_low_reg_318; + + struct { + u32 reserved : 8; + u32 A3_byte : 8; + u32 A2_byte : 8; + u32 A1_byte : 8; + } mac_high_reg_31c; + + struct { + u32 data_Tag_ID :16; + u32 reserved :16; + } data_tag_400; + + struct { + u32 Card_IDbyte3 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte6 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte1 : 8; + u32 Card_IDbyte2 : 8; + } card_id_40c; + + struct { + u32 MAC6 : 8; + u32 MAC3 : 8; + u32 MAC2 : 8; + u32 MAC1 : 8; + } mac_address_418; + + struct { + u32 reserved :16; + u32 MAC8 : 8; + u32 MAC7 : 8; + } mac_address_41c; + + struct { + u32 reserved :21; + u32 txbuffempty : 1; + u32 ReceiveByteFrameError : 1; + u32 ReceiveDataReady : 1; + u32 transmitter_data_byte : 8; + } ci_600; + + struct { + u32 pi_component_reg : 3; + u32 pi_rw : 1; + u32 pi_ha :20; + u32 pi_d : 8; + } pi_604; + + struct { + u32 pi_busy_n : 1; + u32 pi_wait_n : 1; + u32 pi_timeout_status : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 config_cclk : 1; + u32 config_cs_n : 1; + u32 config_wr_n : 1; + u32 config_Prog_n : 1; + u32 config_Init_stat : 1; + u32 config_Done_stat : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 pcmcia_a_mod_pwr_n : 1; + u32 reserved : 3; + u32 Timer_addr : 5; + u32 unused : 1; + u32 timer_data : 7; + u32 Timer_Load_req : 1; + u32 Timer_Read_req : 1; + u32 oncecycle_read : 1; + u32 serialReset : 1; + } pi_608; + + struct { + u32 reserved : 6; + u32 rw_flag : 1; + u32 dvb_en : 1; + u32 key_array_row : 5; + u32 key_array_col : 3; + u32 key_code : 2; + u32 key_enable : 1; + u32 PID :13; + } dvb_reg_60c; + + struct { + u32 start_sram_ibi : 1; + u32 reserved2 : 1; + u32 ce_pin_reg : 1; + u32 oe_pin_reg : 1; + u32 reserved1 : 3; + u32 sc_xfer_bit : 1; + u32 sram_data : 8; + u32 sram_rw : 1; + u32 sram_addr :15; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_write :16; + u32 net_addr_read :16; + } net_buf_reg_704; + + struct { + u32 cai_cnt : 4; + u32 reserved2 : 6; + u32 cai_write :11; + u32 reserved1 : 5; + u32 cai_read :11; + } cai_buf_reg_708; + + struct { + u32 cao_cnt : 4; + u32 reserved2 : 6; + u32 cap_write :11; + u32 reserved1 : 5; + u32 cao_read :11; + } cao_buf_reg_70c; + + struct { + u32 media_cnt : 4; + u32 reserved2 : 6; + u32 media_write :11; + u32 reserved1 : 5; + u32 media_read :11; + } media_buf_reg_710; + + struct { + u32 reserved :17; + u32 ctrl_maximumfill : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_usb_wan : 1; + u32 cao_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 net_ovflow_error : 1; + u32 MEDIA_Dest : 2; + u32 CAO_Dest : 2; + u32 CAI_Dest : 2; + u32 NET_Dest : 2; + } sram_dest_reg_714; + + struct { + u32 reserved3 :11; + u32 net_addr_write : 1; + u32 reserved2 : 3; + u32 net_addr_read : 1; + u32 reserved1 : 4; + u32 net_cnt :12; + } net_buf_reg_718; + + struct { + u32 reserved3 : 4; + u32 wan_pkt_frame : 4; + u32 reserved2 : 4; + u32 sram_memmap : 2; + u32 sram_chip : 2; + u32 wan_wait_state : 8; + u32 reserved1 : 6; + u32 wan_speed_sig : 2; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif diff --git a/drivers/media/pci/b2c2/flexcop_ibi_value_le.h b/drivers/media/pci/b2c2/flexcop_ibi_value_le.h new file mode 100644 index 00000000000..c75830d7d94 --- /dev/null +++ b/drivers/media/pci/b2c2/flexcop_ibi_value_le.h @@ -0,0 +1,455 @@ +/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * register descriptions + * see flexcop.c for copyright information + */ +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_0start : 1; + u32 dma_0No_update : 1; + u32 dma_address0 :30; + } dma_0x0; + + struct { + u32 DMA_maxpackets : 8; + u32 dma_addr_size :24; + } dma_0x4_remap; + + struct { + u32 dma1timer : 7; + u32 unused : 1; + u32 dma_addr_size :24; + } dma_0x4_read; + + struct { + u32 unused : 1; + u32 dmatimer : 7; + u32 dma_addr_size :24; + } dma_0x4_write; + + struct { + u32 unused : 2; + u32 dma_cur_addr :30; + } dma_0x8; + + struct { + u32 dma_1start : 1; + u32 remap_enable : 1; + u32 dma_address1 :30; + } dma_0xc; + + struct { + u32 chipaddr : 7; + u32 reserved1 : 1; + u32 baseaddr : 8; + u32 data1_reg : 8; + u32 working_start : 1; + u32 twoWS_rw : 1; + u32 total_bytes : 2; + u32 twoWS_port_reg : 2; + u32 no_base_addr_ack_error : 1; + u32 st_done : 1; + } tw_sm_c_100; + + struct { + u32 data2_reg : 8; + u32 data3_reg : 8; + u32 data4_reg : 8; + u32 exlicit_stops : 1; + u32 force_stop : 1; + u32 unused : 6; + } tw_sm_c_104; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_108; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_10c; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_110; + + struct { + u32 LNB_CTLHighCount_sig :15; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLPrescaler_sig : 2; + } lnb_switch_freq_200; + + struct { + u32 ACPI1_sig : 1; + u32 ACPI3_sig : 1; + u32 LNB_L_H_sig : 1; + u32 Per_reset_sig : 1; + u32 reserved :20; + u32 Rev_N_sig_revision_hi : 4; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved2 : 1; + } misc_204; + + struct { + u32 Stream1_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 Mask_filter_sig : 1; + u32 WAN_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Rcv_Data_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 unused : 9; + } ctrl_208; + + struct { + u32 DMA1_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 Data_receiver_error : 1; + u32 Continuity_error_flag : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Transport_Error : 1; + u32 reserved :21; + } irq_20c; + + struct { + u32 reset_block_000 : 1; + u32 reset_block_100 : 1; + u32 reset_block_200 : 1; + u32 reset_block_300 : 1; + u32 reset_block_400 : 1; + u32 reset_block_500 : 1; + u32 reset_block_600 : 1; + u32 reset_block_700 : 1; + u32 Block_reset_enable : 8; + u32 Special_controls :16; + } sw_reset_210; + + struct { + u32 vuart_oe_sig : 1; + u32 v2WS_oe_sig : 1; + u32 halt_V8_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 s2p_sel_sig : 1; + u32 unused1 : 3; + u32 polarity_PS_CLK_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_ERR_sig : 1; + u32 unused2 :20; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_data : 8; + u32 sysramaccess_addr :15; + u32 unused : 7; + u32 sysramaccess_write : 1; + u32 sysramaccess_busmuster : 1; + } mbox_host_to_v8_21c; + + struct { + u32 Stream1_PID :13; + u32 Stream1_trans : 1; + u32 MAC_Multicast_filter : 1; + u32 debug_flag_pid_saved : 1; + u32 Stream2_PID :13; + u32 Stream2_trans : 1; + u32 debug_flag_write_status00 : 1; + u32 debug_fifo_problem : 1; + } pid_filter_300; + + struct { + u32 PCR_PID :13; + u32 PCR_trans : 1; + u32 debug_overrun3 : 1; + u32 debug_overrun2 : 1; + u32 PMT_PID :13; + u32 PMT_trans : 1; + u32 reserved : 2; + } pid_filter_304; + + struct { + u32 EMM_PID :13; + u32 EMM_trans : 1; + u32 EMM_filter_4 : 1; + u32 EMM_filter_6 : 1; + u32 ECM_PID :13; + u32 ECM_trans : 1; + u32 reserved : 2; + } pid_filter_308; + + struct { + u32 Group_PID :13; + u32 Group_trans : 1; + u32 unused1 : 2; + u32 Group_mask :13; + u32 unused2 : 3; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 net_master_read :17; + u32 unused :15; + } pid_filter_30c_ext_ind_1; + + struct { + u32 net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_2; + + struct { + u32 next_net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_3; + + struct { + u32 unused1 : 1; + u32 state_write :10; + u32 reserved1 : 6; + u32 stack_read :10; + u32 reserved2 : 5; + } pid_filter_30c_ext_ind_4; + + struct { + u32 stack_cnt :10; + u32 unused :22; + } pid_filter_30c_ext_ind_5; + + struct { + u32 pid_fsm_save_reg0 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 write_status1 : 2; + u32 write_status4 : 2; + u32 data_size_reg :12; + u32 unused : 4; + } pid_filter_30c_ext_ind_6; + + struct { + u32 index_reg : 5; + u32 extra_index_reg : 3; + u32 AB_select : 1; + u32 pass_alltables : 1; + u32 unused :22; + } index_reg_310; + + struct { + u32 PID :13; + u32 PID_trans : 1; + u32 PID_enable_bit : 1; + u32 reserved :17; + } pid_n_reg_314; + + struct { + u32 A4_byte : 8; + u32 A5_byte : 8; + u32 A6_byte : 8; + u32 Enable_bit : 1; + u32 HighAB_bit : 1; + u32 reserved : 6; + } mac_low_reg_318; + + struct { + u32 A1_byte : 8; + u32 A2_byte : 8; + u32 A3_byte : 8; + u32 reserved : 8; + } mac_high_reg_31c; + + struct { + u32 reserved :16; + u32 data_Tag_ID :16; + } data_tag_400; + + struct { + u32 Card_IDbyte6 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte3 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte2 : 8; + u32 Card_IDbyte1 : 8; + } card_id_40c; + + struct { + u32 MAC1 : 8; + u32 MAC2 : 8; + u32 MAC3 : 8; + u32 MAC6 : 8; + } mac_address_418; + + struct { + u32 MAC7 : 8; + u32 MAC8 : 8; + u32 reserved :16; + } mac_address_41c; + + struct { + u32 transmitter_data_byte : 8; + u32 ReceiveDataReady : 1; + u32 ReceiveByteFrameError : 1; + u32 txbuffempty : 1; + u32 reserved :21; + } ci_600; + + struct { + u32 pi_d : 8; + u32 pi_ha :20; + u32 pi_rw : 1; + u32 pi_component_reg : 3; + } pi_604; + + struct { + u32 serialReset : 1; + u32 oncecycle_read : 1; + u32 Timer_Read_req : 1; + u32 Timer_Load_req : 1; + u32 timer_data : 7; + u32 unused : 1; + u32 Timer_addr : 5; + u32 reserved : 3; + u32 pcmcia_a_mod_pwr_n : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 config_Done_stat : 1; + u32 config_Init_stat : 1; + u32 config_Prog_n : 1; + u32 config_wr_n : 1; + u32 config_cs_n : 1; + u32 config_cclk : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 pi_timeout_status : 1; + u32 pi_wait_n : 1; + u32 pi_busy_n : 1; + } pi_608; + + struct { + u32 PID :13; + u32 key_enable : 1; + u32 key_code : 2; + u32 key_array_col : 3; + u32 key_array_row : 5; + u32 dvb_en : 1; + u32 rw_flag : 1; + u32 reserved : 6; + } dvb_reg_60c; + + struct { + u32 sram_addr :15; + u32 sram_rw : 1; + u32 sram_data : 8; + u32 sc_xfer_bit : 1; + u32 reserved1 : 3; + u32 oe_pin_reg : 1; + u32 ce_pin_reg : 1; + u32 reserved2 : 1; + u32 start_sram_ibi : 1; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_read :16; + u32 net_addr_write :16; + } net_buf_reg_704; + + struct { + u32 cai_read :11; + u32 reserved1 : 5; + u32 cai_write :11; + u32 reserved2 : 6; + u32 cai_cnt : 4; + } cai_buf_reg_708; + + struct { + u32 cao_read :11; + u32 reserved1 : 5; + u32 cap_write :11; + u32 reserved2 : 6; + u32 cao_cnt : 4; + } cao_buf_reg_70c; + + struct { + u32 media_read :11; + u32 reserved1 : 5; + u32 media_write :11; + u32 reserved2 : 6; + u32 media_cnt : 4; + } media_buf_reg_710; + + struct { + u32 NET_Dest : 2; + u32 CAI_Dest : 2; + u32 CAO_Dest : 2; + u32 MEDIA_Dest : 2; + u32 net_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 cao_ovflow_error : 1; + u32 ctrl_usb_wan : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_maximumfill : 1; + u32 reserved :17; + } sram_dest_reg_714; + + struct { + u32 net_cnt :12; + u32 reserved1 : 4; + u32 net_addr_read : 1; + u32 reserved2 : 3; + u32 net_addr_write : 1; + u32 reserved3 :11; + } net_buf_reg_718; + + struct { + u32 wan_speed_sig : 2; + u32 reserved1 : 6; + u32 wan_wait_state : 8; + u32 sram_chip : 2; + u32 sram_memmap : 2; + u32 reserved2 : 4; + u32 wan_pkt_frame : 4; + u32 reserved3 : 4; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig new file mode 100644 index 00000000000..8668e634c7e --- /dev/null +++ b/drivers/media/pci/bt8xx/Kconfig @@ -0,0 +1,22 @@ +config DVB_BT8XX + tristate "BT8xx based PCI cards" + depends on DVB_CORE && PCI && I2C && VIDEO_BT848 + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_SP887X if !DVB_FE_CUSTOMISE + select DVB_NXT6000 if !DVB_FE_CUSTOMISE + select DVB_CX24110 if !DVB_FE_CUSTOMISE + select DVB_OR51211 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + help + Support for PCI cards based on the Bt8xx PCI bridge. Examples are + the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, + the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and + some AVerMedia 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 if you own such a device and want to use it. diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile new file mode 100644 index 00000000000..36591ae505f --- /dev/null +++ b/drivers/media/pci/bt8xx/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends +ccflags-y += -Idrivers/media/video/bt8xx +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c new file mode 100644 index 00000000000..b34fa95185e --- /dev/null +++ b/drivers/media/pci/bt8xx/bt878.c @@ -0,0 +1,609 @@ +/* + * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card + * + * Copyright (C) 2002 Peter Hettkamp + * + * large parts based on the bttv driver + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) + * & Marcus Metzler (mocm@metzlerbros.de) + * (c) 1999,2000 Gerd Knorr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "bt878.h" +#include "dst_priv.h" + + +/**************************************/ +/* Miscellaneous utility definitions */ +/**************************************/ + +static unsigned int bt878_verbose = 1; +static unsigned int bt878_debug; + +module_param_named(verbose, bt878_verbose, int, 0444); +MODULE_PARM_DESC(verbose, + "verbose startup messages, default is 1 (yes)"); +module_param_named(debug, bt878_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); + +int bt878_num; +struct bt878 bt878[BT878_MAX]; + +EXPORT_SYMBOL(bt878_num); +EXPORT_SYMBOL(bt878); + +#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr))) +#define btread(adr) bmtread(bt->bt878_mem+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#if defined(dprintk) +#undef dprintk +#endif +#define dprintk(fmt, arg...) \ + do { \ + if (bt878_debug) \ + printk(KERN_DEBUG fmt, ##arg); \ + } while (0) + +static void bt878_mem_free(struct bt878 *bt) +{ + if (bt->buf_cpu) { + pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, + bt->buf_dma); + bt->buf_cpu = NULL; + } + + if (bt->risc_cpu) { + pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, + bt->risc_dma); + bt->risc_cpu = NULL; + } +} + +static int bt878_mem_alloc(struct bt878 *bt) +{ + if (!bt->buf_cpu) { + bt->buf_size = 128 * 1024; + + bt->buf_cpu = + pci_alloc_consistent(bt->dev, bt->buf_size, + &bt->buf_dma); + + if (!bt->buf_cpu) + return -ENOMEM; + + memset(bt->buf_cpu, 0, bt->buf_size); + } + + if (!bt->risc_cpu) { + bt->risc_size = PAGE_SIZE; + bt->risc_cpu = + pci_alloc_consistent(bt->dev, bt->risc_size, + &bt->risc_dma); + + if (!bt->risc_cpu) { + bt878_mem_free(bt); + return -ENOMEM; + } + + memset(bt->risc_cpu, 0, bt->risc_size); + } + + return 0; +} + +/* RISC instructions */ +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_SYNC (0x08 << 28) + +/* RISC bits */ +#define RISC_WR_SOL (1 << 27) +#define RISC_WR_EOL (1 << 26) +#define RISC_IRQ (1 << 24) +#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) +#define RISC_SYNC_RESYNC (1 << 15) +#define RISC_SYNC_FM1 0x06 +#define RISC_SYNC_VRO 0x0C + +#define RISC_FLUSH() bt->risc_pos = 0 +#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) + +static int bt878_make_risc(struct bt878 *bt) +{ + bt->block_bytes = bt->buf_size >> 4; + bt->block_count = 1 << 4; + bt->line_bytes = bt->block_bytes; + bt->line_count = bt->block_count; + + while (bt->line_bytes > 4095) { + bt->line_bytes >>= 1; + bt->line_count <<= 1; + } + + if (bt->line_count > 255) { + printk(KERN_ERR "bt878: buffer size error!\n"); + return -EINVAL; + } + return 0; +} + + +static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) +{ + u32 buf_pos = 0; + u32 line; + + RISC_FLUSH(); + RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); + RISC_INSTR(0); + + dprintk("bt878: risc len lines %u, bytes per line %u\n", + bt->line_count, bt->line_bytes); + for (line = 0; line < bt->line_count; line++) { + // At the beginning of every block we issue an IRQ with previous (finished) block number set + if (!(buf_pos % bt->block_bytes)) + RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | + RISC_IRQ | + RISC_STATUS(((buf_pos / + bt->block_bytes) + + (bt->block_count - + 1)) % + bt->block_count) | bt-> + line_bytes); + else + RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | + bt->line_bytes); + RISC_INSTR(bt->buf_dma + buf_pos); + buf_pos += bt->line_bytes; + } + + RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO); + RISC_INSTR(0); + + RISC_INSTR(RISC_JUMP); + RISC_INSTR(bt->risc_dma); + + btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); +} + +/*****************************/ +/* Start/Stop grabbing funcs */ +/*****************************/ + +void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, + u32 irq_err_ignore) +{ + u32 int_mask; + + dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg); + /* complete the writing of the risc dma program now we have + * the card specifics + */ + bt878_risc_program(bt, op_sync_orin); + controlreg &= ~0x1f; + controlreg |= 0x1b; + + btwrite(bt->risc_dma, BT878_ARISC_START); + + /* original int mask had : + * 6 2 8 4 0 + * 1111 1111 1000 0000 0000 + * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI + * Hacked for DST to: + * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI + */ + int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | + BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | + BT878_AFBUS | BT878_ARISCI; + + + /* ignore pesky bits */ + int_mask &= ~irq_err_ignore; + + btwrite(int_mask, BT878_AINT_MASK); + btwrite(controlreg, BT878_AGPIO_DMA_CTL); +} + +void bt878_stop(struct bt878 *bt) +{ + u32 stat; + int i = 0; + + dprintk("bt878 debug: bt878_stop\n"); + + btwrite(0, BT878_AINT_MASK); + btand(~0x13, BT878_AGPIO_DMA_CTL); + + do { + stat = btread(BT878_AINT_STAT); + if (!(stat & BT878_ARISC_EN)) + break; + i++; + } while (i < 500); + + dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n", + bt->nr, i, stat); +} + +EXPORT_SYMBOL(bt878_start); +EXPORT_SYMBOL(bt878_stop); + +/*****************************/ +/* Interrupt service routine */ +/*****************************/ + +static irqreturn_t bt878_irq(int irq, void *dev_id) +{ + u32 stat, astat, mask; + int count; + struct bt878 *bt; + + bt = (struct bt878 *) dev_id; + + count = 0; + while (1) { + stat = btread(BT878_AINT_STAT); + mask = btread(BT878_AINT_MASK); + if (!(astat = (stat & mask))) + return IRQ_NONE; /* this interrupt is not for me */ +/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ + btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */ + + + if (astat & (BT878_ASCERR | BT878_AOCERR)) { + if (bt878_verbose) { + printk(KERN_INFO + "bt878(%d): irq%s%s risc_pc=%08x\n", + bt->nr, + (astat & BT878_ASCERR) ? " SCERR" : + "", + (astat & BT878_AOCERR) ? " OCERR" : + "", btread(BT878_ARISC_PC)); + } + } + if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { + if (bt878_verbose) { + printk(KERN_INFO + "bt878(%d): irq%s%s%s risc_pc=%08x\n", + bt->nr, + (astat & BT878_APABORT) ? " PABORT" : + "", + (astat & BT878_ARIPERR) ? " RIPERR" : + "", + (astat & BT878_APPERR) ? " PPERR" : + "", btread(BT878_ARISC_PC)); + } + } + if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { + if (bt878_verbose) { + printk(KERN_INFO + "bt878(%d): irq%s%s%s risc_pc=%08x\n", + bt->nr, + (astat & BT878_AFDSR) ? " FDSR" : "", + (astat & BT878_AFTRGT) ? " FTRGT" : + "", + (astat & BT878_AFBUS) ? " FBUS" : "", + btread(BT878_ARISC_PC)); + } + } + if (astat & BT878_ARISCI) { + bt->finished_block = (stat & BT878_ARISCS) >> 28; + tasklet_schedule(&bt->tasklet); + break; + } + count++; + if (count > 20) { + btwrite(0, BT878_AINT_MASK); + printk(KERN_ERR + "bt878(%d): IRQ lockup, cleared int mask\n", + bt->nr); + break; + } + } + return IRQ_HANDLED; +} + +int +bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp) +{ + int retval; + + retval = 0; + if (mutex_lock_interruptible(&bt->gpio_lock)) + return -ERESTARTSYS; + /* special gpio signal */ + switch (cmd) { + case DST_IG_ENABLE: + // dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable); + retval = bttv_gpio_enable(bt->bttv_nr, + mp->enb.mask, + mp->enb.enable); + break; + case DST_IG_WRITE: + // dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals); + retval = bttv_write_gpio(bt->bttv_nr, + mp->outp.mask, + mp->outp.highvals); + + break; + case DST_IG_READ: + /* read */ + retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value); + // dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value); + break; + case DST_IG_TS: + /* Set packet size */ + bt->TS_Size = mp->psize; + break; + + default: + retval = -EINVAL; + break; + } + mutex_unlock(&bt->gpio_lock); + return retval; +} + +EXPORT_SYMBOL(bt878_device_control); + +#define BROOKTREE_878_DEVICE(vend, dev, name) \ + { \ + .vendor = PCI_VENDOR_ID_BROOKTREE, \ + .device = PCI_DEVICE_ID_BROOKTREE_878, \ + .subvendor = (vend), .subdevice = (dev), \ + .driver_data = (unsigned long) name \ + } + +static struct pci_device_id bt878_pci_tbl[] __devinitdata = { + BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), + BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), + BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), + BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), + BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), + BROOKTREE_878_DEVICE(0x270f, 0xfc00, + "ChainTech digitop DST-1000 DVB-S"), + BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), + BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), + BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), + { } +}; + +MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); + +static const char * __devinit card_name(const struct pci_device_id *id) +{ + return id->driver_data ? (const char *)id->driver_data : "Unknown"; +} + +/***********************/ +/* PCI device handling */ +/***********************/ + +static int __devinit bt878_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int result = 0; + unsigned char lat; + struct bt878 *bt; +#if defined(__powerpc__) + unsigned int cmd; +#endif + unsigned int cardid; + + printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", + bt878_num); + if (bt878_num >= BT878_MAX) { + printk(KERN_ERR "bt878: Too many devices inserted\n"); + result = -ENOMEM; + goto fail0; + } + if (pci_enable_device(dev)) + return -EIO; + + cardid = dev->subsystem_device << 16; + cardid |= dev->subsystem_vendor; + + printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", + __func__, cardid, card_name(pci_id)); + + bt = &bt878[bt878_num]; + bt->dev = dev; + bt->nr = bt878_num; + bt->shutdown = 0; + + bt->id = dev->device; + bt->irq = dev->irq; + bt->bt878_adr = pci_resource_start(dev, 0); + if (!request_mem_region(pci_resource_start(dev, 0), + pci_resource_len(dev, 0), "bt878")) { + result = -EBUSY; + goto fail0; + } + + bt->revision = dev->revision; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + + + printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", + bt878_num, bt->id, bt->revision, dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + printk("irq: %d, latency: %d, memory: 0x%lx\n", + bt->irq, lat, bt->bt878_adr); + + +#if defined(__powerpc__) + /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ + /* response on cards with no firmware is not enabled by OF */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif + +#ifdef __sparc__ + bt->bt878_mem = (unsigned char *) bt->bt878_adr; +#else + bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000); +#endif + + /* clear interrupt mask */ + btwrite(0, BT848_INT_MASK); + + result = request_irq(bt->irq, bt878_irq, + IRQF_SHARED | IRQF_DISABLED, "bt878", + (void *) bt); + if (result == -EINVAL) { + printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", + bt878_num); + goto fail1; + } + if (result == -EBUSY) { + printk(KERN_ERR + "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n", + bt878_num, bt->irq); + goto fail1; + } + if (result < 0) + goto fail1; + + pci_set_master(dev); + pci_set_drvdata(dev, bt); + + if ((result = bt878_mem_alloc(bt))) { + printk(KERN_ERR "bt878: failed to allocate memory!\n"); + goto fail2; + } + + bt878_make_risc(bt); + btwrite(0, BT878_AINT_MASK); + bt878_num++; + + return 0; + + fail2: + free_irq(bt->irq, bt); + fail1: + release_mem_region(pci_resource_start(bt->dev, 0), + pci_resource_len(bt->dev, 0)); + fail0: + pci_disable_device(dev); + return result; +} + +static void __devexit bt878_remove(struct pci_dev *pci_dev) +{ + u8 command; + struct bt878 *bt = pci_get_drvdata(pci_dev); + + if (bt878_verbose) + printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); + + /* turn off all capturing, DMA and IRQs */ + btand(~0x13, BT878_AGPIO_DMA_CTL); + + /* first disable interrupts before unmapping the memory! */ + btwrite(0, BT878_AINT_MASK); + btwrite(~0U, BT878_AINT_STAT); + + /* disable PCI bus-mastering */ + pci_read_config_byte(bt->dev, PCI_COMMAND, &command); + /* Should this be &=~ ?? */ + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(bt->dev, PCI_COMMAND, command); + + free_irq(bt->irq, bt); + printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); + if (bt->bt878_mem) + iounmap(bt->bt878_mem); + + release_mem_region(pci_resource_start(bt->dev, 0), + pci_resource_len(bt->dev, 0)); + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + bt->shutdown = 1; + bt878_mem_free(bt); + + pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); + return; +} + +static struct pci_driver bt878_pci_driver = { + .name = "bt878", + .id_table = bt878_pci_tbl, + .probe = bt878_probe, + .remove = __devexit_p(bt878_remove), +}; + +/*******************************/ +/* Module management functions */ +/*******************************/ + +static int __init bt878_init_module(void) +{ + bt878_num = 0; + + printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", + (BT878_VERSION_CODE >> 16) & 0xff, + (BT878_VERSION_CODE >> 8) & 0xff, + BT878_VERSION_CODE & 0xff); + + return pci_register_driver(&bt878_pci_driver); +} + +static void __exit bt878_cleanup_module(void) +{ + pci_unregister_driver(&bt878_pci_driver); +} + +module_init(bt878_init_module); +module_exit(bt878_cleanup_module); + +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bt878.h b/drivers/media/pci/bt8xx/bt878.h new file mode 100644 index 00000000000..d19b59299d7 --- /dev/null +++ b/drivers/media/pci/bt8xx/bt878.h @@ -0,0 +1,159 @@ +/* + bt878.h - Bt878 audio module (register offsets) + + Copyright (C) 2002 Peter Hettkamp + + 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 _BT878_H_ +#define _BT878_H_ + +#include +#include +#include +#include +#include + +#include "bt848.h" +#include "bttv.h" + +#define BT878_VERSION_CODE 0x000000 + +#define BT878_AINT_STAT 0x100 +#define BT878_ARISCS (0xf<<28) +#define BT878_ARISC_EN (1<<27) +#define BT878_ASCERR (1<<19) +#define BT878_AOCERR (1<<18) +#define BT878_APABORT (1<<17) +#define BT878_ARIPERR (1<<16) +#define BT878_APPERR (1<<15) +#define BT878_AFDSR (1<<14) +#define BT878_AFTRGT (1<<13) +#define BT878_AFBUS (1<<12) +#define BT878_ARISCI (1<<11) +#define BT878_AOFLOW (1<<3) + +#define BT878_AINT_MASK 0x104 + +#define BT878_AGPIO_DMA_CTL 0x10c +#define BT878_A_GAIN (0xf<<28) +#define BT878_A_G2X (1<<27) +#define BT878_A_PWRDN (1<<26) +#define BT878_A_SEL (3<<24) +#define BT878_DA_SCE (1<<23) +#define BT878_DA_LRI (1<<22) +#define BT878_DA_MLB (1<<21) +#define BT878_DA_LRD (0x1f<<16) +#define BT878_DA_DPM (1<<15) +#define BT878_DA_SBR (1<<14) +#define BT878_DA_ES2 (1<<13) +#define BT878_DA_LMT (1<<12) +#define BT878_DA_SDR (0xf<<8) +#define BT878_DA_IOM (3<<6) +#define BT878_DA_APP (1<<5) +#define BT878_ACAP_EN (1<<4) +#define BT878_PKTP (3<<2) +#define BT878_RISC_EN (1<<1) +#define BT878_FIFO_EN 1 + +#define BT878_APACK_LEN 0x110 +#define BT878_AFP_LEN (0xff<<16) +#define BT878_ALP_LEN 0xfff + +#define BT878_ARISC_START 0x114 + +#define BT878_ARISC_PC 0x120 + +/* BT878 FUNCTION 0 REGISTERS */ +#define BT878_GPIO_DMA_CTL 0x10c + +/* Interrupt register */ +#define BT878_INT_STAT 0x100 +#define BT878_INT_MASK 0x104 +#define BT878_I2CRACK (1<<25) +#define BT878_I2CDONE (1<<8) + +#define BT878_MAX 4 + +#define BT878_RISC_SYNC_MASK (1 << 15) + + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 + +extern int bt878_num; + +struct bt878 { + struct mutex gpio_lock; + unsigned int nr; + unsigned int bttv_nr; + struct i2c_adapter *adapter; + struct pci_dev *dev; + unsigned int id; + unsigned int TS_Size; + unsigned char revision; + unsigned int irq; + unsigned long bt878_adr; + volatile void __iomem *bt878_mem; /* function 1 */ + + volatile u32 finished_block; + volatile u32 last_block; + u32 block_count; + u32 block_bytes; + u32 line_bytes; + u32 line_count; + + u32 buf_size; + u8 *buf_cpu; + dma_addr_t buf_dma; + + u32 risc_size; + __le32 *risc_cpu; + dma_addr_t risc_dma; + u32 risc_pos; + + struct tasklet_struct tasklet; + int shutdown; +}; + +extern struct bt878 bt878[BT878_MAX]; + +void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, + u32 irq_err_ignore); +void bt878_stop(struct bt878 *bt); + +#if defined(__powerpc__) /* big-endian */ +static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) +{ + st_le32(addr, val); + eieio(); +} + +#define bmtwrite(dat,adr) io_st_le32((adr),(dat)) +#define bmtread(adr) ld_le32((adr)) +#else +#define bmtwrite(dat,adr) writel((dat), (adr)) +#define bmtread(adr) readl(adr) +#endif + +#endif diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c new file mode 100644 index 00000000000..430b3eb1181 --- /dev/null +++ b/drivers/media/pci/bt8xx/dst.c @@ -0,0 +1,1873 @@ +/* + Frontend/Card driver for TwinHan DST Frontend + Copyright (C) 2003 Jamie Honan + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dst_priv.h" +#include "dst_common.h" + +static unsigned int verbose = 1; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +static unsigned int dst_addons; +module_param(dst_addons, int, 0644); +MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); + +static unsigned int dst_algo; +module_param(dst_algo, int, 0644); +MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); + +#define HAS_LOCK 1 +#define ATTEMPT_TUNE 2 +#define HAS_POWER 4 + +#define DST_ERROR 0 +#define DST_NOTICE 1 +#define DST_INFO 2 +#define DST_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_ERROR) && (x > y)) \ + printk(KERN_ERR "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_INFO) && (x > y)) \ + printk(KERN_INFO "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +static int dst_command(struct dst_state *state, u8 *data, u8 len); + +static void dst_packsize(struct dst_state *state, int psize) +{ + union dst_gpio_packet bits; + + bits.psize = psize; + bt878_device_control(state->bt, DST_IG_TS, &bits); +} + +static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, + u32 outhigh, int delay) +{ + union dst_gpio_packet enb; + union dst_gpio_packet bits; + int err; + + enb.enb.mask = mask; + enb.enb.enable = enbb; + + dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); + if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { + dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); + return -EREMOTEIO; + } + udelay(1000); + /* because complete disabling means no output, no need to do output packet */ + if (enbb == 0) + return 0; + if (delay) + msleep(10); + bits.outp.mask = enbb; + bits.outp.highvals = outhigh; + if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { + dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); + return -EREMOTEIO; + } + + return 0; +} + +static int dst_gpio_inb(struct dst_state *state, u8 *result) +{ + union dst_gpio_packet rd_packet; + int err; + + *result = 0; + if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); + return -EREMOTEIO; + } + *result = (u8) rd_packet.rd.value; + + return 0; +} + +int rdc_reset_state(struct dst_state *state) +{ + dprintk(verbose, DST_INFO, 1, "Resetting state machine"); + if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + msleep(10); + if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + msleep(10); + return -1; + } + + return 0; +} +EXPORT_SYMBOL(rdc_reset_state); + +static int rdc_8820_reset(struct dst_state *state) +{ + dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); + if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + udelay(1000); + if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + + return 0; +} + +static int dst_pio_enable(struct dst_state *state) +{ + if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + udelay(1000); + + return 0; +} + +int dst_pio_disable(struct dst_state *state) +{ + if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + if (state->type_flags & DST_TYPE_HAS_FW_1) + udelay(1000); + + return 0; +} +EXPORT_SYMBOL(dst_pio_disable); + +int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) +{ + u8 reply; + int i; + + for (i = 0; i < 200; i++) { + if (dst_gpio_inb(state, &reply) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); + return -1; + } + if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { + dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); + return 1; + } + msleep(10); + } + dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); + + return 0; +} +EXPORT_SYMBOL(dst_wait_dst_ready); + +int dst_error_recovery(struct dst_state *state) +{ + dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); + dst_pio_disable(state); + msleep(10); + dst_pio_enable(state); + msleep(10); + + return 0; +} +EXPORT_SYMBOL(dst_error_recovery); + +int dst_error_bailout(struct dst_state *state) +{ + dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); + rdc_8820_reset(state); + dst_pio_disable(state); + msleep(10); + + return 0; +} +EXPORT_SYMBOL(dst_error_bailout); + +int dst_comm_init(struct dst_state *state) +{ + dprintk(verbose, DST_INFO, 1, "Initializing DST."); + if ((dst_pio_enable(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); + return -1; + } + if ((rdc_reset_state(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); + return -1; + } + if (state->type_flags & DST_TYPE_HAS_FW_1) + msleep(100); + else + msleep(5); + + return 0; +} +EXPORT_SYMBOL(dst_comm_init); + +int write_dst(struct dst_state *state, u8 *data, u8 len) +{ + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = data, + .len = len + }; + + int err; + u8 cnt, i; + + dprintk(verbose, DST_NOTICE, 0, "writing [ "); + for (i = 0; i < len; i++) + dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); + dprintk(verbose, DST_NOTICE, 0, "]\n"); + + for (cnt = 0; cnt < 2; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); + dst_error_recovery(state); + continue; + } else + break; + } + if (cnt >= 2) { + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); + dst_error_bailout(state); + + return -1; + } + + return 0; +} +EXPORT_SYMBOL(write_dst); + +int read_dst(struct dst_state *state, u8 *ret, u8 len) +{ + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = ret, + .len = len + }; + + int err; + int cnt; + + for (cnt = 0; cnt < 2; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); + dst_error_recovery(state); + continue; + } else + break; + } + if (cnt >= 2) { + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); + dst_error_bailout(state); + + return -1; + } + dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); + for (err = 1; err < len; err++) + dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); + if (err > 1) + dprintk(verbose, DST_DEBUG, 0, "\n"); + + return 0; +} +EXPORT_SYMBOL(read_dst); + +static int dst_set_polarization(struct dst_state *state) +{ + switch (state->voltage) { + case SEC_VOLTAGE_13: /* Vertical */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); + state->tx_tuna[8] &= ~0x40; + break; + case SEC_VOLTAGE_18: /* Horizontal */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); + state->tx_tuna[8] |= 0x40; + break; + case SEC_VOLTAGE_OFF: + break; + } + + return 0; +} + +static int dst_set_freq(struct dst_state *state, u32 freq) +{ + state->frequency = freq; + dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); + + if (state->dst_type == DST_TYPE_IS_SAT) { + freq = freq / 1000; + if (freq < 950 || freq > 2150) + return -EINVAL; + state->tx_tuna[2] = (freq >> 8); + state->tx_tuna[3] = (u8) freq; + state->tx_tuna[4] = 0x01; + state->tx_tuna[8] &= ~0x04; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (freq < 1531) + state->tx_tuna[8] |= 0x04; + } + } else if (state->dst_type == DST_TYPE_IS_TERR) { + freq = freq / 1000; + if (freq < 137000 || freq > 858000) + return -EINVAL; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + freq = freq / 1000; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + } else if (state->dst_type == DST_TYPE_IS_ATSC) { + freq = freq / 1000; + if (freq < 51000 || freq > 858000) + return -EINVAL; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + state->tx_tuna[5] = 0x00; /* ATSC */ + state->tx_tuna[6] = 0x00; + if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) + state->tx_tuna[7] = 0x00; /* Digital */ + } else + return -EINVAL; + + return 0; +} + +static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) +{ + state->bandwidth = bandwidth; + + if (state->dst_type != DST_TYPE_IS_TERR) + return -EOPNOTSUPP; + + switch (bandwidth) { + case 6000000: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x06; + else { + state->tx_tuna[6] = 0x06; + state->tx_tuna[7] = 0x00; + } + break; + case 7000000: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x07; + else { + state->tx_tuna[6] = 0x07; + state->tx_tuna[7] = 0x00; + } + break; + case 8000000: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x08; + else { + state->tx_tuna[6] = 0x08; + state->tx_tuna[7] = 0x00; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) +{ + state->inversion = inversion; + switch (inversion) { + case INVERSION_OFF: /* Inversion = Normal */ + state->tx_tuna[8] &= ~0x80; + break; + case INVERSION_ON: + state->tx_tuna[8] |= 0x80; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) +{ + state->fec = fec; + return 0; +} + +static fe_code_rate_t dst_get_fec(struct dst_state *state) +{ + return state->fec; +} + +static int dst_set_symbolrate(struct dst_state *state, u32 srate) +{ + u32 symcalc; + u64 sval; + + state->symbol_rate = srate; + if (state->dst_type == DST_TYPE_IS_TERR) { + return -EOPNOTSUPP; + } + dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); + srate /= 1000; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_SYMDIV) { + sval = srate; + sval <<= 20; + do_div(sval, 88000); + symcalc = (u32) sval; + dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); + state->tx_tuna[5] = (u8) (symcalc >> 12); + state->tx_tuna[6] = (u8) (symcalc >> 4); + state->tx_tuna[7] = (u8) (symcalc << 4); + } else { + state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + state->tx_tuna[8] &= ~0x20; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (srate > 8000) + state->tx_tuna[8] |= 0x20; + } + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); + if (!strncmp(state->fw_name, "DCTNEW", 6)) { + state->tx_tuna[5] = (u8) (srate >> 8); + state->tx_tuna[6] = (u8) srate; + state->tx_tuna[7] = 0x00; + } else if (!strncmp(state->fw_name, "DCT-CI", 6)) { + state->tx_tuna[5] = 0x00; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + } + return 0; +} + +static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) +{ + if (state->dst_type != DST_TYPE_IS_CABLE) + return -EOPNOTSUPP; + + state->modulation = modulation; + switch (modulation) { + case QAM_16: + state->tx_tuna[8] = 0x10; + break; + case QAM_32: + state->tx_tuna[8] = 0x20; + break; + case QAM_64: + state->tx_tuna[8] = 0x40; + break; + case QAM_128: + state->tx_tuna[8] = 0x80; + break; + case QAM_256: + if (!strncmp(state->fw_name, "DCTNEW", 6)) + state->tx_tuna[8] = 0xff; + else if (!strncmp(state->fw_name, "DCT-CI", 6)) + state->tx_tuna[8] = 0x00; + break; + case QPSK: + case QAM_AUTO: + case VSB_8: + case VSB_16: + default: + return -EINVAL; + + } + + return 0; +} + +static fe_modulation_t dst_get_modulation(struct dst_state *state) +{ + return state->modulation; +} + + +u8 dst_check_sum(u8 *buf, u32 len) +{ + u32 i; + u8 val = 0; + if (!len) + return 0; + for (i = 0; i < len; i++) { + val += buf[i]; + } + return ((~val) + 1); +} +EXPORT_SYMBOL(dst_check_sum); + +static void dst_type_flags_print(struct dst_state *state) +{ + u32 type_flags = state->type_flags; + + dprintk(verbose, DST_ERROR, 0, "DST type flags :"); + if (type_flags & DST_TYPE_HAS_TS188) + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); + if (type_flags & DST_TYPE_HAS_NEWTUNE_2) + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); + if (type_flags & DST_TYPE_HAS_TS204) + dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); + if (type_flags & DST_TYPE_HAS_VLF) + dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); + if (type_flags & DST_TYPE_HAS_SYMDIV) + dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + if (type_flags & DST_TYPE_HAS_FW_1) + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); + if (type_flags & DST_TYPE_HAS_FW_2) + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); + if (type_flags & DST_TYPE_HAS_FW_3) + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); + dprintk(verbose, DST_ERROR, 0, "\n"); +} + + +static int dst_type_print(struct dst_state *state, u8 type) +{ + char *otype; + switch (type) { + case DST_TYPE_IS_SAT: + otype = "satellite"; + break; + + case DST_TYPE_IS_TERR: + otype = "terrestrial"; + break; + + case DST_TYPE_IS_CABLE: + otype = "cable"; + break; + + case DST_TYPE_IS_ATSC: + otype = "atsc"; + break; + + default: + dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); + return -EINVAL; + } + dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); + + return 0; +} + +static struct tuner_types tuner_list[] = { + { + .tuner_type = TUNER_TYPE_L64724, + .tuner_name = "L 64724", + .board_name = "UNKNOWN", + .fw_name = "UNKNOWN" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1020", + .fw_name = "DST-MOT" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1020", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_MB86A15, + .tuner_name = "MB 86A15", + .board_name = "VP1022", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_MB86A15, + .tuner_name = "MB 86A15", + .board_name = "VP1025", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1030", + .fw_name = "DST-CI" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1030", + .fw_name = "DSTMCI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2021", + .fw_name = "DCTNEW" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2030", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2031", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2040", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3020", + .fw_name = "DTTFTA" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3021", + .fw_name = "DTTFTA" + }, + + { + .tuner_type = TUNER_TYPE_TDA10046, + .tuner_name = "TDA10046", + .board_name = "VP3040", + .fw_name = "DTT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3051", + .fw_name = "DTTNXT" + }, + + { + .tuner_type = TUNER_TYPE_NXT200x, + .tuner_name = "NXT200x", + .board_name = "VP3220", + .fw_name = "ATSCDI" + }, + + { + .tuner_type = TUNER_TYPE_NXT200x, + .tuner_name = "NXT200x", + .board_name = "VP3250", + .fw_name = "ATSCAD" + }, +}; + +/* + Known cards list + Satellite + ------------------- + 200103A + VP-1020 DST-MOT LG(old), TS=188 + + VP-1020 DST-03T LG(new), TS=204 + VP-1022 DST-03T LG(new), TS=204 + VP-1025 DST-03T LG(new), TS=204 + + VP-1030 DSTMCI, LG(new), TS=188 + VP-1032 DSTMCI, LG(new), TS=188 + + Cable + ------------------- + VP-2030 DCT-CI, Samsung, TS=204 + VP-2021 DCT-CI, Unknown, TS=204 + VP-2031 DCT-CI, Philips, TS=188 + VP-2040 DCT-CI, Philips, TS=188, with CA daughter board + VP-2040 DCT-CI, Philips, TS=204, without CA daughter board + + Terrestrial + ------------------- + VP-3050 DTTNXT TS=188 + VP-3040 DTT-CI, Philips, TS=188 + VP-3040 DTT-CI, Philips, TS=204 + + ATSC + ------------------- + VP-3220 ATSCDI, TS=188 + VP-3250 ATSCAD, TS=188 + +*/ + +static struct dst_types dst_tlist[] = { + { + .device_id = "200103A", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-020", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-030", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-03T", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 + | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, + .tuner_type = TUNER_TYPE_MULTI + }, + + { + .device_id = "DST-MOT", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 + }, /* An OEM board */ + + { + .device_id = "DSTMCI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 + | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, + .tuner_type = TUNER_TYPE_MULTI + }, + + { + .device_id = "DSTFCI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* unknown to vendor */ + + { + .device_id = "DCT-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_CABLE, + .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 + }, + + { + .device_id = "DCTNEW", + .offset = 1, + .dst_type = DST_TYPE_IS_CABLE, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, + .dst_feature = 0, + .tuner_type = 0 + }, + + { + .device_id = "DTT-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 + }, + + { + .device_id = "DTTDIG", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0, + .tuner_type = 0 + }, + + { + .device_id = "DTTNXT", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_ANALOG, + .tuner_type = 0 + }, + + { + .device_id = "ATSCDI", + .offset = 1, + .dst_type = DST_TYPE_IS_ATSC, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0, + .tuner_type = 0 + }, + + { + .device_id = "ATSCAD", + .offset = 1, + .dst_type = DST_TYPE_IS_ATSC, + .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, + .tuner_type = 0 + }, + + { } + +}; + +static int dst_get_mac(struct dst_state *state) +{ + u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_mac[7] = dst_check_sum(get_mac, 7); + if (dst_command(state, get_mac, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->mac_address, '\0', 8); + memcpy(&state->mac_address, &state->rxbuffer, 6); + dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); + + return 0; +} + +static int dst_fw_ver(struct dst_state *state) +{ + u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_ver[7] = dst_check_sum(get_ver, 7); + if (dst_command(state, get_ver, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memcpy(&state->fw_version, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", + state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, + state->fw_version[1], + state->fw_version[5], state->fw_version[6], + state->fw_version[4], state->fw_version[3], state->fw_version[2]); + + return 0; +} + +static int dst_card_type(struct dst_state *state) +{ + int j; + struct tuner_types *p_tuner_list = NULL; + + u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_type[7] = dst_check_sum(get_type, 7); + if (dst_command(state, get_type, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->card_info, '\0', 8); + memcpy(&state->card_info, &state->rxbuffer, 7); + dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); + + for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { + if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { + state->tuner_type = p_tuner_list->tuner_type; + dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", + p_tuner_list->tuner_name, p_tuner_list->tuner_type); + } + } + + return 0; +} + +static int dst_get_vendor(struct dst_state *state) +{ + u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_vendor[7] = dst_check_sum(get_vendor, 7); + if (dst_command(state, get_vendor, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->vendor, '\0', 8); + memcpy(&state->vendor, &state->rxbuffer, 7); + dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); + + return 0; +} + +static void debug_dst_buffer(struct dst_state *state) +{ + int i; + + if (verbose > 2) { + printk("%s: [", __func__); + for (i = 0; i < 8; i++) + printk(" %02x", state->rxbuffer[i]); + printk("]\n"); + } +} + +static int dst_check_stv0299(struct dst_state *state) +{ + u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_stv0299[7] = dst_check_sum(check_stv0299, 7); + if (dst_command(state, check_stv0299, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); + return -1; + } + debug_dst_buffer(state); + + if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { + dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); + state->tuner_type = TUNER_TYPE_STV0299; + return 0; + } + + return -1; +} + +static int dst_check_mb86a15(struct dst_state *state) +{ + u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); + if (dst_command(state, check_mb86a15, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); + return -1; + } + debug_dst_buffer(state); + + if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); + state->tuner_type = TUNER_TYPE_MB86A15; + return 0; + } + + return -1; +} + +static int dst_get_tuner_info(struct dst_state *state) +{ + u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); + get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); + dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); + if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { + if (dst_command(state, get_tuner_1, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); + goto force; + } + } else { + if (dst_command(state, get_tuner_2, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); + goto force; + } + } + memcpy(&state->board_info, &state->rxbuffer, 8); + if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { + dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); + } + if (state->board_info[0] == 0xbc) { + if (state->dst_type != DST_TYPE_IS_ATSC) + state->type_flags |= DST_TYPE_HAS_TS188; + else + state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; + + if (state->board_info[1] == 0x01) { + state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; + dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); + } + } + + return 0; +force: + if (!strncmp(state->fw_name, "DCT-CI", 6)) { + state->type_flags |= DST_TYPE_HAS_TS204; + dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); + } + + return -1; +} + +static int dst_get_device_id(struct dst_state *state) +{ + u8 reply; + + int i, j; + struct dst_types *p_dst_type = NULL; + struct tuner_types *p_tuner_list = NULL; + + u8 use_dst_type = 0; + u32 use_type_flags = 0; + + static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + state->tuner_type = 0; + device_type[7] = dst_check_sum(device_type, 7); + + if (write_dst(state, device_type, FIXED_COMM)) + return -1; /* Write failed */ + if ((dst_pio_disable(state)) < 0) + return -1; + if (read_dst(state, &reply, GET_ACK)) + return -1; /* Read failure */ + if (reply != ACK) { + dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); + return -1; /* Unack'd write */ + } + if (!dst_wait_dst_ready(state, DEVICE_INIT)) + return -1; /* DST not ready yet */ + if (read_dst(state, state->rxbuffer, FIXED_COMM)) + return -1; + + dst_pio_disable(state); + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk(verbose, DST_INFO, 1, "Checksum failure!"); + return -1; /* Checksum failure */ + } + state->rxbuffer[7] = '\0'; + + for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { + if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { + use_type_flags = p_dst_type->type_flags; + use_dst_type = p_dst_type->dst_type; + + /* Card capabilities */ + state->dst_hw_cap = p_dst_type->dst_feature; + dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); + strncpy(&state->fw_name[0], p_dst_type->device_id, 6); + /* Multiple tuners */ + if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { + switch (use_dst_type) { + case DST_TYPE_IS_SAT: + /* STV0299 check */ + if (dst_check_stv0299(state) < 0) { + dprintk(verbose, DST_ERROR, 1, "Unsupported"); + state->tuner_type = TUNER_TYPE_MB86A15; + } + break; + default: + break; + } + if (dst_check_mb86a15(state) < 0) + dprintk(verbose, DST_ERROR, 1, "Unsupported"); + /* Single tuner */ + } else { + state->tuner_type = p_dst_type->tuner_type; + } + for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { + if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && + p_tuner_list->tuner_type == state->tuner_type) { + dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", + p_dst_type->device_id, p_tuner_list->tuner_name); + } + } + break; + } + } + + if (i >= ARRAY_SIZE(dst_tlist)) { + dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); + dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); + use_dst_type = DST_TYPE_IS_SAT; + use_type_flags = DST_TYPE_HAS_SYMDIV; + } + dst_type_print(state, use_dst_type); + state->type_flags = use_type_flags; + state->dst_type = use_dst_type; + dst_type_flags_print(state); + + return 0; +} + +static int dst_probe(struct dst_state *state) +{ + mutex_init(&state->dst_mutex); + if (dst_addons & DST_TYPE_HAS_CA) { + if ((rdc_8820_reset(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); + return -1; + } + msleep(4000); + } else { + msleep(100); + } + if ((dst_comm_init(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); + return -1; + } + msleep(100); + if (dst_get_device_id(state) < 0) { + dprintk(verbose, DST_ERROR, 1, "unknown device."); + return -1; + } + if (dst_get_mac(state) < 0) { + dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); + } + if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { + if (dst_get_tuner_info(state) < 0) + dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); + } + if (state->type_flags & DST_TYPE_HAS_TS204) { + dst_packsize(state, 204); + } + if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { + if (dst_fw_ver(state) < 0) { + dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); + return 0; + } + if (dst_card_type(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); + return 0; + } + if (dst_get_vendor(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); + return 0; + } + } + + return 0; +} + +static int dst_command(struct dst_state *state, u8 *data, u8 len) +{ + u8 reply; + + mutex_lock(&state->dst_mutex); + if ((dst_comm_init(state)) < 0) { + dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); + goto error; + } + if (write_dst(state, data, len)) { + dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); + if ((dst_error_recovery(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); + goto error; + } + goto error; + } + if ((dst_pio_disable(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); + goto error; + } + if (state->type_flags & DST_TYPE_HAS_FW_1) + mdelay(3); + if (read_dst(state, &reply, GET_ACK)) { + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); + if ((dst_error_recovery(state)) < 0) { + dprintk(verbose, DST_INFO, 1, "Recovery Failed."); + goto error; + } + goto error; + } + if (reply != ACK) { + dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); + goto error; + } + if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) + goto error; + if (state->type_flags & DST_TYPE_HAS_FW_1) + mdelay(3); + else + udelay(2000); + if (!dst_wait_dst_ready(state, NO_DELAY)) + goto error; + if (read_dst(state, state->rxbuffer, FIXED_COMM)) { + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); + if ((dst_error_recovery(state)) < 0) { + dprintk(verbose, DST_INFO, 1, "Recovery failed."); + goto error; + } + goto error; + } + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk(verbose, DST_INFO, 1, "checksum failure"); + goto error; + } + mutex_unlock(&state->dst_mutex); + return 0; + +error: + mutex_unlock(&state->dst_mutex); + return -EIO; + +} + +static int dst_get_signal(struct dst_state *state) +{ + int retval; + u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; + //dprintk("%s: Getting Signal strength and other parameters\n", __func__); + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (0 == (state->diseq_flags & HAS_LOCK)) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { + retval = dst_command(state, get_signal, 8); + if (retval < 0) + return retval; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; + state->decode_strength = state->rxbuffer[5] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; + } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { + state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[3] << 8; + } else if (state->dst_type == DST_TYPE_IS_ATSC) { + state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; + } + state->cur_jiff = jiffies; + } + return 0; +} + +static int dst_tone_power_cmd(struct dst_state *state) +{ + u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; + + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + paket[4] = state->tx_tuna[4]; + paket[2] = state->tx_tuna[2]; + paket[3] = state->tx_tuna[3]; + paket[7] = dst_check_sum (paket, 7); + return dst_command(state, paket, 8); +} + +static int dst_get_tuna(struct dst_state *state) +{ + int retval; + + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) + return 0; + state->diseq_flags &= ~(HAS_LOCK); + if (!dst_wait_dst_ready(state, NO_DELAY)) + return -EIO; + if ((state->type_flags & DST_TYPE_HAS_VLF) && + !(state->dst_type == DST_TYPE_IS_ATSC)) + + retval = read_dst(state, state->rx_tuna, 10); + else + retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); + if (retval < 0) { + dprintk(verbose, DST_DEBUG, 1, "read not successful"); + return retval; + } + if ((state->type_flags & DST_TYPE_HAS_VLF) && + !(state->dst_type == DST_TYPE_IS_ATSC)) { + + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { + dprintk(verbose, DST_INFO, 1, "checksum failure ? "); + return -EIO; + } + } else { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { + dprintk(verbose, DST_INFO, 1, "checksum failure? "); + return -EIO; + } + } + if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) + return 0; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; + } else { + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; + } + state->decode_freq = state->decode_freq * 1000; + state->decode_lock = 1; + state->diseq_flags |= HAS_LOCK; + + return 1; +} + +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + +static int dst_write_tuna(struct dvb_frontend *fe) +{ + struct dst_state *state = fe->demodulator_priv; + int retval; + u8 reply; + + dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); + state->decode_freq = 0; + state->decode_lock = state->decode_strength = state->decode_snr = 0; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (!(state->diseq_flags & HAS_POWER)) + dst_set_voltage(fe, SEC_VOLTAGE_13); + } + state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); + mutex_lock(&state->dst_mutex); + if ((dst_comm_init(state)) < 0) { + dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); + goto error; + } +// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if ((state->type_flags & DST_TYPE_HAS_VLF) && + (!(state->dst_type == DST_TYPE_IS_ATSC))) { + + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); + retval = write_dst(state, &state->tx_tuna[0], 10); + } else { + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); + retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); + } + if (retval < 0) { + dst_pio_disable(state); + dprintk(verbose, DST_DEBUG, 1, "write not successful"); + goto werr; + } + if ((dst_pio_disable(state)) < 0) { + dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); + goto error; + } + if ((read_dst(state, &reply, GET_ACK) < 0)) { + dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); + goto error; + } + if (reply != ACK) { + dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); + goto error; + } + state->diseq_flags |= ATTEMPT_TUNE; + retval = dst_get_tuna(state); +werr: + mutex_unlock(&state->dst_mutex); + return retval; + +error: + mutex_unlock(&state->dst_mutex); + return -EIO; +} + +/* + * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 + * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 + * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 + * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 + * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec + * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 + * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 + * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 + */ + +static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct dst_state *state = fe->demodulator_priv; + u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; + + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + if (cmd->msg_len > 0 && cmd->msg_len < 5) + memcpy(&paket[3], cmd->msg, cmd->msg_len); + else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) + memcpy(&paket[2], cmd->msg, cmd->msg_len); + else + return -EINVAL; + paket[7] = dst_check_sum(&paket[0], 7); + return dst_command(state, paket, 8); +} + +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + int need_cmd, retval = 0; + struct dst_state *state = fe->demodulator_priv; + + state->voltage = voltage; + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + + need_cmd = 0; + + switch (voltage) { + case SEC_VOLTAGE_13: + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + state->tx_tuna[4] = 0x01; + break; + case SEC_VOLTAGE_OFF: + need_cmd = 1; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + state->tx_tuna[4] = 0x00; + break; + default: + return -EINVAL; + } + + if (need_cmd) + retval = dst_tone_power_cmd(state); + + return retval; +} + +static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct dst_state *state = fe->demodulator_priv; + + state->tone = tone; + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + + switch (tone) { + case SEC_TONE_OFF: + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + state->tx_tuna[2] = 0x00; + else + state->tx_tuna[2] = 0xff; + break; + + case SEC_TONE_ON: + state->tx_tuna[2] = 0x02; + break; + default: + return -EINVAL; + } + return dst_tone_power_cmd(state); +} + +static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) +{ + struct dst_state *state = fe->demodulator_priv; + + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + state->minicmd = minicmd; + switch (minicmd) { + case SEC_MINI_A: + state->tx_tuna[3] = 0x02; + break; + case SEC_MINI_B: + state->tx_tuna[3] = 0xff; + break; + } + return dst_tone_power_cmd(state); +} + + +static int dst_init(struct dvb_frontend *fe) +{ + struct dst_state *state = fe->demodulator_priv; + + static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; + static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; + static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + + state->inversion = INVERSION_OFF; + state->voltage = SEC_VOLTAGE_13; + state->tone = SEC_TONE_OFF; + state->diseq_flags = 0; + state->k22 = 0x02; + state->bandwidth = 7000000; + state->cur_jiff = jiffies; + if (state->dst_type == DST_TYPE_IS_SAT) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_TERR) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_CABLE) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_ATSC) + memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); + + return 0; +} + +static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct dst_state *state = fe->demodulator_priv; + + *status = 0; + if (state->diseq_flags & HAS_LOCK) { +// dst_get_signal(state); // don't require(?) to ask MCU + if (state->decode_lock) + *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; + } + + return 0; +} + +static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dst_state *state = fe->demodulator_priv; + + int retval = dst_get_signal(state); + *strength = state->decode_strength; + + return retval; +} + +static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct dst_state *state = fe->demodulator_priv; + + int retval = dst_get_signal(state); + *snr = state->decode_snr; + + return retval; +} + +static int dst_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int retval = -EINVAL; + struct dst_state *state = fe->demodulator_priv; + + if (p != NULL) { + retval = dst_set_freq(state, p->frequency); + if(retval != 0) + return retval; + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_polarization(state); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); + + } else if (state->dst_type == DST_TYPE_IS_TERR) + dst_set_bandwidth(state, p->bandwidth_hz); + else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_modulation(state, p->modulation); + } + retval = dst_write_tuna(fe); + } + + return retval; +} + +static int dst_tune_frontend(struct dvb_frontend* fe, + bool re_tune, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) +{ + struct dst_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + if (re_tune) { + dst_set_freq(state, p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_polarization(state); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); + + } else if (state->dst_type == DST_TYPE_IS_TERR) + dst_set_bandwidth(state, p->bandwidth_hz); + else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_modulation(state, p->modulation); + } + dst_write_tuna(fe); + } + + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + dst_read_status(fe, status); + + *delay = HZ/10; + return 0; +} + +static int dst_get_tuning_algo(struct dvb_frontend *fe) +{ + return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; +} + +static int dst_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dst_state *state = fe->demodulator_priv; + + p->frequency = state->decode_freq; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + p->inversion = state->inversion; + p->symbol_rate = state->symbol_rate; + p->fec_inner = dst_get_fec(state); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + p->bandwidth_hz = state->bandwidth; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + p->symbol_rate = state->symbol_rate; + p->fec_inner = dst_get_fec(state); + p->modulation = dst_get_modulation(state); + } + + return 0; +} + +static void dst_release(struct dvb_frontend *fe) +{ + struct dst_state *state = fe->demodulator_priv; + if (state->dst_ca) { + dvb_unregister_device(state->dst_ca); +#ifdef CONFIG_MEDIA_ATTACH + symbol_put(dst_ca_attach); +#endif + } + kfree(state); +} + +static struct dvb_frontend_ops dst_dvbt_ops; +static struct dvb_frontend_ops dst_dvbs_ops; +static struct dvb_frontend_ops dst_dvbc_ops; +static struct dvb_frontend_ops dst_atsc_ops; + +struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) +{ + /* check if the ASIC is there */ + if (dst_probe(state) < 0) { + kfree(state); + return NULL; + } + /* determine settings based on type */ + /* create dvb_frontend */ + switch (state->dst_type) { + case DST_TYPE_IS_TERR: + memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_CABLE: + memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_SAT: + memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_ATSC: + memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); + kfree(state); + return NULL; + } + state->frontend.demodulator_priv = state; + + return state; /* Manu (DST is a card not a frontend) */ +} + +EXPORT_SYMBOL(dst_attach); + +static struct dvb_frontend_ops dst_dvbt_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "DST DVB-T", + .frequency_min = 137000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_dvbs_ops = { + .delsys = { SYS_DVBS }, + .info = { + .name = "DST DVB-S", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* . symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, + .diseqc_send_burst = dst_send_burst, + .diseqc_send_master_cmd = dst_set_diseqc, + .set_voltage = dst_set_voltage, + .set_tone = dst_set_tone, +}; + +static struct dvb_frontend_ops dst_dvbc_ops = { + .delsys = { SYS_DVBC_ANNEX_A }, + .info = { + .name = "DST DVB-C", + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_atsc_ops = { + .delsys = { SYS_ATSC }, + .info = { + .name = "DST ATSC", + .frequency_stepsize = 62500, + .frequency_min = 510000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); +MODULE_AUTHOR("Jamie Honan, Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c new file mode 100644 index 00000000000..ee3884fbc9c --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -0,0 +1,726 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "dvbdev.h" +#include "dvb_frontend.h" +#include "dst_ca.h" +#include "dst_common.h" + +#define DST_CA_ERROR 0 +#define DST_CA_NOTICE 1 +#define DST_CA_INFO 2 +#define DST_CA_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_CA_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((x > DST_CA_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((x > DST_CA_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((x > DST_CA_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ## arg); \ + } \ +} while(0) + + +static DEFINE_MUTEX(dst_ca_mutex); +static unsigned int verbose = 5; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +/* Need some more work */ +static int ca_set_slot_descr(void) +{ + /* We could make this more graceful ? */ + return -EOPNOTSUPP; +} + +/* Need some more work */ +static int ca_set_pid(void) +{ + /* We could make this more graceful ? */ + return -EOPNOTSUPP; +} + +static void put_command_and_length(u8 *data, int command, int length) +{ + data[0] = (command >> 16) & 0xff; + data[1] = (command >> 8) & 0xff; + data[2] = command & 0xff; + data[3] = length; +} + +static void put_checksum(u8 *check_string, int length) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum."); + dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length); + check_string[length] = dst_check_sum (check_string, length); + dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]); +} + +static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) +{ + u8 reply; + + mutex_lock(&state->dst_mutex); + dst_comm_init(state); + msleep(65); + + if (write_dst(state, data, len)) { + dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); + dst_error_recovery(state); + goto error; + } + if ((dst_pio_disable(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); + goto error; + } + if (read_dst(state, &reply, GET_ACK) < 0) { + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); + dst_error_recovery(state); + goto error; + } + if (read) { + if (! dst_wait_dst_ready(state, LONG_DELAY)) { + dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); + goto error; + } + if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); + dst_error_recovery(state); + goto error; + } + } + mutex_unlock(&state->dst_mutex); + return 0; + +error: + mutex_unlock(&state->dst_mutex); + return -EIO; +} + + +static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read) +{ + u8 dst_ca_comm_err = 0; + + while (dst_ca_comm_err < RETRIES) { + dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); + if (dst_ci_command(state, data, ca_string, len, read)) { // If error + dst_error_recovery(state); + dst_ca_comm_err++; // work required here. + } else { + break; + } + } + + if(dst_ca_comm_err == RETRIES) + return -1; + + return 0; +} + + + +static int ca_get_app_info(struct dst_state *state) +{ + int length, str_length; + static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; + + put_checksum(&command[0], command[0]); + if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); + dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", + state->messages[7], (state->messages[8] << 8) | state->messages[9], + (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12])); + dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); + + // Transform dst message to correct application_info message + length = state->messages[5]; + str_length = length - 6; + if (str_length < 0) { + str_length = 0; + dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering."); + } + + // First, the command and length fields + put_command_and_length(&state->messages[0], CA_APP_INFO, length); + + // Copy application_type, application_manufacturer and manufacturer_code + memcpy(&state->messages[4], &state->messages[7], 5); + + // Set string length and copy string + state->messages[9] = str_length; + memcpy(&state->messages[10], &state->messages[12], str_length); + + return 0; +} + +static int ca_get_ca_info(struct dst_state *state) +{ + int srcPtr, dstPtr, i, num_ids; + static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; + const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + + // Print raw data + dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); + for (i = 0; i < state->messages[0] + 1; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + + // Set the command and length of the output + num_ids = state->messages[in_num_ids_pos]; + if (num_ids >= 100) { + num_ids = 100; + dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering."); + } + put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2); + + dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); + srcPtr = in_system_id_pos; + dstPtr = out_system_id_pos; + for(i = 0; i < num_ids; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); + // Append to output + state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; + state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; + srcPtr += 2; + dstPtr += 2; + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + + return 0; +} + +static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg) +{ + int i; + u8 slot_cap[256]; + static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff}; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); + + /* Will implement the rest soon */ + + dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < slot_cap[0] + 1; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); + + p_ca_caps->slot_num = 1; + p_ca_caps->slot_type = 1; + p_ca_caps->descr_num = slot_cap[7]; + p_ca_caps->descr_type = 1; + + if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps))) + return -EFAULT; + + return 0; +} + +/* Need some more work */ +static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) +{ + return -EOPNOTSUPP; +} + + +static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg) +{ + int i; + static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + u8 *slot_info = state->messages; + + put_checksum(&slot_command[0], 7); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + + /* Will implement the rest soon */ + + dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < 8; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); + + if (slot_info[4] & 0x80) { + p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; + p_ca_slot_info->num = 1; + p_ca_slot_info->type = CA_CI; + } else if (slot_info[4] & 0x40) { + p_ca_slot_info->flags = CA_CI_MODULE_READY; + p_ca_slot_info->num = 1; + p_ca_slot_info->type = CA_CI; + } else + p_ca_slot_info->flags = 0; + + if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info))) + return -EFAULT; + + return 0; +} + + +static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) +{ + u8 i = 0; + u32 command = 0; + + if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) + return -EFAULT; + + if (p_ca_message->msg) { + dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", + 3, p_ca_message->msg); + + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); + + switch (command) { + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + case CA_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + } + } + + return 0; +} + +static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) +{ + if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { + hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ + hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ + } else { + if (length > 247) { + dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); + return -1; + } + hw_buffer->msg[0] = (length & 0xff) + 7; + hw_buffer->msg[1] = 0x40; + hw_buffer->msg[2] = 0x03; + hw_buffer->msg[3] = 0x00; + hw_buffer->msg[4] = 0x03; + hw_buffer->msg[5] = length & 0xff; + hw_buffer->msg[6] = 0x00; + + /* + * Need to compute length for EN50221 section 8.3.2, for the time being + * assuming 8.3.2 is not applicable + */ + memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); + } + + return 0; +} + +static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) +{ + if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); + dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); + rdc_reset_state(state); + return -1; + } + dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); + + return 0; +} + +static u32 asn_1_decode(u8 *asn_1_array) +{ + u8 length_field = 0, word_count = 0, count = 0; + u32 length = 0; + + length_field = asn_1_array[0]; + dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); + if (length_field < 0x80) { + length = length_field & 0x7f; + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); + } else { + word_count = length_field & 0x7f; + for (count = 0; count < word_count; count++) { + length = length << 8; + length += asn_1_array[count + 1]; + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); + } + } + return length; +} + +static int debug_string(u8 *msg, u32 length, u32 offset) +{ + u32 i; + + dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); + for (i = offset; i < length; i++) + dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); + dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); + + return 0; +} + + +static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +{ + u32 length = 0; + u8 tag_length = 8; + + length = asn_1_decode(&p_ca_message->msg[3]); + dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); + debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ + + memset(hw_buffer->msg, '\0', length); + handle_dst_tag(state, p_ca_message, hw_buffer, length); + put_checksum(hw_buffer->msg, hw_buffer->msg[0]); + + debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ + write_to_8820(state, hw_buffer, (length + tag_length), reply); + + return 0; +} + + +/* Board supports CA PMT reply ? */ +static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +{ + int ca_pmt_reply_test = 0; + + /* Do test board */ + /* Not there yet but soon */ + + /* CA PMT Reply capable */ + if (ca_pmt_reply_test) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); + return -1; + } + + /* Process CA PMT Reply */ + /* will implement soon */ + dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); + } + /* CA PMT Reply not capable */ + if (!ca_pmt_reply_test) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); + return -1; + } + dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); + /* put a dummy message */ + + } + return 0; +} + +static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) +{ + int i = 0; + + u32 command = 0; + struct ca_msg *hw_buffer; + int result = 0; + + if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); + return -ENOMEM; + } + dprintk(verbose, DST_CA_DEBUG, 1, " "); + + if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) { + result = -EFAULT; + goto free_mem_and_exit; + } + + + if (p_ca_message->msg) { + /* EN50221 tag */ + command = 0; + + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); + + switch (command) { + case CA_PMT: + dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); + break; + case CA_PMT_REPLY: + dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); + break; + case CA_APP_INFO_ENQUIRY: // only for debugging + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); + + if ((ca_get_app_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); + break; + case CA_INFO_ENQUIRY: + dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); + + if ((ca_get_ca_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); + break; + } + } +free_mem_and_exit: + kfree (hw_buffer); + + return result; +} + +static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg) +{ + struct dvb_device *dvbdev; + struct dst_state *state; + struct ca_slot_info *p_ca_slot_info; + struct ca_caps *p_ca_caps; + struct ca_msg *p_ca_message; + void __user *arg = (void __user *)ioctl_arg; + int result = 0; + + mutex_lock(&dst_ca_mutex); + dvbdev = file->private_data; + state = (struct dst_state *)dvbdev->priv; + p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); + p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL); + p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL); + if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) { + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); + result = -ENOMEM; + goto free_mem_and_exit; + } + + /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ + switch (cmd) { + case CA_SEND_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Sending message"); + if ((ca_send_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); + result = -1; + goto free_mem_and_exit; + } + break; + case CA_GET_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Getting message"); + if ((ca_get_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); + break; + case CA_RESET: + dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); + dst_error_bailout(state); + msleep(4000); + break; + case CA_GET_SLOT_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); + if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); + break; + case CA_GET_CAP: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); + if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); + break; + case CA_GET_DESCR_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); + if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); + break; + case CA_SET_DESCR: + dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); + if ((ca_set_slot_descr()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); + break; + case CA_SET_PID: + dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); + if ((ca_set_pid()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); + default: + result = -EOPNOTSUPP; + }; + free_mem_and_exit: + kfree (p_ca_message); + kfree (p_ca_slot_info); + kfree (p_ca_caps); + + mutex_unlock(&dst_ca_mutex); + return result; +} + +static int dst_ca_open(struct inode *inode, struct file *file) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); + try_module_get(THIS_MODULE); + + return 0; +} + +static int dst_ca_release(struct inode *inode, struct file *file) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); + module_put(THIS_MODULE); + + return 0; +} + +static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) +{ + ssize_t bytes_read = 0; + + dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); + + return bytes_read; +} + +static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); + + return 0; +} + +static const struct file_operations dst_ca_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dst_ca_ioctl, + .open = dst_ca_open, + .release = dst_ca_release, + .read = dst_ca_read, + .write = dst_ca_write, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &dst_ca_fops +}; + +struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) +{ + struct dvb_device *dvbdev; + + dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); + if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) { + dst->dst_ca = dvbdev; + return dst->dst_ca; + } + + return NULL; +} + +EXPORT_SYMBOL(dst_ca_attach); + +MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/bt8xx/dst_ca.h b/drivers/media/pci/bt8xx/dst_ca.h new file mode 100644 index 00000000000..59cd0ddd6d8 --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_ca.h @@ -0,0 +1,58 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _DST_CA_H_ +#define _DST_CA_H_ + +#define RETRIES 5 + + +#define CA_APP_INFO_ENQUIRY 0x9f8020 +#define CA_APP_INFO 0x9f8021 +#define CA_ENTER_MENU 0x9f8022 +#define CA_INFO_ENQUIRY 0x9f8030 +#define CA_INFO 0x9f8031 +#define CA_PMT 0x9f8032 +#define CA_PMT_REPLY 0x9f8033 + +#define CA_CLOSE_MMI 0x9f8800 +#define CA_DISPLAY_CONTROL 0x9f8801 +#define CA_DISPLAY_REPLY 0x9f8802 +#define CA_TEXT_LAST 0x9f8803 +#define CA_TEXT_MORE 0x9f8804 +#define CA_KEYPAD_CONTROL 0x9f8805 +#define CA_KEYPRESS 0x9f8806 + +#define CA_ENQUIRY 0x9f8807 +#define CA_ANSWER 0x9f8808 +#define CA_MENU_LAST 0x9f8809 +#define CA_MENU_MORE 0x9f880a +#define CA_MENU_ANSWER 0x9f880b +#define CA_LIST_LAST 0x9f880c +#define CA_LIST_MORE 0x9f880d + + +struct dst_ca_private { + struct dst_state *dst; + struct dvb_device *dvbdev; +}; + + +#endif diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h new file mode 100644 index 00000000000..d70d98f1a57 --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_common.h @@ -0,0 +1,182 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DST_COMMON_H +#define DST_COMMON_H + +#include +#include +#include +#include "bt878.h" + +#include "dst_ca.h" + + +#define NO_DELAY 0 +#define LONG_DELAY 1 +#define DEVICE_INIT 2 + +#define DELAY 1 + +#define DST_TYPE_IS_SAT 0 +#define DST_TYPE_IS_TERR 1 +#define DST_TYPE_IS_CABLE 2 +#define DST_TYPE_IS_ATSC 3 + +#define DST_TYPE_HAS_TS188 1 +#define DST_TYPE_HAS_TS204 2 +#define DST_TYPE_HAS_SYMDIV 4 +#define DST_TYPE_HAS_FW_1 8 +#define DST_TYPE_HAS_FW_2 16 +#define DST_TYPE_HAS_FW_3 32 +#define DST_TYPE_HAS_FW_BUILD 64 +#define DST_TYPE_HAS_OBS_REGS 128 +#define DST_TYPE_HAS_INC_COUNT 256 +#define DST_TYPE_HAS_MULTI_FE 512 +#define DST_TYPE_HAS_NEWTUNE_2 1024 +#define DST_TYPE_HAS_DBOARD 2048 +#define DST_TYPE_HAS_VLF 4096 + +/* Card capability list */ + +#define DST_TYPE_HAS_MAC 1 +#define DST_TYPE_HAS_DISEQC3 2 +#define DST_TYPE_HAS_DISEQC4 4 +#define DST_TYPE_HAS_DISEQC5 8 +#define DST_TYPE_HAS_MOTO 16 +#define DST_TYPE_HAS_CA 32 +#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ +#define DST_TYPE_HAS_SESSION 128 + +#define TUNER_TYPE_MULTI 1 +#define TUNER_TYPE_UNKNOWN 2 +/* DVB-S */ +#define TUNER_TYPE_L64724 4 +#define TUNER_TYPE_STV0299 8 +#define TUNER_TYPE_MB86A15 16 + +/* DVB-T */ +#define TUNER_TYPE_TDA10046 32 + +/* ATSC */ +#define TUNER_TYPE_NXT200x 64 + + +#define RDC_8820_PIO_0_DISABLE 0 +#define RDC_8820_PIO_0_ENABLE 1 +#define RDC_8820_INT 2 +#define RDC_8820_RESET 4 + +/* DST Communication */ +#define GET_REPLY 1 +#define NO_REPLY 0 + +#define GET_ACK 1 +#define FIXED_COMM 8 + +#define ACK 0xff + +struct dst_state { + + struct i2c_adapter* i2c; + + struct bt878* bt; + + /* configuration settings */ + const struct dst_config* config; + + struct dvb_frontend frontend; + + /* private ASIC data */ + u8 tx_tuna[10]; + u8 rx_tuna[10]; + u8 rxbuffer[10]; + u8 diseq_flags; + u8 dst_type; + u32 type_flags; + u32 frequency; /* intermediate frequency in kHz for QPSK */ + fe_spectral_inversion_t inversion; + u32 symbol_rate; /* symbol rate in Symbols per second */ + fe_code_rate_t fec; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + u32 decode_freq; + u8 decode_lock; + u16 decode_strength; + u16 decode_snr; + unsigned long cur_jiff; + u8 k22; + u32 bandwidth; + u32 dst_hw_cap; + u8 dst_fw_version; + fe_sec_mini_cmd_t minicmd; + fe_modulation_t modulation; + u8 messages[256]; + u8 mac_address[8]; + u8 fw_version[8]; + u8 card_info[8]; + u8 vendor[8]; + u8 board_info[8]; + u32 tuner_type; + char *tuner_name; + struct mutex dst_mutex; + u8 fw_name[8]; + struct dvb_device *dst_ca; +}; + +struct tuner_types { + u32 tuner_type; + char *tuner_name; + char *board_name; + char *fw_name; +}; + +struct dst_types { + char *device_id; + int offset; + u8 dst_type; + u32 type_flags; + u32 dst_feature; + u32 tuner_type; +}; + +struct dst_config +{ + /* the ASIC i2c address */ + u8 demod_address; +}; + +int rdc_reset_state(struct dst_state *state); + +int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); +int dst_pio_disable(struct dst_state *state); +int dst_error_recovery(struct dst_state* state); +int dst_error_bailout(struct dst_state *state); +int dst_comm_init(struct dst_state* state); + +int write_dst(struct dst_state *state, u8 * data, u8 len); +int read_dst(struct dst_state *state, u8 * ret, u8 len); +u8 dst_check_sum(u8 * buf, u32 len); +struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); +struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); + + +#endif // DST_COMMON_H diff --git a/drivers/media/pci/bt8xx/dst_priv.h b/drivers/media/pci/bt8xx/dst_priv.h new file mode 100644 index 00000000000..3974a4c6ebe --- /dev/null +++ b/drivers/media/pci/bt8xx/dst_priv.h @@ -0,0 +1,35 @@ +/* + * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend + * + * Copyright (C) 2003 Jamie Honan + */ + +struct dst_gpio_enable { + u32 mask; + u32 enable; +}; + +struct dst_gpio_output { + u32 mask; + u32 highvals; +}; + +struct dst_gpio_read { + unsigned long value; +}; + +union dst_gpio_packet { + struct dst_gpio_enable enb; + struct dst_gpio_output outp; + struct dst_gpio_read rd; + int psize; +}; + +#define DST_IG_ENABLE 0 +#define DST_IG_WRITE 1 +#define DST_IG_READ 2 +#define DST_IG_TS 3 + +struct bt878; + +int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c new file mode 100644 index 00000000000..81fab9adc1c --- /dev/null +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -0,0 +1,975 @@ +/* + * Bt8xx based DVB adapter driver + * + * Copyright (C) 2002,2003 Florian Schirmer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define pr_fmt(fmt) "dvb_bt8xx: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb-bt8xx.h" +#include "bt878.h" + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk( args... ) \ + do { \ + if (debug) printk(KERN_DEBUG args); \ + } while (0) + +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + +static void dvb_bt8xx_task(unsigned long data) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; + + //printk("%d ", card->bt->finished_block); + + while (card->bt->last_block != card->bt->finished_block) { + (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) + (&card->demux, + &card->bt->buf_cpu[card->bt->last_block * + card->bt->block_bytes], + card->bt->block_bytes); + card->bt->last_block = (card->bt->last_block + 1) % + card->bt->block_count; + } +} + +static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux*dvbdmx = dvbdmxfeed->demux; + struct dvb_bt8xx_card *card = dvbdmx->priv; + int rc; + + dprintk("dvb_bt8xx: start_feed\n"); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + mutex_lock(&card->lock); + card->nfeeds++; + rc = card->nfeeds; + if (card->nfeeds == 1) + bt878_start(card->bt, card->gpio_mode, + card->op_sync_orin, card->irq_err_ignore); + mutex_unlock(&card->lock); + return rc; +} + +static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct dvb_bt8xx_card *card = dvbdmx->priv; + + dprintk("dvb_bt8xx: stop_feed\n"); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + mutex_lock(&card->lock); + card->nfeeds--; + if (card->nfeeds == 0) + bt878_stop(card->bt); + mutex_unlock(&card->lock); + + return 0; +} + +static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) +{ + if ((adev->subsystem_vendor == bdev->subsystem_vendor) && + (adev->subsystem_device == bdev->subsystem_device) && + (adev->bus->number == bdev->bus->number) && + (PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn))) + return 1; + return 0; +} + +static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) +{ + unsigned int card_nr; + + /* Hmm, n squared. Hope n is small */ + for (card_nr = 0; card_nr < bt878_num; card_nr++) + if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) + return &bt878[card_nr]; + return NULL; +} + +static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; + static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + if (buf_len < 5) + return -EINVAL; + + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (c->frequency < 542000000) + cp = 0xb4; + else if (c->frequency < 771000000) + cp = 0xbc; + else + cp = 0xf4; + + if (c->frequency == 0) + bs = 0x03; + else if (c->frequency < 443250000) + bs = 0x02; + else + bs = 0x08; + + pllbuf[0] = 0x60; + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 5; +} + +static struct mt352_config thomson_dtt7579_config = { + .demod_address = 0x0f, + .demod_init = thomson_dtt7579_demod_init, +}; + +static struct zl10353_config thomson_dtt7579_zl10353_config = { + .demod_address = 0x0f, +}; + +static int cx24108_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 freq = c->frequency; + int i, a, n, pump; + u32 band, pll; + u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, + 1576000,1718000,1856000,2036000,2150000}; + u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, + 0x00102000,0x00104000,0x00108000,0x00110000, + 0x00120000,0x00140000}; + + #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ + dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); + + /* This is really the bit driving the tuner chip cx24108 */ + + if (freq<950000) + freq = 950000; /* kHz */ + else if (freq>2150000) + freq = 2150000; /* satellite IF is 950..2150MHz */ + + /* decide which VCO to use for the input frequency */ + for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); + dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq); + band=bandsel[i]; + /* the gain values must be set by SetSymbolrate */ + /* compute the pll divider needed, from Conexant data sheet, + resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4, + depending on the divider bit. It is set to /4 on the 2 lowest + bands */ + n=((i<=2?2:1)*freq*10L)/(XTAL/100); + a=n%32; n/=32; if(a==0) n--; + pump=(freq<(osci[i-1]+osci[i])/2); + pll=0xf8000000| + ((pump?1:2)<<(14+11))| + ((n&0x1ff)<<(5+11))| + ((a&0x1f)<<11); + /* everything is shifted left 11 bits to left-align the bits in the + 32bit word. Output to the tuner goes MSB-aligned, after all */ + dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a); + cx24110_pll_write(fe,band); + /* set vga and vca to their widest-band settings, as a precaution. + SetSymbolrate might not be called to set this up */ + cx24110_pll_write(fe,0x500c0000); + cx24110_pll_write(fe,0x83f1f800); + cx24110_pll_write(fe,pll); + //writereg(client,0x56,0x7f); + + return 0; +} + +static int pinnsat_tuner_init(struct dvb_frontend* fe) +{ + struct dvb_bt8xx_card *card = fe->dvb->priv; + + bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */ + bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */ + + return 0; +} + +static int pinnsat_tuner_sleep(struct dvb_frontend* fe) +{ + struct dvb_bt8xx_card *card = fe->dvb->priv; + + bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */ + + return 0; +} + +static struct cx24110_config pctvsat_config = { + .demod_address = 0x55, +}; + +static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 cfg, cpump, band_select; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36000000 + c->frequency + 83333) / 166666; + cfg = 0x88; + + if (c->frequency < 175000000) + cpump = 2; + else if (c->frequency < 390000000) + cpump = 1; + else if (c->frequency < 470000000) + cpump = 2; + else if (c->frequency < 750000000) + cpump = 2; + else + cpump = 3; + + if (c->frequency < 175000000) + band_select = 0x0e; + else if (c->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(card->i2c_adapter, &msg, 1); + return (div * 166666 - 36000000); +} + +static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; + + return request_firmware(fw, name, &bt->bt->dev->dev); +} + +static struct sp887x_config microtune_mt7202dtf_config = { + .demod_address = 0x70, + .request_firmware = microtune_mt7202dtf_request_firmware, +}; + +static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + udelay(2000); + mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + if (buf_len < 5) return -EINVAL; + + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (c->frequency < 150000000) + cp = 0xB4; + else if (c->frequency < 173000000) + cp = 0xBC; + else if (c->frequency < 250000000) + cp = 0xB4; + else if (c->frequency < 400000000) + cp = 0xBC; + else if (c->frequency < 420000000) + cp = 0xF4; + else if (c->frequency < 470000000) + cp = 0xFC; + else if (c->frequency < 600000000) + cp = 0xBC; + else if (c->frequency < 730000000) + cp = 0xF4; + else + cp = 0xFC; + + if (c->frequency < 150000000) + bs = 0x01; + else if (c->frequency < 173000000) + bs = 0x01; + else if (c->frequency < 250000000) + bs = 0x02; + else if (c->frequency < 400000000) + bs = 0x02; + else if (c->frequency < 420000000) + bs = 0x02; + else if (c->frequency < 470000000) + bs = 0x02; + else if (c->frequency < 600000000) + bs = 0x08; + else if (c->frequency < 730000000) + bs = 0x08; + else + bs = 0x08; + + pllbuf[0] = 0x61; + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 5; +} + +static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { + .demod_address = 0x0f, + .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, +}; + +static struct dst_config dst_config = { + .demod_address = 0x55, +}; + +static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; + + return request_firmware(fw, name, &bt->bt->dev->dev); +} + +static void or51211_setmode(struct dvb_frontend * fe, int mode) +{ + struct dvb_bt8xx_card *bt = fe->dvb->priv; + bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */ + msleep(20); +} + +static void or51211_reset(struct dvb_frontend * fe) +{ + struct dvb_bt8xx_card *bt = fe->dvb->priv; + + /* RESET DEVICE + * reset is controlled by GPIO-0 + * when set to 0 causes reset and when to 1 for normal op + * must remain reset for 128 clock cycles on a 50Mhz clock + * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4 + * We assume that the reset has be held low long enough or we + * have been reset by a power on. When the driver is unloaded + * reset set to 0 so if reloaded we have been reset. + */ + /* reset & PRM1,2&4 are outputs */ + int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); + if (ret != 0) + printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); + bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ + msleep(20); + /* Now set for normal operation */ + bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001); + /* wait for operation to begin */ + msleep(500); +} + +static void or51211_sleep(struct dvb_frontend * fe) +{ + struct dvb_bt8xx_card *bt = fe->dvb->priv; + bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000); +} + +static struct or51211_config or51211_config = { + .demod_address = 0x15, + .request_firmware = or51211_request_firmware, + .setmode = or51211_setmode, + .reset = or51211_reset, + .sleep = or51211_sleep, +}; + +static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; + + div = (c->frequency + 36166667) / 166667; + + buf[0] = (div >> 8) & 0x7F; + buf[1] = div & 0xFF; + buf[2] = 0x85; + if ((c->frequency >= 47000000) && (c->frequency < 153000000)) + buf[3] = 0x01; + else if ((c->frequency >= 153000000) && (c->frequency < 430000000)) + buf[3] = 0x02; + else if ((c->frequency >= 430000000) && (c->frequency < 824000000)) + buf[3] = 0x0C; + else if ((c->frequency >= 824000000) && (c->frequency < 863000000)) + buf[3] = 0x8C; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(card->i2c_adapter, &msg, 1); + return 0; +} + +static struct nxt6000_config vp3021_alps_tded4_config = { + .demod_address = 0x0a, + .clock_inversion = 1, +}; + +static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) +{ + u32 div; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (buf_len < 5) + return -EINVAL; + + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + pllbuf[0] = 0x61; + pllbuf[1] = (div >> 8) & 0x7F; + pllbuf[2] = div & 0xFF; + pllbuf[3] = 0x85; + + dprintk("frequency %u, div %u\n", c->frequency, div); + + if (c->frequency < 470000000) + pllbuf[4] = 0x02; + else if (c->frequency > 823000000) + pllbuf[4] = 0x88; + else + pllbuf[4] = 0x08; + + if (c->bandwidth_hz == 8000000) + pllbuf[4] |= 0x04; + + return 5; +} + +static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) +{ + /* + * Reset the frontend, must be called before trying + * to initialise the MT352 or mt352_attach + * will fail. Same goes for the nxt6000 frontend. + * + */ + + int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); + if (ret != 0) + printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ +} + +static struct mt352_config digitv_alps_tded4_config = { + .demod_address = 0x0a, + .demod_init = digitv_alps_tded4_demod_init, +}; + +static struct lgdt330x_config tdvs_tua6034_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ +}; + +static void lgdt330x_reset(struct dvb_bt8xx_card *bt) +{ + /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ + msleep(100); +} + +static void frontend_init(struct dvb_bt8xx_card *card, u32 type) +{ + struct dst_state* state = NULL; + + switch(type) { + case BTTV_BOARD_DVICO_DVBT_LITE: + card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter); + + if (card->fe == NULL) + card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config, + card->i2c_adapter); + + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; + card->fe->ops.info.frequency_min = 174000000; + card->fe->ops.info.frequency_max = 862000000; + } + break; + + case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: + lgdt330x_reset(card); + card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); + if (card->fe != NULL) { + dvb_attach(simple_tuner_attach, card->fe, + card->i2c_adapter, 0x61, + TUNER_LG_TDVS_H06XF); + dprintk ("dvb_bt8xx: lgdt330x detected\n"); + } + break; + + case BTTV_BOARD_NEBULA_DIGITV: + /* + * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); + * this would be a cleaner solution than trying each frontend in turn. + */ + + /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ + digitv_alps_tded4_reset(card); + card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; + dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); + break; + } + + /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ + digitv_alps_tded4_reset(card); + card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter); + + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; + dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); + } + break; + + case BTTV_BOARD_AVDVBT_761: + card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter); + if (card->fe) { + card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; + } + break; + + case BTTV_BOARD_AVDVBT_771: + card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; + card->fe->ops.info.frequency_min = 174000000; + card->fe->ops.info.frequency_max = 862000000; + } + break; + + case BTTV_BOARD_TWINHAN_DST: + /* DST is not a frontend driver !!! */ + state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); + if (!state) { + pr_err("No memory\n"); + break; + } + /* Setup the Card */ + state->config = &dst_config; + state->i2c = card->i2c_adapter; + state->bt = card->bt; + state->dst_ca = NULL; + /* DST is not a frontend, attaching the ASIC */ + if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { + pr_err("%s: Could not find a Twinhan DST\n", __func__); + break; + } + /* Attach other DST peripherals if any */ + /* Conditional Access device */ + card->fe = &state->frontend; + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + dvb_attach(dst_ca_attach, state, &card->dvb_adapter); + break; + + case BTTV_BOARD_PINNACLESAT: + card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter); + if (card->fe) { + card->fe->ops.tuner_ops.init = pinnsat_tuner_init; + card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; + card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; + } + break; + + case BTTV_BOARD_PC_HDTV: + card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); + if (card->fe != NULL) + dvb_attach(simple_tuner_attach, card->fe, + card->i2c_adapter, 0x61, + TUNER_PHILIPS_FCV1236D); + break; + } + + if (card->fe == NULL) + pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + card->bt->dev->vendor, + card->bt->dev->device, + card->bt->dev->subsystem_vendor, + card->bt->dev->subsystem_device); + else + if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { + pr_err("Frontend registration failed!\n"); + dvb_frontend_detach(card->fe); + card->fe = NULL; + } +} + +static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) +{ + int result; + + result = dvb_register_adapter(&card->dvb_adapter, card->card_name, + THIS_MODULE, &card->bt->dev->dev, + adapter_nr); + if (result < 0) { + pr_err("dvb_register_adapter failed (errno = %d)\n", result); + return result; + } + card->dvb_adapter.priv = card; + + card->bt->adapter = card->i2c_adapter; + + memset(&card->demux, 0, sizeof(struct dvb_demux)); + + card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; + + card->demux.priv = card; + card->demux.filternum = 256; + card->demux.feednum = 256; + card->demux.start_feed = dvb_bt8xx_start_feed; + card->demux.stop_feed = dvb_bt8xx_stop_feed; + card->demux.write_to_decoder = NULL; + + result = dvb_dmx_init(&card->demux); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_unregister_adaptor; + } + + card->dmxdev.filternum = 256; + card->dmxdev.demux = &card->demux.dmx; + card->dmxdev.capabilities = 0; + + result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter); + if (result < 0) { + pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); + goto err_dmx_release; + } + + card->fe_hw.source = DMX_FRONTEND_0; + + result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_dmxdev_release; + } + + card->fe_mem.source = DMX_MEMORY_FE; + + result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_remove_hw_frontend; + } + + result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_remove_mem_frontend; + } + + result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + if (result < 0) { + pr_err("dvb_net_init failed (errno = %d)\n", result); + goto err_disconnect_frontend; + } + + tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); + + frontend_init(card, type); + + return 0; + +err_disconnect_frontend: + card->demux.dmx.disconnect_frontend(&card->demux.dmx); +err_remove_mem_frontend: + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); +err_remove_hw_frontend: + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); +err_dmxdev_release: + dvb_dmxdev_release(&card->dmxdev); +err_dmx_release: + dvb_dmx_release(&card->demux); +err_unregister_adaptor: + dvb_unregister_adapter(&card->dvb_adapter); + return result; +} + +static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) +{ + struct dvb_bt8xx_card *card; + struct pci_dev* bttv_pci_dev; + int ret; + + if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) + return -ENOMEM; + + mutex_init(&card->lock); + card->bttv_nr = sub->core->nr; + strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name)); + card->i2c_adapter = &sub->core->i2c_adap; + + switch(sub->core->type) { + case BTTV_BOARD_PINNACLESAT: + card->gpio_mode = 0x0400c060; + /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, + BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + + case BTTV_BOARD_DVICO_DVBT_LITE: + card->gpio_mode = 0x0400C060; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + /* 26, 15, 14, 6, 5 + * A_PWRDN DA_DPM DA_SBR DA_IOM_DA + * DA_APP(parallel) */ + break; + + case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: + card->gpio_mode = 0x0400c060; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + + case BTTV_BOARD_NEBULA_DIGITV: + case BTTV_BOARD_AVDVBT_761: + card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + /* A_PWRDN DA_SBR DA_APP (high speed serial) */ + break; + + case BTTV_BOARD_AVDVBT_771: //case 0x07711461: + card->gpio_mode = 0x0400402B; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ + break; + + case BTTV_BOARD_TWINHAN_DST: + card->gpio_mode = 0x2204f2c; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | + BT878_APPERR | BT878_AFBUS; + /* 25,21,14,11,10,9,8,3,2 then + * 0x33 = 5,4,1,0 + * A_SEL=SML, DA_MLB, DA_SBR, + * DA_SDR=f, fifo trigger = 32 DWORDS + * IOM = 0 == audio A/D + * DPM = 0 == digital audio mode + * == async data parallel port + * then 0x33 (13 is set by start_capture) + * DA_APP = async data parallel port, + * ACAP_EN = 1, + * RISC+FIFO ENABLE */ + break; + + case BTTV_BOARD_PC_HDTV: + card->gpio_mode = 0x0100EC7B; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + + default: + pr_err("Unknown bttv card type: %d\n", sub->core->type); + kfree(card); + return -ENODEV; + } + + dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); + + if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { + pr_err("no pci device for card %d\n", card->bttv_nr); + kfree(card); + return -ENODEV; + } + + if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { + pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr); + pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n"); + + kfree(card); + return -ENODEV; + } + + mutex_init(&card->bt->gpio_lock); + card->bt->bttv_nr = sub->core->nr; + + if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { + kfree(card); + return ret; + } + + dev_set_drvdata(&sub->dev, card); + return 0; +} + +static void dvb_bt8xx_remove(struct bttv_sub_device *sub) +{ + struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); + + dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); + + bt878_stop(card->bt); + tasklet_kill(&card->bt->tasklet); + dvb_net_release(&card->dvbnet); + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); + dvb_dmxdev_release(&card->dmxdev); + dvb_dmx_release(&card->demux); + if (card->fe) { + dvb_unregister_frontend(card->fe); + dvb_frontend_detach(card->fe); + } + dvb_unregister_adapter(&card->dvb_adapter); + + kfree(card); +} + +static struct bttv_sub_driver driver = { + .drv = { + .name = "dvb-bt8xx", + }, + .probe = dvb_bt8xx_probe, + .remove = dvb_bt8xx_remove, + /* FIXME: + * .shutdown = dvb_bt8xx_shutdown, + * .suspend = dvb_bt8xx_suspend, + * .resume = dvb_bt8xx_resume, + */ +}; + +static int __init dvb_bt8xx_init(void) +{ + return bttv_sub_register(&driver, "dvb"); +} + +static void __exit dvb_bt8xx_exit(void) +{ + bttv_sub_unregister(&driver); +} + +module_init(dvb_bt8xx_init); +module_exit(dvb_bt8xx_exit); + +MODULE_DESCRIPTION("Bt8xx based DVB adapter driver"); +MODULE_AUTHOR("Florian Schirmer "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.h b/drivers/media/pci/bt8xx/dvb-bt8xx.h new file mode 100644 index 00000000000..4499ed2ac0e --- /dev/null +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.h @@ -0,0 +1,63 @@ +/* + * Bt8xx based DVB adapter driver + * + * Copyright (C) 2002,2003 Florian Schirmer + * Copyright (C) 2002 Peter Hettkamp + * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH + * Copyright (C) 1998,1999 Christian Theiss + * + * 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 DVB_BT8XX_H +#define DVB_BT8XX_H + +#include +#include +#include "dvbdev.h" +#include "dvb_net.h" +#include "bttv.h" +#include "mt352.h" +#include "sp887x.h" +#include "dst_common.h" +#include "nxt6000.h" +#include "cx24110.h" +#include "or51211.h" +#include "lgdt330x.h" +#include "zl10353.h" +#include "tuner-simple.h" + +struct dvb_bt8xx_card { + struct mutex lock; + int nfeeds; + char card_name[32]; + struct dvb_adapter dvb_adapter; + struct bt878 *bt; + unsigned int bttv_nr; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + u32 gpio_mode; + u32 op_sync_orin; + u32 irq_err_ignore; + struct i2c_adapter *i2c_adapter; + struct dvb_net dvbnet; + + struct dvb_frontend* fe; +}; + +#endif /* DVB_BT8XX_H */ diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig new file mode 100644 index 00000000000..d099e1a12c8 --- /dev/null +++ b/drivers/media/pci/ddbridge/Kconfig @@ -0,0 +1,18 @@ +config DVB_DDBRIDGE + tristate "Digital Devices bridge support" + depends on DVB_CORE && PCI && I2C + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + ---help--- + Support for cards with the Digital Devices PCI express bridge: + - Octopus PCIe Bridge + - Octopus mini PCIe Bridge + - Octopus LE + - DuoFlex S2 Octopus + - DuoFlex CT Octopus + - cineS2(v6) + + Say Y if you own such a card and want to use it. diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile new file mode 100644 index 00000000000..9d083c98ce5 --- /dev/null +++ b/drivers/media/pci/ddbridge/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the ddbridge device driver +# + +ddbridge-objs := ddbridge-core.o + +obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o + +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/dvb-frontends/ +ccflags-y += -Idrivers/media/common/tuners/ + +# For the staging CI driver cxd2099 +ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c new file mode 100644 index 00000000000..ebf3f05839d --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -0,0 +1,1723 @@ +/* + * ddbridge.c: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ddbridge.h" + +#include "ddbridge-regs.h" + +#include "tda18271c2dd.h" +#include "stv6110x.h" +#include "stv090x.h" +#include "lnbh24.h" +#include "drxk.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* MSI had problems with lost interrupts, fixed but needs testing */ +#undef CONFIG_PCI_MSI + +/******************************************************************************/ + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg>>8, reg&0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) +{ + struct ddb *dev = i2c->dev; + int stat; + u32 val; + + i2c->done = 0; + ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); + stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); + if (stat <= 0) { + printk(KERN_ERR "I2C timeout\n"); + { /* MSI debugging*/ + u32 istat = ddbreadl(INTERRUPT_STATUS); + printk(KERN_ERR "IRS %08x\n", istat); + ddbwritel(istat, INTERRUPT_ACK); + } + return -EIO; + } + val = ddbreadl(i2c->regs+I2C_COMMAND); + if (val & 0x70000) + return -EIO; + return 0; +} + +static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); + struct ddb *dev = i2c->dev; + u8 addr = 0; + + if (num) + addr = msg[0].addr; + + if (num == 2 && msg[1].flags & I2C_M_RD && + !(msg[0].flags & I2C_M_RD)) { + memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, + msg[0].buf, msg[0].len); + ddbwritel(msg[0].len|(msg[1].len << 16), + i2c->regs+I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 1)) { + memcpy_fromio(msg[1].buf, + dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, + msg[1].len); + return num; + } + } + + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); + ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 2)) + return num; + } + if (num == 1 && (msg[0].flags & I2C_M_RD)) { + ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 3)) { + ddbcpyfrom(msg[0].buf, + I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); + return num; + } + } + return -EIO; +} + + +static u32 ddb_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +struct i2c_algorithm ddb_i2c_algo = { + .master_xfer = ddb_i2c_master_xfer, + .functionality = ddb_i2c_functionality, +}; + +static void ddb_i2c_release(struct ddb *dev) +{ + int i; + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + + for (i = 0; i < dev->info->port_num; i++) { + i2c = &dev->i2c[i]; + adap = &i2c->adap; + i2c_del_adapter(adap); + } +} + +static int ddb_i2c_init(struct ddb *dev) +{ + int i, j, stat = 0; + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + + for (i = 0; i < dev->info->port_num; i++) { + i2c = &dev->i2c[i]; + i2c->dev = dev; + i2c->nr = i; + i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); + i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); + i2c->regs = 0x80 + i * 0x20; + ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); + ddbwritel((i2c->rbuf << 16) | i2c->wbuf, + i2c->regs + I2C_TASKADDRESS); + init_waitqueue_head(&i2c->wq); + + adap = &i2c->adap; + i2c_set_adapdata(adap, i2c); +#ifdef I2C_ADAP_CLASS_TV_DIGITAL + adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; +#else +#ifdef I2C_CLASS_TV_ANALOG + adap->class = I2C_CLASS_TV_ANALOG; +#endif +#endif + strcpy(adap->name, "ddbridge"); + adap->algo = &ddb_i2c_algo; + adap->algo_data = (void *)i2c; + adap->dev.parent = &dev->pdev->dev; + stat = i2c_add_adapter(adap); + if (stat) + break; + } + if (stat) + for (j = 0; j < i; j++) { + i2c = &dev->i2c[j]; + adap = &i2c->adap; + i2c_del_adapter(adap); + } + return stat; +} + + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +#if 0 +static void set_table(struct ddb *dev, u32 off, + dma_addr_t *pbuf, u32 num) +{ + u32 i, base; + u64 mem; + + base = DMA_BASE_ADDRESS_TABLE + off; + for (i = 0; i < num; i++) { + mem = pbuf[i]; + ddbwritel(mem & 0xffffffff, base + i * 8); + ddbwritel(mem >> 32, base + i * 8 + 4); + } +} +#endif + +static void ddb_address_table(struct ddb *dev) +{ + u32 i, j, base; + u64 mem; + dma_addr_t *pbuf; + + for (i = 0; i < dev->info->port_num * 2; i++) { + base = DMA_BASE_ADDRESS_TABLE + i * 0x100; + pbuf = dev->input[i].pbuf; + for (j = 0; j < dev->input[i].dma_buf_num; j++) { + mem = pbuf[j]; + ddbwritel(mem & 0xffffffff, base + j * 8); + ddbwritel(mem >> 32, base + j * 8 + 4); + } + } + for (i = 0; i < dev->info->port_num; i++) { + base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; + pbuf = dev->output[i].pbuf; + for (j = 0; j < dev->output[i].dma_buf_num; j++) { + mem = pbuf[j]; + ddbwritel(mem & 0xffffffff, base + j * 8); + ddbwritel(mem >> 32, base + j * 8 + 4); + } + } +} + +static void io_free(struct pci_dev *pdev, u8 **vbuf, + dma_addr_t *pbuf, u32 size, int num) +{ + int i; + + for (i = 0; i < num; i++) { + if (vbuf[i]) { + pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); + vbuf[i] = 0; + } + } +} + +static int io_alloc(struct pci_dev *pdev, u8 **vbuf, + dma_addr_t *pbuf, u32 size, int num) +{ + int i; + + for (i = 0; i < num; i++) { + vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); + if (!vbuf[i]) + return -ENOMEM; + } + return 0; +} + +static int ddb_buffers_alloc(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: + if (io_alloc(dev->pdev, port->input[0]->vbuf, + port->input[0]->pbuf, + port->input[0]->dma_buf_size, + port->input[0]->dma_buf_num) < 0) + return -1; + if (io_alloc(dev->pdev, port->input[1]->vbuf, + port->input[1]->pbuf, + port->input[1]->dma_buf_size, + port->input[1]->dma_buf_num) < 0) + return -1; + break; + case DDB_PORT_CI: + if (io_alloc(dev->pdev, port->input[0]->vbuf, + port->input[0]->pbuf, + port->input[0]->dma_buf_size, + port->input[0]->dma_buf_num) < 0) + return -1; + if (io_alloc(dev->pdev, port->output->vbuf, + port->output->pbuf, + port->output->dma_buf_size, + port->output->dma_buf_num) < 0) + return -1; + break; + default: + break; + } + } + ddb_address_table(dev); + return 0; +} + +static void ddb_buffers_free(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + io_free(dev->pdev, port->input[0]->vbuf, + port->input[0]->pbuf, + port->input[0]->dma_buf_size, + port->input[0]->dma_buf_num); + io_free(dev->pdev, port->input[1]->vbuf, + port->input[1]->pbuf, + port->input[1]->dma_buf_size, + port->input[1]->dma_buf_num); + io_free(dev->pdev, port->output->vbuf, + port->output->pbuf, + port->output->dma_buf_size, + port->output->dma_buf_num); + } +} + +static void ddb_input_start(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + + spin_lock_irq(&input->lock); + input->cbuf = 0; + input->coff = 0; + + /* reset */ + ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + ddbwritel(2, TS_INPUT_CONTROL(input->nr)); + ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + + ddbwritel((1 << 16) | + (input->dma_buf_num << 11) | + (input->dma_buf_size >> 7), + DMA_BUFFER_SIZE(input->nr)); + ddbwritel(0, DMA_BUFFER_ACK(input->nr)); + + ddbwritel(1, DMA_BASE_WRITE); + ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); + ddbwritel(9, TS_INPUT_CONTROL(input->nr)); + input->running = 1; + spin_unlock_irq(&input->lock); +} + +static void ddb_input_stop(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + + spin_lock_irq(&input->lock); + ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); + input->running = 0; + spin_unlock_irq(&input->lock); +} + +static void ddb_output_start(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + + spin_lock_irq(&output->lock); + output->cbuf = 0; + output->coff = 0; + ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel((1 << 16) | + (output->dma_buf_num << 11) | + (output->dma_buf_size >> 7), + DMA_BUFFER_SIZE(output->nr + 8)); + ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); + + ddbwritel(1, DMA_BASE_READ); + ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); + /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ + ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); + output->running = 1; + spin_unlock_irq(&output->lock); +} + +static void ddb_output_stop(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + + spin_lock_irq(&output->lock); + ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); + ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); + output->running = 0; + spin_unlock_irq(&output->lock); +} + +static u32 ddb_output_free(struct ddb_output *output) +{ + u32 idx, off, stat = output->stat; + s32 diff; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + if (output->cbuf != idx) { + if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && + (output->dma_buf_size - output->coff <= 188)) + return 0; + return 188; + } + diff = off - output->coff; + if (diff <= 0 || diff > 188) + return 188; + return 0; +} + +static ssize_t ddb_output_write(struct ddb_output *output, + const u8 *buf, size_t count) +{ + struct ddb *dev = output->port->dev; + u32 idx, off, stat = output->stat; + u32 left = count, len; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + while (left) { + len = output->dma_buf_size - output->coff; + if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && + (off == 0)) { + if (len <= 188) + break; + len -= 188; + } + if (output->cbuf == idx) { + if (off > output->coff) { +#if 1 + len = off - output->coff; + len -= (len % 188); + if (len <= 188) + +#endif + break; + len -= 188; + } + } + if (len > left) + len = left; + if (copy_from_user(output->vbuf[output->cbuf] + output->coff, + buf, len)) + return -EIO; + left -= len; + buf += len; + output->coff += len; + if (output->coff == output->dma_buf_size) { + output->coff = 0; + output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); + } + ddbwritel((output->cbuf << 11) | (output->coff >> 7), + DMA_BUFFER_ACK(output->nr + 8)); + } + return count - left; +} + +static u32 ddb_input_avail(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + u32 idx, off, stat = input->stat; + u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + if (ctrl & 4) { + printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); + ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); + return 0; + } + if (input->cbuf != idx) + return 188; + return 0; +} + +static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) +{ + struct ddb *dev = input->port->dev; + u32 left = count; + u32 idx, free, stat = input->stat; + int ret; + + idx = (stat >> 11) & 0x1f; + + while (left) { + if (input->cbuf == idx) + return count - left; + free = input->dma_buf_size - input->coff; + if (free > left) + free = left; + ret = copy_to_user(buf, input->vbuf[input->cbuf] + + input->coff, free); + if (ret) + return -EFAULT; + input->coff += free; + if (input->coff == input->dma_buf_size) { + input->coff = 0; + input->cbuf = (input->cbuf+1) % input->dma_buf_num; + } + left -= free; + ddbwritel((input->cbuf << 11) | (input->coff >> 7), + DMA_BUFFER_ACK(input->nr)); + } + return count; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +#if 0 +static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe) +{ + int i; + + for (i = 0; i < dev->info->port_num * 2; i++) { + if (dev->input[i].fe == fe) + return &dev->input[i]; + } + return NULL; +} +#endif + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + int status; + + if (enable) { + mutex_lock(&port->i2c_gate_lock); + status = input->gate_ctrl(fe, 1); + } else { + status = input->gate_ctrl(fe, 0); + mutex_unlock(&port->i2c_gate_lock); + } + return status; +} + +static int demod_attach_drxk(struct ddb_input *input) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct dvb_frontend *fe; + struct drxk_config config; + + memset(&config, 0, sizeof(config)); + config.microcode_name = "drxk_a3.mc"; + config.qam_demod_parameter_count = 4; + config.adr = 0x29 + (input->nr & 1); + + fe = input->fe = dvb_attach(drxk_attach, &config, i2c); + if (!input->fe) { + printk(KERN_ERR "No DRXK found!\n"); + return -ENODEV; + } + fe->sec_priv = input; + input->gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + +static int tuner_attach_tda18271(struct ddb_input *input) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct dvb_frontend *fe; + + if (input->fe->ops.i2c_gate_ctrl) + input->fe->ops.i2c_gate_ctrl(input->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); + if (!fe) { + printk(KERN_ERR "No TDA18271 found!\n"); + return -ENODEV; + } + if (input->fe->ops.i2c_gate_ctrl) + input->fe->ops.i2c_gate_ctrl(input->fe, 0); + return 0; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static struct stv090x_config stv0900 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x69, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, +}; + +static struct stv090x_config stv0900_aa = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, +}; + +static struct stv6110x_config stv6110a = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct stv6110x_config stv6110b = { + .addr = 0x63, + .refclk = 27000000, + .clk_div = 1, +}; + +static int demod_attach_stv0900(struct ddb_input *input, int type) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + + input->fe = dvb_attach(stv090x_attach, feconf, i2c, + (input->nr & 1) ? STV090x_DEMODULATOR_1 + : STV090x_DEMODULATOR_0); + if (!input->fe) { + printk(KERN_ERR "No STV0900 found!\n"); + return -ENODEV; + } + if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, + 0, (input->nr & 1) ? + (0x09 - type) : (0x0b - type))) { + printk(KERN_ERR "No LNBH24 found!\n"); + return -ENODEV; + } + return 0; +} + +static int tuner_attach_stv6110(struct ddb_input *input, int type) +{ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + struct stv6110x_config *tunerconf = (input->nr & 1) ? + &stv6110b : &stv6110a; + struct stv6110x_devctl *ctl; + + ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); + if (!ctl) { + printk(KERN_ERR "No STV6110X found!\n"); + return -ENODEV; + } + printk(KERN_INFO "attach tuner input %d adr %02x\n", + input->nr, tunerconf->addr); + + feconf->tuner_init = ctl->tuner_init; + feconf->tuner_sleep = ctl->tuner_sleep; + feconf->tuner_set_mode = ctl->tuner_set_mode; + feconf->tuner_set_frequency = ctl->tuner_set_frequency; + feconf->tuner_get_frequency = ctl->tuner_get_frequency; + feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; + feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; + feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; + feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; + feconf->tuner_set_refclk = ctl->tuner_set_refclk; + feconf->tuner_get_status = ctl->tuner_get_status; + + return 0; +} + +static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv) +{ + dvbdemux->priv = priv; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->write_to_decoder = NULL; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + return dvb_dmx_init(dvbdemux); +} + +static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter) +{ + int ret; + + dmxdev->filternum = 256; + dmxdev->demux = &dvbdemux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); + if (ret < 0) + return ret; + + hw_frontend->source = DMX_FRONTEND_0; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); + mem_frontend->source = DMX_MEMORY_FE; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); +} + +static int start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ddb_input *input = dvbdmx->priv; + + if (!input->users) + ddb_input_start(input); + + return ++input->users; +} + +static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ddb_input *input = dvbdmx->priv; + + if (--input->users) + return input->users; + + ddb_input_stop(input); + return 0; +} + + +static void dvb_input_detach(struct ddb_input *input) +{ + struct dvb_adapter *adap = &input->adap; + struct dvb_demux *dvbdemux = &input->demux; + + switch (input->attached) { + case 5: + if (input->fe2) + dvb_unregister_frontend(input->fe2); + if (input->fe) { + dvb_unregister_frontend(input->fe); + dvb_frontend_detach(input->fe); + input->fe = NULL; + } + case 4: + dvb_net_release(&input->dvbnet); + + case 3: + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &input->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &input->mem_frontend); + dvb_dmxdev_release(&input->dmxdev); + + case 2: + dvb_dmx_release(&input->demux); + + case 1: + dvb_unregister_adapter(adap); + } + input->attached = 0; +} + +static int dvb_input_attach(struct ddb_input *input) +{ + int ret; + struct ddb_port *port = input->port; + struct dvb_adapter *adap = &input->adap; + struct dvb_demux *dvbdemux = &input->demux; + + ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, + &input->port->dev->pdev->dev, + adapter_nr); + if (ret < 0) { + printk(KERN_ERR "ddbridge: Could not register adapter." + "Check if you enabled enough adapters in dvb-core!\n"); + return ret; + } + input->attached = 1; + + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + start_feed, + stop_feed, input); + if (ret < 0) + return ret; + input->attached = 2; + + ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, + &input->hw_frontend, + &input->mem_frontend, adap); + if (ret < 0) + return ret; + input->attached = 3; + + ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); + if (ret < 0) + return ret; + input->attached = 4; + + input->fe = 0; + switch (port->type) { + case DDB_TUNER_DVBS_ST: + if (demod_attach_stv0900(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6110(input, 0) < 0) + return -ENODEV; + if (input->fe) { + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; + } + break; + case DDB_TUNER_DVBS_ST_AA: + if (demod_attach_stv0900(input, 1) < 0) + return -ENODEV; + if (tuner_attach_stv6110(input, 1) < 0) + return -ENODEV; + if (input->fe) { + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; + } + break; + case DDB_TUNER_DVBCT_TR: + if (demod_attach_drxk(input) < 0) + return -ENODEV; + if (tuner_attach_tda18271(input) < 0) + return -ENODEV; + if (input->fe) { + if (dvb_register_frontend(adap, input->fe) < 0) + return -ENODEV; + } + if (input->fe2) { + if (dvb_register_frontend(adap, input->fe2) < 0) + return -ENODEV; + input->fe2->tuner_priv = input->fe->tuner_priv; + memcpy(&input->fe2->ops.tuner_ops, + &input->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } + break; + } + input->attached = 5; + return 0; +} + +/****************************************************************************/ +/****************************************************************************/ + +static ssize_t ts_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + size_t left = count; + int stat; + + while (left) { + if (ddb_output_free(output) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + output->wq, ddb_output_free(output) >= 188) < 0) + break; + } + stat = ddb_output_write(output, buf, left); + if (stat < 0) + break; + buf += stat; + left -= stat; + } + return (left == count) ? -EAGAIN : (count - left); +} + +static ssize_t ts_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + int left, read; + + count -= count % 188; + left = count; + while (left) { + if (ddb_input_avail(input) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + input->wq, ddb_input_avail(input) >= 188) < 0) + break; + } + read = ddb_input_read(input, buf, left); + if (read < 0) + return read; + left -= read; + buf += read; + } + return (left == count) ? -EAGAIN : (count - left); +} + +static unsigned int ts_poll(struct file *file, poll_table *wait) +{ + /* + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + */ + unsigned int mask = 0; + +#if 0 + if (data_avail_to_read) + mask |= POLLIN | POLLRDNORM; + if (data_avail_to_write) + mask |= POLLOUT | POLLWRNORM; + + poll_wait(file, &read_queue, wait); + poll_wait(file, &write_queue, wait); +#endif + return mask; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = ts_poll, + .mmap = 0, +}; + +static struct dvb_device dvbdev_ci = { + .priv = 0, + .readers = -1, + .writers = -1, + .users = -1, + .fops = &ci_fops, +}; + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void input_tasklet(unsigned long data) +{ + struct ddb_input *input = (struct ddb_input *) data; + struct ddb *dev = input->port->dev; + + spin_lock(&input->lock); + if (!input->running) { + spin_unlock(&input->lock); + return; + } + input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); + + if (input->port->class == DDB_PORT_TUNER) { + if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) + printk(KERN_ERR "Overflow input %d\n", input->nr); + while (input->cbuf != ((input->stat >> 11) & 0x1f) + || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) { + dvb_dmx_swfilter_packets(&input->demux, + input->vbuf[input->cbuf], + input->dma_buf_size / 188); + + input->cbuf = (input->cbuf + 1) % input->dma_buf_num; + ddbwritel((input->cbuf << 11), + DMA_BUFFER_ACK(input->nr)); + input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); + } + } + if (input->port->class == DDB_PORT_CI) + wake_up(&input->wq); + spin_unlock(&input->lock); +} + +static void output_tasklet(unsigned long data) +{ + struct ddb_output *output = (struct ddb_output *) data; + struct ddb *dev = output->port->dev; + + spin_lock(&output->lock); + if (!output->running) { + spin_unlock(&output->lock); + return; + } + output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); + wake_up(&output->wq); + spin_unlock(&output->lock); +} + + +struct cxd2099_cfg cxd_cfg = { + .bitrate = 62000, + .adr = 0x40, + .polarity = 1, + .clock_mode = 1, +}; + +static int ddb_ci_attach(struct ddb_port *port) +{ + int ret; + + ret = dvb_register_adapter(&port->output->adap, + "DDBridge", + THIS_MODULE, + &port->dev->pdev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + if (!port->en) { + dvb_unregister_adapter(&port->output->adap); + return -ENODEV; + } + ddb_input_start(port->input[0]); + ddb_output_start(port->output); + dvb_ca_en50221_init(&port->output->adap, + port->en, 0, 1); + ret = dvb_register_device(&port->output->adap, &port->output->dev, + &dvbdev_ci, (void *) port->output, + DVB_DEVICE_SEC); + return ret; +} + +static int ddb_port_attach(struct ddb_port *port) +{ + int ret = 0; + + switch (port->class) { + case DDB_PORT_TUNER: + ret = dvb_input_attach(port->input[0]); + if (ret < 0) + break; + ret = dvb_input_attach(port->input[1]); + break; + case DDB_PORT_CI: + ret = ddb_ci_attach(port); + break; + default: + break; + } + if (ret < 0) + printk(KERN_ERR "port_attach on port %d failed\n", port->nr); + return ret; +} + +static int ddb_ports_attach(struct ddb *dev) +{ + int i, ret = 0; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + ret = ddb_port_attach(port); + if (ret < 0) + break; + } + return ret; +} + +static void ddb_ports_detach(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: + dvb_input_detach(port->input[0]); + dvb_input_detach(port->input[1]); + break; + case DDB_PORT_CI: + if (port->output->dev) + dvb_unregister_device(port->output->dev); + if (port->en) { + ddb_input_stop(port->input[0]); + ddb_output_stop(port->output); + dvb_ca_en50221_release(port->en); + kfree(port->en); + port->en = 0; + dvb_unregister_adapter(&port->output->adap); + } + break; + } + } +} + +/****************************************************************************/ +/****************************************************************************/ + +static int port_has_ci(struct ddb_port *port) +{ + u8 val; + return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; +} + +static int port_has_stv0900(struct ddb_port *port) +{ + u8 val; + if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_stv0900_aa(struct ddb_port *port) +{ + u8 val; + if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_drxks(struct ddb_port *port) +{ + u8 val; + if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) + return 0; + if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) + return 0; + return 1; +} + +static void ddb_port_probe(struct ddb_port *port) +{ + struct ddb *dev = port->dev; + char *modname = "NO MODULE"; + + port->class = DDB_PORT_NONE; + + if (port_has_ci(port)) { + modname = "CI"; + port->class = DDB_PORT_CI; + ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900(port)) { + modname = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST; + ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900_aa(port)) { + modname = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST_AA; + ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_drxks(port)) { + modname = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_TR; + ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } + printk(KERN_INFO "Port %d (TAB %d): %s\n", + port->nr, port->nr+1, modname); +} + +static void ddb_input_init(struct ddb_port *port, int nr) +{ + struct ddb *dev = port->dev; + struct ddb_input *input = &dev->input[nr]; + + input->nr = nr; + input->port = port; + input->dma_buf_num = INPUT_DMA_BUFS; + input->dma_buf_size = INPUT_DMA_SIZE; + ddbwritel(0, TS_INPUT_CONTROL(nr)); + ddbwritel(2, TS_INPUT_CONTROL(nr)); + ddbwritel(0, TS_INPUT_CONTROL(nr)); + ddbwritel(0, DMA_BUFFER_ACK(nr)); + tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); + spin_lock_init(&input->lock); + init_waitqueue_head(&input->wq); +} + +static void ddb_output_init(struct ddb_port *port, int nr) +{ + struct ddb *dev = port->dev; + struct ddb_output *output = &dev->output[nr]; + output->nr = nr; + output->port = port; + output->dma_buf_num = OUTPUT_DMA_BUFS; + output->dma_buf_size = OUTPUT_DMA_SIZE; + + ddbwritel(0, TS_OUTPUT_CONTROL(nr)); + ddbwritel(2, TS_OUTPUT_CONTROL(nr)); + ddbwritel(0, TS_OUTPUT_CONTROL(nr)); + tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); + init_waitqueue_head(&output->wq); +} + +static void ddb_ports_init(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + port->dev = dev; + port->nr = i; + port->i2c = &dev->i2c[i]; + port->input[0] = &dev->input[2 * i]; + port->input[1] = &dev->input[2 * i + 1]; + port->output = &dev->output[i]; + + mutex_init(&port->i2c_gate_lock); + ddb_port_probe(port); + ddb_input_init(port, 2 * i); + ddb_input_init(port, 2 * i + 1); + ddb_output_init(port, i); + } +} + +static void ddb_ports_release(struct ddb *dev) +{ + int i; + struct ddb_port *port; + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + port->dev = dev; + tasklet_kill(&port->input[0]->tasklet); + tasklet_kill(&port->input[1]->tasklet); + tasklet_kill(&port->output->tasklet); + } +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void irq_handle_i2c(struct ddb *dev, int n) +{ + struct ddb_i2c *i2c = &dev->i2c[n]; + + i2c->done = 1; + wake_up(&i2c->wq); +} + +static irqreturn_t irq_handler(int irq, void *dev_id) +{ + struct ddb *dev = (struct ddb *) dev_id; + u32 s = ddbreadl(INTERRUPT_STATUS); + + if (!s) + return IRQ_NONE; + + do { + ddbwritel(s, INTERRUPT_ACK); + + if (s & 0x00000001) + irq_handle_i2c(dev, 0); + if (s & 0x00000002) + irq_handle_i2c(dev, 1); + if (s & 0x00000004) + irq_handle_i2c(dev, 2); + if (s & 0x00000008) + irq_handle_i2c(dev, 3); + + if (s & 0x00000100) + tasklet_schedule(&dev->input[0].tasklet); + if (s & 0x00000200) + tasklet_schedule(&dev->input[1].tasklet); + if (s & 0x00000400) + tasklet_schedule(&dev->input[2].tasklet); + if (s & 0x00000800) + tasklet_schedule(&dev->input[3].tasklet); + if (s & 0x00001000) + tasklet_schedule(&dev->input[4].tasklet); + if (s & 0x00002000) + tasklet_schedule(&dev->input[5].tasklet); + if (s & 0x00004000) + tasklet_schedule(&dev->input[6].tasklet); + if (s & 0x00008000) + tasklet_schedule(&dev->input[7].tasklet); + + if (s & 0x00010000) + tasklet_schedule(&dev->output[0].tasklet); + if (s & 0x00020000) + tasklet_schedule(&dev->output[1].tasklet); + if (s & 0x00040000) + tasklet_schedule(&dev->output[2].tasklet); + if (s & 0x00080000) + tasklet_schedule(&dev->output[3].tasklet); + + /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ + } while ((s = ddbreadl(INTERRUPT_STATUS))); + + return IRQ_HANDLED; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + u32 data, shift; + + if (wlen > 4) + ddbwritel(1, SPI_CONTROL); + while (wlen > 4) { + /* FIXME: check for big-endian */ + data = swab32(*(u32 *)wbuf); + wbuf += 4; + wlen -= 4; + ddbwritel(data, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + } + + if (rlen) + ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + else + ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + + data = 0; + shift = ((4 - wlen) * 8); + while (wlen) { + data <<= 8; + data |= *wbuf; + wlen--; + wbuf++; + } + if (shift) + data <<= shift; + ddbwritel(data, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + + if (!rlen) { + ddbwritel(0, SPI_CONTROL); + return 0; + } + if (rlen > 4) + ddbwritel(1, SPI_CONTROL); + + while (rlen > 4) { + ddbwritel(0xffffffff, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + data = ddbreadl(SPI_DATA); + *(u32 *) rbuf = swab32(data); + rbuf += 4; + rlen -= 4; + } + ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); + ddbwritel(0xffffffff, SPI_DATA); + while (ddbreadl(SPI_CONTROL) & 0x0004) + ; + + data = ddbreadl(SPI_DATA); + ddbwritel(0, SPI_CONTROL); + + if (rlen < 4) + data <<= ((4 - rlen) * 8); + + while (rlen > 0) { + *rbuf = ((data >> 24) & 0xff); + data <<= 8; + rbuf++; + rlen--; + } + return 0; +} + +#define DDB_MAGIC 'd' + +struct ddb_flashio { + __u8 *write_buf; + __u32 write_len; + __u8 *read_buf; + __u32 read_len; +}; + +#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) + +#define DDB_NAME "ddbridge" + +static u32 ddb_num; +static struct ddb *ddbs[32]; +static struct class *ddb_class; +static int ddb_major; + +static int ddb_open(struct inode *inode, struct file *file) +{ + struct ddb *dev = ddbs[iminor(inode)]; + + file->private_data = dev; + return 0; +} + +static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ddb *dev = file->private_data; + void *parg = (void *)arg; + int res; + + switch (cmd) { + case IOCTL_DDB_FLASHIO: + { + struct ddb_flashio fio; + u8 *rbuf, *wbuf; + + if (copy_from_user(&fio, parg, sizeof(fio))) + return -EFAULT; + + if (fio.write_len > 1028 || fio.read_len > 1028) + return -EINVAL; + if (fio.write_len + fio.read_len > 1028) + return -EINVAL; + + wbuf = &dev->iobuf[0]; + rbuf = wbuf + fio.write_len; + + if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) + return -EFAULT; + res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len); + if (res) + return res; + if (copy_to_user(fio.read_buf, rbuf, fio.read_len)) + return -EFAULT; + break; + } + default: + return -ENOTTY; + } + return 0; +} + +static const struct file_operations ddb_fops = { + .unlocked_ioctl = ddb_ioctl, + .open = ddb_open, +}; + +static char *ddb_devnode(struct device *device, umode_t *mode) +{ + struct ddb *dev = dev_get_drvdata(device); + + return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); +} + +static int ddb_class_create(void) +{ + ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); + if (ddb_major < 0) + return ddb_major; + + ddb_class = class_create(THIS_MODULE, DDB_NAME); + if (IS_ERR(ddb_class)) { + unregister_chrdev(ddb_major, DDB_NAME); + return -1; + } + ddb_class->devnode = ddb_devnode; + return 0; +} + +static void ddb_class_destroy(void) +{ + class_destroy(ddb_class); + unregister_chrdev(ddb_major, DDB_NAME); +} + +static int ddb_device_create(struct ddb *dev) +{ + dev->nr = ddb_num++; + dev->ddb_dev = device_create(ddb_class, NULL, + MKDEV(ddb_major, dev->nr), + dev, "ddbridge%d", dev->nr); + ddbs[dev->nr] = dev; + if (IS_ERR(dev->ddb_dev)) + return -1; + return 0; +} + +static void ddb_device_destroy(struct ddb *dev) +{ + ddb_num--; + if (IS_ERR(dev->ddb_dev)) + return; + device_destroy(ddb_class, MKDEV(ddb_major, 0)); +} + + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void ddb_unmap(struct ddb *dev) +{ + if (dev->regs) + iounmap(dev->regs); + vfree(dev); +} + + +static void __devexit ddb_remove(struct pci_dev *pdev) +{ + struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev); + + ddb_ports_detach(dev); + ddb_i2c_release(dev); + + ddbwritel(0, INTERRUPT_ENABLE); + free_irq(dev->pdev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi) + pci_disable_msi(dev->pdev); +#endif + ddb_ports_release(dev); + ddb_buffers_free(dev); + ddb_device_destroy(dev); + + ddb_unmap(dev); + pci_set_drvdata(pdev, 0); + pci_disable_device(pdev); +} + + +static int __devinit ddb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ddb *dev; + int stat = 0; + int irq_flag = IRQF_SHARED; + + if (pci_enable_device(pdev) < 0) + return -ENODEV; + + dev = vmalloc(sizeof(struct ddb)); + if (dev == NULL) + return -ENOMEM; + memset(dev, 0, sizeof(struct ddb)); + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + dev->info = (struct ddb_info *) id->driver_data; + printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name); + + dev->regs = ioremap(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + if (!dev->regs) { + stat = -ENOMEM; + goto fail; + } + printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); + +#ifdef CONFIG_PCI_MSI + if (pci_msi_enabled()) + stat = pci_enable_msi(dev->pdev); + if (stat) { + printk(KERN_INFO ": MSI not available.\n"); + } else { + irq_flag = 0; + dev->msi = 1; + } +#endif + stat = request_irq(dev->pdev->irq, irq_handler, + irq_flag, "DDBridge", (void *) dev); + if (stat < 0) + goto fail1; + ddbwritel(0, DMA_BASE_WRITE); + ddbwritel(0, DMA_BASE_READ); + ddbwritel(0xffffffff, INTERRUPT_ACK); + ddbwritel(0xfff0f, INTERRUPT_ENABLE); + ddbwritel(0, MSI1_ENABLE); + + if (ddb_i2c_init(dev) < 0) + goto fail1; + ddb_ports_init(dev); + if (ddb_buffers_alloc(dev) < 0) { + printk(KERN_INFO ": Could not allocate buffer memory\n"); + goto fail2; + } + if (ddb_ports_attach(dev) < 0) + goto fail3; + ddb_device_create(dev); + return 0; + +fail3: + ddb_ports_detach(dev); + printk(KERN_ERR "fail3\n"); + ddb_ports_release(dev); +fail2: + printk(KERN_ERR "fail2\n"); + ddb_buffers_free(dev); +fail1: + printk(KERN_ERR "fail1\n"); + if (dev->msi) + pci_disable_msi(dev->pdev); + free_irq(dev->pdev->irq, dev); +fail: + printk(KERN_ERR "fail\n"); + ddb_unmap(dev); + pci_set_drvdata(pdev, 0); + pci_disable_device(pdev); + return -1; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static struct ddb_info ddb_none = { + .type = DDB_NONE, + .name = "Digital Devices PCIe bridge", +}; + +static struct ddb_info ddb_octopus = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus DVB adapter", + .port_num = 4, +}; + +static struct ddb_info ddb_octopus_le = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus LE DVB adapter", + .port_num = 2, +}; + +static struct ddb_info ddb_v6 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6 DVB adapter", + .port_num = 3, +}; + +#define DDVID 0xdd01 /* Digital Devices Vendor ID */ + +#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ + .vendor = _vend, .device = _dev, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long)&_driverdata } + +static const struct pci_device_id ddb_id_tbl[] __devinitdata = { + DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), + DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), + /* in case sub-ids got deleted in flash */ + DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), + {0} +}; +MODULE_DEVICE_TABLE(pci, ddb_id_tbl); + + +static struct pci_driver ddb_pci_driver = { + .name = "DDBridge", + .id_table = ddb_id_tbl, + .probe = ddb_probe, + .remove = __devexit_p(ddb_remove), +}; + +static __init int module_init_ddbridge(void) +{ + printk(KERN_INFO "Digital Devices PCIE bridge driver, " + "Copyright (C) 2010-11 Digital Devices GmbH\n"); + if (ddb_class_create()) + return -1; + return pci_register_driver(&ddb_pci_driver); +} + +static __exit void module_exit_ddbridge(void) +{ + pci_unregister_driver(&ddb_pci_driver); + ddb_class_destroy(); +} + +module_init(module_init_ddbridge); +module_exit(module_exit_ddbridge); + +MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); +MODULE_AUTHOR("Ralph Metzler"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.5"); diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h new file mode 100644 index 00000000000..a3ccb318b50 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-regs.h @@ -0,0 +1,151 @@ +/* + * ddbridge-regs.h: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ + +/* Register Definitions */ + +#define CUR_REGISTERMAP_VERSION 0x10000 + +#define HARDWARE_VERSION 0x00 +#define REGISTERMAP_VERSION 0x04 + +/* ------------------------------------------------------------------------- */ +/* SPI Controller */ + +#define SPI_CONTROL 0x10 +#define SPI_DATA 0x14 + +/* ------------------------------------------------------------------------- */ + +/* Interrupt controller */ +/* How many MSI's are available depends on HW (Min 2 max 8) */ +/* How many are usable also depends on Host platform */ + +#define INTERRUPT_BASE (0x40) + +#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00) +#define MSI0_ENABLE (INTERRUPT_BASE + 0x00) +#define MSI1_ENABLE (INTERRUPT_BASE + 0x04) +#define MSI2_ENABLE (INTERRUPT_BASE + 0x08) +#define MSI3_ENABLE (INTERRUPT_BASE + 0x0C) +#define MSI4_ENABLE (INTERRUPT_BASE + 0x10) +#define MSI5_ENABLE (INTERRUPT_BASE + 0x14) +#define MSI6_ENABLE (INTERRUPT_BASE + 0x18) +#define MSI7_ENABLE (INTERRUPT_BASE + 0x1C) + +#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20) +#define INTERRUPT_ACK (INTERRUPT_BASE + 0x20) + +#define INTMASK_I2C1 (0x00000001) +#define INTMASK_I2C2 (0x00000002) +#define INTMASK_I2C3 (0x00000004) +#define INTMASK_I2C4 (0x00000008) + +#define INTMASK_CIRQ1 (0x00000010) +#define INTMASK_CIRQ2 (0x00000020) +#define INTMASK_CIRQ3 (0x00000040) +#define INTMASK_CIRQ4 (0x00000080) + +#define INTMASK_TSINPUT1 (0x00000100) +#define INTMASK_TSINPUT2 (0x00000200) +#define INTMASK_TSINPUT3 (0x00000400) +#define INTMASK_TSINPUT4 (0x00000800) +#define INTMASK_TSINPUT5 (0x00001000) +#define INTMASK_TSINPUT6 (0x00002000) +#define INTMASK_TSINPUT7 (0x00004000) +#define INTMASK_TSINPUT8 (0x00008000) + +#define INTMASK_TSOUTPUT1 (0x00010000) +#define INTMASK_TSOUTPUT2 (0x00020000) +#define INTMASK_TSOUTPUT3 (0x00040000) +#define INTMASK_TSOUTPUT4 (0x00080000) + +/* ------------------------------------------------------------------------- */ +/* I2C Master Controller */ + +#define I2C_BASE (0x80) /* Byte offset */ + +#define I2C_COMMAND (0x00) +#define I2C_TIMING (0x04) +#define I2C_TASKLENGTH (0x08) /* High read, low write */ +#define I2C_TASKADDRESS (0x0C) /* High read, low write */ + +#define I2C_MONITOR (0x1C) + +#define I2C_BASE_1 (I2C_BASE + 0x00) +#define I2C_BASE_2 (I2C_BASE + 0x20) +#define I2C_BASE_3 (I2C_BASE + 0x40) +#define I2C_BASE_4 (I2C_BASE + 0x60) + +#define I2C_BASE_N(i) (I2C_BASE + (i) * 0x20) + +#define I2C_TASKMEM_BASE (0x1000) /* Byte offset */ +#define I2C_TASKMEM_SIZE (0x1000) + +#define I2C_SPEED_400 (0x04030404) +#define I2C_SPEED_200 (0x09080909) +#define I2C_SPEED_154 (0x0C0B0C0C) +#define I2C_SPEED_100 (0x13121313) +#define I2C_SPEED_77 (0x19181919) +#define I2C_SPEED_50 (0x27262727) + + +/* ------------------------------------------------------------------------- */ +/* DMA Controller */ + +#define DMA_BASE_WRITE (0x100) +#define DMA_BASE_READ (0x140) + +#define DMA_CONTROL (0x00) /* 64 */ +#define DMA_ERROR (0x04) /* 65 ( only read instance ) */ + +#define DMA_DIAG_CONTROL (0x1C) /* 71 */ +#define DMA_DIAG_PACKETCOUNTER_LOW (0x20) /* 72 */ +#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24) /* 73 */ +#define DMA_DIAG_TIMECOUNTER_LOW (0x28) /* 74 */ +#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C) /* 75 */ +#define DMA_DIAG_RECHECKCOUNTER (0x30) /* 76 ( Split completions on read ) */ +#define DMA_DIAG_WAITTIMEOUTINIT (0x34) /* 77 */ +#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38) /* 78 */ +#define DMA_DIAG_WAITCOUNTER (0x3C) /* 79 */ + +/* ------------------------------------------------------------------------- */ +/* DMA Buffer */ + +#define TS_INPUT_BASE (0x200) +#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 16 + 0x00) + +#define TS_OUTPUT_BASE (0x280) +#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 16 + 0x00) + +#define DMA_BUFFER_BASE (0x300) + +#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 16 + 0x00) +#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 16 + 0x04) +#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 16 + 0x08) +#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 16 + 0x0c) + +#define DMA_BASE_ADDRESS_TABLE (0x2000) +#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) + diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h new file mode 100644 index 00000000000..8b1b41d2a52 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -0,0 +1,185 @@ +/* + * ddbridge.h: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _DDBRIDGE_H_ +#define _DDBRIDGE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_ringbuffer.h" +#include "dvb_ca_en50221.h" +#include "dvb_net.h" +#include "cxd2099.h" + +#define DDB_MAX_I2C 4 +#define DDB_MAX_PORT 4 +#define DDB_MAX_INPUT 8 +#define DDB_MAX_OUTPUT 4 + +struct ddb_info { + int type; +#define DDB_NONE 0 +#define DDB_OCTOPUS 1 + char *name; + int port_num; + u32 port_type[DDB_MAX_PORT]; +}; + +/* DMA_SIZE MUST be divisible by 188 and 128 !!! */ + +#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ +#define INPUT_DMA_BUFS 8 +#define INPUT_DMA_SIZE (128*47*21) + +#define OUTPUT_DMA_MAX_BUFS 32 +#define OUTPUT_DMA_BUFS 8 +#define OUTPUT_DMA_SIZE (128*47*21) + +struct ddb; +struct ddb_port; + +struct ddb_input { + struct ddb_port *port; + u32 nr; + int attached; + + dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; + u8 *vbuf[INPUT_DMA_MAX_BUFS]; + u32 dma_buf_num; + u32 dma_buf_size; + + struct tasklet_struct tasklet; + spinlock_t lock; + wait_queue_head_t wq; + int running; + u32 stat; + u32 cbuf; + u32 coff; + + struct dvb_adapter adap; + struct dvb_device *dev; + struct dvb_frontend *fe; + struct dvb_frontend *fe2; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvbnet; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int users; + int (*gate_ctrl)(struct dvb_frontend *, int); +}; + +struct ddb_output { + struct ddb_port *port; + u32 nr; + dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; + u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; + u32 dma_buf_num; + u32 dma_buf_size; + struct tasklet_struct tasklet; + spinlock_t lock; + wait_queue_head_t wq; + int running; + u32 stat; + u32 cbuf; + u32 coff; + + struct dvb_adapter adap; + struct dvb_device *dev; +}; + +struct ddb_i2c { + struct ddb *dev; + u32 nr; + struct i2c_adapter adap; + struct i2c_adapter adap2; + u32 regs; + u32 rbuf; + u32 wbuf; + int done; + wait_queue_head_t wq; +}; + +struct ddb_port { + struct ddb *dev; + u32 nr; + struct ddb_i2c *i2c; + struct mutex i2c_gate_lock; + u32 class; +#define DDB_PORT_NONE 0 +#define DDB_PORT_CI 1 +#define DDB_PORT_TUNER 2 + u32 type; +#define DDB_TUNER_NONE 0 +#define DDB_TUNER_DVBS_ST 1 +#define DDB_TUNER_DVBS_ST_AA 2 +#define DDB_TUNER_DVBCT_TR 16 +#define DDB_TUNER_DVBCT_ST 17 + u32 adr; + + struct ddb_input *input[2]; + struct ddb_output *output; + struct dvb_ca_en50221 *en; +}; + +struct ddb { + struct pci_dev *pdev; + unsigned char *regs; + struct ddb_port port[DDB_MAX_PORT]; + struct ddb_i2c i2c[DDB_MAX_I2C]; + struct ddb_input input[DDB_MAX_INPUT]; + struct ddb_output output[DDB_MAX_OUTPUT]; + + struct device *ddb_dev; + int nr; + u8 iobuf[1028]; + + struct ddb_info *info; + int msi; +}; + +/****************************************************************************/ + +#define ddbwritel(_val, _adr) writel((_val), \ + (char *) (dev->regs+(_adr))) +#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) +#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ + (dev->regs+(_adr)), (_src), (_count)) +#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ + (dev->regs+(_adr)), (_count)) + +/****************************************************************************/ + +#endif diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig new file mode 100644 index 00000000000..f3de0a4d63f --- /dev/null +++ b/drivers/media/pci/dm1105/Kconfig @@ -0,0 +1,20 @@ +config DVB_DM1105 + tristate "SDMC DM1105 based PCI cards" + depends on DVB_CORE && PCI && I2C + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + depends on RC_CORE + help + Support for cards based on the SDMC DM1105 PCI chip like + DvbWorld 2002 + + 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/drivers/media/pci/dm1105/Makefile b/drivers/media/pci/dm1105/Makefile new file mode 100644 index 00000000000..327585143c8 --- /dev/null +++ b/drivers/media/pci/dm1105/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_DM1105) += dm1105.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c new file mode 100644 index 00000000000..a609b3a9b14 --- /dev/null +++ b/drivers/media/pci/dm1105/dm1105.c @@ -0,0 +1,1248 @@ +/* + * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip + * + * Copyright (C) 2008 Igor M. Liplianin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "dvb-pll.h" + +#include "stv0299.h" +#include "stv0288.h" +#include "stb6000.h" +#include "si21xx.h" +#include "cx24116.h" +#include "z0194a.h" +#include "ds3000.h" + +#define MODULE_NAME "dm1105" + +#define UNSET (-1U) + +#define DM1105_BOARD_NOAUTO UNSET +#define DM1105_BOARD_UNKNOWN 0 +#define DM1105_BOARD_DVBWORLD_2002 1 +#define DM1105_BOARD_DVBWORLD_2004 2 +#define DM1105_BOARD_AXESS_DM05 3 +#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO 4 + +/* ----------------------------------------------- */ +/* + * PCI ID's + */ +#ifndef PCI_VENDOR_ID_TRIGEM +#define PCI_VENDOR_ID_TRIGEM 0x109f +#endif +#ifndef PCI_VENDOR_ID_AXESS +#define PCI_VENDOR_ID_AXESS 0x195d +#endif +#ifndef PCI_DEVICE_ID_DM1105 +#define PCI_DEVICE_ID_DM1105 0x036f +#endif +#ifndef PCI_DEVICE_ID_DW2002 +#define PCI_DEVICE_ID_DW2002 0x2002 +#endif +#ifndef PCI_DEVICE_ID_DW2004 +#define PCI_DEVICE_ID_DW2004 0x2004 +#endif +#ifndef PCI_DEVICE_ID_DM05 +#define PCI_DEVICE_ID_DM05 0x1105 +#endif +/* ----------------------------------------------- */ +/* sdmc dm1105 registers */ + +/* TS Control */ +#define DM1105_TSCTR 0x00 +#define DM1105_DTALENTH 0x04 + +/* GPIO Interface */ +#define DM1105_GPIOVAL 0x08 +#define DM1105_GPIOCTR 0x0c + +/* PID serial number */ +#define DM1105_PIDN 0x10 + +/* Odd-even secret key select */ +#define DM1105_CWSEL 0x14 + +/* Host Command Interface */ +#define DM1105_HOST_CTR 0x18 +#define DM1105_HOST_AD 0x1c + +/* PCI Interface */ +#define DM1105_CR 0x30 +#define DM1105_RST 0x34 +#define DM1105_STADR 0x38 +#define DM1105_RLEN 0x3c +#define DM1105_WRP 0x40 +#define DM1105_INTCNT 0x44 +#define DM1105_INTMAK 0x48 +#define DM1105_INTSTS 0x4c + +/* CW Value */ +#define DM1105_ODD 0x50 +#define DM1105_EVEN 0x58 + +/* PID Value */ +#define DM1105_PID 0x60 + +/* IR Control */ +#define DM1105_IRCTR 0x64 +#define DM1105_IRMODE 0x68 +#define DM1105_SYSTEMCODE 0x6c +#define DM1105_IRCODE 0x70 + +/* Unknown Values */ +#define DM1105_ENCRYPT 0x74 +#define DM1105_VER 0x7c + +/* I2C Interface */ +#define DM1105_I2CCTR 0x80 +#define DM1105_I2CSTS 0x81 +#define DM1105_I2CDAT 0x82 +#define DM1105_I2C_RA 0x83 +/* ----------------------------------------------- */ +/* Interrupt Mask Bits */ + +#define INTMAK_TSIRQM 0x01 +#define INTMAK_HIRQM 0x04 +#define INTMAK_IRM 0x08 +#define INTMAK_ALLMASK (INTMAK_TSIRQM | \ + INTMAK_HIRQM | \ + INTMAK_IRM) +#define INTMAK_NONEMASK 0x00 + +/* Interrupt Status Bits */ +#define INTSTS_TSIRQ 0x01 +#define INTSTS_HIRQ 0x04 +#define INTSTS_IR 0x08 + +/* IR Control Bits */ +#define DM1105_IR_EN 0x01 +#define DM1105_SYS_CHK 0x02 +#define DM1105_REP_FLG 0x08 + +/* EEPROM addr */ +#define IIC_24C01_addr 0xa0 +/* Max board count */ +#define DM1105_MAX 0x04 + +#define DRIVER_NAME "dm1105" +#define DM1105_I2C_GPIO_NAME "dm1105-gpio" + +#define DM1105_DMA_PACKETS 47 +#define DM1105_DMA_PACKET_LENGTH (128*4) +#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) + +/* */ +#define GPIO08 (1 << 8) +#define GPIO13 (1 << 13) +#define GPIO14 (1 << 14) +#define GPIO15 (1 << 15) +#define GPIO16 (1 << 16) +#define GPIO17 (1 << 17) +#define GPIO_ALL 0x03ffff + +/* GPIO's for LNB power control */ +#define DM1105_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) +#define DM1105_LNB_OFF GPIO17 +#define DM1105_LNB_13V (GPIO16 | GPIO08) +#define DM1105_LNB_18V GPIO08 + +/* GPIO's for LNB power control for Axess DM05 */ +#define DM05_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) +#define DM05_LNB_OFF GPIO17/* actually 13v */ +#define DM05_LNB_13V GPIO17 +#define DM05_LNB_18V (GPIO17 | GPIO16) + +/* GPIO's for LNB power control for unbranded with I2C on GPIO */ +#define UNBR_LNB_MASK (GPIO17 | GPIO16) +#define UNBR_LNB_OFF 0 +#define UNBR_LNB_13V GPIO17 +#define UNBR_LNB_18V (GPIO17 | GPIO16) + +static unsigned int card[] = {[0 ... 3] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); + +static int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); + +static unsigned int dm1105_devcount; + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct dm1105_board { + char *name; + struct { + u32 mask, off, v13, v18; + } lnb; + u32 gpio_scl, gpio_sda; +}; + +struct dm1105_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +static const struct dm1105_board dm1105_boards[] = { + [DM1105_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + .lnb = { + .mask = DM1105_LNB_MASK, + .off = DM1105_LNB_OFF, + .v13 = DM1105_LNB_13V, + .v18 = DM1105_LNB_18V, + }, + }, + [DM1105_BOARD_DVBWORLD_2002] = { + .name = "DVBWorld PCI 2002", + .lnb = { + .mask = DM1105_LNB_MASK, + .off = DM1105_LNB_OFF, + .v13 = DM1105_LNB_13V, + .v18 = DM1105_LNB_18V, + }, + }, + [DM1105_BOARD_DVBWORLD_2004] = { + .name = "DVBWorld PCI 2004", + .lnb = { + .mask = DM1105_LNB_MASK, + .off = DM1105_LNB_OFF, + .v13 = DM1105_LNB_13V, + .v18 = DM1105_LNB_18V, + }, + }, + [DM1105_BOARD_AXESS_DM05] = { + .name = "Axess/EasyTv DM05", + .lnb = { + .mask = DM05_LNB_MASK, + .off = DM05_LNB_OFF, + .v13 = DM05_LNB_13V, + .v18 = DM05_LNB_18V, + }, + }, + [DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = { + .name = "Unbranded DM1105 with i2c on GPIOs", + .lnb = { + .mask = UNBR_LNB_MASK, + .off = UNBR_LNB_OFF, + .v13 = UNBR_LNB_13V, + .v18 = UNBR_LNB_18V, + }, + .gpio_scl = GPIO14, + .gpio_sda = GPIO13, + }, +}; + +static const struct dm1105_subid dm1105_subids[] = { + { + .subvendor = 0x0000, + .subdevice = 0x2002, + .card = DM1105_BOARD_DVBWORLD_2002, + }, { + .subvendor = 0x0001, + .subdevice = 0x2002, + .card = DM1105_BOARD_DVBWORLD_2002, + }, { + .subvendor = 0x0000, + .subdevice = 0x2004, + .card = DM1105_BOARD_DVBWORLD_2004, + }, { + .subvendor = 0x0001, + .subdevice = 0x2004, + .card = DM1105_BOARD_DVBWORLD_2004, + }, { + .subvendor = 0x195d, + .subdevice = 0x1105, + .card = DM1105_BOARD_AXESS_DM05, + }, +}; + +static void dm1105_card_list(struct pci_dev *pci) +{ + int i; + + if (0 == pci->subsystem_vendor && + 0 == pci->subsystem_device) { + printk(KERN_ERR + "dm1105: Your board has no valid PCI Subsystem ID\n" + "dm1105: and thus can't be autodetected\n" + "dm1105: Please pass card= insmod option to\n" + "dm1105: workaround that. Redirect complaints to\n" + "dm1105: the vendor of the TV card. Best regards,\n" + "dm1105: -- tux\n"); + } else { + printk(KERN_ERR + "dm1105: Your board isn't known (yet) to the driver.\n" + "dm1105: You can try to pick one of the existing\n" + "dm1105: card configs via card= insmod option.\n" + "dm1105: Updating to the latest version might help\n" + "dm1105: as well.\n"); + } + printk(KERN_ERR "Here is a list of valid choices for the card= " + "insmod option:\n"); + for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++) + printk(KERN_ERR "dm1105: card=%d -> %s\n", + i, dm1105_boards[i].name); +} + +/* infrared remote control */ +struct infrared { + struct rc_dev *dev; + char input_phys[32]; + struct work_struct work; + u32 ir_command; +}; + +struct dm1105_dev { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* ir */ + struct infrared ir; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + unsigned int boardnr; + int nr; + + /* i2c */ + struct i2c_adapter i2c_adap; + struct i2c_adapter i2c_bb_adap; + struct i2c_algo_bit_data i2c_bit; + + /* irq */ + struct work_struct work; + struct workqueue_struct *wq; + char wqn[16]; + + /* dma */ + dma_addr_t dma_addr; + unsigned char *ts_buf; + u32 wrp; + u32 nextwrp; + u32 buffer_size; + unsigned int PacketErrorCount; + unsigned int dmarst; + spinlock_t lock; +}; + +#define dm_io_mem(reg) ((unsigned long)(&dev->io_mem[reg])) + +#define dm_readb(reg) inb(dm_io_mem(reg)) +#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg))) + +#define dm_readw(reg) inw(dm_io_mem(reg)) +#define dm_writew(reg, value) outw((value), (dm_io_mem(reg))) + +#define dm_readl(reg) inl(dm_io_mem(reg)) +#define dm_writel(reg, value) outl((value), (dm_io_mem(reg))) + +#define dm_andorl(reg, mask, value) \ + outl((inl(dm_io_mem(reg)) & ~(mask)) |\ + ((value) & (mask)), (dm_io_mem(reg))) + +#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit)) +#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0) + +/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines, + so we can use only 3 GPIO's from GPIO15 to GPIO17. + Here I don't check whether HOST is enebled as it is not implemented yet. + */ +static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff); + +} + +static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff); + +} + +static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val); + +} + +static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff; + + return 0; +} + +static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if ((mask & 0x0003ffff) && asoutput) + dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff); + else if ((mask & 0x0003ffff) && !asoutput) + dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff); + +} + +static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state) +{ + if (state) + dm1105_gpio_enable(dev, line, 0); + else { + dm1105_gpio_enable(dev, line, 1); + dm1105_gpio_clear(dev, line); + } +} + +static void dm1105_setsda(void *data, int state) +{ + struct dm1105_dev *dev = data; + + dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state); +} + +static void dm1105_setscl(void *data, int state) +{ + struct dm1105_dev *dev = data; + + dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state); +} + +static int dm1105_getsda(void *data) +{ + struct dm1105_dev *dev = data; + + return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda) + ? 1 : 0; +} + +static int dm1105_getscl(void *data) +{ + struct dm1105_dev *dev = data; + + return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl) + ? 1 : 0; +} + +static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct dm1105_dev *dev ; + + int addr, rc, i, j, k, len, byte, data; + u8 status; + + dev = i2c_adap->algo_data; + for (i = 0; i < num; i++) { + dm_writeb(DM1105_I2CCTR, 0x00); + if (msgs[i].flags & I2C_M_RD) { + /* read bytes */ + addr = msgs[i].addr << 1; + addr |= 1; + dm_writeb(DM1105_I2CDAT, addr); + for (byte = 0; byte < msgs[i].len; byte++) + dm_writeb(DM1105_I2CDAT + byte + 1, 0); + + dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); + for (j = 0; j < 55; j++) { + mdelay(10); + status = dm_readb(DM1105_I2CSTS); + if ((status & 0xc0) == 0x40) + break; + } + if (j >= 55) + return -1; + + for (byte = 0; byte < msgs[i].len; byte++) { + rc = dm_readb(DM1105_I2CDAT + byte + 1); + if (rc < 0) + goto err; + msgs[i].buf[byte] = rc; + } + } else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { + /* prepaired for cx24116 firmware */ + /* Write in small blocks */ + len = msgs[i].len - 1; + k = 1; + do { + dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); + dm_writeb(DM1105_I2CDAT + 1, 0xf7); + for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { + data = msgs[i].buf[k + byte]; + dm_writeb(DM1105_I2CDAT + byte + 2, data); + } + dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len)); + for (j = 0; j < 25; j++) { + mdelay(10); + status = dm_readb(DM1105_I2CSTS); + if ((status & 0xc0) == 0x40) + break; + } + + if (j >= 25) + return -1; + + k += 48; + len -= 48; + } while (len > 0); + } else { + /* write bytes */ + dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); + for (byte = 0; byte < msgs[i].len; byte++) { + data = msgs[i].buf[byte]; + dm_writeb(DM1105_I2CDAT + byte + 1, data); + } + dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); + for (j = 0; j < 25; j++) { + mdelay(10); + status = dm_readb(DM1105_I2CSTS); + if ((status & 0xc0) == 0x40) + break; + } + + if (j >= 25) + return -1; + } + } + return num; + err: + return rc; +} + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dm1105_algo = { + .master_xfer = dm1105_i2c_xfer, + .functionality = functionality, +}; + +static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct dm1105_dev, demux); +} + +static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct dm1105_dev, dvb_adapter); +} + +static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); + + dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1); + if (voltage == SEC_VOLTAGE_18) + dm1105_gpio_andor(dev, + dm1105_boards[dev->boardnr].lnb.mask, + dm1105_boards[dev->boardnr].lnb.v18); + else if (voltage == SEC_VOLTAGE_13) + dm1105_gpio_andor(dev, + dm1105_boards[dev->boardnr].lnb.mask, + dm1105_boards[dev->boardnr].lnb.v13); + else + dm1105_gpio_andor(dev, + dm1105_boards[dev->boardnr].lnb.mask, + dm1105_boards[dev->boardnr].lnb.off); + + return 0; +} + +static void dm1105_set_dma_addr(struct dm1105_dev *dev) +{ + dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr)); +} + +static int __devinit dm1105_dma_map(struct dm1105_dev *dev) +{ + dev->ts_buf = pci_alloc_consistent(dev->pdev, + 6 * DM1105_DMA_BYTES, + &dev->dma_addr); + + return !dev->ts_buf; +} + +static void dm1105_dma_unmap(struct dm1105_dev *dev) +{ + pci_free_consistent(dev->pdev, + 6 * DM1105_DMA_BYTES, + dev->ts_buf, + dev->dma_addr); +} + +static void dm1105_enable_irqs(struct dm1105_dev *dev) +{ + dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK); + dm_writeb(DM1105_CR, 1); +} + +static void dm1105_disable_irqs(struct dm1105_dev *dev) +{ + dm_writeb(DM1105_INTMAK, INTMAK_IRM); + dm_writeb(DM1105_CR, 0); +} + +static int dm1105_start_feed(struct dvb_demux_feed *f) +{ + struct dm1105_dev *dev = feed_to_dm1105_dev(f); + + if (dev->full_ts_users++ == 0) + dm1105_enable_irqs(dev); + + return 0; +} + +static int dm1105_stop_feed(struct dvb_demux_feed *f) +{ + struct dm1105_dev *dev = feed_to_dm1105_dev(f); + + if (--dev->full_ts_users == 0) + dm1105_disable_irqs(dev); + + return 0; +} + +/* ir work handler */ +static void dm1105_emit_key(struct work_struct *work) +{ + struct infrared *ir = container_of(work, struct infrared, work); + u32 ircom = ir->ir_command; + u8 data; + + if (ir_debug) + printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom); + + data = (ircom >> 8) & 0x7f; + + rc_keydown(ir->dev, data, 0); +} + +/* work handler */ +static void dm1105_dmx_buffer(struct work_struct *work) +{ + struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work); + unsigned int nbpackets; + u32 oldwrp = dev->wrp; + u32 nextwrp = dev->nextwrp; + + if (!((dev->ts_buf[oldwrp] == 0x47) && + (dev->ts_buf[oldwrp + 188] == 0x47) && + (dev->ts_buf[oldwrp + 188 * 2] == 0x47))) { + dev->PacketErrorCount++; + /* bad packet found */ + if ((dev->PacketErrorCount >= 2) && + (dev->dmarst == 0)) { + dm_writeb(DM1105_RST, 1); + dev->wrp = 0; + dev->PacketErrorCount = 0; + dev->dmarst = 0; + return; + } + } + + if (nextwrp < oldwrp) { + memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp); + nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188; + } else + nbpackets = (nextwrp - oldwrp) / 188; + + dev->wrp = nextwrp; + dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets); +} + +static irqreturn_t dm1105_irq(int irq, void *dev_id) +{ + struct dm1105_dev *dev = dev_id; + + /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ + unsigned int intsts = dm_readb(DM1105_INTSTS); + dm_writeb(DM1105_INTSTS, intsts); + + switch (intsts) { + case INTSTS_TSIRQ: + case (INTSTS_TSIRQ | INTSTS_IR): + dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR); + queue_work(dev->wq, &dev->work); + break; + case INTSTS_IR: + dev->ir.ir_command = dm_readl(DM1105_IRCODE); + schedule_work(&dev->ir.work); + break; + } + + return IRQ_HANDLED; +} + +int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) +{ + struct rc_dev *dev; + int err = -ENOMEM; + + dev = rc_allocate_device(); + if (!dev) + return -ENOMEM; + + snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), + "pci-%s/ir0", pci_name(dm1105->pdev)); + + dev->driver_name = MODULE_NAME; + dev->map_name = RC_MAP_DM1105_NEC; + dev->driver_type = RC_DRIVER_SCANCODE; + dev->input_name = "DVB on-card IR receiver"; + dev->input_phys = dm1105->ir.input_phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.version = 1; + if (dm1105->pdev->subsystem_vendor) { + dev->input_id.vendor = dm1105->pdev->subsystem_vendor; + dev->input_id.product = dm1105->pdev->subsystem_device; + } else { + dev->input_id.vendor = dm1105->pdev->vendor; + dev->input_id.product = dm1105->pdev->device; + } + dev->dev.parent = &dm1105->pdev->dev; + + INIT_WORK(&dm1105->ir.work, dm1105_emit_key); + + err = rc_register_device(dev); + if (err < 0) { + rc_free_device(dev); + return err; + } + + dm1105->ir.dev = dev; + return 0; +} + +void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105) +{ + rc_unregister_device(dm1105->ir.dev); +} + +static int __devinit dm1105_hw_init(struct dm1105_dev *dev) +{ + dm1105_disable_irqs(dev); + + dm_writeb(DM1105_HOST_CTR, 0); + + /*DATALEN 188,*/ + dm_writeb(DM1105_DTALENTH, 188); + /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/ + dm_writew(DM1105_TSCTR, 0xc10a); + + /* map DMA and set address */ + dm1105_dma_map(dev); + dm1105_set_dma_addr(dev); + /* big buffer */ + dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES); + dm_writeb(DM1105_INTCNT, 47); + + /* IR NEC mode enable */ + dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK)); + dm_writeb(DM1105_IRMODE, 0); + dm_writew(DM1105_SYSTEMCODE, 0); + + return 0; +} + +static void dm1105_hw_exit(struct dm1105_dev *dev) +{ + dm1105_disable_irqs(dev); + + /* IR disable */ + dm_writeb(DM1105_IRCTR, 0); + dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK); + + dm1105_dma_unmap(dev); +} + +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static struct stv0288_config earda_config = { + .demod_address = 0x68, + .min_delay_ms = 100, +}; + +static struct si21xx_config serit_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + +}; + +static struct cx24116_config serit_sp2633_config = { + .demod_address = 0x55, +}; + +static struct ds3000_config dvbworld_ds3000_config = { + .demod_address = 0x68, +}; + +static int __devinit frontend_init(struct dm1105_dev *dev) +{ + int ret; + + switch (dev->boardnr) { + case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO: + dm1105_gpio_enable(dev, GPIO15, 1); + dm1105_gpio_clear(dev, GPIO15); + msleep(100); + dm1105_gpio_set(dev, GPIO15); + msleep(200); + dev->fe = dvb_attach( + stv0299_attach, &sharp_z0194a_config, + &dev->i2c_bb_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(dvb_pll_attach, dev->fe, 0x60, + &dev->i2c_bb_adap, DVB_PLL_OPERA1); + break; + } + + dev->fe = dvb_attach( + stv0288_attach, &earda_config, + &dev->i2c_bb_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(stb6000_attach, dev->fe, 0x61, + &dev->i2c_bb_adap); + break; + } + + dev->fe = dvb_attach( + si21xx_attach, &serit_config, + &dev->i2c_bb_adap); + if (dev->fe) + dev->fe->ops.set_voltage = dm1105_set_voltage; + break; + case DM1105_BOARD_DVBWORLD_2004: + dev->fe = dvb_attach( + cx24116_attach, &serit_sp2633_config, + &dev->i2c_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + break; + } + + dev->fe = dvb_attach( + ds3000_attach, &dvbworld_ds3000_config, + &dev->i2c_adap); + if (dev->fe) + dev->fe->ops.set_voltage = dm1105_set_voltage; + + break; + case DM1105_BOARD_DVBWORLD_2002: + case DM1105_BOARD_AXESS_DM05: + default: + dev->fe = dvb_attach( + stv0299_attach, &sharp_z0194a_config, + &dev->i2c_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(dvb_pll_attach, dev->fe, 0x60, + &dev->i2c_adap, DVB_PLL_OPERA1); + break; + } + + dev->fe = dvb_attach( + stv0288_attach, &earda_config, + &dev->i2c_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(stb6000_attach, dev->fe, 0x61, + &dev->i2c_adap); + break; + } + + dev->fe = dvb_attach( + si21xx_attach, &serit_config, + &dev->i2c_adap); + if (dev->fe) + dev->fe->ops.set_voltage = dm1105_set_voltage; + + } + + if (!dev->fe) { + dev_err(&dev->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + + ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe); + if (ret < 0) { + if (dev->fe->ops.release) + dev->fe->ops.release(dev->fe); + dev->fe = NULL; + return ret; + } + + return 0; +} + +static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac) +{ + static u8 command[1] = { 0x28 }; + + struct i2c_msg msg[] = { + { + .addr = IIC_24C01_addr >> 1, + .flags = 0, + .buf = command, + .len = 1 + }, { + .addr = IIC_24C01_addr >> 1, + .flags = I2C_M_RD, + .buf = mac, + .len = 6 + }, + }; + + dm1105_i2c_xfer(&dev->i2c_adap, msg , 2); + dev_info(&dev->pdev->dev, "MAC %pM\n", mac); +} + +static int __devinit dm1105_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct dm1105_dev *dev; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + int i; + + dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + /* board config */ + dev->nr = dm1105_devcount; + dev->boardnr = UNSET; + if (card[dev->nr] < ARRAY_SIZE(dm1105_boards)) + dev->boardnr = card[dev->nr]; + for (i = 0; UNSET == dev->boardnr && + i < ARRAY_SIZE(dm1105_subids); i++) + if (pdev->subsystem_vendor == + dm1105_subids[i].subvendor && + pdev->subsystem_device == + dm1105_subids[i].subdevice) + dev->boardnr = dm1105_subids[i].card; + + if (UNSET == dev->boardnr) { + dev->boardnr = DM1105_BOARD_UNKNOWN; + dm1105_card_list(pdev); + } + + dm1105_devcount++; + dev->pdev = pdev; + dev->buffer_size = 5 * DM1105_DMA_BYTES; + dev->PacketErrorCount = 0; + dev->dmarst = 0; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + 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; + + dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!dev->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + spin_lock_init(&dev->lock); + pci_set_drvdata(pdev, dev); + + ret = dm1105_hw_init(dev); + if (ret < 0) + goto err_pci_iounmap; + + /* i2c */ + i2c_set_adapdata(&dev->i2c_adap, dev); + strcpy(dev->i2c_adap.name, DRIVER_NAME); + dev->i2c_adap.owner = THIS_MODULE; + dev->i2c_adap.dev.parent = &pdev->dev; + dev->i2c_adap.algo = &dm1105_algo; + dev->i2c_adap.algo_data = dev; + ret = i2c_add_adapter(&dev->i2c_adap); + + if (ret < 0) + goto err_dm1105_hw_exit; + + i2c_set_adapdata(&dev->i2c_bb_adap, dev); + strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME); + dev->i2c_bb_adap.owner = THIS_MODULE; + dev->i2c_bb_adap.dev.parent = &pdev->dev; + dev->i2c_bb_adap.algo_data = &dev->i2c_bit; + dev->i2c_bit.data = dev; + dev->i2c_bit.setsda = dm1105_setsda; + dev->i2c_bit.setscl = dm1105_setscl; + dev->i2c_bit.getsda = dm1105_getsda; + dev->i2c_bit.getscl = dm1105_getscl; + dev->i2c_bit.udelay = 10; + dev->i2c_bit.timeout = 10; + + /* Raise SCL and SDA */ + dm1105_setsda(dev, 1); + dm1105_setscl(dev, 1); + + ret = i2c_bit_add_bus(&dev->i2c_bb_adap); + if (ret < 0) + goto err_i2c_del_adapter; + + /* dvb */ + ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME, + THIS_MODULE, &pdev->dev, adapter_nr); + if (ret < 0) + goto err_i2c_del_adapters; + + dvb_adapter = &dev->dvb_adapter; + + dm1105_read_mac(dev, dvb_adapter->proposed_mac); + + dvbdemux = &dev->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = dm1105_start_feed; + dvbdemux->stop_feed = dm1105_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + dev->dmxdev.filternum = 256; + dev->dmxdev.demux = dmx; + dev->dmxdev.capabilities = 0; + + ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + dev->hw_frontend.source = DMX_FRONTEND_0; + + ret = dmx->add_frontend(dmx, &dev->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + dev->mem_frontend.source = DMX_MEMORY_FE; + + ret = dmx->add_frontend(dmx, &dev->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dev->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); + if (ret < 0) + goto err_disconnect_frontend; + + ret = frontend_init(dev); + if (ret < 0) + goto err_dvb_net; + + dm1105_ir_init(dev); + + INIT_WORK(&dev->work, dm1105_dmx_buffer); + sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); + dev->wq = create_singlethread_workqueue(dev->wqn); + if (!dev->wq) + goto err_dvb_net; + + ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED, + DRIVER_NAME, dev); + if (ret < 0) + goto err_workqueue; + + return 0; + +err_workqueue: + destroy_workqueue(dev->wq); +err_dvb_net: + dvb_net_release(&dev->dvbnet); +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dev->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dev->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dev->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_i2c_del_adapters: + i2c_del_adapter(&dev->i2c_bb_adap); +err_i2c_del_adapter: + i2c_del_adapter(&dev->i2c_adap); +err_dm1105_hw_exit: + dm1105_hw_exit(dev); +err_pci_iounmap: + pci_iounmap(pdev, dev->io_mem); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(dev); + return ret; +} + +static void __devexit dm1105_remove(struct pci_dev *pdev) +{ + struct dm1105_dev *dev = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &dev->dvb_adapter; + struct dvb_demux *dvbdemux = &dev->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dm1105_ir_exit(dev); + dmx->close(dmx); + dvb_net_release(&dev->dvbnet); + if (dev->fe) + dvb_unregister_frontend(dev->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &dev->mem_frontend); + dmx->remove_frontend(dmx, &dev->hw_frontend); + dvb_dmxdev_release(&dev->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + if (&dev->i2c_adap) + i2c_del_adapter(&dev->i2c_adap); + + dm1105_hw_exit(dev); + synchronize_irq(pdev->irq); + free_irq(pdev->irq, dev); + pci_iounmap(pdev, dev->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + dm1105_devcount--; + kfree(dev); +} + +static struct pci_device_id dm1105_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_TRIGEM, + .device = PCI_DEVICE_ID_DM1105, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + .vendor = PCI_VENDOR_ID_AXESS, + .device = PCI_DEVICE_ID_DM05, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, dm1105_id_table); + +static struct pci_driver dm1105_driver = { + .name = DRIVER_NAME, + .id_table = dm1105_id_table, + .probe = dm1105_probe, + .remove = __devexit_p(dm1105_remove), +}; + +static int __init dm1105_init(void) +{ + return pci_register_driver(&dm1105_driver); +} + +static void __exit dm1105_exit(void) +{ + pci_unregister_driver(&dm1105_driver); +} + +module_init(dm1105_init); +module_exit(dm1105_exit); + +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_DESCRIPTION("SDMC DM1105 DVB driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/Kconfig b/drivers/media/pci/mantis/Kconfig new file mode 100644 index 00000000000..a13a5050313 --- /dev/null +++ b/drivers/media/pci/mantis/Kconfig @@ -0,0 +1,38 @@ +config MANTIS_CORE + tristate "Mantis/Hopper PCI bridge based devices" + depends on PCI && I2C && INPUT && RC_CORE + + help + Support for PCI cards based on the Mantis and Hopper PCi bridge. + + Say Y if you own such a device and want to use it. + +config DVB_MANTIS + tristate "MANTIS based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C + select DVB_MB86A16 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_TDA665x if !DVB_FE_CUSTOMISE + select DVB_TDA10021 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_PLL + help + Support for PCI cards based on the Mantis PCI bridge. + Say Y when you have a Mantis based DVB card and want to use it. + + If unsure say N. + +config DVB_HOPPER + tristate "HOPPER based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_PLL + help + Support for PCI cards based on the Hopper PCI bridge. + Say Y when you have a Hopper based DVB card and want to use it. + + If unsure say N diff --git a/drivers/media/pci/mantis/Makefile b/drivers/media/pci/mantis/Makefile new file mode 100644 index 00000000000..f715051e445 --- /dev/null +++ b/drivers/media/pci/mantis/Makefile @@ -0,0 +1,28 @@ +mantis_core-objs := mantis_ioc.o \ + mantis_uart.o \ + mantis_dma.o \ + mantis_pci.o \ + mantis_i2c.o \ + mantis_dvb.o \ + mantis_evm.o \ + mantis_hif.o \ + mantis_ca.o \ + mantis_pcmcia.o \ + mantis_input.o + +mantis-objs := mantis_cards.o \ + mantis_vp1033.o \ + mantis_vp1034.o \ + mantis_vp1041.o \ + mantis_vp2033.o \ + mantis_vp2040.o \ + mantis_vp3030.o + +hopper-objs := hopper_cards.o \ + hopper_vp3028.o + +obj-$(CONFIG_MANTIS_CORE) += mantis_core.o +obj-$(CONFIG_DVB_MANTIS) += mantis.o +obj-$(CONFIG_DVB_HOPPER) += hopper.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c new file mode 100644 index 00000000000..cc0251e0107 --- /dev/null +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -0,0 +1,277 @@ +/* + Hopper PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "hopper_vp3028.h" +#include "mantis_dma.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); + +#define DRIVER_NAME "Hopper" + +static char *label[10] = { + "DMA", + "IRQ-0", + "IRQ-1", + "OCERR", + "PABRT", + "RIPRR", + "PPERR", + "FTRGT", + "RISCI", + "RACK" +}; + +static int devs; + +static irqreturn_t hopper_irq_handler(int irq, void *dev_id) +{ + u32 stat = 0, mask = 0; + u32 rst_stat = 0, rst_mask = 0; + + struct mantis_pci *mantis; + struct mantis_ca *ca; + + mantis = (struct mantis_pci *) dev_id; + if (unlikely(mantis == NULL)) { + dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + return IRQ_NONE; + } + ca = mantis->mantis_ca; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + if (!(stat & mask)) + return IRQ_NONE; + + rst_mask = MANTIS_GPIF_WRACK | + MANTIS_GPIF_OTHERR | + MANTIS_SBUF_WSTO | + MANTIS_GPIF_EXTIRQ; + + rst_stat = mmread(MANTIS_GPIF_STATUS); + rst_stat &= rst_mask; + mmwrite(rst_stat, MANTIS_GPIF_STATUS); + + mantis->mantis_int_stat = stat; + mantis->mantis_int_mask = mask; + dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); + if (stat & MANTIS_INT_RISCEN) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); + } + if (stat & MANTIS_INT_IRQ0) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); + mantis->gpif_status = rst_stat; + wake_up(&ca->hif_write_wq); + schedule_work(&ca->hif_evm_work); + } + if (stat & MANTIS_INT_IRQ1) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + schedule_work(&mantis->uart_work); + } + if (stat & MANTIS_INT_OCERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); + } + if (stat & MANTIS_INT_PABORT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); + } + if (stat & MANTIS_INT_RIPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); + } + if (stat & MANTIS_INT_PPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); + } + if (stat & MANTIS_INT_FTRGT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); + } + if (stat & MANTIS_INT_RISCI) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); + mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + tasklet_schedule(&mantis->tasklet); + } + if (stat & MANTIS_INT_I2CDONE) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); + wake_up(&mantis->i2c_wq); + } + mmwrite(stat, MANTIS_INT_STAT); + stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | + MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | + MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | + MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | + MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | + MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | + MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | + MANTIS_INT_PABORT | MANTIS_INT_RIPERR | + MANTIS_INT_PPERR | MANTIS_INT_FTRGT | + MANTIS_INT_RISCI); + + if (stat) + dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); + + dprintk(MANTIS_DEBUG, 0, "\n"); + return IRQ_HANDLED; +} + +static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + int err = 0; + + mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + if (mantis == NULL) { + printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); + err = -ENOMEM; + goto fail0; + } + + mantis->num = devs; + mantis->verbose = verbose; + mantis->pdev = pdev; + config = (struct mantis_hwconfig *) pci_id->driver_data; + config->irq_handler = &hopper_irq_handler; + mantis->hwconfig = config; + + err = mantis_pci_init(mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); + goto fail1; + } + + err = mantis_stream_control(mantis, STREAM_TO_HIF); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); + goto fail1; + } + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); + goto fail2; + } + + err = mantis_get_mac(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); + goto fail2; + } + + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); + goto fail3; + } + + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); + goto fail4; + } + devs++; + + return err; + +fail4: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); + mantis_dma_exit(mantis); + +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); + mantis_i2c_exit(mantis); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); + mantis_pci_exit(mantis); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); + kfree(mantis); + +fail0: + return err; +} + +static void __devexit hopper_pci_remove(struct pci_dev *pdev) +{ + struct mantis_pci *mantis = pci_get_drvdata(pdev); + + if (mantis) { + mantis_dvb_exit(mantis); + mantis_dma_exit(mantis); + mantis_i2c_exit(mantis); + mantis_pci_exit(mantis); + kfree(mantis); + } + return; + +} + +static struct pci_device_id hopper_pci_table[] = { + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), + { } +}; + +MODULE_DEVICE_TABLE(pci, hopper_pci_table); + +static struct pci_driver hopper_pci_driver = { + .name = DRIVER_NAME, + .id_table = hopper_pci_table, + .probe = hopper_pci_probe, + .remove = hopper_pci_remove, +}; + +static int __devinit hopper_init(void) +{ + return pci_register_driver(&hopper_pci_driver); +} + +static void __devexit hopper_exit(void) +{ + return pci_unregister_driver(&hopper_pci_driver); +} + +module_init(hopper_init); +module_exit(hopper_exit); + +MODULE_DESCRIPTION("HOPPER driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c new file mode 100644 index 00000000000..68a29f8bdf7 --- /dev/null +++ b/drivers/media/pci/mantis/hopper_vp3028.c @@ -0,0 +1,88 @@ +/* + Hopper VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "hopper_vp3028.h" + +struct zl10353_config hopper_vp3028_config = { + .demod_address = 0x0f, +}; + +#define MANTIS_MODEL_NAME "VP-3028" +#define MANTIS_DEV_TYPE "DVB-T" + +static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + struct mantis_hwconfig *config = mantis->hwconfig; + int err = 0; + + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + err = mantis_frontend_power(mantis, POWER_ON); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + msleep(250); + dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); + fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter); + + if (!fe) + return -1; + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp3028_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp3028_frontend_init, + .power = GPIF_A00, + .reset = GPIF_A03, +}; diff --git a/drivers/media/pci/mantis/hopper_vp3028.h b/drivers/media/pci/mantis/hopper_vp3028.h new file mode 100644 index 00000000000..57239498bc8 --- /dev/null +++ b/drivers/media/pci/mantis/hopper_vp3028.h @@ -0,0 +1,30 @@ +/* + Hopper VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "mantis_common.h" + +#define MANTIS_VP_3028_DVB_T 0x0028 + +extern struct mantis_hwconfig vp3028_config; + +#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/pci/mantis/mantis_ca.c b/drivers/media/pci/mantis/mantis_ca.c new file mode 100644 index 00000000000..3d704690900 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ca.c @@ -0,0 +1,209 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +#include "mantis_ca.h" + +static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_read_mem(ca, addr); +} + +static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_write_mem(ca, addr, data); +} + +static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_read_iom(ca, addr); +} + +static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_write_iom(ca, addr, data); +} + +static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot); + udelay(500); /* Wait.. */ + mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ + udelay(500); + mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ + msleep(1000); + dvb_ca_en50221_camready_irq(&ca->en50221, 0); + + return 0; +} + +static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot); + + return 0; +} + +static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); +/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ + + return 0; +} + +static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot); + + if (ca->slot_state == MODULE_INSERTED) { + dprintk(MANTIS_DEBUG, 1, "CA Module present and ready"); + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } else { + dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready"); + } + + return 0; +} + +int mantis_ca_init(struct mantis_pci *mantis) +{ + struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter; + struct mantis_ca *ca; + int ca_flags = 0, result; + + dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA"); + ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL); + if (!ca) { + dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .."); + result = -ENOMEM; + goto err; + } + + ca->ca_priv = mantis; + mantis->mantis_ca = ca; + ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; + /* register CA interface */ + ca->en50221.owner = THIS_MODULE; + ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem; + ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem; + ca->en50221.read_cam_control = mantis_ca_read_cam_ctl; + ca->en50221.write_cam_control = mantis_ca_write_cam_ctl; + ca->en50221.slot_reset = mantis_ca_slot_reset; + ca->en50221.slot_shutdown = mantis_ca_slot_shutdown; + ca->en50221.slot_ts_enable = mantis_ts_control; + ca->en50221.poll_slot_status = mantis_slot_status; + ca->en50221.data = ca; + + mutex_init(&ca->ca_lock); + + init_waitqueue_head(&ca->hif_data_wq); + init_waitqueue_head(&ca->hif_opdone_wq); + init_waitqueue_head(&ca->hif_write_wq); + + dprintk(MANTIS_ERROR, 1, "Registering EN50221 device"); + result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1); + if (result != 0) { + dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result); + goto err; + } + dprintk(MANTIS_ERROR, 1, "Registered EN50221 device"); + mantis_evmgr_init(ca); + return 0; +err: + kfree(ca); + return result; +} +EXPORT_SYMBOL_GPL(mantis_ca_init); + +void mantis_ca_exit(struct mantis_pci *mantis) +{ + struct mantis_ca *ca = mantis->mantis_ca; + + dprintk(MANTIS_DEBUG, 1, "Mantis CA exit"); + + mantis_evmgr_exit(ca); + dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device"); + if (ca) + dvb_ca_en50221_release(&ca->en50221); + + kfree(ca); +} +EXPORT_SYMBOL_GPL(mantis_ca_exit); diff --git a/drivers/media/pci/mantis/mantis_ca.h b/drivers/media/pci/mantis/mantis_ca.h new file mode 100644 index 00000000000..dc63e55f7ec --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ca.h @@ -0,0 +1,27 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_CA_H +#define __MANTIS_CA_H + +extern int mantis_ca_init(struct mantis_pci *mantis); +extern void mantis_ca_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CA_H */ diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c new file mode 100644 index 00000000000..0207d1f064e --- /dev/null +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -0,0 +1,307 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); + +static int devs; + +#define DRIVER_NAME "Mantis" + +static char *label[10] = { + "DMA", + "IRQ-0", + "IRQ-1", + "OCERR", + "PABRT", + "RIPRR", + "PPERR", + "FTRGT", + "RISCI", + "RACK" +}; + +static irqreturn_t mantis_irq_handler(int irq, void *dev_id) +{ + u32 stat = 0, mask = 0; + u32 rst_stat = 0, rst_mask = 0; + + struct mantis_pci *mantis; + struct mantis_ca *ca; + + mantis = (struct mantis_pci *) dev_id; + if (unlikely(mantis == NULL)) { + dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + return IRQ_NONE; + } + ca = mantis->mantis_ca; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + if (!(stat & mask)) + return IRQ_NONE; + + rst_mask = MANTIS_GPIF_WRACK | + MANTIS_GPIF_OTHERR | + MANTIS_SBUF_WSTO | + MANTIS_GPIF_EXTIRQ; + + rst_stat = mmread(MANTIS_GPIF_STATUS); + rst_stat &= rst_mask; + mmwrite(rst_stat, MANTIS_GPIF_STATUS); + + mantis->mantis_int_stat = stat; + mantis->mantis_int_mask = mask; + dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); + if (stat & MANTIS_INT_RISCEN) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); + } + if (stat & MANTIS_INT_IRQ0) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); + mantis->gpif_status = rst_stat; + wake_up(&ca->hif_write_wq); + schedule_work(&ca->hif_evm_work); + } + if (stat & MANTIS_INT_IRQ1) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + schedule_work(&mantis->uart_work); + } + if (stat & MANTIS_INT_OCERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); + } + if (stat & MANTIS_INT_PABORT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); + } + if (stat & MANTIS_INT_RIPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); + } + if (stat & MANTIS_INT_PPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); + } + if (stat & MANTIS_INT_FTRGT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); + } + if (stat & MANTIS_INT_RISCI) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); + mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + tasklet_schedule(&mantis->tasklet); + } + if (stat & MANTIS_INT_I2CDONE) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); + wake_up(&mantis->i2c_wq); + } + mmwrite(stat, MANTIS_INT_STAT); + stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | + MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | + MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | + MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | + MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | + MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | + MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | + MANTIS_INT_PABORT | MANTIS_INT_RIPERR | + MANTIS_INT_PPERR | MANTIS_INT_FTRGT | + MANTIS_INT_RISCI); + + if (stat) + dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); + + dprintk(MANTIS_DEBUG, 0, "\n"); + return IRQ_HANDLED; +} + +static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + int err = 0; + + mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + if (mantis == NULL) { + printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); + err = -ENOMEM; + goto fail0; + } + + mantis->num = devs; + mantis->verbose = verbose; + mantis->pdev = pdev; + config = (struct mantis_hwconfig *) pci_id->driver_data; + config->irq_handler = &mantis_irq_handler; + mantis->hwconfig = config; + + err = mantis_pci_init(mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); + goto fail1; + } + + err = mantis_stream_control(mantis, STREAM_TO_HIF); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); + goto fail1; + } + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); + goto fail2; + } + + err = mantis_get_mac(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); + goto fail2; + } + + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); + goto fail3; + } + + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); + goto fail4; + } + err = mantis_uart_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); + goto fail6; + } + + devs++; + + return err; + + + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); + mantis_uart_exit(mantis); + +fail6: +fail4: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); + mantis_dma_exit(mantis); + +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); + mantis_i2c_exit(mantis); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); + mantis_pci_exit(mantis); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); + kfree(mantis); + +fail0: + return err; +} + +static void __devexit mantis_pci_remove(struct pci_dev *pdev) +{ + struct mantis_pci *mantis = pci_get_drvdata(pdev); + + if (mantis) { + + mantis_uart_exit(mantis); + mantis_dvb_exit(mantis); + mantis_dma_exit(mantis); + mantis_i2c_exit(mantis); + mantis_pci_exit(mantis); + kfree(mantis); + } + return; +} + +static struct pci_device_id mantis_pci_table[] = { + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), + MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), + MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), + MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), + { } +}; + +MODULE_DEVICE_TABLE(pci, mantis_pci_table); + +static struct pci_driver mantis_pci_driver = { + .name = DRIVER_NAME, + .id_table = mantis_pci_table, + .probe = mantis_pci_probe, + .remove = mantis_pci_remove, +}; + +static int __devinit mantis_init(void) +{ + return pci_register_driver(&mantis_pci_driver); +} + +static void __devexit mantis_exit(void) +{ + return pci_unregister_driver(&mantis_pci_driver); +} + +module_init(mantis_init); +module_exit(mantis_exit); + +MODULE_DESCRIPTION("MANTIS driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h new file mode 100644 index 00000000000..f2410cf0a6b --- /dev/null +++ b/drivers/media/pci/mantis/mantis_common.h @@ -0,0 +1,179 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_COMMON_H +#define __MANTIS_COMMON_H + +#include +#include +#include + +#include "mantis_uart.h" + +#include "mantis_link.h" + +#define MANTIS_ERROR 0 +#define MANTIS_NOTICE 1 +#define MANTIS_INFO 2 +#define MANTIS_DEBUG 3 +#define MANTIS_TMG 9 + +#define dprintk(y, z, format, arg...) do { \ + if (z) { \ + if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \ + printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \ + printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \ + printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \ + printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \ + printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + } else { \ + if (mantis->verbose > y) \ + printk(format , ##arg); \ + } \ +} while(0) + +#define mwrite(dat, addr) writel((dat), addr) +#define mread(addr) readl(addr) + +#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr))) +#define mmread(addr) mread(mantis->mmio + (addr)) + +#define MANTIS_TS_188 0 +#define MANTIS_TS_204 1 + +#define TWINHAN_TECHNOLOGIES 0x1822 +#define MANTIS 0x4e35 + +#define TECHNISAT 0x1ae4 +#define TERRATEC 0x153b + +#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ + .vendor = TWINHAN_TECHNOLOGIES, \ + .device = MANTIS, \ + .subvendor = (__subven), \ + .subdevice = (__subdev), \ + .driver_data = (unsigned long) (__configptr) \ +} + +enum mantis_i2c_mode { + MANTIS_PAGE_MODE = 0, + MANTIS_BYTE_MODE, +}; + +struct mantis_pci; + +struct mantis_hwconfig { + char *model_name; + char *dev_type; + u32 ts_size; + + enum mantis_baud baud_rate; + enum mantis_parity parity; + u32 bytes; + + irqreturn_t (*irq_handler)(int irq, void *dev_id); + int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe); + + u8 power; + u8 reset; + + enum mantis_i2c_mode i2c_mode; +}; + +struct mantis_pci { + unsigned int verbose; + + /* PCI stuff */ + u16 vendor_id; + u16 device_id; + u16 subsystem_vendor; + u16 subsystem_device; + + u8 latency; + + struct pci_dev *pdev; + + unsigned long mantis_addr; + void __iomem *mmio; + + u8 irq; + u8 revision; + + unsigned int num; + + /* RISC Core */ + u32 busy_block; + u32 last_block; + u8 *buf_cpu; + dma_addr_t buf_dma; + u32 *risc_cpu; + dma_addr_t risc_dma; + + struct tasklet_struct tasklet; + + struct i2c_adapter adapter; + int i2c_rc; + wait_queue_head_t i2c_wq; + struct mutex i2c_lock; + + /* DVB stuff */ + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net dvbnet; + + u8 feeds; + + struct mantis_hwconfig *hwconfig; + + u32 mantis_int_stat; + u32 mantis_int_mask; + + /* board specific */ + u8 mac_address[8]; + u32 sub_vendor_id; + u32 sub_device_id; + + /* A12 A13 A14 */ + u32 gpio_status; + + u32 gpif_status; + + struct mantis_ca *mantis_ca; + + wait_queue_head_t uart_wq; + struct work_struct uart_work; + spinlock_t uart_lock; + + struct rc_dev *rc; + char input_name[80]; + char input_phys[80]; +}; + +#define MANTIS_HIF_STATUS (mantis->gpio_status) + +#endif /* __MANTIS_COMMON_H */ diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c new file mode 100644 index 00000000000..684d9061fe2 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_core.c @@ -0,0 +1,235 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "mantis_common.h" +#include "mantis_core.h" +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ + int err; + struct i2c_msg msg[] = { + { + .addr = 0x50, + .flags = 0, + .buf = data, + .len = 1 + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .buf = data, + .len = length + }, + }; + + err = i2c_transfer(&mantis->adapter, msg, 2); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, + "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", + err, data[0], data[1]); + + return err; + } + + return 0; +} + +static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ + int err; + + struct i2c_msg msg = { + .addr = 0x50, + .flags = 0, + .buf = data, + .len = length + }; + + err = i2c_transfer(&mantis->adapter, &msg, 1); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, + "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", + err, length, data[0], data[1]); + + return err; + } + + return 0; +} + +static int get_mac_address(struct mantis_pci *mantis) +{ + int err; + + mantis->mac_address[0] = 0x08; + err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); + + return err; + } + dprintk(verbose, MANTIS_ERROR, 0, + " MAC Address=[%pM]\n", mantis->mac_address); + + return 0; +} + +#define MANTIS_MODEL_UNKNOWN "UNKNOWN" +#define MANTIS_DEV_UNKNOWN "UNKNOWN" + +struct mantis_hwconfig unknown_device = { + .model_name = MANTIS_MODEL_UNKNOWN, + .dev_type = MANTIS_DEV_UNKNOWN, +}; + +static void mantis_load_config(struct mantis_pci *mantis) +{ + switch (mantis->subsystem_device) { + case MANTIS_VP_1033_DVB_S: /* VP-1033 */ + mantis->hwconfig = &vp1033_mantis_config; + break; + case MANTIS_VP_1034_DVB_S: /* VP-1034 */ + mantis->hwconfig = &vp1034_mantis_config; + break; + case MANTIS_VP_1041_DVB_S2: /* VP-1041 */ + case TECHNISAT_SKYSTAR_HD2: + mantis->hwconfig = &vp1041_mantis_config; + break; + case MANTIS_VP_2033_DVB_C: /* VP-2033 */ + mantis->hwconfig = &vp2033_mantis_config; + break; + case MANTIS_VP_2040_DVB_C: /* VP-2040 */ + case CINERGY_C: /* VP-2040 clone */ + case TECHNISAT_CABLESTAR_HD2: + mantis->hwconfig = &vp2040_mantis_config; + break; + case MANTIS_VP_3030_DVB_T: /* VP-3030 */ + mantis->hwconfig = &vp3030_mantis_config; + break; + default: + mantis->hwconfig = &unknown_device; + break; + } +} + +int mantis_core_init(struct mantis_pci *mantis) +{ + int err = 0; + + mantis_load_config(mantis); + dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", + mantis->hwconfig->model_name, mantis->hwconfig->dev_type, + mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); + dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", + mantis->revision, + mantis->subsystem_vendor, mantis->subsystem_device); + dprintk(verbose, MANTIS_ERROR, 0, + "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", + mantis->pdev->irq, mantis->latency, + mantis->mantis_addr, mantis->mantis_mmio); + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); + return err; + } + err = get_mac_address(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); + return err; + } + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); + return err; + } + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); + return err; + } + err = mantis_uart_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); + return err; + } + + return 0; +} + +int mantis_core_exit(struct mantis_pci *mantis) +{ + mantis_dma_stop(mantis); + dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); + + mantis_uart_exit(mantis); + dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); + + if (mantis_dma_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); + if (mantis_dvb_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); + if (mantis_i2c_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); + + return 0; +} + +/* Turn the given bit on or off. */ +void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ + u32 cur; + + cur = mmread(MANTIS_GPIF_ADDR); + if (value) + mantis->gpio_status = cur | (1 << bitpos); + else + mantis->gpio_status = cur & (~(1 << bitpos)); + + mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); + mmwrite(0x00, MANTIS_GPIF_DOUT); + udelay(100); +} + +/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ +void mantis_set_direction(struct mantis_pci *mantis, int direction) +{ + u32 reg; + + reg = mmread(0x28); + dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); + if (direction == 0x01) { + /* to CI */ + reg |= 0x04; + mmwrite(reg, 0x28); + reg &= 0xff - 0x04; + mmwrite(reg, 0x28); + } else { + reg &= 0xff - 0x04; + mmwrite(reg, 0x28); + reg |= 0x04; + mmwrite(reg, 0x28); + } +} diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h new file mode 100644 index 00000000000..833ee42e694 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_core.h @@ -0,0 +1,57 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_CORE_H +#define __MANTIS_CORE_H + +#include "mantis_common.h" + + +#define FE_TYPE_SAT 0 +#define FE_TYPE_CAB 1 +#define FE_TYPE_TER 2 + +#define FE_TYPE_TS204 0 +#define FE_TYPE_TS188 1 + + +struct vendorname { + u8 *sub_vendor_name; + u32 sub_vendor_id; +}; + +struct devicetype { + u8 *sub_device_name; + u32 sub_device_id; + u8 device_type; + u32 type_flags; +}; + + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); +extern int mantis_core_init(struct mantis_pci *mantis); +extern int mantis_core_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c new file mode 100644 index 00000000000..566c407175a --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dma.c @@ -0,0 +1,230 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_dma.h" + +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_IRQ (0x01 << 24) + +#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) +#define RISC_FLUSH(risc_pos) (risc_pos = 0) +#define RISC_INSTR(risc_pos, opcode) (mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode)) + +#define MANTIS_BUF_SIZE (64 * 1024) +#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE / 4) +#define MANTIS_DMA_TR_BYTES (2 * 1024) /* upper limit: 4095 bytes. */ +#define MANTIS_BLOCK_COUNT (MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES) + +#define MANTIS_DMA_TR_UNITS (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES) +/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */ +#define MANTIS_RISC_SIZE PAGE_SIZE /* RISC program must fit here. */ + +int mantis_dma_exit(struct mantis_pci *mantis) +{ + if (mantis->buf_cpu) { + dprintk(MANTIS_ERROR, 1, + "DMA=0x%lx cpu=0x%p size=%d", + (unsigned long) mantis->buf_dma, + mantis->buf_cpu, + MANTIS_BUF_SIZE); + + pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, + mantis->buf_cpu, mantis->buf_dma); + + mantis->buf_cpu = NULL; + } + if (mantis->risc_cpu) { + dprintk(MANTIS_ERROR, 1, + "RISC=0x%lx cpu=0x%p size=%lx", + (unsigned long) mantis->risc_dma, + mantis->risc_cpu, + MANTIS_RISC_SIZE); + + pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, + mantis->risc_cpu, mantis->risc_dma); + + mantis->risc_cpu = NULL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_dma_exit); + +static inline int mantis_alloc_buffers(struct mantis_pci *mantis) +{ + if (!mantis->buf_cpu) { + mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, + MANTIS_BUF_SIZE, + &mantis->buf_dma); + if (!mantis->buf_cpu) { + dprintk(MANTIS_ERROR, 1, + "DMA buffer allocation failed"); + + goto err; + } + dprintk(MANTIS_ERROR, 1, + "DMA=0x%lx cpu=0x%p size=%d", + (unsigned long) mantis->buf_dma, + mantis->buf_cpu, MANTIS_BUF_SIZE); + } + if (!mantis->risc_cpu) { + mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, + MANTIS_RISC_SIZE, + &mantis->risc_dma); + + if (!mantis->risc_cpu) { + dprintk(MANTIS_ERROR, 1, + "RISC program allocation failed"); + + mantis_dma_exit(mantis); + + goto err; + } + dprintk(MANTIS_ERROR, 1, + "RISC=0x%lx cpu=0x%p size=%lx", + (unsigned long) mantis->risc_dma, + mantis->risc_cpu, MANTIS_RISC_SIZE); + } + + return 0; +err: + dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); + return -ENOMEM; +} + +int mantis_dma_init(struct mantis_pci *mantis) +{ + int err = 0; + + dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); + if (mantis_alloc_buffers(mantis) < 0) { + dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); + + /* Stop RISC Engine */ + mmwrite(0, MANTIS_DMA_CTL); + + goto err; + } + + return 0; +err: + return err; +} +EXPORT_SYMBOL_GPL(mantis_dma_init); + +static inline void mantis_risc_program(struct mantis_pci *mantis) +{ + u32 buf_pos = 0; + u32 line, step; + u32 risc_pos; + + dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); + RISC_FLUSH(risc_pos); + + dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u", + MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES); + + for (line = 0; line < MANTIS_BLOCK_COUNT; line++) { + for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) { + dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step); + if (step == 0) { + RISC_INSTR(risc_pos, RISC_WRITE | + RISC_IRQ | + RISC_STATUS(line) | + MANTIS_DMA_TR_BYTES); + } else { + RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES); + } + RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos); + buf_pos += MANTIS_DMA_TR_BYTES; + } + } + RISC_INSTR(risc_pos, RISC_JUMP); + RISC_INSTR(risc_pos, mantis->risc_dma); +} + +void mantis_dma_start(struct mantis_pci *mantis) +{ + dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); + + mantis_risc_program(mantis); + mmwrite(mantis->risc_dma, MANTIS_RISC_START); + mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + mmwrite(0, MANTIS_DMA_CTL); + mantis->last_block = mantis->busy_block = 0; + + mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); + + mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN + | MANTIS_RISC_EN, MANTIS_DMA_CTL); + +} + +void mantis_dma_stop(struct mantis_pci *mantis) +{ + dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); + + mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); + + mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | + MANTIS_DCAP_EN | + MANTIS_RISC_EN)), MANTIS_DMA_CTL); + + mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); + + mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | + MANTIS_INT_RISCEN), MANTIS_INT_MASK); +} + + +void mantis_dma_xfer(unsigned long data) +{ + struct mantis_pci *mantis = (struct mantis_pci *) data; + struct mantis_hwconfig *config = mantis->hwconfig; + + while (mantis->last_block != mantis->busy_block) { + dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", + mantis->last_block, mantis->busy_block); + + (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) + (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); + mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; + } +} diff --git a/drivers/media/pci/mantis/mantis_dma.h b/drivers/media/pci/mantis/mantis_dma.h new file mode 100644 index 00000000000..6be00fa8209 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dma.h @@ -0,0 +1,30 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_DMA_H +#define __MANTIS_DMA_H + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern void mantis_dma_xfer(unsigned long data); + +#endif /* __MANTIS_DMA_H */ diff --git a/drivers/media/pci/mantis/mantis_dvb.c b/drivers/media/pci/mantis/mantis_dvb.c new file mode 100644 index 00000000000..5d15c6b74d9 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dvb.c @@ -0,0 +1,301 @@ +/* + Mantis PCI bridge driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + + switch (power) { + case POWER_ON: + dprintk(MANTIS_DEBUG, 1, "Power ON"); + mantis_gpio_set_bits(mantis, config->power, POWER_ON); + msleep(100); + mantis_gpio_set_bits(mantis, config->power, POWER_ON); + msleep(100); + break; + + case POWER_OFF: + dprintk(MANTIS_DEBUG, 1, "Power OFF"); + mantis_gpio_set_bits(mantis, config->power, POWER_OFF); + msleep(100); + break; + + default: + dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_frontend_power); + +void mantis_frontend_soft_reset(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + + dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + msleep(100); + + return; +} +EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); + +static int mantis_frontend_shutdown(struct mantis_pci *mantis) +{ + int err; + + mantis_frontend_soft_reset(mantis); + err = mantis_frontend_power(mantis, POWER_OFF); + if (err != 0) { + dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); + return 1; + } + + return 0; +} + +static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct mantis_pci *mantis = dvbdmx->priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(MANTIS_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + + mantis->feeds++; + dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); + + if (mantis->feeds == 1) { + dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); + mantis_dma_start(mantis); + tasklet_enable(&mantis->tasklet); + } + + return mantis->feeds; +} + +static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct mantis_pci *mantis = dvbdmx->priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(MANTIS_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + + mantis->feeds--; + if (mantis->feeds == 0) { + dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); + tasklet_disable(&mantis->tasklet); + mantis_dma_stop(mantis); + } + + return 0; +} + +int __devinit mantis_dvb_init(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + int result = -1; + + dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); + + result = dvb_register_adapter(&mantis->dvb_adapter, + "Mantis DVB adapter", + THIS_MODULE, + &mantis->pdev->dev, + adapter_nr); + + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "Error registering adapter"); + return -ENODEV; + } + + mantis->dvb_adapter.priv = mantis; + mantis->demux.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + + mantis->demux.priv = mantis; + mantis->demux.filternum = 256; + mantis->demux.feednum = 256; + mantis->demux.start_feed = mantis_dvb_start_feed; + mantis->demux.stop_feed = mantis_dvb_stop_feed; + mantis->demux.write_to_decoder = NULL; + + dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); + result = dvb_dmx_init(&mantis->demux); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + + goto err0; + } + + mantis->dmxdev.filternum = 256; + mantis->dmxdev.demux = &mantis->demux.dmx; + mantis->dmxdev.capabilities = 0; + dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); + + result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); + goto err1; + } + + mantis->fe_hw.source = DMX_FRONTEND_0; + result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err2; + } + + mantis->fe_mem.source = DMX_MEMORY_FE; + result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err3; + } + + result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err4; + } + + dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); + tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); + tasklet_disable(&mantis->tasklet); + if (mantis->hwconfig) { + result = config->frontend_init(mantis, mantis->fe); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); + goto err5; + } else { + if (mantis->fe == NULL) { + dprintk(MANTIS_ERROR, 1, "FE "); + goto err5; + } + + if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { + dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); + + if (mantis->fe->ops.release) + mantis->fe->ops.release(mantis->fe); + + mantis->fe = NULL; + goto err5; + } + } + } + + return 0; + + /* Error conditions .. */ +err5: + tasklet_kill(&mantis->tasklet); + dvb_net_release(&mantis->dvbnet); + if (mantis->fe) { + dvb_unregister_frontend(mantis->fe); + dvb_frontend_detach(mantis->fe); + } +err4: + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + +err3: + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + +err2: + dvb_dmxdev_release(&mantis->dmxdev); + +err1: + dvb_dmx_release(&mantis->demux); + +err0: + dvb_unregister_adapter(&mantis->dvb_adapter); + + return result; +} +EXPORT_SYMBOL_GPL(mantis_dvb_init); + +int __devexit mantis_dvb_exit(struct mantis_pci *mantis) +{ + int err; + + if (mantis->fe) { + /* mantis_ca_exit(mantis); */ + err = mantis_frontend_shutdown(mantis); + if (err != 0) + dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); + dvb_unregister_frontend(mantis->fe); + dvb_frontend_detach(mantis->fe); + } + + tasklet_kill(&mantis->tasklet); + dvb_net_release(&mantis->dvbnet); + + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + + dvb_dmxdev_release(&mantis->dmxdev); + dvb_dmx_release(&mantis->demux); + + dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); + dvb_unregister_adapter(&mantis->dvb_adapter); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_dvb_exit); diff --git a/drivers/media/pci/mantis/mantis_dvb.h b/drivers/media/pci/mantis/mantis_dvb.h new file mode 100644 index 00000000000..464199db304 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_dvb.h @@ -0,0 +1,35 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_DVB_H +#define __MANTIS_DVB_H + +enum mantis_power { + POWER_OFF = 0, + POWER_ON = 1 +}; + +extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power); +extern void mantis_frontend_soft_reset(struct mantis_pci *mantis); + +extern int mantis_dvb_init(struct mantis_pci *mantis); +extern int mantis_dvb_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_DVB_H */ diff --git a/drivers/media/pci/mantis/mantis_evm.c b/drivers/media/pci/mantis/mantis_evm.c new file mode 100644 index 00000000000..71ce52875c3 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_evm.c @@ -0,0 +1,117 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +static void mantis_hifevm_work(struct work_struct *work) +{ + struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_stat; + + gpif_stat = mmread(MANTIS_GPIF_STATUS); + + if (gpif_stat & MANTIS_GPIF_DETSTAT) { + if (gpif_stat & MANTIS_CARD_PLUGIN) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num); + mmwrite(0xdada0000, MANTIS_CARD_RESET); + mantis_event_cam_plugin(ca); + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } + } else { + if (gpif_stat & MANTIS_CARD_PLUGOUT) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num); + mmwrite(0xdada0000, MANTIS_CARD_RESET); + mantis_event_cam_unplug(ca); + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + } + + if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num); + + if (mantis->gpif_status & MANTIS_SBUF_WSTO) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num); + + if (mantis->gpif_status & MANTIS_GPIF_OTHERR) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num); + + if (gpif_stat & MANTIS_SBUF_OVFLW) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num); + + if (gpif_stat & MANTIS_GPIF_BRRDY) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num); + + if (gpif_stat & MANTIS_GPIF_INTSTAT) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num); + + if (gpif_stat & MANTIS_SBUF_EMPTY) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num); + + if (gpif_stat & MANTIS_SBUF_OPDONE) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num); + ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL; + ca->hif_event = MANTIS_SBUF_OPDONE; + wake_up(&ca->hif_opdone_wq); + } +} + +int mantis_evmgr_init(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager"); + INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work); + mantis_pcmcia_init(ca); + schedule_work(&ca->hif_evm_work); + mantis_hif_init(ca); + return 0; +} + +void mantis_evmgr_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); + flush_work_sync(&ca->hif_evm_work); + mantis_hif_exit(ca); + mantis_pcmcia_exit(ca); +} diff --git a/drivers/media/pci/mantis/mantis_hif.c b/drivers/media/pci/mantis/mantis_hif.c new file mode 100644 index 00000000000..10c68df7e16 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_hif.c @@ -0,0 +1,239 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_hif.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ + +#include "mantis_reg.h" + + +static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + int rc = 0; + + if (wait_event_timeout(ca->hif_opdone_wq, + ca->hif_event & MANTIS_SBUF_OPDONE, + msecs_to_jiffies(500)) == -ERESTARTSYS) { + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num); + rc = -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete"); + ca->hif_event &= ~MANTIS_SBUF_OPDONE; + return rc; +} + +static int mantis_hif_write_wait(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 opdone = 0, timeout = 0; + int rc = 0; + + if (wait_event_timeout(ca->hif_write_wq, + mantis->gpif_status & MANTIS_GPIF_WRACK, + msecs_to_jiffies(500)) == -ERESTARTSYS) { + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num); + rc = -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Write Acknowledged"); + mantis->gpif_status &= ~MANTIS_GPIF_WRACK; + while (!opdone) { + opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE); + udelay(500); + timeout++; + if (timeout > 100) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num); + rc = -ETIMEDOUT; + break; + } + } + dprintk(MANTIS_DEBUG, 1, "HIF Write success"); + return rc; +} + + +int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0, data, count = 4; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_BRADDR); + mmwrite(count, MANTIS_GPIF_BRBYTES); + udelay(20); + mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + if (mantis_hif_sbuf_opdone_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + data = mmread(MANTIS_GPIF_DIN); + mutex_unlock(&ca->ca_lock); + dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data); + return (data >> 24) & 0xff; +} + +int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data) +{ + struct mantis_slot *slot = ca->slot; + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_HIFRDWRN; + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */ + mmwrite(hif_addr, MANTIS_GPIF_ADDR); + mmwrite(data, MANTIS_GPIF_DOUT); + + if (mantis_hif_write_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr); + mutex_unlock(&ca->ca_lock); + + return 0; +} + +int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 data, hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr |= MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_BRADDR); + mmwrite(1, MANTIS_GPIF_BRBYTES); + udelay(20); + mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + if (mantis_hif_sbuf_opdone_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + data = mmread(MANTIS_GPIF_DIN); + dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data); + udelay(50); + mutex_unlock(&ca->ca_lock); + + return (u8) data; +} + +int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_HIFRDWRN; + hif_addr |= MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_ADDR); + mmwrite(data, MANTIS_GPIF_DOUT); + + if (mantis_hif_write_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr); + mutex_unlock(&ca->ca_lock); + udelay(50); + + return 0; +} + +int mantis_hif_init(struct mantis_ca *ca) +{ + struct mantis_slot *slot = ca->slot; + struct mantis_pci *mantis = ca->ca_priv; + u32 irqcfg; + + slot[0].slave_cfg = 0x70773028; + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num); + + mutex_lock(&ca->ca_lock); + irqcfg = mmread(MANTIS_GPIF_IRQCFG); + irqcfg = MANTIS_MASK_BRRDY | + MANTIS_MASK_WRACK | + MANTIS_MASK_EXTIRQ | + MANTIS_MASK_WSTO | + MANTIS_MASK_OTHERR | + MANTIS_MASK_OVFLW; + + mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); + mutex_unlock(&ca->ca_lock); + + return 0; +} + +void mantis_hif_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 irqcfg; + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num); + mutex_lock(&ca->ca_lock); + irqcfg = mmread(MANTIS_GPIF_IRQCFG); + irqcfg &= ~MANTIS_MASK_BRRDY; + mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); + mutex_unlock(&ca->ca_lock); +} diff --git a/drivers/media/pci/mantis/mantis_hif.h b/drivers/media/pci/mantis/mantis_hif.h new file mode 100644 index 00000000000..9094f9ed236 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_hif.h @@ -0,0 +1,29 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_HIF_H +#define __MANTIS_HIF_H + +#define MANTIS_HIF_MEMRD 1 +#define MANTIS_HIF_MEMWR 2 +#define MANTIS_HIF_IOMRD 3 +#define MANTIS_HIF_IOMWR 4 + +#endif /* __MANTIS_HIF_H */ diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c new file mode 100644 index 00000000000..e7794517fe2 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -0,0 +1,266 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_i2c.h" + +#define TRIALS 10000 + +static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ + u32 rxd, i, stat, trials; + + dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", + __func__, msg->addr); + + for (i = 0; i < msg->len; i++) { + rxd = (msg->addr << 25) | (1 << 24) + | MANTIS_I2C_RATE_3 + | MANTIS_I2C_STOP + | MANTIS_I2C_PGMODE; + + if (i == (msg->len - 1)) + rxd &= ~MANTIS_I2C_STOP; + + mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); + mmwrite(rxd, MANTIS_I2CDATA_CTL); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CRACK) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + + rxd = mmread(MANTIS_I2CDATA_CTL); + msg->buf[i] = (u8)((rxd >> 8) & 0xFF); + dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); + } + dprintk(MANTIS_INFO, 0, "]\n"); + + return 0; +} + +static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ + int i; + u32 txd = 0, stat, trials; + + dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", + __func__, msg->addr); + + for (i = 0; i < msg->len; i++) { + dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); + txd = (msg->addr << 25) | (msg->buf[i] << 8) + | MANTIS_I2C_RATE_3 + | MANTIS_I2C_STOP + | MANTIS_I2C_PGMODE; + + if (i == (msg->len - 1)) + txd &= ~MANTIS_I2C_STOP; + + mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); + mmwrite(txd, MANTIS_I2CDATA_CTL); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CRACK) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + } + dprintk(MANTIS_INFO, 0, "]\n"); + + return 0; +} + +static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + int ret = 0, i = 0, trials; + u32 stat, data, txd; + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + + mantis = i2c_get_adapdata(adapter); + BUG_ON(!mantis); + config = mantis->hwconfig; + BUG_ON(!config); + + dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); + mutex_lock(&mantis->i2c_lock); + + while (i < num) { + /* Byte MODE */ + if ((config->i2c_mode & MANTIS_BYTE_MODE) && + ((i + 1) < num) && + (msgs[i].len < 2) && + (msgs[i + 1].len < 2) && + (msgs[i + 1].flags & I2C_M_RD)) { + + dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); + + /* Read operation */ + txd = msgs[i].addr << 25 | (0x1 << 24) + | (msgs[i].buf[0] << 16) + | MANTIS_I2C_RATE_3; + + mmwrite(txd, MANTIS_I2CDATA_CTL); + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + /* check for xfer completion */ + if (stat & MANTIS_INT_I2CDONE) { + /* check xfer was acknowledged */ + if (stat & MANTIS_INT_I2CRACK) { + data = mmread(MANTIS_I2CDATA_CTL); + msgs[i + 1].buf[0] = (data >> 8) & 0xff; + dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); + } else { + /* I/O error */ + dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); + ret = -EIO; + break; + } + } else { + /* I/O error */ + dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); + ret = -EIO; + break; + } + i += 2; /* Write/Read operation in one go */ + } + + if (i < num) { + if (msgs[i].flags & I2C_M_RD) + ret = mantis_i2c_read(mantis, &msgs[i]); + else + ret = mantis_i2c_write(mantis, &msgs[i]); + + i++; + if (ret < 0) + goto bail_out; + } + + } + + mutex_unlock(&mantis->i2c_lock); + + return num; + +bail_out: + mutex_unlock(&mantis->i2c_lock); + return ret; +} + +static u32 mantis_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm mantis_algo = { + .master_xfer = mantis_i2c_xfer, + .functionality = mantis_i2c_func, +}; + +int __devinit mantis_i2c_init(struct mantis_pci *mantis) +{ + u32 intstat, intmask; + struct i2c_adapter *i2c_adapter = &mantis->adapter; + struct pci_dev *pdev = mantis->pdev; + + init_waitqueue_head(&mantis->i2c_wq); + mutex_init(&mantis->i2c_lock); + strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); + i2c_set_adapdata(i2c_adapter, mantis); + + i2c_adapter->owner = THIS_MODULE; + i2c_adapter->algo = &mantis_algo; + i2c_adapter->algo_data = NULL; + i2c_adapter->timeout = 500; + i2c_adapter->retries = 3; + i2c_adapter->dev.parent = &pdev->dev; + + mantis->i2c_rc = i2c_add_adapter(i2c_adapter); + if (mantis->i2c_rc < 0) + return mantis->i2c_rc; + + dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); + + intstat = mmread(MANTIS_INT_STAT); + intmask = mmread(MANTIS_INT_MASK); + mmwrite(intstat, MANTIS_INT_STAT); + dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); + intmask = mmread(MANTIS_INT_MASK); + mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_i2c_init); + +int mantis_i2c_exit(struct mantis_pci *mantis) +{ + u32 intmask; + + dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); + intmask = mmread(MANTIS_INT_MASK); + mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + + dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); + return i2c_del_adapter(&mantis->adapter); +} +EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff --git a/drivers/media/pci/mantis/mantis_i2c.h b/drivers/media/pci/mantis/mantis_i2c.h new file mode 100644 index 00000000000..1342df2faed --- /dev/null +++ b/drivers/media/pci/mantis/mantis_i2c.h @@ -0,0 +1,30 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_I2C_H +#define __MANTIS_I2C_H + +#define I2C_STOP (1 << 0) +#define I2C_READ (1 << 1) + +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_I2C_H */ diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c new file mode 100644 index 00000000000..db6d54d3fec --- /dev/null +++ b/drivers/media/pci/mantis/mantis_input.c @@ -0,0 +1,159 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +#define MODULE_NAME "mantis_core" +#define RC_MAP_MANTIS "rc-mantis" + +static struct rc_map_table mantis_ir_table[] = { + { 0x29, KEY_POWER }, + { 0x28, KEY_FAVORITES }, + { 0x30, KEY_TEXT }, + { 0x17, KEY_INFO }, /* Preview */ + { 0x23, KEY_EPG }, + { 0x3b, KEY_F22 }, /* Record List */ + { 0x3c, KEY_1 }, + { 0x3e, KEY_2 }, + { 0x39, KEY_3 }, + { 0x36, KEY_4 }, + { 0x22, KEY_5 }, + { 0x20, KEY_6 }, + { 0x32, KEY_7 }, + { 0x26, KEY_8 }, + { 0x24, KEY_9 }, + { 0x2a, KEY_0 }, + + { 0x33, KEY_CANCEL }, + { 0x2c, KEY_BACK }, + { 0x15, KEY_CLEAR }, + { 0x3f, KEY_TAB }, + { 0x10, KEY_ENTER }, + { 0x14, KEY_UP }, + { 0x0d, KEY_RIGHT }, + { 0x0e, KEY_DOWN }, + { 0x11, KEY_LEFT }, + + { 0x21, KEY_VOLUMEUP }, + { 0x35, KEY_VOLUMEDOWN }, + { 0x3d, KEY_CHANNELDOWN }, + { 0x3a, KEY_CHANNELUP }, + { 0x2e, KEY_RECORD }, + { 0x2b, KEY_PLAY }, + { 0x13, KEY_PAUSE }, + { 0x25, KEY_STOP }, + + { 0x1f, KEY_REWIND }, + { 0x2d, KEY_FASTFORWARD }, + { 0x1e, KEY_PREVIOUS }, /* Replay |< */ + { 0x1d, KEY_NEXT }, /* Skip >| */ + + { 0x0b, KEY_CAMERA }, /* Capture */ + { 0x0f, KEY_LANGUAGE }, /* SAP */ + { 0x18, KEY_MODE }, /* PIP */ + { 0x12, KEY_ZOOM }, /* Full screen */ + { 0x1c, KEY_SUBTITLE }, + { 0x2f, KEY_MUTE }, + { 0x16, KEY_F20 }, /* L/R */ + { 0x38, KEY_F21 }, /* Hibernate */ + + { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ + { 0x31, KEY_AGAIN }, /* Recall */ + { 0x1a, KEY_KPPLUS }, /* Zoom+ */ + { 0x19, KEY_KPMINUS }, /* Zoom- */ + { 0x27, KEY_RED }, + { 0x0C, KEY_GREEN }, + { 0x01, KEY_YELLOW }, + { 0x00, KEY_BLUE }, +}; + +static struct rc_map_list ir_mantis_map = { + .map = { + .scan = mantis_ir_table, + .size = ARRAY_SIZE(mantis_ir_table), + .rc_type = RC_TYPE_UNKNOWN, + .name = RC_MAP_MANTIS, + } +}; + +int mantis_input_init(struct mantis_pci *mantis) +{ + struct rc_dev *dev; + int err; + + err = rc_map_register(&ir_mantis_map); + if (err) + goto out; + + dev = rc_allocate_device(); + if (!dev) { + dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); + err = -ENOMEM; + goto out_map; + } + + sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); + sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); + + dev->input_name = mantis->input_name; + dev->input_phys = mantis->input_phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.vendor = mantis->vendor_id; + dev->input_id.product = mantis->device_id; + dev->input_id.version = 1; + dev->driver_name = MODULE_NAME; + dev->map_name = RC_MAP_MANTIS; + dev->dev.parent = &mantis->pdev->dev; + + err = rc_register_device(dev); + if (err) { + dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err); + goto out_dev; + } + + mantis->rc = dev; + return 0; + +out_dev: + rc_free_device(dev); +out_map: + rc_map_unregister(&ir_mantis_map); +out: + return err; +} + +int mantis_exit(struct mantis_pci *mantis) +{ + rc_unregister_device(mantis->rc); + rc_map_unregister(&ir_mantis_map); + return 0; +} + diff --git a/drivers/media/pci/mantis/mantis_ioc.c b/drivers/media/pci/mantis/mantis_ioc.c new file mode 100644 index 00000000000..24fcdc63d6d --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ioc.c @@ -0,0 +1,124 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_ioc.h" + +static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length) +{ + struct i2c_adapter *adapter = &mantis->adapter; + int err; + u8 buf = reg; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length }, + }; + + err = i2c_transfer(adapter, msg, 2); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", + err, data[0], data[1]); + + return err; + } + + return 0; +} +int mantis_get_mac(struct mantis_pci *mantis) +{ + int err; + u8 mac_addr[6] = {0}; + + err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err); + + return err; + } + + dprintk(MANTIS_ERROR, 0, " MAC Address=[%pM]\n", mac_addr); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_get_mac); + +/* Turn the given bit on or off. */ +void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ + u32 cur; + + dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value); + cur = mmread(MANTIS_GPIF_ADDR); + if (value) + mantis->gpio_status = cur | (1 << bitpos); + else + mantis->gpio_status = cur & (~(1 << bitpos)); + + dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status); + mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); + mmwrite(0x00, MANTIS_GPIF_DOUT); +} +EXPORT_SYMBOL_GPL(mantis_gpio_set_bits); + +int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl) +{ + u32 reg; + + reg = mmread(MANTIS_CONTROL); + switch (stream_ctl) { + case STREAM_TO_HIF: + dprintk(MANTIS_DEBUG, 1, "Set stream to HIF"); + reg &= 0xff - MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + reg |= MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + break; + + case STREAM_TO_CAM: + dprintk(MANTIS_DEBUG, 1, "Set stream to CAM"); + reg |= MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + reg &= 0xff - MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + break; + default: + dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl); + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_stream_control); diff --git a/drivers/media/pci/mantis/mantis_ioc.h b/drivers/media/pci/mantis/mantis_ioc.h new file mode 100644 index 00000000000..d56e002b295 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_ioc.h @@ -0,0 +1,51 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_IOC_H +#define __MANTIS_IOC_H + +#define GPIF_A00 0x00 +#define GPIF_A01 0x01 +#define GPIF_A02 0x02 +#define GPIF_A03 0x03 +#define GPIF_A04 0x04 +#define GPIF_A05 0x05 +#define GPIF_A06 0x06 +#define GPIF_A07 0x07 +#define GPIF_A08 0x08 +#define GPIF_A09 0x09 +#define GPIF_A10 0x0a +#define GPIF_A11 0x0b + +#define GPIF_A12 0x0c +#define GPIF_A13 0x0d +#define GPIF_A14 0x0e + +enum mantis_stream_control { + STREAM_TO_HIF = 0, + STREAM_TO_CAM +}; + +extern int mantis_get_mac(struct mantis_pci *mantis); +extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value); + +extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl); + +#endif /* __MANTIS_IOC_H */ diff --git a/drivers/media/pci/mantis/mantis_link.h b/drivers/media/pci/mantis/mantis_link.h new file mode 100644 index 00000000000..2a814774a00 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_link.h @@ -0,0 +1,83 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_LINK_H +#define __MANTIS_LINK_H + +#include +#include +#include "dvb_ca_en50221.h" + +enum mantis_sbuf_status { + MANTIS_SBUF_DATA_AVAIL = 1, + MANTIS_SBUF_DATA_EMPTY = 2, + MANTIS_SBUF_DATA_OVFLW = 3 +}; + +struct mantis_slot { + u32 timeout; + u32 slave_cfg; + u32 bar; +}; + +/* Physical layer */ +enum mantis_slot_state { + MODULE_INSERTED = 3, + MODULE_XTRACTED = 4 +}; + +struct mantis_ca { + struct mantis_slot slot[4]; + + struct work_struct hif_evm_work; + + u32 hif_event; + wait_queue_head_t hif_opdone_wq; + wait_queue_head_t hif_brrdyw_wq; + wait_queue_head_t hif_data_wq; + wait_queue_head_t hif_write_wq; /* HIF Write op */ + + enum mantis_sbuf_status sbuf_status; + + enum mantis_slot_state slot_state; + + void *ca_priv; + + struct dvb_ca_en50221 en50221; + struct mutex ca_lock; +}; + +/* CA */ +extern void mantis_event_cam_plugin(struct mantis_ca *ca); +extern void mantis_event_cam_unplug(struct mantis_ca *ca); +extern int mantis_pcmcia_init(struct mantis_ca *ca); +extern void mantis_pcmcia_exit(struct mantis_ca *ca); +extern int mantis_evmgr_init(struct mantis_ca *ca); +extern void mantis_evmgr_exit(struct mantis_ca *ca); + +/* HIF */ +extern int mantis_hif_init(struct mantis_ca *ca); +extern void mantis_hif_exit(struct mantis_ca *ca); +extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data); +extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data); + +#endif /* __MANTIS_LINK_H */ diff --git a/drivers/media/pci/mantis/mantis_pci.c b/drivers/media/pci/mantis/mantis_pci.c new file mode 100644 index 00000000000..371558af2d9 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_pci.c @@ -0,0 +1,170 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_pci.h" + +#define DRIVER_NAME "Mantis Core" + +int __devinit mantis_pci_init(struct mantis_pci *mantis) +{ + u8 latency; + struct mantis_hwconfig *config = mantis->hwconfig; + struct pci_dev *pdev = mantis->pdev; + int err, ret = 0; + + dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", + config->model_name, + config->dev_type, + mantis->pdev->bus->number, + PCI_SLOT(mantis->pdev->devfn), + PCI_FUNC(mantis->pdev->devfn)); + + err = pci_enable_device(pdev); + if (err != 0) { + ret = -ENODEV; + dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err); + goto fail0; + } + + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err != 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); + ret = -ENOMEM; + goto fail1; + } + + pci_set_master(pdev); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), + DRIVER_NAME)) { + + dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !"); + ret = -ENODEV; + goto fail1; + } + + mantis->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + if (!mantis->mmio) { + dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !"); + ret = -ENODEV; + goto fail2; + } + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); + mantis->latency = latency; + mantis->revision = pdev->revision; + + dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", + mantis->revision, + mantis->pdev->subsystem_vendor, + mantis->pdev->subsystem_device); + + dprintk(MANTIS_ERROR, 0, + "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", + mantis->pdev->irq, + mantis->latency, + mantis->mantis_addr, + mantis->mmio); + + err = request_irq(pdev->irq, + config->irq_handler, + IRQF_SHARED, + DRIVER_NAME, + mantis); + + if (err != 0) { + + dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err); + ret = -ENODEV; + goto fail3; + } + + pci_set_drvdata(pdev, mantis); + return ret; + + /* Error conditions */ +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret); + if (mantis->mmio) + iounmap(mantis->mmio); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret); + pci_disable_device(pdev); + +fail0: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret); + pci_set_drvdata(pdev, NULL); + return ret; +} +EXPORT_SYMBOL_GPL(mantis_pci_init); + +void mantis_pci_exit(struct mantis_pci *mantis) +{ + struct pci_dev *pdev = mantis->pdev; + + dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio); + free_irq(pdev->irq, mantis); + if (mantis->mmio) { + iounmap(mantis->mmio); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + } + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} +EXPORT_SYMBOL_GPL(mantis_pci_exit); + +MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/mantis/mantis_pci.h b/drivers/media/pci/mantis/mantis_pci.h new file mode 100644 index 00000000000..65f00451908 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_pci.h @@ -0,0 +1,27 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_PCI_H +#define __MANTIS_PCI_H + +extern int mantis_pci_init(struct mantis_pci *mantis); +extern void mantis_pci_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_PCI_H */ diff --git a/drivers/media/pci/mantis/mantis_pcmcia.c b/drivers/media/pci/mantis/mantis_pcmcia.c new file mode 100644 index 00000000000..2f188c08966 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_pcmcia.c @@ -0,0 +1,121 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ +#include "mantis_reg.h" + +/* + * If Slot state is already PLUG_IN event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_plugin(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_irqcfg; + + if (ca->slot_state == MODULE_XTRACTED) { + dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num); + udelay(50); + mmwrite(0xda000000, MANTIS_CARD_RESET); + gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); + gpif_irqcfg |= MANTIS_MASK_PLUGOUT; + gpif_irqcfg &= ~MANTIS_MASK_PLUGIN; + mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); + udelay(500); + ca->slot_state = MODULE_INSERTED; + } + udelay(100); +} + +/* + * If Slot state is already UN_PLUG event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_unplug(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_irqcfg; + + if (ca->slot_state == MODULE_INSERTED) { + dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num); + udelay(50); + mmwrite(0x00da0000, MANTIS_CARD_RESET); + gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); + gpif_irqcfg |= MANTIS_MASK_PLUGIN; + gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT; + mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); + udelay(500); + ca->slot_state = MODULE_XTRACTED; + } + udelay(100); +} + +int mantis_pcmcia_init(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_stat, card_stat; + + mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); + gpif_stat = mmread(MANTIS_GPIF_STATUS); + card_stat = mmread(MANTIS_GPIF_IRQCFG); + + if (gpif_stat & MANTIS_GPIF_DETSTAT) { + dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num); + mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG); + ca->slot_state = MODULE_INSERTED; + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } else { + dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num); + mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG); + ca->slot_state = MODULE_XTRACTED; + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + + return 0; +} + +void mantis_pcmcia_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); + mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); +} diff --git a/drivers/media/pci/mantis/mantis_reg.h b/drivers/media/pci/mantis/mantis_reg.h new file mode 100644 index 00000000000..7761f9dc7fe --- /dev/null +++ b/drivers/media/pci/mantis/mantis_reg.h @@ -0,0 +1,197 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_REG_H +#define __MANTIS_REG_H + +/* Interrupts */ +#define MANTIS_INT_STAT 0x00 +#define MANTIS_INT_MASK 0x04 + +#define MANTIS_INT_RISCSTAT (0x0f << 28) +#define MANTIS_INT_RISCEN (0x01 << 27) +#define MANTIS_INT_I2CRACK (0x01 << 26) + +/* #define MANTIS_INT_GPIF (0xff << 12) */ + +#define MANTIS_INT_PCMCIA7 (0x01 << 19) +#define MANTIS_INT_PCMCIA6 (0x01 << 18) +#define MANTIS_INT_PCMCIA5 (0x01 << 17) +#define MANTIS_INT_PCMCIA4 (0x01 << 16) +#define MANTIS_INT_PCMCIA3 (0x01 << 15) +#define MANTIS_INT_PCMCIA2 (0x01 << 14) +#define MANTIS_INT_PCMCIA1 (0x01 << 13) +#define MANTIS_INT_PCMCIA0 (0x01 << 12) +#define MANTIS_INT_IRQ1 (0x01 << 11) +#define MANTIS_INT_IRQ0 (0x01 << 10) +#define MANTIS_INT_OCERR (0x01 << 8) +#define MANTIS_INT_PABORT (0x01 << 7) +#define MANTIS_INT_RIPERR (0x01 << 6) +#define MANTIS_INT_PPERR (0x01 << 5) +#define MANTIS_INT_FTRGT (0x01 << 3) +#define MANTIS_INT_RISCI (0x01 << 1) +#define MANTIS_INT_I2CDONE (0x01 << 0) + +/* DMA */ +#define MANTIS_DMA_CTL 0x08 +#define MANTIS_GPIF_RD (0xff << 24) +#define MANTIS_GPIF_WR (0xff << 16) +#define MANTIS_CPU_DO (0x01 << 10) +#define MANTIS_DRV_DO (0x01 << 9) +#define MANTIS_I2C_RD (0x01 << 7) +#define MANTIS_I2C_WR (0x01 << 6) +#define MANTIS_DCAP_MODE (0x01 << 5) +#define MANTIS_FIFO_TP_4 (0x00 << 3) +#define MANTIS_FIFO_TP_8 (0x01 << 3) +#define MANTIS_FIFO_TP_16 (0x02 << 3) +#define MANTIS_FIFO_EN (0x01 << 2) +#define MANTIS_DCAP_EN (0x01 << 1) +#define MANTIS_RISC_EN (0x01 << 0) + +/* DEBUG */ +#define MANTIS_DEBUGREG 0x0c +#define MANTIS_DATINV (0x0e << 7) +#define MANTIS_TOP_DEBUGSEL (0x07 << 4) +#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0) + +#define MANTIS_RISC_START 0x10 +#define MANTIS_RISC_PC 0x14 + +/* I2C */ +#define MANTIS_I2CDATA_CTL 0x18 +#define MANTIS_I2C_RATE_1 (0x00 << 6) +#define MANTIS_I2C_RATE_2 (0x01 << 6) +#define MANTIS_I2C_RATE_3 (0x02 << 6) +#define MANTIS_I2C_RATE_4 (0x03 << 6) +#define MANTIS_I2C_STOP (0x01 << 5) +#define MANTIS_I2C_PGMODE (0x01 << 3) + +/* DATA */ +#define MANTIS_CMD_DATA_R1 0x20 +#define MANTIS_CMD_DATA_3 (0xff << 24) +#define MANTIS_CMD_DATA_2 (0xff << 16) +#define MANTIS_CMD_DATA_1 (0xff << 8) +#define MANTIS_CMD_DATA_0 (0xff << 0) + +#define MANTIS_CMD_DATA_R2 0x24 +#define MANTIS_CMD_DATA_7 (0xff << 24) +#define MANTIS_CMD_DATA_6 (0xff << 16) +#define MANTIS_CMD_DATA_5 (0xff << 8) +#define MANTIS_CMD_DATA_4 (0xff << 0) + +#define MANTIS_CONTROL 0x28 +#define MANTIS_DET (0x01 << 7) +#define MANTIS_DAT_CF_EN (0x01 << 6) +#define MANTIS_ACS (0x03 << 4) +#define MANTIS_VCCEN (0x01 << 3) +#define MANTIS_BYPASS (0x01 << 2) +#define MANTIS_MRST (0x01 << 1) +#define MANTIS_CRST_INT (0x01 << 0) + +#define MANTIS_GPIF_CFGSLA 0x84 +#define MANTIS_GPIF_WAITSMPL (0x07 << 28) +#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) +#define MANTIS_GPIF_WAITPOL (0x01 << 24) +#define MANTIS_GPIF_NCDELAY (0x07 << 20) +#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) +#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) +#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) +#define MANTIS_GPIF_DEVTYPE (0x07 << 4) +#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) +#define MANTIS_GPIF_FETCHCMD (0x03 << 1) +#define MANTIS_GPIF_HWORDDEV (0x01 << 0) + +#define MANTIS_GPIF_WSTOPER 0x90 +#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) +#define MANTIS_GPIF_PARBOOTN (0x01 << 29) +#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) +#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) +#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) +#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) +#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) +#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) +#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) + +#define MANTIS_GPIF_CS2RW 0x94 +#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) +#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) +#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) +#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) +#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) +#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) +#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) +#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) + +#define MANTIS_GPIF_IRQCFG 0x98 +#define MANTIS_GPIF_IRQPOL (0x01 << 8) +#define MANTIS_MASK_WRACK (0x01 << 7) +#define MANTIS_MASK_BRRDY (0x01 << 6) +#define MANTIS_MASK_OVFLW (0x01 << 5) +#define MANTIS_MASK_OTHERR (0x01 << 4) +#define MANTIS_MASK_WSTO (0x01 << 3) +#define MANTIS_MASK_EXTIRQ (0x01 << 2) +#define MANTIS_MASK_PLUGIN (0x01 << 1) +#define MANTIS_MASK_PLUGOUT (0x01 << 0) + +#define MANTIS_GPIF_STATUS 0x9c +#define MANTIS_SBUF_KILLOP (0x01 << 15) +#define MANTIS_SBUF_OPDONE (0x01 << 14) +#define MANTIS_SBUF_EMPTY (0x01 << 13) +#define MANTIS_GPIF_DETSTAT (0x01 << 9) +#define MANTIS_GPIF_INTSTAT (0x01 << 8) +#define MANTIS_GPIF_WRACK (0x01 << 7) +#define MANTIS_GPIF_BRRDY (0x01 << 6) +#define MANTIS_SBUF_OVFLW (0x01 << 5) +#define MANTIS_GPIF_OTHERR (0x01 << 4) +#define MANTIS_SBUF_WSTO (0x01 << 3) +#define MANTIS_GPIF_EXTIRQ (0x01 << 2) +#define MANTIS_CARD_PLUGIN (0x01 << 1) +#define MANTIS_CARD_PLUGOUT (0x01 << 0) + +#define MANTIS_GPIF_BRADDR 0xa0 +#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) +#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) + +#define MANTIS_GPIF_BRBYTES 0xa4 +#define MANTIS_GPIF_BRCNT (0xfff << 0) + +#define MANTIS_PCMCIA_RESET 0xa8 +#define MANTIS_PCMCIA_RSTVAL (0xff << 0) + +#define MANTIS_CARD_RESET 0xac + +#define MANTIS_GPIF_ADDR 0xb0 +#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) +#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) +#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_HIFADDR (0xfffffff << 0) + +#define MANTIS_GPIF_DOUT 0xb4 +#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0) + +#define MANTIS_GPIF_DIN 0xb8 +#define MANTIS_GPIF_HIFDIN (0xfffffff << 0) + +#define MANTIS_GPIF_SPARE 0xbc +#define MANTIS_GPIF_LOGICRD (0xffff << 16) +#define MANTIS_GPIF_LOGICRW (0xffff << 0) + +#endif /* __MANTIS_REG_H */ diff --git a/drivers/media/pci/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c new file mode 100644 index 00000000000..18340dafa42 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_uart.c @@ -0,0 +1,188 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +struct mantis_uart_params { + enum mantis_baud baud_rate; + enum mantis_parity parity; +}; + +static struct { + char string[7]; +} rates[5] = { + { "9600" }, + { "19200" }, + { "38400" }, + { "57600" }, + { "115200" } +}; + +static struct { + char string[5]; +} parity[3] = { + { "NONE" }, + { "ODD" }, + { "EVEN" } +}; + +#define UART_MAX_BUF 16 + +int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + u32 stat = 0, i; + + /* get data */ + for (i = 0; i < (config->bytes + 1); i++) { + + stat = mmread(MANTIS_UART_STAT); + + if (stat & MANTIS_UART_RXFIFO_FULL) { + dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); + } + data[i] = mmread(MANTIS_UART_RXD) & 0x3f; + + dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); + + if (data[i] & (1 << 7)) { + dprintk(MANTIS_ERROR, 1, "UART framing error"); + return -EINVAL; + } + if (data[i] & (1 << 6)) { + dprintk(MANTIS_ERROR, 1, "UART parity error"); + return -EINVAL; + } + } + + return 0; +} + +static void mantis_uart_work(struct work_struct *work) +{ + struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); + struct mantis_hwconfig *config = mantis->hwconfig; + u8 buf[16]; + int i; + + mantis_uart_read(mantis, buf); + + for (i = 0; i < (config->bytes + 1); i++) + dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); + + dprintk(MANTIS_DEBUG, 0, "\n"); +} + +static int mantis_uart_setup(struct mantis_pci *mantis, + struct mantis_uart_params *params) +{ + u32 reg; + + mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); + + reg = mmread(MANTIS_UART_BAUD); + + switch (params->baud_rate) { + case MANTIS_BAUD_9600: + reg |= 0xd8; + break; + case MANTIS_BAUD_19200: + reg |= 0x6c; + break; + case MANTIS_BAUD_38400: + reg |= 0x36; + break; + case MANTIS_BAUD_57600: + reg |= 0x23; + break; + case MANTIS_BAUD_115200: + reg |= 0x11; + break; + default: + return -EINVAL; + } + + mmwrite(reg, MANTIS_UART_BAUD); + + return 0; +} + +int mantis_uart_init(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + struct mantis_uart_params params; + + /* default parity: */ + params.baud_rate = config->baud_rate; + params.parity = config->parity; + dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s", + rates[params.baud_rate].string, + parity[params.parity].string); + + init_waitqueue_head(&mantis->uart_wq); + spin_lock_init(&mantis->uart_lock); + + INIT_WORK(&mantis->uart_work, mantis_uart_work); + + /* disable interrupt */ + mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); + + mantis_uart_setup(mantis, ¶ms); + + /* default 1 byte */ + mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); + + /* flush buffer */ + mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); + + /* enable interrupt */ + mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); + mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); + + schedule_work(&mantis->uart_work); + dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_uart_init); + +void mantis_uart_exit(struct mantis_pci *mantis) +{ + /* disable interrupt */ + mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); + flush_work_sync(&mantis->uart_work); +} +EXPORT_SYMBOL_GPL(mantis_uart_exit); diff --git a/drivers/media/pci/mantis/mantis_uart.h b/drivers/media/pci/mantis/mantis_uart.h new file mode 100644 index 00000000000..ffb62a0a5a1 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_uart.h @@ -0,0 +1,58 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_UART_H +#define __MANTIS_UART_H + +#define MANTIS_UART_CTL 0xe0 +#define MANTIS_UART_RXINT (1 << 4) +#define MANTIS_UART_RXFLUSH (1 << 2) + +#define MANTIS_UART_RXD 0xe8 +#define MANTIS_UART_BAUD 0xec + +#define MANTIS_UART_STAT 0xf0 +#define MANTIS_UART_RXFIFO_DATA (1 << 7) +#define MANTIS_UART_RXFIFO_EMPTY (1 << 6) +#define MANTIS_UART_RXFIFO_FULL (1 << 3) +#define MANTIS_UART_FRAME_ERR (1 << 2) +#define MANTIS_UART_PARITY_ERR (1 << 1) +#define MANTIS_UART_RXTHRESH_INT (1 << 0) + +enum mantis_baud { + MANTIS_BAUD_9600 = 0, + MANTIS_BAUD_19200, + MANTIS_BAUD_38400, + MANTIS_BAUD_57600, + MANTIS_BAUD_115200 +}; + +enum mantis_parity { + MANTIS_PARITY_NONE = 0, + MANTIS_PARITY_EVEN, + MANTIS_PARITY_ODD, +}; + +struct mantis_pci; + +extern int mantis_uart_init(struct mantis_pci *mantis); +extern void mantis_uart_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_UART_H */ diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c new file mode 100644 index 00000000000..ad013e93ed1 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1033.c @@ -0,0 +1,212 @@ +/* + Mantis VP-1033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "stv0299.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1033.h" +#include "mantis_reg.h" + +u8 lgtdqcs001f_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x2a, + 0x05, 0x85, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x00, + 0x0c, 0x01, + 0x0d, 0x81, + 0x0e, 0x44, + 0x0f, 0x94, + 0x10, 0x3c, + 0x11, 0x84, + 0x12, 0xb9, + 0x13, 0xb5, + 0x14, 0x4f, + 0x15, 0xc9, + 0x16, 0x80, + 0x17, 0x36, + 0x18, 0xfb, + 0x19, 0xcf, + 0x1a, 0xbc, + 0x1c, 0x2b, + 0x1d, 0x27, + 0x1e, 0x00, + 0x1f, 0x0b, + 0x20, 0xa1, + 0x21, 0x60, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x05, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x13, + 0xff, 0xff, +}; + +#define MANTIS_MODEL_NAME "VP-1033" +#define MANTIS_DEV_TYPE "DVB-S/DSS" + +int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[4]; + u32 div; + + + struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; + + div = p->frequency / 250; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x83; + buf[3] = 0xc0; + + if (p->frequency < 1531000) + buf[3] |= 0x04; + else + buf[3] &= ~0x04; + if (i2c_transfer(adapter, &msg, 1) < 0) { + dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed"); + return -EIO; + } + msleep_interruptible(100); + + return 0; +} + +int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + + return 0; +} + +struct stv0299_config lgtdqcs001f_config = { + .demod_address = 0x68, + .inittab = lgtdqcs001f_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = lgtdqcs001f_set_symbol_rate, +}; + +static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)"); + fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter); + + if (fe) { + fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set; + dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", + lgtdqcs001f_config.demod_address); + + dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1033_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1033_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp1033.h b/drivers/media/pci/mantis/mantis_vp1033.h new file mode 100644 index 00000000000..7daaa1bf127 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1033.h @@ -0,0 +1,30 @@ +/* + Mantis VP-1033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1033_H +#define __MANTIS_VP1033_H + +#include "mantis_common.h" + +#define MANTIS_VP_1033_DVB_S 0x0016 + +extern struct mantis_hwconfig vp1033_config; + +#endif /* __MANTIS_VP1033_H */ diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c new file mode 100644 index 00000000000..430ae84ce52 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1034.c @@ -0,0 +1,120 @@ +/* + Mantis VP-1034 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mb86a16.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1034.h" +#include "mantis_reg.h" + +struct mb86a16_config vp1034_mb86a16_config = { + .demod_address = 0x08, + .set_voltage = vp1034_set_voltage, +}; + +#define MANTIS_MODEL_NAME "VP-1034" +#define MANTIS_DEV_TYPE "DVB-S/DSS" + +int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct mantis_pci *mantis = fe->dvb->priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk(MANTIS_ERROR, 1, "Polarization=[13V]"); + mantis_gpio_set_bits(mantis, 13, 1); + mantis_gpio_set_bits(mantis, 14, 0); + break; + case SEC_VOLTAGE_18: + dprintk(MANTIS_ERROR, 1, "Polarization=[18V]"); + mantis_gpio_set_bits(mantis, 13, 1); + mantis_gpio_set_bits(mantis, 14, 1); + break; + case SEC_VOLTAGE_OFF: + dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN"); + break; + default: + dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage); + return -EINVAL; + } + mmwrite(0x00, MANTIS_GPIF_DOUT); + + return 0; +} + +static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); + fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter); + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found MB86A16 DVB-S/DSS frontend @0x%02x", + vp1034_mb86a16_config.demod_address); + + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1034_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1034_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp1034.h b/drivers/media/pci/mantis/mantis_vp1034.h new file mode 100644 index 00000000000..323f38ef8e3 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1034.h @@ -0,0 +1,33 @@ +/* + Mantis VP-1034 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1034_H +#define __MANTIS_VP1034_H + +#include "dvb_frontend.h" +#include "mantis_common.h" + + +#define MANTIS_VP_1034_DVB_S 0x0014 + +extern struct mantis_hwconfig vp1034_config; +extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + +#endif /* __MANTIS_VP1034_H */ diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c new file mode 100644 index 00000000000..07aa887a4b4 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1041.c @@ -0,0 +1,357 @@ +/* + Mantis VP-1041 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1041.h" +#include "stb0899_reg.h" +#include "stb0899_drv.h" +#include "stb0899_cfg.h" +#include "stb6100_cfg.h" +#include "stb6100.h" +#include "lnbp21.h" + +#define MANTIS_MODEL_NAME "VP-1041" +#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2" + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { + + /* 0x0000000b, *//* SYSREG */ + { STB0899_DEV_ID , 0x30 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x99 }, + { STB0899_DISF22RX , 0xa8 }, + /* SYSREG ? */ + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0xfe }, + { STB0899_IRQSTATUS_2 , 0x03 }, + { STB0899_IRQSTATUS_1 , 0x7c }, + { STB0899_IRQSTATUS_0 , 0xf4 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x33 }, + { STB0899_IOPVALUE3 , 0x6d }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x60 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x01 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x01 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x23 }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xf7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xf1 }, + { STB0899_LDT2 , 0xe3 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfd }, + { STB0899_QDCCOMP , 0xff }, + { STB0899_POWERI , 0x0c }, + { STB0899_POWERQ , 0x0f }, + { STB0899_RCOMP , 0x6c }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x06 }, + { STB0899_AGC2I2 , 0x00 }, + { STB0899_TLIR , 0x30 }, + { STB0899_RTF , 0x7f }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xbc }, + { STB0899_CFRM , 0xea }, + { STB0899_CFRL , 0x31 }, + { STB0899_NIRM , 0x2b }, + { STB0899_NIRL , 0x80 }, + { STB0899_ISYMB , 0x1d }, + { STB0899_QSYMB , 0xa6 }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0x02 }, + { STB0899_EQUAQ1 , 0xff }, + { STB0899_EQUAI2 , 0x04 }, + { STB0899_EQUAQ2 , 0x05 }, + { STB0899_EQUAI3 , 0x02 }, + { STB0899_EQUAQ3 , 0xfd }, + { STB0899_EQUAI4 , 0x03 }, + { STB0899_EQUAQ4 , 0x07 }, + { STB0899_EQUAI5 , 0x08 }, + { STB0899_EQUAQ5 , 0xf5 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0x86 }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x0a }, + { STB0899_ECNT3L , 0xad }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xb0 }, + { STB0899_VTH23 , 0x7a }, + { STB0899_VTH34 , 0x58 }, + { STB0899_VTH56 , 0x38 }, + { STB0899_VTH67 , 0x34 }, + { STB0899_VTH78 , 0x24 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x41 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x00 }, + { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x1b }, + { STB0899_TSLLSTKL , 0xb3 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0x00 }, + { STB0899_PCKLENUL , 0xbc }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xbd }, + { STB0899_TSSTATUS , 0x90 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x95 }, + { STB0899_ERRCTRL3 , 0x8d }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x19 }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0xf0 }, + { STB0899_MATSTRL , 0x02 }, + { STB0899_UPLSTRM , 0x45 }, + { STB0899_UPLSTRL , 0x60 }, + { STB0899_DFLSTRM , 0xe3 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x47 }, + { STB0899_SYNCDSTRM , 0x05 }, + { STB0899_SYNCDSTRL , 0x18 }, + { STB0899_CFGPDELSTATUS1 , 0x19 }, + { STB0899_CFGPDELSTATUS2 , 0x2b }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x01 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +struct stb0899_config vp1041_stb0899_config = { + .init_dev = vp1041_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = vp1041_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = 0x68, /* 0xd0 >> 1 */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, +}; + +struct stb6100_config vp1041_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter); + if (mantis->fe) { + dprintk(MANTIS_ERROR, 1, + "found STB0899 DVB-S/DVB-S2 frontend @0x%02x", + vp1041_stb0899_config.demod_address); + + if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) { + if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0)) + dprintk(MANTIS_ERROR, 1, "No LNBP21 found!"); + } + } else { + return -EREMOTEIO; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + + + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1041_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1041_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp1041.h b/drivers/media/pci/mantis/mantis_vp1041.h new file mode 100644 index 00000000000..1ae5b3de808 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp1041.h @@ -0,0 +1,33 @@ +/* + Mantis VP-1041 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1041_H +#define __MANTIS_VP1041_H + +#include "mantis_common.h" + +#define MANTIS_VP_1041_DVB_S2 0x0031 +#define SKYSTAR_HD2_10 0x0001 +#define SKYSTAR_HD2_20 0x0003 +#define CINERGY_S2_PCI_HD 0x1179 + +extern struct mantis_hwconfig vp1041_config; + +#endif /* __MANTIS_VP1041_H */ diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c new file mode 100644 index 00000000000..1ca6837fbe4 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2033.c @@ -0,0 +1,188 @@ +/* + Mantis VP-2033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2033.h" + +#define MANTIS_MODEL_NAME "VP-2033" +#define MANTIS_DEV_TYPE "DVB-C" + +struct tda1002x_config vp2033_tda1002x_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +struct tda10023_config vp2033_tda10023_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +static u8 read_pwm(struct mantis_pci *mantis) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { + {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} + }; + + if ((i2c_transfer(adapter, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (p->frequency < 150000000 ? 0x01 : + p->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); + fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", + vp2033_tda1002x_cu1216_config.demod_address); + } else { + fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", + vp2033_tda1002x_cu1216_config.demod_address); + } + } + + if (fe) { + fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; + dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + + mantis->fe = fe; + dprintk(MANTIS_DEBUG, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp2033_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp2033_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp2033.h b/drivers/media/pci/mantis/mantis_vp2033.h new file mode 100644 index 00000000000..c55242b79d5 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2033.h @@ -0,0 +1,30 @@ +/* + Mantis VP-2033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP2033_H +#define __MANTIS_VP2033_H + +#include "mantis_common.h" + +#define MANTIS_VP_2033_DVB_C 0x0008 + +extern struct mantis_hwconfig vp2033_config; + +#endif /* __MANTIS_VP2033_H */ diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c new file mode 100644 index 00000000000..d480741afd7 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2040.c @@ -0,0 +1,187 @@ +/* + Mantis VP-2040 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2040.h" + +#define MANTIS_MODEL_NAME "VP-2040" +#define MANTIS_DEV_TYPE "DVB-C" + +struct tda1002x_config vp2040_tda1002x_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +struct tda10023_config vp2040_tda10023_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (p->frequency < 150000000 ? 0x01 : + p->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static u8 read_pwm(struct mantis_pci *mantis) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { + {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} + }; + + if ((i2c_transfer(adapter, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); + fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", + vp2040_tda1002x_cu1216_config.demod_address); + } else { + fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", + vp2040_tda1002x_cu1216_config.demod_address); + } + } + + if (fe) { + fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; + dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_DEBUG, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp2040_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp2040_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/pci/mantis/mantis_vp2040.h b/drivers/media/pci/mantis/mantis_vp2040.h new file mode 100644 index 00000000000..d125e219b68 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp2040.h @@ -0,0 +1,32 @@ +/* + Mantis VP-2040 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP2040_H +#define __MANTIS_VP2040_H + +#include "mantis_common.h" + +#define MANTIS_VP_2040_DVB_C 0x0043 +#define CINERGY_C 0x1178 +#define CABLESTAR_HD2 0x0002 + +extern struct mantis_hwconfig vp2040_config; + +#endif /* __MANTIS_VP2040_H */ diff --git a/drivers/media/pci/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c new file mode 100644 index 00000000000..4155c838a18 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3028.c @@ -0,0 +1,38 @@ +/* + Mantis VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "mantis_common.h" +#include "mantis_vp3028.h" + +struct zl10353_config mantis_vp3028_config = { + .demod_address = 0x0f, +}; + +#define MANTIS_MODEL_NAME "VP-3028" +#define MANTIS_DEV_TYPE "DVB-T" + +struct mantis_hwconfig vp3028_mantis_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, +}; diff --git a/drivers/media/pci/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h new file mode 100644 index 00000000000..b07be6adc52 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3028.h @@ -0,0 +1,33 @@ +/* + Mantis VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "dvb_frontend.h" +#include "mantis_common.h" +#include "zl10353.h" + +#define MANTIS_VP_3028_DVB_T 0x0028 + +extern struct zl10353_config mantis_vp3028_config; +extern struct mantis_hwconfig vp3028_mantis_config; + +#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c new file mode 100644 index 00000000000..c09308cd3ac --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3030.c @@ -0,0 +1,105 @@ +/* + Mantis VP-3030 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "tda665x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp3030.h" + +struct zl10353_config mantis_vp3030_config = { + .demod_address = 0x0f, +}; + +struct tda665x_config env57h12d5_config = { + .name = "ENV57H12D5 (ET-50DT)", + .addr = 0x60, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_offst = 3616667, + .ref_multiplier = 6, /* 1/6 MHz */ + .ref_divider = 100000, /* 1/6 MHz */ +}; + +#define MANTIS_MODEL_NAME "VP-3030" +#define MANTIS_DEV_TYPE "DVB-T" + + +static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + struct mantis_hwconfig *config = mantis->hwconfig; + int err = 0; + + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + err = mantis_frontend_power(mantis, POWER_ON); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + + if (err == 0) { + msleep(250); + dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); + fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter); + + if (!fe) + return -1; + + dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter); + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp3030_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp3030_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, + + .i2c_mode = MANTIS_BYTE_MODE +}; diff --git a/drivers/media/pci/mantis/mantis_vp3030.h b/drivers/media/pci/mantis/mantis_vp3030.h new file mode 100644 index 00000000000..5f12c426627 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_vp3030.h @@ -0,0 +1,30 @@ +/* + Mantis VP-3030 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3030_H +#define __MANTIS_VP3030_H + +#include "mantis_common.h" + +#define MANTIS_VP_3030_DVB_T 0x0024 + +extern struct mantis_hwconfig vp3030_config; + +#endif /* __MANTIS_VP3030_H */ diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig new file mode 100644 index 00000000000..64c84702ba5 --- /dev/null +++ b/drivers/media/pci/ngene/Kconfig @@ -0,0 +1,13 @@ +config DVB_NGENE + tristate "Micronas nGene support" + depends on DVB_CORE && PCI && I2C + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE + ---help--- + Support for Micronas PCI express cards with nGene bridge. + diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile new file mode 100644 index 00000000000..63997089f9d --- /dev/null +++ b/drivers/media/pci/ngene/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the nGene device driver +# + +ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o + +obj-$(CONFIG_DVB_NGENE) += ngene.o + +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/dvb-frontends/ +ccflags-y += -Idrivers/media/common/tuners/ + +# For the staging CI driver cxd2099 +ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c new file mode 100644 index 00000000000..a6cd6959ad1 --- /dev/null +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -0,0 +1,823 @@ +/* + * ngene-cards.c: nGene PCIe bridge driver - card specific info + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include + +#include "ngene.h" + +/* demods/tuners */ +#include "stv6110x.h" +#include "stv090x.h" +#include "lnbh24.h" +#include "lgdt330x.h" +#include "mt2131.h" +#include "tda18271c2dd.h" +#include "drxk.h" +#include "drxd.h" +#include "dvb-pll.h" + + +/****************************************************************************/ +/* Demod/tuner attachment ***************************************************/ +/****************************************************************************/ + +static int tuner_attach_stv6110(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *feconf = (struct stv090x_config *) + chan->dev->card_info->fe_config[chan->number]; + struct stv6110x_config *tunerconf = (struct stv6110x_config *) + chan->dev->card_info->tuner_config[chan->number]; + struct stv6110x_devctl *ctl; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); + if (ctl == NULL) { + printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + return -ENODEV; + } + + feconf->tuner_init = ctl->tuner_init; + feconf->tuner_sleep = ctl->tuner_sleep; + feconf->tuner_set_mode = ctl->tuner_set_mode; + feconf->tuner_set_frequency = ctl->tuner_set_frequency; + feconf->tuner_get_frequency = ctl->tuner_get_frequency; + feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; + feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; + feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; + feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; + feconf->tuner_set_refclk = ctl->tuner_set_refclk; + feconf->tuner_get_status = ctl->tuner_get_status; + + return 0; +} + + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct ngene_channel *chan = fe->sec_priv; + int status; + + if (enable) { + down(&chan->dev->pll_mutex); + status = chan->gate_ctrl(fe, 1); + } else { + status = chan->gate_ctrl(fe, 0); + up(&chan->dev->pll_mutex); + } + return status; +} + +static int tuner_attach_tda18271(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + + i2c = &chan->dev->channel[0].i2c_adapter; + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); + if (!fe) { + printk(KERN_ERR "No TDA18271 found!\n"); + return -ENODEV; + } + + return 0; +} + +static int tuner_attach_probe(struct ngene_channel *chan) +{ + if (chan->demod_type == 0) + return tuner_attach_stv6110(chan); + if (chan->demod_type == 1) + return tuner_attach_tda18271(chan); + return -EINVAL; +} + +static int demod_attach_stv0900(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *feconf = (struct stv090x_config *) + chan->dev->card_info->fe_config[chan->number]; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + /* Note: Both adapters share the same i2c bus, but the demod */ + /* driver requires that each demod has its own i2c adapter */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + chan->fe = dvb_attach(stv090x_attach, feconf, i2c, + (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 + : STV090x_DEMODULATOR_1); + if (chan->fe == NULL) { + printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + return -ENODEV; + } + + /* store channel info */ + if (feconf->tuner_i2c_lock) + chan->fe->analog_demod_priv = chan; + + if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, + 0, chan->dev->card_info->lnb[chan->number])) { + printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + return -ENODEV; + } + + return 0; +} + +static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) +{ + struct ngene_channel *chan = fe->analog_demod_priv; + + if (lock) + down(&chan->dev->pll_mutex); + else + up(&chan->dev->pll_mutex); +} + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg>>8, reg&0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int port_has_stv0900(struct i2c_adapter *i2c, int port) +{ + u8 val; + if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_drxk(struct i2c_adapter *i2c, int port) +{ + u8 val; + + if (i2c_read(i2c, 0x29+port, &val) < 0) + return 0; + return 1; +} + +static int demod_attach_drxk(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct drxk_config config; + + memset(&config, 0, sizeof(config)); + config.microcode_name = "drxk_a3.mc"; + config.qam_demod_parameter_count = 4; + config.adr = 0x29 + (chan->number ^ 2); + + chan->fe = dvb_attach(drxk_attach, &config, i2c); + if (!chan->fe) { + printk(KERN_ERR "No DRXK found!\n"); + return -ENODEV; + } + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + +static int cineS2_probe(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *fe_conf; + u8 buf[3]; + struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; + int rc; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + if (port_has_stv0900(i2c, chan->number)) { + chan->demod_type = 0; + fe_conf = chan->dev->card_info->fe_config[chan->number]; + /* demod found, attach it */ + rc = demod_attach_stv0900(chan); + if (rc < 0 || chan->number < 2) + return rc; + + /* demod #2: reprogram outputs DPN1 & DPN2 */ + i2c_msg.addr = fe_conf->address; + i2c_msg.len = 3; + buf[0] = 0xf1; + switch (chan->number) { + case 2: + buf[1] = 0x5c; + buf[2] = 0xc2; + break; + case 3: + buf[1] = 0x61; + buf[2] = 0xcc; + break; + default: + return -ENODEV; + } + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) { + printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + return -EIO; + } + } else if (port_has_drxk(i2c, chan->number^2)) { + chan->demod_type = 1; + demod_attach_drxk(chan, i2c); + } else { + printk(KERN_ERR "No demod found on chan %d\n", chan->number); + return -ENODEV; + } + return 0; +} + + +static struct lgdt330x_config aver_m780 = { + .demod_address = 0xb2 >> 1, + .demod_chip = LGDT3303, + .serial_mpeg = 0x00, /* PARALLEL */ + .clock_polarity_flip = 1, +}; + +static struct mt2131_config m780_tunerconfig = { + 0xc0 >> 1 +}; + +/* A single func to attach the demo and tuner, rather than + * use two sep funcs like the current design mandates. + */ +static int demod_attach_lg330x(struct ngene_channel *chan) +{ + chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); + if (chan->fe == NULL) { + printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); + return -ENODEV; + } + + dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, + &m780_tunerconfig, 0); + + return (chan->fe) ? 0 : -ENODEV; +} + +static int demod_attach_drxd(struct ngene_channel *chan) +{ + struct drxd_config *feconf; + + feconf = chan->dev->card_info->fe_config[chan->number]; + + chan->fe = dvb_attach(drxd_attach, feconf, chan, + &chan->i2c_adapter, &chan->dev->pci_dev->dev); + if (!chan->fe) { + pr_err("No DRXD found!\n"); + return -ENODEV; + } + + if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address, + &chan->i2c_adapter, + feconf->pll_type)) { + pr_err("No pll(%d) found!\n", feconf->pll_type); + return -ENODEV; + } + return 0; +} + +/****************************************************************************/ +/* EEPROM TAGS **************************************************************/ +/****************************************************************************/ + +#define MICNG_EE_START 0x0100 +#define MICNG_EE_END 0x0FF0 + +#define MICNG_EETAG_END0 0x0000 +#define MICNG_EETAG_END1 0xFFFF + +/* 0x0001 - 0x000F reserved for housekeeping */ +/* 0xFFFF - 0xFFFE reserved for housekeeping */ + +/* Micronas assigned tags + EEProm tags for hardware support */ + +#define MICNG_EETAG_DRXD1_OSCDEVIATION 0x1000 /* 2 Bytes data */ +#define MICNG_EETAG_DRXD2_OSCDEVIATION 0x1001 /* 2 Bytes data */ + +#define MICNG_EETAG_MT2060_1_1STIF 0x1100 /* 2 Bytes data */ +#define MICNG_EETAG_MT2060_2_1STIF 0x1101 /* 2 Bytes data */ + +/* Tag range for OEMs */ + +#define MICNG_EETAG_OEM_FIRST 0xC000 +#define MICNG_EETAG_OEM_LAST 0xFFEF + +static int i2c_write_eeprom(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 data) +{ + u8 m[3] = {(reg >> 8), (reg & 0xff), data}; + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, + .len = sizeof(m)}; + + if (i2c_transfer(adapter, &msg, 1) != 1) { + pr_err(DEVICE_NAME ": Error writing EEPROM!\n"); + return -EIO; + } + return 0; +} + +static int i2c_read_eeprom(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 *data, int len) +{ + u8 msg[2] = {(reg >> 8), (reg & 0xff)}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = data, .len = len} }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + pr_err(DEVICE_NAME ": Error reading EEPROM\n"); + return -EIO; + } + return 0; +} + +static int ReadEEProm(struct i2c_adapter *adapter, + u16 Tag, u32 MaxLen, u8 *data, u32 *pLength) +{ + int status = 0; + u16 Addr = MICNG_EE_START, Length, tag = 0; + u8 EETag[3]; + + while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { + if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) + return -1; + tag = (EETag[0] << 8) | EETag[1]; + if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) + return -1; + if (tag == Tag) + break; + Addr += sizeof(u16) + 1 + EETag[2]; + } + if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { + pr_err(DEVICE_NAME + ": Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); + return -1; + } + Length = EETag[2]; + if (Length > MaxLen) + Length = (u16) MaxLen; + if (Length > 0) { + Addr += sizeof(u16) + 1; + status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length); + if (!status) { + *pLength = EETag[2]; + if (Length < EETag[2]) + ; /*status=STATUS_BUFFER_OVERFLOW; */ + } + } + return status; +} + +static int WriteEEProm(struct i2c_adapter *adapter, + u16 Tag, u32 Length, u8 *data) +{ + int status = 0; + u16 Addr = MICNG_EE_START; + u8 EETag[3]; + u16 tag = 0; + int retry, i; + + while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { + if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) + return -1; + tag = (EETag[0] << 8) | EETag[1]; + if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) + return -1; + if (tag == Tag) + break; + Addr += sizeof(u16) + 1 + EETag[2]; + } + if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { + pr_err(DEVICE_NAME + ": Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); + return -1; + } + + if (Length > EETag[2]) + return -EINVAL; + /* Note: We write the data one byte at a time to avoid + issues with page sizes. (which are different for + each manufacture and eeprom size) + */ + Addr += sizeof(u16) + 1; + for (i = 0; i < Length; i++, Addr++) { + status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]); + + if (status) + break; + + /* Poll for finishing write cycle */ + retry = 10; + while (retry) { + u8 Tmp; + + msleep(50); + status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1); + if (status) + break; + if (Tmp != data[i]) + pr_err(DEVICE_NAME + "eeprom write error\n"); + retry -= 1; + } + if (status) { + pr_err(DEVICE_NAME + ": Timeout polling eeprom\n"); + break; + } + } + return status; +} + +static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data) +{ + int stat; + u8 buf[2]; + u32 len = 0; + + stat = ReadEEProm(adapter, tag, 2, buf, &len); + if (stat) + return stat; + if (len != 2) + return -EINVAL; + + *data = (buf[0] << 8) | buf[1]; + return 0; +} + +static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) +{ + int stat; + u8 buf[2]; + + buf[0] = data >> 8; + buf[1] = data & 0xff; + stat = WriteEEProm(adapter, tag, 2, buf); + if (stat) + return stat; + return 0; +} + +static s16 osc_deviation(void *priv, s16 deviation, int flag) +{ + struct ngene_channel *chan = priv; + struct i2c_adapter *adap = &chan->i2c_adapter; + u16 data = 0; + + if (flag) { + data = (u16) deviation; + pr_info(DEVICE_NAME ": write deviation %d\n", + deviation); + eeprom_write_ushort(adap, 0x1000 + chan->number, data); + } else { + if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data)) + data = 0; + pr_info(DEVICE_NAME ": read deviation %d\n", + (s16) data); + } + + return (s16) data; +} + +/****************************************************************************/ +/* Switch control (I2C gates, etc.) *****************************************/ +/****************************************************************************/ + + +static struct stv090x_config fe_cineS2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv090x_config fe_cineS2_2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x69, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv6110x_config tuner_cineS2_0 = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct stv6110x_config tuner_cineS2_1 = { + .addr = 0x63, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct ngene_info ngene_info_cineS2 = { + .type = NGENE_SIDEWINDER, + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0b, 0x08}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_satixS2 = { + .type = NGENE_SIDEWINDER, + .name = "Mystique SaTiX-S2 Dual", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0b, 0x08}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_satixS2v2 = { + .type = NGENE_SIDEWINDER, + .name = "Mystique SaTiX-S2 Dual (v2)", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_cineS2v5 = { + .type = NGENE_SIDEWINDER, + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + + +static struct ngene_info ngene_info_duoFlex = { + .type = NGENE_SIDEWINDER, + .name = "Digital Devices DuoFlex PCIe or miniPCIe", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_m780 = { + .type = NGENE_APP, + .name = "Aver M780 ATSC/QAM-B", + + /* Channel 0 is analog, which is currently unsupported */ + .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, + .demod_attach = { NULL, demod_attach_lg330x }, + + /* Ensure these are NULL else the frame will call them (as funcs) */ + .tuner_attach = { 0, 0, 0, 0 }, + .fe_config = { NULL, &aver_m780 }, + .avf = { 0 }, + + /* A custom electrical interface config for the demod to bridge */ + .tsf = { 4, 4 }, + .fw_version = 15, +}; + +static struct drxd_config fe_terratec_dvbt_0 = { + .index = 0, + .demod_address = 0x70, + .demod_revision = 0xa2, + .demoda_address = 0x00, + .pll_address = 0x60, + .pll_type = DVB_PLL_THOMSON_DTT7520X, + .clock = 20000, + .osc_deviation = osc_deviation, +}; + +static struct drxd_config fe_terratec_dvbt_1 = { + .index = 1, + .demod_address = 0x71, + .demod_revision = 0xa2, + .demoda_address = 0x00, + .pll_address = 0x60, + .pll_type = DVB_PLL_THOMSON_DTT7520X, + .clock = 20000, + .osc_deviation = osc_deviation, +}; + +static struct ngene_info ngene_info_terratec = { + .type = NGENE_TERRATEC, + .name = "Terratec Integra/Cinergy2400i Dual DVB-T", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_drxd, demod_attach_drxd}, + .fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1}, + .i2c_access = 1, +}; + +/****************************************************************************/ + + + +/****************************************************************************/ +/* PCI Subsystem ID *********************************************************/ +/****************************************************************************/ + +#define NGENE_ID(_subvend, _subdev, _driverdata) { \ + .vendor = NGENE_VID, .device = NGENE_PID, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long) &_driverdata } + +/****************************************************************************/ + +static const struct pci_device_id ngene_id_tbl[] __devinitdata = { + NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), + NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), + NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), + NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex), + NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), + NGENE_ID(0x1461, 0x062e, ngene_info_m780), + NGENE_ID(0x153b, 0x1167, ngene_info_terratec), + {0} +}; +MODULE_DEVICE_TABLE(pci, ngene_id_tbl); + +/****************************************************************************/ +/* Init/Exit ****************************************************************/ +/****************************************************************************/ + +static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, + enum pci_channel_state state) +{ + printk(KERN_ERR DEVICE_NAME ": PCI error\n"); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (state == pci_channel_io_frozen) + return PCI_ERS_RESULT_NEED_RESET; + return PCI_ERS_RESULT_CAN_RECOVER; +} + +static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": link reset\n"); + return 0; +} + +static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": slot reset\n"); + return 0; +} + +static void ngene_resume(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": resume\n"); +} + +static struct pci_error_handlers ngene_errors = { + .error_detected = ngene_error_detected, + .link_reset = ngene_link_reset, + .slot_reset = ngene_slot_reset, + .resume = ngene_resume, +}; + +static struct pci_driver ngene_pci_driver = { + .name = "ngene", + .id_table = ngene_id_tbl, + .probe = ngene_probe, + .remove = __devexit_p(ngene_remove), + .err_handler = &ngene_errors, + .shutdown = ngene_shutdown, +}; + +static __init int module_init_ngene(void) +{ + printk(KERN_INFO + "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + return pci_register_driver(&ngene_pci_driver); +} + +static __exit void module_exit_ngene(void) +{ + pci_unregister_driver(&ngene_pci_driver); +} + +module_init(module_init_ngene); +module_exit(module_exit_ngene); + +MODULE_DESCRIPTION("nGene"); +MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c new file mode 100644 index 00000000000..c8e0d5b99d4 --- /dev/null +++ b/drivers/media/pci/ngene/ngene-core.c @@ -0,0 +1,1707 @@ +/* + * ngene.c: nGene PCIe bridge driver + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + +static int one_adapter; +module_param(one_adapter, int, 0444); +MODULE_PARM_DESC(one_adapter, "Use only one adapter."); + +static int shutdown_workaround; +module_param(shutdown_workaround, int, 0644); +MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); + +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Print debugging information."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk if (debug) printk + +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngreadl(adr) readl(dev->iomem + (adr)) +#define ngreadb(adr) readb(dev->iomem + (adr)) +#define ngcpyto(adr, src, count) memcpy_toio((char *) \ + (dev->iomem + (adr)), (src), (count)) +#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ + (dev->iomem + (adr)), (count)) + +/****************************************************************************/ +/* nGene interrupt handler **************************************************/ +/****************************************************************************/ + +static void event_tasklet(unsigned long data) +{ + struct ngene *dev = (struct ngene *)data; + + while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { + struct EVENT_BUFFER Event = + dev->EventQueue[dev->EventQueueReadIndex]; + dev->EventQueueReadIndex = + (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); + + if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) + dev->TxEventNotify(dev, Event.TimeStamp); + if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) + dev->RxEventNotify(dev, Event.TimeStamp, + Event.RXCharacter); + } +} + +static void demux_tasklet(unsigned long data) +{ + struct ngene_channel *chan = (struct ngene_channel *)data; + struct SBufferHeader *Cur = chan->nextBuffer; + + spin_lock_irq(&chan->state_lock); + + while (Cur->ngeneBuffer.SR.Flags & 0x80) { + if (chan->mode & NGENE_IO_TSOUT) { + u32 Flags = chan->DataFormatFlags; + if (Cur->ngeneBuffer.SR.Flags & 0x20) + Flags |= BEF_OVERFLOW; + if (chan->pBufferExchange) { + if (!chan->pBufferExchange(chan, + Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR. + Clock, Flags)) { + /* + We didn't get data + Clear in service flag to make sure we + get called on next interrupt again. + leave fill/empty (0x80) flag alone + to avoid hardware running out of + buffers during startup, we hold only + in run state ( the source may be late + delivering data ) + */ + + if (chan->HWState == HWSTATE_RUN) { + Cur->ngeneBuffer.SR.Flags &= + ~0x40; + break; + /* Stop processing stream */ + } + } else { + /* We got a valid buffer, + so switch to run state */ + chan->HWState = HWSTATE_RUN; + } + } else { + printk(KERN_ERR DEVICE_NAME ": OOPS\n"); + if (chan->HWState == HWSTATE_RUN) { + Cur->ngeneBuffer.SR.Flags &= ~0x40; + break; /* Stop processing stream */ + } + } + if (chan->AudioDTOUpdated) { + printk(KERN_INFO DEVICE_NAME + ": Update AudioDTO = %d\n", + chan->AudioDTOValue); + Cur->ngeneBuffer.SR.DTOUpdate = + chan->AudioDTOValue; + chan->AudioDTOUpdated = 0; + } + } else { + if (chan->HWState == HWSTATE_RUN) { + u32 Flags = chan->DataFormatFlags; + IBufferExchange *exch1 = chan->pBufferExchange; + IBufferExchange *exch2 = chan->pBufferExchange2; + if (Cur->ngeneBuffer.SR.Flags & 0x01) + Flags |= BEF_EVEN_FIELD; + if (Cur->ngeneBuffer.SR.Flags & 0x20) + Flags |= BEF_OVERFLOW; + spin_unlock_irq(&chan->state_lock); + if (exch1) + exch1(chan, Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + if (exch2) + exch2(chan, Cur->Buffer2, + chan->Capture2Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + spin_lock_irq(&chan->state_lock); + } else if (chan->HWState != HWSTATE_STOP) + chan->HWState = HWSTATE_RUN; + } + Cur->ngeneBuffer.SR.Flags = 0x00; + Cur = Cur->Next; + } + chan->nextBuffer = Cur; + + spin_unlock_irq(&chan->state_lock); +} + +static irqreturn_t irq_handler(int irq, void *dev_id) +{ + struct ngene *dev = (struct ngene *)dev_id; + u32 icounts = 0; + irqreturn_t rc = IRQ_NONE; + u32 i = MAX_STREAM; + u8 *tmpCmdDoneByte; + + if (dev->BootFirmware) { + icounts = ngreadl(NGENE_INT_COUNTS); + if (icounts != dev->icounts) { + ngwritel(0, FORCE_NMI); + dev->cmd_done = 1; + wake_up(&dev->cmd_wq); + dev->icounts = icounts; + rc = IRQ_HANDLED; + } + return rc; + } + + ngwritel(0, FORCE_NMI); + + spin_lock(&dev->cmd_lock); + tmpCmdDoneByte = dev->CmdDoneByte; + if (tmpCmdDoneByte && + (*tmpCmdDoneByte || + (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { + dev->CmdDoneByte = NULL; + dev->cmd_done = 1; + wake_up(&dev->cmd_wq); + rc = IRQ_HANDLED; + } + spin_unlock(&dev->cmd_lock); + + if (dev->EventBuffer->EventStatus & 0x80) { + u8 nextWriteIndex = + (dev->EventQueueWriteIndex + 1) & + (EVENT_QUEUE_SIZE - 1); + if (nextWriteIndex != dev->EventQueueReadIndex) { + dev->EventQueue[dev->EventQueueWriteIndex] = + *(dev->EventBuffer); + dev->EventQueueWriteIndex = nextWriteIndex; + } else { + printk(KERN_ERR DEVICE_NAME ": event overflow\n"); + dev->EventQueueOverflowCount += 1; + dev->EventQueueOverflowFlag = 1; + } + dev->EventBuffer->EventStatus &= ~0x80; + tasklet_schedule(&dev->event_tasklet); + rc = IRQ_HANDLED; + } + + while (i > 0) { + i--; + spin_lock(&dev->channel[i].state_lock); + /* if (dev->channel[i].State>=KSSTATE_RUN) { */ + if (dev->channel[i].nextBuffer) { + if ((dev->channel[i].nextBuffer-> + ngeneBuffer.SR.Flags & 0xC0) == 0x80) { + dev->channel[i].nextBuffer-> + ngeneBuffer.SR.Flags |= 0x40; + tasklet_schedule( + &dev->channel[i].demux_tasklet); + rc = IRQ_HANDLED; + } + } + spin_unlock(&dev->channel[i].state_lock); + } + + /* Request might have been processed by a previous call. */ + return IRQ_HANDLED; +} + +/****************************************************************************/ +/* nGene command interface **************************************************/ +/****************************************************************************/ + +static void dump_command_io(struct ngene *dev) +{ + u8 buf[8], *b; + + ngcpyfrom(buf, HOST_TO_NGENE, 8); + printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); + + ngcpyfrom(buf, NGENE_TO_HOST, 8); + printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); + + b = dev->hosttongene; + printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b); + + b = dev->ngenetohost; + printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b); +} + +static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) +{ + int ret; + u8 *tmpCmdDoneByte; + + dev->cmd_done = 0; + + if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { + dev->BootFirmware = 1; + dev->icounts = ngreadl(NGENE_INT_COUNTS); + ngwritel(0, NGENE_COMMAND); + ngwritel(0, NGENE_COMMAND_HI); + ngwritel(0, NGENE_STATUS); + ngwritel(0, NGENE_STATUS_HI); + ngwritel(0, NGENE_EVENT); + ngwritel(0, NGENE_EVENT_HI); + } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { + u64 fwio = dev->PAFWInterfaceBuffer; + + ngwritel(fwio & 0xffffffff, NGENE_COMMAND); + ngwritel(fwio >> 32, NGENE_COMMAND_HI); + ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); + ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); + ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); + ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); + } + + memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); + + if (dev->BootFirmware) + ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); + + spin_lock_irq(&dev->cmd_lock); + tmpCmdDoneByte = dev->ngenetohost + com->out_len; + if (!com->out_len) + tmpCmdDoneByte++; + *tmpCmdDoneByte = 0; + dev->ngenetohost[0] = 0; + dev->ngenetohost[1] = 0; + dev->CmdDoneByte = tmpCmdDoneByte; + spin_unlock_irq(&dev->cmd_lock); + + /* Notify 8051. */ + ngwritel(1, FORCE_INT); + + ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); + if (!ret) { + /*ngwritel(0, FORCE_NMI);*/ + + printk(KERN_ERR DEVICE_NAME + ": Command timeout cmd=%02x prev=%02x\n", + com->cmd.hdr.Opcode, dev->prev_cmd); + dump_command_io(dev); + return -1; + } + if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) + dev->BootFirmware = 0; + + dev->prev_cmd = com->cmd.hdr.Opcode; + + if (!com->out_len) + return 0; + + memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); + + return 0; +} + +int ngene_command(struct ngene *dev, struct ngene_command *com) +{ + int result; + + down(&dev->cmd_mutex); + result = ngene_command_mutex(dev, com); + up(&dev->cmd_mutex); + return result; +} + + +static int ngene_command_load_firmware(struct ngene *dev, + u8 *ngene_fw, u32 size) +{ +#define FIRSTCHUNK (1024) + u32 cleft; + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; + com.cmd.hdr.Length = 0; + com.in_len = 0; + com.out_len = 0; + + ngene_command(dev, &com); + + cleft = (size + 3) & ~3; + if (cleft > FIRSTCHUNK) { + ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, + cleft - FIRSTCHUNK); + cleft = FIRSTCHUNK; + } + ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); + + memset(&com, 0, sizeof(struct ngene_command)); + com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; + com.cmd.hdr.Length = 4; + com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; + com.cmd.FWLoadFinish.Length = (unsigned short)cleft; + com.in_len = 4; + com.out_len = 0; + + return ngene_command(dev, &com); +} + + +static int ngene_command_config_buf(struct ngene *dev, u8 config) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; + com.cmd.hdr.Length = 1; + com.cmd.ConfigureBuffers.config = config; + com.in_len = 1; + com.out_len = 0; + + if (ngene_command(dev, &com) < 0) + return -EIO; + return 0; +} + +static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; + com.cmd.hdr.Length = 6; + memcpy(&com.cmd.ConfigureBuffers.config, config, 6); + com.in_len = 6; + com.out_len = 0; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + return 0; +} + +int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; + com.cmd.hdr.Length = 1; + com.cmd.SetGpioPin.select = select | (level << 7); + com.in_len = 1; + com.out_len = 0; + + return ngene_command(dev, &com); +} + + +/* + 02000640 is sample on rising edge. + 02000740 is sample on falling edge. + 02000040 is ignore "valid" signal + + 0: FD_CTL1 Bit 7,6 must be 0,1 + 7 disable(fw controlled) + 6 0-AUX,1-TS + 5 0-par,1-ser + 4 0-lsb/1-msb + 3,2 reserved + 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both + 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge + 2: FD_STA is read-only. 0-sync + 3: FD_INSYNC is number of 47s to trigger "in sync". + 4: FD_OUTSYNC is number of 47s to trigger "out of sync". + 5: FD_MAXBYTE1 is low-order of bytes per packet. + 6: FD_MAXBYTE2 is high-order of bytes per packet. + 7: Top byte is unused. +*/ + +/****************************************************************************/ + +static u8 TSFeatureDecoderSetup[8 * 5] = { + 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ + 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ + 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ + 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ +}; + +/* Set NGENE I2S Config to 16 bit packed */ +static u8 I2SConfiguration[] = { + 0x00, 0x10, 0x00, 0x00, + 0x80, 0x10, 0x00, 0x00, +}; + +static u8 SPDIFConfiguration[10] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Set NGENE I2S Config to transport stream compatible mode */ + +static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; + +static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; + +static u8 ITUDecoderSetup[4][16] = { + {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ + 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, + {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, + {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, + {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, +}; + +/* + * 50 48 60 gleich + * 27p50 9f 00 22 80 42 69 18 ... + * 27p60 93 00 22 80 82 69 1c ... + */ + +/* Maxbyte to 1144 (for raw data) */ +static u8 ITUFeatureDecoderSetup[8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 +}; + +void FillTSBuffer(void *Buffer, int Length, u32 Flags) +{ + u32 *ptr = Buffer; + + memset(Buffer, TS_FILLER, Length); + while (Length > 0) { + if (Flags & DF_SWAP32) + *ptr = 0x471FFF10; + else + *ptr = 0x10FF1F47; + ptr += (188 / 4); + Length -= 188; + } +} + + +static void flush_buffers(struct ngene_channel *chan) +{ + u8 val; + + do { + msleep(1); + spin_lock_irq(&chan->state_lock); + val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; + spin_unlock_irq(&chan->state_lock); + } while (val); +} + +static void clear_buffers(struct ngene_channel *chan) +{ + struct SBufferHeader *Cur = chan->nextBuffer; + + do { + memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); + if (chan->mode & NGENE_IO_TSOUT) + FillTSBuffer(Cur->Buffer1, + chan->Capture1Length, + chan->DataFormatFlags); + Cur = Cur->Next; + } while (Cur != chan->nextBuffer); + + if (chan->mode & NGENE_IO_TSOUT) { + chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = + chan->AudioDTOValue; + chan->AudioDTOUpdated = 0; + + Cur = chan->TSIdleBuffer.Head; + + do { + memset(&Cur->ngeneBuffer.SR, 0, + sizeof(Cur->ngeneBuffer.SR)); + FillTSBuffer(Cur->Buffer1, + chan->Capture1Length, + chan->DataFormatFlags); + Cur = Cur->Next; + } while (Cur != chan->TSIdleBuffer.Head); + } +} + +static int ngene_command_stream_control(struct ngene *dev, u8 stream, + u8 control, u8 mode, u8 flags) +{ + struct ngene_channel *chan = &dev->channel[stream]; + struct ngene_command com; + u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); + u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); + u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); + u16 BsSDO = 0x9B00; + + down(&dev->stream_mutex); + memset(&com, 0, sizeof(com)); + com.cmd.hdr.Opcode = CMD_CONTROL; + com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; + com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); + if (chan->mode & NGENE_IO_TSOUT) + com.cmd.StreamControl.Stream |= 0x07; + com.cmd.StreamControl.Control = control | + (flags & SFLAG_ORDER_LUMA_CHROMA); + com.cmd.StreamControl.Mode = mode; + com.in_len = sizeof(struct FW_STREAM_CONTROL); + com.out_len = 0; + + dprintk(KERN_INFO DEVICE_NAME + ": Stream=%02x, Control=%02x, Mode=%02x\n", + com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, + com.cmd.StreamControl.Mode); + + chan->Mode = mode; + + if (!(control & 0x80)) { + spin_lock_irq(&chan->state_lock); + if (chan->State == KSSTATE_RUN) { + chan->State = KSSTATE_ACQUIRE; + chan->HWState = HWSTATE_STOP; + spin_unlock_irq(&chan->state_lock); + if (ngene_command(dev, &com) < 0) { + up(&dev->stream_mutex); + return -1; + } + /* clear_buffers(chan); */ + flush_buffers(chan); + up(&dev->stream_mutex); + return 0; + } + spin_unlock_irq(&chan->state_lock); + up(&dev->stream_mutex); + return 0; + } + + if (mode & SMODE_AUDIO_CAPTURE) { + com.cmd.StreamControl.CaptureBlockCount = + chan->Capture1Length / AUDIO_BLOCK_SIZE; + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; + } else if (mode & SMODE_TRANSPORT_STREAM) { + com.cmd.StreamControl.CaptureBlockCount = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.MaxLinesPerField = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.Buffer_Address = + chan->TSRingBuffer.PAHead; + if (chan->mode & NGENE_IO_TSOUT) { + com.cmd.StreamControl.BytesPerVBILine = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.Stream |= 0x07; + } + } else { + com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; + com.cmd.StreamControl.MaxLinesPerField = chan->nLines; + com.cmd.StreamControl.MinLinesPerField = 100; + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; + + if (mode & SMODE_VBI_CAPTURE) { + com.cmd.StreamControl.MaxVBILinesPerField = + chan->nVBILines; + com.cmd.StreamControl.MinVBILinesPerField = 0; + com.cmd.StreamControl.BytesPerVBILine = + chan->nBytesPerVBILine; + } + if (flags & SFLAG_COLORBAR) + com.cmd.StreamControl.Stream |= 0x04; + } + + spin_lock_irq(&chan->state_lock); + if (mode & SMODE_AUDIO_CAPTURE) { + chan->nextBuffer = chan->RingBuffer.Head; + if (mode & SMODE_AUDIO_SPDIF) { + com.cmd.StreamControl.SetupDataLen = + sizeof(SPDIFConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSPI; + memcpy(com.cmd.StreamControl.SetupData, + SPDIFConfiguration, sizeof(SPDIFConfiguration)); + } else { + com.cmd.StreamControl.SetupDataLen = 4; + com.cmd.StreamControl.SetupDataAddr = BsSDI; + memcpy(com.cmd.StreamControl.SetupData, + I2SConfiguration + + 4 * dev->card_info->i2s[stream], 4); + } + } else if (mode & SMODE_TRANSPORT_STREAM) { + chan->nextBuffer = chan->TSRingBuffer.Head; + if (stream >= STREAM_AUDIOIN1) { + if (chan->mode & NGENE_IO_TSOUT) { + com.cmd.StreamControl.SetupDataLen = + sizeof(TS_I2SOutConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSDO; + memcpy(com.cmd.StreamControl.SetupData, + TS_I2SOutConfiguration, + sizeof(TS_I2SOutConfiguration)); + } else { + com.cmd.StreamControl.SetupDataLen = + sizeof(TS_I2SConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSDI; + memcpy(com.cmd.StreamControl.SetupData, + TS_I2SConfiguration, + sizeof(TS_I2SConfiguration)); + } + } else { + com.cmd.StreamControl.SetupDataLen = 8; + com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; + memcpy(com.cmd.StreamControl.SetupData, + TSFeatureDecoderSetup + + 8 * dev->card_info->tsf[stream], 8); + } + } else { + chan->nextBuffer = chan->RingBuffer.Head; + com.cmd.StreamControl.SetupDataLen = + 16 + sizeof(ITUFeatureDecoderSetup); + com.cmd.StreamControl.SetupDataAddr = BsUVI; + memcpy(com.cmd.StreamControl.SetupData, + ITUDecoderSetup[chan->itumode], 16); + memcpy(com.cmd.StreamControl.SetupData + 16, + ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); + } + clear_buffers(chan); + chan->State = KSSTATE_RUN; + if (mode & SMODE_TRANSPORT_STREAM) + chan->HWState = HWSTATE_RUN; + else + chan->HWState = HWSTATE_STARTUP; + spin_unlock_irq(&chan->state_lock); + + if (ngene_command(dev, &com) < 0) { + up(&dev->stream_mutex); + return -1; + } + up(&dev->stream_mutex); + return 0; +} + +void set_transfer(struct ngene_channel *chan, int state) +{ + u8 control = 0, mode = 0, flags = 0; + struct ngene *dev = chan->dev; + int ret; + + /* + printk(KERN_INFO DEVICE_NAME ": st %d\n", state); + msleep(100); + */ + + if (state) { + if (chan->running) { + printk(KERN_INFO DEVICE_NAME ": already running\n"); + return; + } + } else { + if (!chan->running) { + printk(KERN_INFO DEVICE_NAME ": already stopped\n"); + return; + } + } + + if (dev->card_info->switch_ctrl) + dev->card_info->switch_ctrl(chan, 1, state ^ 1); + + if (state) { + spin_lock_irq(&chan->state_lock); + + /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + ngreadl(0x9310)); */ + dvb_ringbuffer_flush(&dev->tsout_rbuf); + control = 0x80; + if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + chan->Capture1Length = 512 * 188; + mode = SMODE_TRANSPORT_STREAM; + } + if (chan->mode & NGENE_IO_TSOUT) { + chan->pBufferExchange = tsout_exchange; + /* 0x66666666 = 50MHz *2^33 /250MHz */ + chan->AudioDTOValue = 0x80000000; + chan->AudioDTOUpdated = 1; + } + if (chan->mode & NGENE_IO_TSIN) + chan->pBufferExchange = tsin_exchange; + spin_unlock_irq(&chan->state_lock); + } else + ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + ngreadl(0x9310)); */ + + ret = ngene_command_stream_control(dev, chan->number, + control, mode, flags); + if (!ret) + chan->running = state; + else + printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", + state); + if (!state) { + spin_lock_irq(&chan->state_lock); + chan->pBufferExchange = NULL; + dvb_ringbuffer_flush(&dev->tsout_rbuf); + spin_unlock_irq(&chan->state_lock); + } +} + + +/****************************************************************************/ +/* nGene hardware init and release functions ********************************/ +/****************************************************************************/ + +static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) +{ + struct SBufferHeader *Cur = rb->Head; + u32 j; + + if (!Cur) + return; + + for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { + if (Cur->Buffer1) + pci_free_consistent(dev->pci_dev, + rb->Buffer1Length, + Cur->Buffer1, + Cur->scList1->Address); + + if (Cur->Buffer2) + pci_free_consistent(dev->pci_dev, + rb->Buffer2Length, + Cur->Buffer2, + Cur->scList2->Address); + } + + if (rb->SCListMem) + pci_free_consistent(dev->pci_dev, rb->SCListMemSize, + rb->SCListMem, rb->PASCListMem); + + pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); +} + +static void free_idlebuffer(struct ngene *dev, + struct SRingBufferDescriptor *rb, + struct SRingBufferDescriptor *tb) +{ + int j; + struct SBufferHeader *Cur = tb->Head; + + if (!rb->Head) + return; + free_ringbuffer(dev, rb); + for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { + Cur->Buffer2 = NULL; + Cur->scList2 = NULL; + Cur->ngeneBuffer.Address_of_first_entry_2 = 0; + Cur->ngeneBuffer.Number_of_entries_2 = 0; + } +} + +static void free_common_buffers(struct ngene *dev) +{ + u32 i; + struct ngene_channel *chan; + + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { + chan = &dev->channel[i]; + free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); + free_ringbuffer(dev, &chan->RingBuffer); + free_ringbuffer(dev, &chan->TSRingBuffer); + } + + if (dev->OverflowBuffer) + pci_free_consistent(dev->pci_dev, + OVERFLOW_BUFFER_SIZE, + dev->OverflowBuffer, dev->PAOverflowBuffer); + + if (dev->FWInterfaceBuffer) + pci_free_consistent(dev->pci_dev, + 4096, + dev->FWInterfaceBuffer, + dev->PAFWInterfaceBuffer); +} + +/****************************************************************************/ +/* Ring buffer handling *****************************************************/ +/****************************************************************************/ + +static int create_ring_buffer(struct pci_dev *pci_dev, + struct SRingBufferDescriptor *descr, u32 NumBuffers) +{ + dma_addr_t tmp; + struct SBufferHeader *Head; + u32 i; + u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; + u64 PARingBufferHead; + u64 PARingBufferCur; + u64 PARingBufferNext; + struct SBufferHeader *Cur, *Next; + + descr->Head = NULL; + descr->MemSize = 0; + descr->PAHead = 0; + descr->NumBuffers = 0; + + if (MemSize < 4096) + MemSize = 4096; + + Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); + PARingBufferHead = tmp; + + if (!Head) + return -ENOMEM; + + memset(Head, 0, MemSize); + + PARingBufferCur = PARingBufferHead; + Cur = Head; + + for (i = 0; i < NumBuffers - 1; i++) { + Next = (struct SBufferHeader *) + (((u8 *) Cur) + SIZEOF_SBufferHeader); + PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; + Cur->Next = Next; + Cur->ngeneBuffer.Next = PARingBufferNext; + Cur = Next; + PARingBufferCur = PARingBufferNext; + } + /* Last Buffer points back to first one */ + Cur->Next = Head; + Cur->ngeneBuffer.Next = PARingBufferHead; + + descr->Head = Head; + descr->MemSize = MemSize; + descr->PAHead = PARingBufferHead; + descr->NumBuffers = NumBuffers; + + return 0; +} + +static int AllocateRingBuffers(struct pci_dev *pci_dev, + dma_addr_t of, + struct SRingBufferDescriptor *pRingBuffer, + u32 Buffer1Length, u32 Buffer2Length) +{ + dma_addr_t tmp; + u32 i, j; + int status = 0; + u32 SCListMemSize = pRingBuffer->NumBuffers + * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : + NUM_SCATTER_GATHER_ENTRIES) + * sizeof(struct HW_SCATTER_GATHER_ELEMENT); + + u64 PASCListMem; + struct HW_SCATTER_GATHER_ELEMENT *SCListEntry; + u64 PASCListEntry; + struct SBufferHeader *Cur; + void *SCListMem; + + if (SCListMemSize < 4096) + SCListMemSize = 4096; + + SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); + + PASCListMem = tmp; + if (SCListMem == NULL) + return -ENOMEM; + + memset(SCListMem, 0, SCListMemSize); + + pRingBuffer->SCListMem = SCListMem; + pRingBuffer->PASCListMem = PASCListMem; + pRingBuffer->SCListMemSize = SCListMemSize; + pRingBuffer->Buffer1Length = Buffer1Length; + pRingBuffer->Buffer2Length = Buffer2Length; + + SCListEntry = SCListMem; + PASCListEntry = PASCListMem; + Cur = pRingBuffer->Head; + + for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { + u64 PABuffer; + + void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, + &tmp); + PABuffer = tmp; + + if (Buffer == NULL) + return -ENOMEM; + + Cur->Buffer1 = Buffer; + + SCListEntry->Address = PABuffer; + SCListEntry->Length = Buffer1Length; + + Cur->scList1 = SCListEntry; + Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; + Cur->ngeneBuffer.Number_of_entries_1 = + NUM_SCATTER_GATHER_ENTRIES; + + SCListEntry += 1; + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); + +#if NUM_SCATTER_GATHER_ENTRIES > 1 + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { + SCListEntry->Address = of; + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; + SCListEntry += 1; + PASCListEntry += + sizeof(struct HW_SCATTER_GATHER_ELEMENT); + } +#endif + + if (!Buffer2Length) + continue; + + Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); + PABuffer = tmp; + + if (Buffer == NULL) + return -ENOMEM; + + Cur->Buffer2 = Buffer; + + SCListEntry->Address = PABuffer; + SCListEntry->Length = Buffer2Length; + + Cur->scList2 = SCListEntry; + Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; + Cur->ngeneBuffer.Number_of_entries_2 = + NUM_SCATTER_GATHER_ENTRIES; + + SCListEntry += 1; + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); + +#if NUM_SCATTER_GATHER_ENTRIES > 1 + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { + SCListEntry->Address = of; + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; + SCListEntry += 1; + PASCListEntry += + sizeof(struct HW_SCATTER_GATHER_ELEMENT); + } +#endif + + } + + return status; +} + +static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, + struct SRingBufferDescriptor *pRingBuffer) +{ + int status = 0; + + /* Copy pointer to scatter gather list in TSRingbuffer + structure for buffer 2 + Load number of buffer + */ + u32 n = pRingBuffer->NumBuffers; + + /* Point to first buffer entry */ + struct SBufferHeader *Cur = pRingBuffer->Head; + int i; + /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ + for (i = 0; i < n; i++) { + Cur->Buffer2 = pIdleBuffer->Head->Buffer1; + Cur->scList2 = pIdleBuffer->Head->scList1; + Cur->ngeneBuffer.Address_of_first_entry_2 = + pIdleBuffer->Head->ngeneBuffer. + Address_of_first_entry_1; + Cur->ngeneBuffer.Number_of_entries_2 = + pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; + Cur = Cur->Next; + } + return status; +} + +static u32 RingBufferSizes[MAX_STREAM] = { + RING_SIZE_VIDEO, + RING_SIZE_VIDEO, + RING_SIZE_AUDIO, + RING_SIZE_AUDIO, + RING_SIZE_AUDIO, +}; + +static u32 Buffer1Sizes[MAX_STREAM] = { + MAX_VIDEO_BUFFER_SIZE, + MAX_VIDEO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE +}; + +static u32 Buffer2Sizes[MAX_STREAM] = { + MAX_VBI_BUFFER_SIZE, + MAX_VBI_BUFFER_SIZE, + 0, + 0, + 0 +}; + + +static int AllocCommonBuffers(struct ngene *dev) +{ + int status = 0, i; + + dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, + &dev->PAFWInterfaceBuffer); + if (!dev->FWInterfaceBuffer) + return -ENOMEM; + dev->hosttongene = dev->FWInterfaceBuffer; + dev->ngenetohost = dev->FWInterfaceBuffer + 256; + dev->EventBuffer = dev->FWInterfaceBuffer + 512; + + dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, + OVERFLOW_BUFFER_SIZE, + &dev->PAOverflowBuffer); + if (!dev->OverflowBuffer) + return -ENOMEM; + memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); + + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { + int type = dev->card_info->io_type[i]; + + dev->channel[i].State = KSSTATE_STOP; + + if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i].RingBuffer, + RingBufferSizes[i]); + if (status < 0) + break; + + if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { + status = AllocateRingBuffers(dev->pci_dev, + dev-> + PAOverflowBuffer, + &dev->channel[i]. + RingBuffer, + Buffer1Sizes[i], + Buffer2Sizes[i]); + if (status < 0) + break; + } else if (type & NGENE_IO_HDTV) { + status = AllocateRingBuffers(dev->pci_dev, + dev-> + PAOverflowBuffer, + &dev->channel[i]. + RingBuffer, + MAX_HDTV_BUFFER_SIZE, + 0); + if (status < 0) + break; + } + } + + if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i]. + TSRingBuffer, RING_SIZE_TS); + if (status < 0) + break; + + status = AllocateRingBuffers(dev->pci_dev, + dev->PAOverflowBuffer, + &dev->channel[i]. + TSRingBuffer, + MAX_TS_BUFFER_SIZE, 0); + if (status) + break; + } + + if (type & NGENE_IO_TSOUT) { + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i]. + TSIdleBuffer, 1); + if (status < 0) + break; + status = AllocateRingBuffers(dev->pci_dev, + dev->PAOverflowBuffer, + &dev->channel[i]. + TSIdleBuffer, + MAX_TS_BUFFER_SIZE, 0); + if (status) + break; + FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, + &dev->channel[i].TSRingBuffer); + } + } + return status; +} + +static void ngene_release_buffers(struct ngene *dev) +{ + if (dev->iomem) + iounmap(dev->iomem); + free_common_buffers(dev); + vfree(dev->tsout_buf); + vfree(dev->tsin_buf); + vfree(dev->ain_buf); + vfree(dev->vin_buf); + vfree(dev); +} + +static int ngene_get_buffers(struct ngene *dev) +{ + if (AllocCommonBuffers(dev)) + return -ENOMEM; + if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { + dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); + if (!dev->tsout_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsout_rbuf, + dev->tsout_buf, TSOUT_BUF_SIZE); + } + if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { + dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); + if (!dev->tsin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsin_rbuf, + dev->tsin_buf, TSIN_BUF_SIZE); + } + if (dev->card_info->io_type[2] & NGENE_IO_AIN) { + dev->ain_buf = vmalloc(AIN_BUF_SIZE); + if (!dev->ain_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); + } + if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { + dev->vin_buf = vmalloc(VIN_BUF_SIZE); + if (!dev->vin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); + } + dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), + pci_resource_len(dev->pci_dev, 0)); + if (!dev->iomem) + return -ENOMEM; + + return 0; +} + +static void ngene_init(struct ngene *dev) +{ + int i; + + tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); + + memset_io(dev->iomem + 0xc000, 0x00, 0x220); + memset_io(dev->iomem + 0xc400, 0x00, 0x100); + + for (i = 0; i < MAX_STREAM; i++) { + dev->channel[i].dev = dev; + dev->channel[i].number = i; + } + + dev->fw_interface_version = 0; + + ngwritel(0, NGENE_INT_ENABLE); + + dev->icounts = ngreadl(NGENE_INT_COUNTS); + + dev->device_version = ngreadl(DEV_VER) & 0x0f; + printk(KERN_INFO DEVICE_NAME ": Device version %d\n", + dev->device_version); +} + +static int ngene_load_firm(struct ngene *dev) +{ + u32 size; + const struct firmware *fw = NULL; + u8 *ngene_fw; + char *fw_name; + int err, version; + + version = dev->card_info->fw_version; + + switch (version) { + default: + case 15: + version = 15; + size = 23466; + fw_name = "ngene_15.fw"; + dev->cmd_timeout_workaround = true; + break; + case 16: + size = 23498; + fw_name = "ngene_16.fw"; + dev->cmd_timeout_workaround = true; + break; + case 17: + size = 24446; + fw_name = "ngene_17.fw"; + dev->cmd_timeout_workaround = true; + break; + case 18: + size = 0; + fw_name = "ngene_18.fw"; + break; + } + + if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { + printk(KERN_ERR DEVICE_NAME + ": Could not load firmware file %s.\n", fw_name); + printk(KERN_INFO DEVICE_NAME + ": Copy %s to your hotplug directory!\n", fw_name); + return -1; + } + if (size == 0) + size = fw->size; + if (size != fw->size) { + printk(KERN_ERR DEVICE_NAME + ": Firmware %s has invalid size!", fw_name); + err = -1; + } else { + printk(KERN_INFO DEVICE_NAME + ": Loading firmware file %s.\n", fw_name); + ngene_fw = (u8 *) fw->data; + err = ngene_command_load_firmware(dev, ngene_fw, size); + } + + release_firmware(fw); + + return err; +} + +static void ngene_stop(struct ngene *dev) +{ + down(&dev->cmd_mutex); + i2c_del_adapter(&(dev->channel[0].i2c_adapter)); + i2c_del_adapter(&(dev->channel[1].i2c_adapter)); + ngwritel(0, NGENE_INT_ENABLE); + ngwritel(0, NGENE_COMMAND); + ngwritel(0, NGENE_COMMAND_HI); + ngwritel(0, NGENE_STATUS); + ngwritel(0, NGENE_STATUS_HI); + ngwritel(0, NGENE_EVENT); + ngwritel(0, NGENE_EVENT_HI); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); +#endif +} + +static int ngene_buffer_config(struct ngene *dev) +{ + int stat; + + if (dev->card_info->fw_version >= 17) { + u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; + u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; + u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; + u8 *bconf = tsin12_config; + + if (dev->card_info->io_type[2]&NGENE_IO_TSIN && + dev->card_info->io_type[3]&NGENE_IO_TSIN) { + bconf = tsin1234_config; + if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && + dev->ci.en) + bconf = tsio1235_config; + } + stat = ngene_command_config_free_buf(dev, bconf); + } else { + int bconf = BUFFER_CONFIG_4422; + + if (dev->card_info->io_type[3] == NGENE_IO_TSIN) + bconf = BUFFER_CONFIG_3333; + stat = ngene_command_config_buf(dev, bconf); + } + return stat; +} + + +static int ngene_start(struct ngene *dev) +{ + int stat; + int i; + + pci_set_master(dev->pci_dev); + ngene_init(dev); + + stat = request_irq(dev->pci_dev->irq, irq_handler, + IRQF_SHARED, "nGene", + (void *)dev); + if (stat < 0) + return stat; + + init_waitqueue_head(&dev->cmd_wq); + init_waitqueue_head(&dev->tx_wq); + init_waitqueue_head(&dev->rx_wq); + sema_init(&dev->cmd_mutex, 1); + sema_init(&dev->stream_mutex, 1); + sema_init(&dev->pll_mutex, 1); + sema_init(&dev->i2c_switch_mutex, 1); + spin_lock_init(&dev->cmd_lock); + for (i = 0; i < MAX_STREAM; i++) + spin_lock_init(&dev->channel[i].state_lock); + ngwritel(1, TIMESTAMPS); + + ngwritel(1, NGENE_INT_ENABLE); + + stat = ngene_load_firm(dev); + if (stat < 0) + goto fail; + +#ifdef CONFIG_PCI_MSI + /* enable MSI if kernel and card support it */ + if (pci_msi_enabled() && dev->card_info->msi_supported) { + unsigned long flags; + + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); + stat = pci_enable_msi(dev->pci_dev); + if (stat) { + printk(KERN_INFO DEVICE_NAME + ": MSI not available\n"); + flags = IRQF_SHARED; + } else { + flags = 0; + dev->msi_enabled = true; + } + stat = request_irq(dev->pci_dev->irq, irq_handler, + flags, "nGene", dev); + if (stat < 0) + goto fail2; + ngwritel(1, NGENE_INT_ENABLE); + } +#endif + + stat = ngene_i2c_init(dev, 0); + if (stat < 0) + goto fail; + + stat = ngene_i2c_init(dev, 1); + if (stat < 0) + goto fail; + + return 0; + +fail: + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI +fail2: + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); +#endif + return stat; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void release_channel(struct ngene_channel *chan) +{ + struct dvb_demux *dvbdemux = &chan->demux; + struct ngene *dev = chan->dev; + + if (chan->running) + set_transfer(chan, 0); + + tasklet_kill(&chan->demux_tasklet); + + if (chan->ci_dev) { + dvb_unregister_device(chan->ci_dev); + chan->ci_dev = NULL; + } + + if (chan->fe2) + dvb_unregister_frontend(chan->fe2); + + if (chan->fe) { + dvb_unregister_frontend(chan->fe); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + + if (chan->has_demux) { + dvb_net_release(&chan->dvbnet); + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &chan->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &chan->mem_frontend); + dvb_dmxdev_release(&chan->dmxdev); + dvb_dmx_release(&chan->demux); + chan->has_demux = false; + } + + if (chan->has_adapter) { + dvb_unregister_adapter(&dev->adapter[chan->number]); + chan->has_adapter = false; + } +} + +static int init_channel(struct ngene_channel *chan) +{ + int ret = 0, nr = chan->number; + struct dvb_adapter *adapter = NULL; + struct dvb_demux *dvbdemux = &chan->demux; + struct ngene *dev = chan->dev; + struct ngene_info *ni = dev->card_info; + int io = ni->io_type[nr]; + + tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); + chan->users = 0; + chan->type = io; + chan->mode = chan->type; /* for now only one mode */ + + if (io & NGENE_IO_TSIN) { + chan->fe = NULL; + if (ni->demod_attach[nr]) { + ret = ni->demod_attach[nr](chan); + if (ret < 0) + goto err; + } + if (chan->fe && ni->tuner_attach[nr]) { + ret = ni->tuner_attach[nr](chan); + if (ret < 0) + goto err; + } + } + + if (!dev->ci.en && (io & NGENE_IO_TSOUT)) + return 0; + + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + if (nr >= STREAM_AUDIOIN1) + chan->DataFormatFlags = DF_SWAP32; + + if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { + adapter = &dev->adapter[nr]; + ret = dvb_register_adapter(adapter, "nGene", + THIS_MODULE, + &chan->dev->pci_dev->dev, + adapter_nr); + if (ret < 0) + goto err; + if (dev->first_adapter == NULL) + dev->first_adapter = adapter; + chan->has_adapter = true; + } else + adapter = dev->first_adapter; + } + + if (dev->ci.en && (io & NGENE_IO_TSOUT)) { + dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); + set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; + set_transfer(&chan->dev->channel[2], 1); + dvb_register_device(adapter, &chan->ci_dev, + &ngene_dvbdev_ci, (void *) chan, + DVB_DEVICE_SEC); + if (!chan->ci_dev) + goto err; + } + + if (chan->fe) { + if (dvb_register_frontend(adapter, chan->fe) < 0) + goto err; + chan->has_demux = true; + } + if (chan->fe2) { + if (dvb_register_frontend(adapter, chan->fe2) < 0) + goto err; + chan->fe2->tuner_priv = chan->fe->tuner_priv; + memcpy(&chan->fe2->ops.tuner_ops, + &chan->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } + + if (chan->has_demux) { + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + ngene_start_feed, + ngene_stop_feed, chan); + ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, + &chan->hw_frontend, + &chan->mem_frontend, adapter); + ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); + } + + return ret; + +err: + if (chan->fe) { + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + release_channel(chan); + return 0; +} + +static int init_channels(struct ngene *dev) +{ + int i, j; + + for (i = 0; i < MAX_STREAM; i++) { + dev->channel[i].number = i; + if (init_channel(&dev->channel[i]) < 0) { + for (j = i - 1; j >= 0; j--) + release_channel(&dev->channel[j]); + return -1; + } + } + return 0; +} + +static struct cxd2099_cfg cxd_cfg = { + .bitrate = 62000, + .adr = 0x40, + .polarity = 0, + .clock_mode = 0, +}; + +static void cxd_attach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); + ci->dev = dev; + return; +} + +static void cxd_detach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + dvb_ca_en50221_release(ci->en); + kfree(ci->en); + ci->en = 0; +} + +/***********************************/ +/* workaround for shutdown failure */ +/***********************************/ + +static void ngene_unlink(struct ngene *dev) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_MEM_WRITE; + com.cmd.hdr.Length = 3; + com.cmd.MemoryWrite.address = 0x910c; + com.cmd.MemoryWrite.data = 0xff; + com.in_len = 3; + com.out_len = 1; + + down(&dev->cmd_mutex); + ngwritel(0, NGENE_INT_ENABLE); + ngene_command_mutex(dev, &com); + up(&dev->cmd_mutex); +} + +void ngene_shutdown(struct pci_dev *pdev) +{ + struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); + + if (!dev || !shutdown_workaround) + return; + + printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); + ngene_unlink(dev); + pci_disable_device(pdev); +} + +/****************************************************************************/ +/* device probe/remove calls ************************************************/ +/****************************************************************************/ + +void __devexit ngene_remove(struct pci_dev *pdev) +{ + struct ngene *dev = pci_get_drvdata(pdev); + int i; + + tasklet_kill(&dev->event_tasklet); + for (i = MAX_STREAM - 1; i >= 0; i--) + release_channel(&dev->channel[i]); + if (dev->ci.en) + cxd_detach(dev); + ngene_stop(dev); + ngene_release_buffers(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +int __devinit ngene_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + struct ngene *dev; + int stat = 0; + + if (pci_enable_device(pci_dev) < 0) + return -ENODEV; + + dev = vzalloc(sizeof(struct ngene)); + if (dev == NULL) { + stat = -ENOMEM; + goto fail0; + } + + dev->pci_dev = pci_dev; + dev->card_info = (struct ngene_info *)id->driver_data; + printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); + + pci_set_drvdata(pci_dev, dev); + + /* Alloc buffers and start nGene */ + stat = ngene_get_buffers(dev); + if (stat < 0) + goto fail1; + stat = ngene_start(dev); + if (stat < 0) + goto fail1; + + cxd_attach(dev); + + stat = ngene_buffer_config(dev); + if (stat < 0) + goto fail1; + + + dev->i2c_current_bus = -1; + + /* Register DVB adapters and devices for both channels */ + if (init_channels(dev) < 0) + goto fail2; + + return 0; + +fail2: + ngene_stop(dev); +fail1: + ngene_release_buffers(dev); +fail0: + pci_disable_device(pci_dev); + pci_set_drvdata(pci_dev, NULL); + return stat; +} diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c new file mode 100644 index 00000000000..fcb16a615aa --- /dev/null +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -0,0 +1,261 @@ +/* + * ngene-dvb.c: nGene PCIe bridge driver - DVB functions + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + + +/****************************************************************************/ +/* COMMAND API interface ****************************************************/ +/****************************************************************************/ + +static ssize_t ts_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + + if (wait_event_interruptible(dev->tsout_rbuf.queue, + dvb_ringbuffer_free + (&dev->tsout_rbuf) >= count) < 0) + return 0; + + dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); + + return count; +} + +static ssize_t ts_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + int left, avail; + + left = count; + while (left) { + if (wait_event_interruptible( + dev->tsin_rbuf.queue, + dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) + return -EAGAIN; + avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); + if (avail > left) + avail = left; + dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); + left -= avail; + buf += avail; + } + return count; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = dvb_generic_open, + .release = dvb_generic_release, +}; + +struct dvb_device ngene_dvbdev_ci = { + .priv = 0, + .readers = -1, + .writers = -1, + .users = -1, + .fops = &ci_fops, +}; + + +/****************************************************************************/ +/* DVB functions and API interface ******************************************/ +/****************************************************************************/ + +static void swap_buffer(u32 *p, u32 len) +{ + while (len) { + *p = swab32(*p); + p++; + len -= 4; + } +} + +/* start of filler packet */ +static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; + +/* #define DEBUG_CI_XFER */ +#ifdef DEBUG_CI_XFER +static u32 ok; +static u32 overflow; +static u32 stripped; +#endif + +void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) +{ + struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + + + if (flags & DF_SWAP32) + swap_buffer(buf, len); + + if (dev->ci.en && chan->number == 2) { + while (len >= 188) { + if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); +#ifdef DEBUG_CI_XFER + ok++; +#endif + } +#ifdef DEBUG_CI_XFER + else + overflow++; +#endif + } +#ifdef DEBUG_CI_XFER + else + stripped++; + + if (ok % 100 == 0 && overflow) + printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); +#endif + buf += 188; + len -= 188; + } + return NULL; + } + + if (chan->users > 0) + dvb_dmx_swfilter(&chan->demux, buf, len); + + return NULL; +} + +void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) +{ + struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + u32 alen; + + alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); + alen -= alen % 188; + + if (alen < len) + FillTSBuffer(buf + alen, len - alen, flags); + else + alen = len; + dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); + if (flags & DF_SWAP32) + swap_buffer((u32 *)buf, alen); + wake_up_interruptible(&dev->tsout_rbuf.queue); + return buf; +} + + + +int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ngene_channel *chan = dvbdmx->priv; + + if (chan->users == 0) { + if (!chan->dev->cmd_timeout_workaround || !chan->running) + set_transfer(chan, 1); + } + + return ++chan->users; +} + +int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ngene_channel *chan = dvbdmx->priv; + + if (--chan->users) + return chan->users; + + if (!chan->dev->cmd_timeout_workaround) + set_transfer(chan, 0); + + return 0; +} + +int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv) +{ + dvbdemux->priv = priv; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->write_to_decoder = NULL; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + return dvb_dmx_init(dvbdemux); +} + +int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter) +{ + int ret; + + dmxdev->filternum = 256; + dmxdev->demux = &dvbdemux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); + if (ret < 0) + return ret; + + hw_frontend->source = DMX_FRONTEND_0; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); + mem_frontend->source = DMX_MEMORY_FE; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); +} diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c new file mode 100644 index 00000000000..d28554f8ce9 --- /dev/null +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -0,0 +1,176 @@ +/* + * ngene-i2c.c: nGene PCIe bridge driver i2c functions + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* FIXME - some of these can probably be removed */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + +/* Firmware command for i2c operations */ +static int ngene_command_i2c_read(struct ngene *dev, u8 adr, + u8 *out, u8 outlen, u8 *in, u8 inlen, int flag) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_I2C_READ; + com.cmd.hdr.Length = outlen + 3; + com.cmd.I2CRead.Device = adr << 1; + memcpy(com.cmd.I2CRead.Data, out, outlen); + com.cmd.I2CRead.Data[outlen] = inlen; + com.cmd.I2CRead.Data[outlen + 1] = 0; + com.in_len = outlen + 3; + com.out_len = inlen + 1; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + if ((com.cmd.raw8[0] >> 1) != adr) + return -EIO; + + if (flag) + memcpy(in, com.cmd.raw8, inlen + 1); + else + memcpy(in, com.cmd.raw8 + 1, inlen); + return 0; +} + +static int ngene_command_i2c_write(struct ngene *dev, u8 adr, + u8 *out, u8 outlen) +{ + struct ngene_command com; + + + com.cmd.hdr.Opcode = CMD_I2C_WRITE; + com.cmd.hdr.Length = outlen + 1; + com.cmd.I2CRead.Device = adr << 1; + memcpy(com.cmd.I2CRead.Data, out, outlen); + com.in_len = outlen + 1; + com.out_len = 1; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + if (com.cmd.raw8[0] == 1) + return -EIO; + + return 0; +} + +static void ngene_i2c_set_bus(struct ngene *dev, int bus) +{ + if (!(dev->card_info->i2c_access & 2)) + return; + if (dev->i2c_current_bus == bus) + return; + + switch (bus) { + case 0: + ngene_command_gpio_set(dev, 3, 0); + ngene_command_gpio_set(dev, 2, 1); + break; + + case 1: + ngene_command_gpio_set(dev, 2, 0); + ngene_command_gpio_set(dev, 3, 1); + break; + } + dev->i2c_current_bus = bus; +} + +static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ngene_channel *chan = + (struct ngene_channel *)i2c_get_adapdata(adapter); + struct ngene *dev = chan->dev; + + down(&dev->i2c_switch_mutex); + ngene_i2c_set_bus(dev, chan->number); + + if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_read(dev, msg[0].addr, + msg[0].buf, msg[0].len, + msg[1].buf, msg[1].len, 0)) + goto done; + + if (num == 1 && !(msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_write(dev, msg[0].addr, + msg[0].buf, msg[0].len)) + goto done; + if (num == 1 && (msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0, + msg[0].buf, msg[0].len, 0)) + goto done; + + up(&dev->i2c_switch_mutex); + return -EIO; + +done: + up(&dev->i2c_switch_mutex); + return num; +} + + +static u32 ngene_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ngene_i2c_algo = { + .master_xfer = ngene_i2c_master_xfer, + .functionality = ngene_i2c_functionality, +}; + +int ngene_i2c_init(struct ngene *dev, int dev_nr) +{ + struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter); + + i2c_set_adapdata(adap, &(dev->channel[dev_nr])); + + strcpy(adap->name, "nGene"); + + adap->algo = &ngene_i2c_algo; + adap->algo_data = (void *)&(dev->channel[dev_nr]); + adap->dev.parent = &dev->pci_dev->dev; + + return i2c_add_adapter(adap); +} + diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h new file mode 100644 index 00000000000..5443dc0caea --- /dev/null +++ b/drivers/media/pci/ngene/ngene.h @@ -0,0 +1,921 @@ +/* + * ngene.h: nGene PCIe bridge driver + * + * Copyright (C) 2005-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _NGENE_H_ +#define _NGENE_H_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_ca_en50221.h" +#include "dvb_frontend.h" +#include "dvb_ringbuffer.h" +#include "dvb_net.h" +#include "cxd2099.h" + +#define DEVICE_NAME "ngene" + +#define NGENE_VID 0x18c3 +#define NGENE_PID 0x0720 + +#ifndef VIDEO_CAP_VC1 +#define VIDEO_CAP_AVC 128 +#define VIDEO_CAP_H264 128 +#define VIDEO_CAP_VC1 256 +#define VIDEO_CAP_WMV9 256 +#define VIDEO_CAP_MPEG4 512 +#endif + +enum STREAM { + STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ + STREAM_VIDEOIN2, + STREAM_AUDIOIN1, /* I2S or SPI Input */ + STREAM_AUDIOIN2, + STREAM_AUDIOOUT, + MAX_STREAM +}; + +enum SMODE_BITS { + SMODE_AUDIO_SPDIF = 0x20, + SMODE_AVSYNC = 0x10, + SMODE_TRANSPORT_STREAM = 0x08, + SMODE_AUDIO_CAPTURE = 0x04, + SMODE_VBI_CAPTURE = 0x02, + SMODE_VIDEO_CAPTURE = 0x01 +}; + +enum STREAM_FLAG_BITS { + SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */ + SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */ + SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */ + SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */ + SFLAG_COLORBAR = 0x04, /* Select colorbar */ +}; + +#define PROGRAM_ROM 0x0000 +#define PROGRAM_SRAM 0x1000 +#define PERIPHERALS0 0x8000 +#define PERIPHERALS1 0x9000 +#define SHARED_BUFFER 0xC000 + +#define HOST_TO_NGENE (SHARED_BUFFER+0x0000) +#define NGENE_TO_HOST (SHARED_BUFFER+0x0100) +#define NGENE_COMMAND (SHARED_BUFFER+0x0200) +#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204) +#define NGENE_STATUS (SHARED_BUFFER+0x0208) +#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C) +#define NGENE_EVENT (SHARED_BUFFER+0x0210) +#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214) +#define VARIABLES (SHARED_BUFFER+0x0210) + +#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260) +#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264) +#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268) + +#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800) +#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900) +#define EEPROM_AREA (SHARED_BUFFER+0x0A00) + +#define SG_V_IN_1 (SHARED_BUFFER+0x0A80) +#define SG_VBI_1 (SHARED_BUFFER+0x0B00) +#define SG_A_IN_1 (SHARED_BUFFER+0x0B80) +#define SG_V_IN_2 (SHARED_BUFFER+0x0C00) +#define SG_VBI_2 (SHARED_BUFFER+0x0C80) +#define SG_A_IN_2 (SHARED_BUFFER+0x0D00) +#define SG_V_OUT (SHARED_BUFFER+0x0D80) +#define SG_A_OUT2 (SHARED_BUFFER+0x0E00) + +#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80) +#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00) +#define DATA_A_OUT (SHARED_BUFFER+0x0F80) +#define DATA_V_IN_1 (SHARED_BUFFER+0x1000) +#define DATA_V_IN_2 (SHARED_BUFFER+0x2000) +#define DATA_V_OUT (SHARED_BUFFER+0x3000) + +#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000) + +#define TIMESTAMPS 0xA000 +#define SCRATCHPAD 0xA080 +#define FORCE_INT 0xA088 +#define FORCE_NMI 0xA090 +#define INT_STATUS 0xA0A0 + +#define DEV_VER 0x9004 + +#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF) + +struct SG_ADDR { + u64 start; + u64 curr; + u16 curr_ptr; + u16 elements; + u32 pad[3]; +} __attribute__ ((__packed__)); + +struct SHARED_MEMORY { + /* C000 */ + u32 HostToNgene[64]; + + /* C100 */ + u32 NgeneToHost[64]; + + /* C200 */ + u64 NgeneCommand; + u64 NgeneStatus; + u64 NgeneEvent; + + /* C210 */ + u8 pad1[0xc260 - 0xc218]; + + /* C260 */ + u32 IntCounts; + u32 IntEnable; + + /* C268 */ + u8 pad2[0xd000 - 0xc268]; + +} __attribute__ ((__packed__)); + +struct BUFFER_STREAM_RESULTS { + u32 Clock; /* Stream time in 100ns units */ + u16 RemainingLines; /* Remaining lines in this field. + 0 for complete field */ + u8 FieldCount; /* Video field number */ + u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow, + Bit 0 = FieldID */ + u16 BlockCount; /* Audio block count (unused) */ + u8 Reserved[2]; + u32 DTOUpdate; +} __attribute__ ((__packed__)); + +struct HW_SCATTER_GATHER_ELEMENT { + u64 Address; + u32 Length; + u32 Reserved; +} __attribute__ ((__packed__)); + +struct BUFFER_HEADER { + u64 Next; + struct BUFFER_STREAM_RESULTS SR; + + u32 Number_of_entries_1; + u32 Reserved5; + u64 Address_of_first_entry_1; + + u32 Number_of_entries_2; + u32 Reserved7; + u64 Address_of_first_entry_2; +} __attribute__ ((__packed__)); + +struct EVENT_BUFFER { + u32 TimeStamp; + u8 GPIOStatus; + u8 UARTStatus; + u8 RXCharacter; + u8 EventStatus; + u32 Reserved[2]; +} __attribute__ ((__packed__)); + +/* Firmware commands. */ + +enum OPCODES { + CMD_NOP = 0, + CMD_FWLOAD_PREPARE = 0x01, + CMD_FWLOAD_FINISH = 0x02, + CMD_I2C_READ = 0x03, + CMD_I2C_WRITE = 0x04, + + CMD_I2C_WRITE_NOSTOP = 0x05, + CMD_I2C_CONTINUE_WRITE = 0x06, + CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07, + + CMD_DEBUG_OUTPUT = 0x09, + + CMD_CONTROL = 0x10, + CMD_CONFIGURE_BUFFER = 0x11, + CMD_CONFIGURE_FREE_BUFFER = 0x12, + + CMD_SPI_READ = 0x13, + CMD_SPI_WRITE = 0x14, + + CMD_MEM_READ = 0x20, + CMD_MEM_WRITE = 0x21, + CMD_SFR_READ = 0x22, + CMD_SFR_WRITE = 0x23, + CMD_IRAM_READ = 0x24, + CMD_IRAM_WRITE = 0x25, + CMD_SET_GPIO_PIN = 0x26, + CMD_SET_GPIO_INT = 0x27, + CMD_CONFIGURE_UART = 0x28, + CMD_WRITE_UART = 0x29, + MAX_CMD +}; + +enum RESPONSES { + OK = 0, + ERROR = 1 +}; + +struct FW_HEADER { + u8 Opcode; + u8 Length; +} __attribute__ ((__packed__)); + +struct FW_I2C_WRITE { + struct FW_HEADER hdr; + u8 Device; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_I2C_CONTINUE_WRITE { + struct FW_HEADER hdr; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_I2C_READ { + struct FW_HEADER hdr; + u8 Device; + u8 Data[252]; /* followed by two bytes of read data count */ +} __attribute__ ((__packed__)); + +struct FW_SPI_WRITE { + struct FW_HEADER hdr; + u8 ModeSelect; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_SPI_READ { + struct FW_HEADER hdr; + u8 ModeSelect; + u8 Data[252]; /* followed by two bytes of read data count */ +} __attribute__ ((__packed__)); + +struct FW_FWLOAD_PREPARE { + struct FW_HEADER hdr; +} __attribute__ ((__packed__)); + +struct FW_FWLOAD_FINISH { + struct FW_HEADER hdr; + u16 Address; /* address of final block */ + u16 Length; +} __attribute__ ((__packed__)); + +/* + * Meaning of FW_STREAM_CONTROL::Mode bits: + * Bit 7: Loopback PEXin to PEXout using TVOut channel + * Bit 6: AVLOOP + * Bit 5: Audio select; 0=I2S, 1=SPDIF + * Bit 4: AVSYNC + * Bit 3: Enable transport stream + * Bit 2: Enable audio capture + * Bit 1: Enable ITU-Video VBI capture + * Bit 0: Enable ITU-Video capture + * + * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL) + * Bit 7: continuous capture + * Bit 6: capture one field + * Bit 5: capture one frame + * Bit 4: unused + * Bit 3: starting field; 0=odd, 1=even + * Bit 2: sample size; 0=8-bit, 1=10-bit + * Bit 1: data format; 0=UYVY, 1=YUY2 + * Bit 0: resets buffer pointers +*/ + +enum FSC_MODE_BITS { + SMODE_LOOPBACK = 0x80, + SMODE_AVLOOP = 0x40, + _SMODE_AUDIO_SPDIF = 0x20, + _SMODE_AVSYNC = 0x10, + _SMODE_TRANSPORT_STREAM = 0x08, + _SMODE_AUDIO_CAPTURE = 0x04, + _SMODE_VBI_CAPTURE = 0x02, + _SMODE_VIDEO_CAPTURE = 0x01 +}; + + +/* Meaning of FW_STREAM_CONTROL::Stream bits: + * Bit 3: Audio sample count: 0 = relative, 1 = absolute + * Bit 2: color bar select; 1=color bars, 0=CV3 decoder + * Bits 1-0: stream select, UVI1, UVI2, TVOUT + */ + +struct FW_STREAM_CONTROL { + struct FW_HEADER hdr; + u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */ + u8 Control; /* Value written to UVI1_CTL */ + u8 Mode; /* Controls clock source */ + u8 SetupDataLen; /* Length of setup data, MSB=1 write + backwards */ + u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer + for TS and Audio */ + u64 Buffer_Address; /* Address of first buffer header */ + u16 BytesPerVideoLine; + u16 MaxLinesPerField; + u16 MinLinesPerField; + u16 Reserved_1; + u16 BytesPerVBILine; + u16 MaxVBILinesPerField; + u16 MinVBILinesPerField; + u16 SetupDataAddr; /* ngene relative address of setup data */ + u8 SetupData[32]; /* setup data */ +} __attribute__((__packed__)); + +#define AUDIO_BLOCK_SIZE 256 +#define TS_BLOCK_SIZE 256 + +struct FW_MEM_READ { + struct FW_HEADER hdr; + u16 address; +} __attribute__ ((__packed__)); + +struct FW_MEM_WRITE { + struct FW_HEADER hdr; + u16 address; + u8 data; +} __attribute__ ((__packed__)); + +struct FW_SFR_IRAM_READ { + struct FW_HEADER hdr; + u8 address; +} __attribute__ ((__packed__)); + +struct FW_SFR_IRAM_WRITE { + struct FW_HEADER hdr; + u8 address; + u8 data; +} __attribute__ ((__packed__)); + +struct FW_SET_GPIO_PIN { + struct FW_HEADER hdr; + u8 select; +} __attribute__ ((__packed__)); + +struct FW_SET_GPIO_INT { + struct FW_HEADER hdr; + u8 select; +} __attribute__ ((__packed__)); + +struct FW_SET_DEBUGMODE { + struct FW_HEADER hdr; + u8 debug_flags; +} __attribute__ ((__packed__)); + +struct FW_CONFIGURE_BUFFERS { + struct FW_HEADER hdr; + u8 config; +} __attribute__ ((__packed__)); + +enum _BUFFER_CONFIGS { + /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */ + BUFFER_CONFIG_4422 = 0, + /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */ + BUFFER_CONFIG_3333 = 1, + /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */ + BUFFER_CONFIG_8022 = 2, + BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */ +}; + +struct FW_CONFIGURE_FREE_BUFFERS { + struct FW_HEADER hdr; + u8 UVI1_BufferLength; + u8 UVI2_BufferLength; + u8 TVO_BufferLength; + u8 AUD1_BufferLength; + u8 AUD2_BufferLength; + u8 TVA_BufferLength; +} __attribute__ ((__packed__)); + +struct FW_CONFIGURE_UART { + struct FW_HEADER hdr; + u8 UartControl; +} __attribute__ ((__packed__)); + +enum _UART_CONFIG { + _UART_BAUDRATE_19200 = 0, + _UART_BAUDRATE_9600 = 1, + _UART_BAUDRATE_4800 = 2, + _UART_BAUDRATE_2400 = 3, + _UART_RX_ENABLE = 0x40, + _UART_TX_ENABLE = 0x80, +}; + +struct FW_WRITE_UART { + struct FW_HEADER hdr; + u8 Data[252]; +} __attribute__ ((__packed__)); + + +struct ngene_command { + u32 in_len; + u32 out_len; + union { + u32 raw[64]; + u8 raw8[256]; + struct FW_HEADER hdr; + struct FW_I2C_WRITE I2CWrite; + struct FW_I2C_CONTINUE_WRITE I2CContinueWrite; + struct FW_I2C_READ I2CRead; + struct FW_STREAM_CONTROL StreamControl; + struct FW_FWLOAD_PREPARE FWLoadPrepare; + struct FW_FWLOAD_FINISH FWLoadFinish; + struct FW_MEM_READ MemoryRead; + struct FW_MEM_WRITE MemoryWrite; + struct FW_SFR_IRAM_READ SfrIramRead; + struct FW_SFR_IRAM_WRITE SfrIramWrite; + struct FW_SPI_WRITE SPIWrite; + struct FW_SPI_READ SPIRead; + struct FW_SET_GPIO_PIN SetGpioPin; + struct FW_SET_GPIO_INT SetGpioInt; + struct FW_SET_DEBUGMODE SetDebugMode; + struct FW_CONFIGURE_BUFFERS ConfigureBuffers; + struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers; + struct FW_CONFIGURE_UART ConfigureUart; + struct FW_WRITE_UART WriteUart; + } cmd; +} __attribute__ ((__packed__)); + +#define NGENE_INTERFACE_VERSION 0x103 +#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */ +#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */ +#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */ +#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */ +#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page + Max: (1920x1080i60) */ + +#define OVERFLOW_BUFFER_SIZE (8192) + +#define RING_SIZE_VIDEO 4 +#define RING_SIZE_AUDIO 8 +#define RING_SIZE_TS 8 + +#define NUM_SCATTER_GATHER_ENTRIES 8 + +#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \ + RING_SIZE_VIDEO * 2) + \ + (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \ + (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \ + (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \ + (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \ + (RING_SIZE_TS * PAGE_SIZE * 4) + \ + 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE) + +#define EVENT_QUEUE_SIZE 16 + +/* Gathers the current state of a single channel. */ + +struct SBufferHeader { + struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */ + struct SBufferHeader *Next; + void *Buffer1; + struct HW_SCATTER_GATHER_ELEMENT *scList1; + void *Buffer2; + struct HW_SCATTER_GATHER_ELEMENT *scList2; +}; + +/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */ +#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63) + +enum HWSTATE { + HWSTATE_STOP, + HWSTATE_STARTUP, + HWSTATE_RUN, + HWSTATE_PAUSE, +}; + +enum KSSTATE { + KSSTATE_STOP, + KSSTATE_ACQUIRE, + KSSTATE_PAUSE, + KSSTATE_RUN, +}; + +struct SRingBufferDescriptor { + struct SBufferHeader *Head; /* Points to first buffer in ring buffer + structure*/ + u64 PAHead; /* Physical address of first buffer */ + u32 MemSize; /* Memory size of allocated ring buffers + (needed for freeing) */ + u32 NumBuffers; /* Number of buffers in the ring */ + u32 Buffer1Length; /* Allocated length of Buffer 1 */ + u32 Buffer2Length; /* Allocated length of Buffer 2 */ + void *SCListMem; /* Memory to hold scatter gather lists for this + ring */ + u64 PASCListMem; /* Physical address .. */ + u32 SCListMemSize; /* Size of this memory */ +}; + +enum STREAMMODEFLAGS { + StreamMode_NONE = 0, /* Stream not used */ + StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */ + StreamMode_TSIN = 2, /* Transport stream input (all) */ + StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60 + (only stream 0) */ + StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */ +}; + + +enum BufferExchangeFlags { + BEF_EVEN_FIELD = 0x00000001, + BEF_CONTINUATION = 0x00000002, + BEF_MORE_DATA = 0x00000004, + BEF_OVERFLOW = 0x00000008, + DF_SWAP32 = 0x00010000, +}; + +typedef void *(IBufferExchange)(void *, void *, u32, u32, u32); + +struct MICI_STREAMINFO { + IBufferExchange *pExchange; + IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */ + u8 Stream; + u8 Flags; + u8 Mode; + u8 Reserved; + u16 nLinesVideo; + u16 nBytesPerLineVideo; + u16 nLinesVBI; + u16 nBytesPerLineVBI; + u32 CaptureLength; /* Used for audio and transport stream */ +}; + +/****************************************************************************/ +/* STRUCTS ******************************************************************/ +/****************************************************************************/ + +/* sound hardware definition */ +#define MIXER_ADDR_TVTUNER 0 +#define MIXER_ADDR_LAST 0 + +struct ngene_channel; + +/*struct sound chip*/ + +struct mychip { + struct ngene_channel *chan; + struct snd_card *card; + struct pci_dev *pci; + struct snd_pcm_substream *substream; + struct snd_pcm *pcm; + unsigned long port; + int irq; + spinlock_t mixer_lock; + spinlock_t lock; + int mixer_volume[MIXER_ADDR_LAST + 1][2]; + int capture_source[MIXER_ADDR_LAST + 1][2]; +}; + +#ifdef NGENE_V4L +struct ngene_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct ngene_tvnorm { + int v4l2_id; + char *name; + u16 swidth, sheight; /* scaled standard width, height */ + int tuner_norm; + int soundstd; +}; + +struct ngene_vopen { + struct ngene_channel *ch; + enum v4l2_priority prio; + int width; + int height; + int depth; + struct videobuf_queue vbuf_q; + struct videobuf_queue vbi; + int fourcc; + int picxcount; + int resources; + enum v4l2_buf_type type; + const struct ngene_format *fmt; + + const struct ngene_format *ovfmt; + struct ngene_overlay ov; +}; +#endif + +struct ngene_channel { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + int number; + int type; + int mode; + bool has_adapter; + bool has_demux; + int demod_type; + int (*gate_ctrl)(struct dvb_frontend *, int); + + struct dvb_frontend *fe; + struct dvb_frontend *fe2; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvbnet; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int users; + struct video_device *v4l_dev; + struct dvb_device *ci_dev; + struct tasklet_struct demux_tasklet; + + struct SBufferHeader *nextBuffer; + enum KSSTATE State; + enum HWSTATE HWState; + u8 Stream; + u8 Flags; + u8 Mode; + IBufferExchange *pBufferExchange; + IBufferExchange *pBufferExchange2; + + spinlock_t state_lock; + u16 nLines; + u16 nBytesPerLine; + u16 nVBILines; + u16 nBytesPerVBILine; + u16 itumode; + u32 Capture1Length; + u32 Capture2Length; + struct SRingBufferDescriptor RingBuffer; + struct SRingBufferDescriptor TSRingBuffer; + struct SRingBufferDescriptor TSIdleBuffer; + + u32 DataFormatFlags; + + int AudioDTOUpdated; + u32 AudioDTOValue; + + int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); + u8 lnbh; + + /* stuff from analog driver */ + + int minor; + struct mychip *mychip; + struct snd_card *soundcard; + u8 *evenbuffer; + u8 dma_on; + int soundstreamon; + int audiomute; + int soundbuffisallocated; + int sndbuffflag; + int tun_rdy; + int dec_rdy; + int tun_dec_rdy; + int lastbufferflag; + + struct ngene_tvnorm *tvnorms; + int tvnorm_num; + int tvnorm; + +#ifdef NGENE_V4L + int videousers; + struct v4l2_prio_state prio; + struct ngene_vopen init; + int resources; + struct v4l2_framebuffer fbuf; + struct ngene_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + spinlock_t s_lock; + struct semaphore reslock; +#endif + + int running; +}; + + +struct ngene_ci { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + struct dvb_ca_en50221 *en; +}; + +struct ngene; + +typedef void (rx_cb_t)(struct ngene *, u32, u8); +typedef void (tx_cb_t)(struct ngene *, u32); + +struct ngene { + int nr; + struct pci_dev *pci_dev; + unsigned char *iomem; + + /*struct i2c_adapter i2c_adapter;*/ + + u32 device_version; + u32 fw_interface_version; + u32 icounts; + bool msi_enabled; + bool cmd_timeout_workaround; + + u8 *CmdDoneByte; + int BootFirmware; + void *OverflowBuffer; + dma_addr_t PAOverflowBuffer; + void *FWInterfaceBuffer; + dma_addr_t PAFWInterfaceBuffer; + u8 *ngenetohost; + u8 *hosttongene; + + struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; + int EventQueueOverflowCount; + int EventQueueOverflowFlag; + struct tasklet_struct event_tasklet; + struct EVENT_BUFFER *EventBuffer; + int EventQueueWriteIndex; + int EventQueueReadIndex; + + wait_queue_head_t cmd_wq; + int cmd_done; + struct semaphore cmd_mutex; + struct semaphore stream_mutex; + struct semaphore pll_mutex; + struct semaphore i2c_switch_mutex; + int i2c_current_channel; + int i2c_current_bus; + spinlock_t cmd_lock; + + struct dvb_adapter adapter[MAX_STREAM]; + struct dvb_adapter *first_adapter; /* "one_adapter" modprobe opt */ + struct ngene_channel channel[MAX_STREAM]; + + struct ngene_info *card_info; + + tx_cb_t *TxEventNotify; + rx_cb_t *RxEventNotify; + int tx_busy; + wait_queue_head_t tx_wq; + wait_queue_head_t rx_wq; +#define UART_RBUF_LEN 4096 + u8 uart_rbuf[UART_RBUF_LEN]; + int uart_rp, uart_wp; + +#define TS_FILLER 0x6f + + u8 *tsout_buf; +#define TSOUT_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsout_rbuf; + + u8 *tsin_buf; +#define TSIN_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsin_rbuf; + + u8 *ain_buf; +#define AIN_BUF_SIZE (128*1024) + struct dvb_ringbuffer ain_rbuf; + + + u8 *vin_buf; +#define VIN_BUF_SIZE (4*1920*1080) + struct dvb_ringbuffer vin_rbuf; + + unsigned long exp_val; + int prev_cmd; + + struct ngene_ci ci; +}; + +struct ngene_info { + int type; +#define NGENE_APP 0 +#define NGENE_TERRATEC 1 +#define NGENE_SIDEWINDER 2 +#define NGENE_RACER 3 +#define NGENE_VIPER 4 +#define NGENE_PYTHON 5 +#define NGENE_VBOX_V1 6 +#define NGENE_VBOX_V2 7 + + int fw_version; + bool msi_supported; + char *name; + + int io_type[MAX_STREAM]; +#define NGENE_IO_NONE 0 +#define NGENE_IO_TV 1 +#define NGENE_IO_HDTV 2 +#define NGENE_IO_TSIN 4 +#define NGENE_IO_TSOUT 8 +#define NGENE_IO_AIN 16 + + void *fe_config[4]; + void *tuner_config[4]; + + int (*demod_attach[4])(struct ngene_channel *); + int (*tuner_attach[4])(struct ngene_channel *); + + u8 avf[4]; + u8 msp[4]; + u8 demoda[4]; + u8 lnb[4]; + int i2c_access; + u8 ntsc; + u8 tsf[4]; + u8 i2s[4]; + + int (*gate_ctrl)(struct dvb_frontend *, int); + int (*switch_ctrl)(struct ngene_channel *, int, int); +}; + +#ifdef NGENE_V4L +struct ngene_format { + char *name; + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int format; + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift, vshift; /* for planar modes */ + int palette; +}; + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +struct ngene_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* ngene specific */ + const struct ngene_format *fmt; + int tvnorm; + int btformat; + int btswap; +}; +#endif + + +/* Provided by ngene-core.c */ +int __devinit ngene_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id); +void __devexit ngene_remove(struct pci_dev *pdev); +void ngene_shutdown(struct pci_dev *pdev); +int ngene_command(struct ngene *dev, struct ngene_command *com); +int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); +void set_transfer(struct ngene_channel *chan, int state); +void FillTSBuffer(void *Buffer, int Length, u32 Flags); + +/* Provided by ngene-i2c.c */ +int ngene_i2c_init(struct ngene *dev, int dev_nr); + +/* Provided by ngene-dvb.c */ +extern struct dvb_device ngene_dvbdev_ci; +void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); +void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); +int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv); +int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter); + +#endif + +/* LocalWords: Endif + */ diff --git a/drivers/media/pci/pluto2/Kconfig b/drivers/media/pci/pluto2/Kconfig new file mode 100644 index 00000000000..7d8e6e87bdb --- /dev/null +++ b/drivers/media/pci/pluto2/Kconfig @@ -0,0 +1,15 @@ +config DVB_PLUTO2 + tristate "Pluto2 cards" + depends on DVB_CORE && PCI && I2C + select I2C_ALGOBIT + select DVB_TDA1004X + help + Support for PCI cards based on the Pluto2 FPGA like the Satelco + Easywatch Mobile Terrestrial DVB-T Receiver. + + 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/drivers/media/pci/pluto2/Makefile b/drivers/media/pci/pluto2/Makefile new file mode 100644 index 00000000000..524bf841f42 --- /dev/null +++ b/drivers/media/pci/pluto2/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_PLUTO2) += pluto2.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c new file mode 100644 index 00000000000..f148b19a206 --- /dev/null +++ b/drivers/media/pci/pluto2/pluto2.c @@ -0,0 +1,815 @@ +/* + * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] + * + * Copyright (C) 2005 Andreas Oberritter + * + * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ + * by Dany Salman + * Copyright (c) 2004 TDF + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "tda1004x.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define DRIVER_NAME "pluto2" + +#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ +#define REG_PCAR 0x0020 /* PC address register */ +#define REG_TSCR 0x0024 /* TS ctrl & status */ +#define REG_MISC 0x0028 /* miscellaneous */ +#define REG_MMAC 0x002c /* MSB MAC address */ +#define REG_IMAC 0x0030 /* ISB MAC address */ +#define REG_LMAC 0x0034 /* LSB MAC address */ +#define REG_SPID 0x0038 /* SPI data */ +#define REG_SLCS 0x003c /* serial links ctrl/status */ + +#define PID0_NOFIL (0x0001 << 16) +#define PIDn_ENP (0x0001 << 15) +#define PID0_END (0x0001 << 14) +#define PID0_AFIL (0x0001 << 13) +#define PIDn_PID (0x1fff << 0) + +#define TSCR_NBPACKETS (0x00ff << 24) +#define TSCR_DEM (0x0001 << 17) +#define TSCR_DE (0x0001 << 16) +#define TSCR_RSTN (0x0001 << 15) +#define TSCR_MSKO (0x0001 << 14) +#define TSCR_MSKA (0x0001 << 13) +#define TSCR_MSKL (0x0001 << 12) +#define TSCR_OVR (0x0001 << 11) +#define TSCR_AFUL (0x0001 << 10) +#define TSCR_LOCK (0x0001 << 9) +#define TSCR_IACK (0x0001 << 8) +#define TSCR_ADEF (0x007f << 0) + +#define MISC_DVR (0x0fff << 4) +#define MISC_ALED (0x0001 << 3) +#define MISC_FRST (0x0001 << 2) +#define MISC_LED1 (0x0001 << 1) +#define MISC_LED0 (0x0001 << 0) + +#define SPID_SPIDR (0x00ff << 0) + +#define SLCS_SCL (0x0001 << 7) +#define SLCS_SDA (0x0001 << 6) +#define SLCS_CSN (0x0001 << 2) +#define SLCS_OVR (0x0001 << 1) +#define SLCS_SWC (0x0001 << 0) + +#define TS_DMA_PACKETS (8) +#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) + +#define I2C_ADDR_TDA10046 0x10 +#define I2C_ADDR_TUA6034 0xc2 +#define NHWFILTERS 8 + +struct pluto { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + unsigned int users; + + /* i2c */ + struct i2c_algo_bit_data i2c_bit; + struct i2c_adapter i2c_adap; + unsigned int i2cbug; + + /* irq */ + unsigned int overflow; + unsigned int dead; + + /* dma */ + dma_addr_t dma_addr; + u8 dma_buf[TS_DMA_BYTES]; + u8 dummy[4096]; +}; + +static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct pluto, demux); +} + +static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct pluto, dvb_adapter); +} + +static inline u32 pluto_readreg(struct pluto *pluto, u32 reg) +{ + return readl(&pluto->io_mem[reg]); +} + +static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) +{ + writel(val, &pluto->io_mem[reg]); +} + +static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) +{ + u32 val = readl(&pluto->io_mem[reg]); + val &= ~mask; + val |= bits; + writel(val, &pluto->io_mem[reg]); +} + +static void pluto_write_tscr(struct pluto *pluto, u32 val) +{ + /* set the number of packets */ + val &= ~TSCR_ADEF; + val |= TS_DMA_PACKETS / 2; + + pluto_writereg(pluto, REG_TSCR, val); +} + +static void pluto_setsda(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); + else + pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); +} + +static void pluto_setscl(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); + else + pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); + + /* try to detect i2c_inb() to workaround hardware bug: + * reset SDA to high after SCL has been set to low */ + if ((state) && (pluto->i2cbug == 0)) { + pluto->i2cbug = 1; + } else { + if ((!state) && (pluto->i2cbug == 1)) + pluto_setsda(pluto, 1); + pluto->i2cbug = 0; + } +} + +static int pluto_getsda(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; +} + +static int pluto_getscl(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; +} + +static void pluto_reset_frontend(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_MISC); + + if (val & MISC_FRST) { + val &= ~MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } + if (reenable) { + val |= MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } +} + +static void pluto_reset_ts(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + if (val & TSCR_RSTN) { + val &= ~TSCR_RSTN; + pluto_write_tscr(pluto, val); + } + if (reenable) { + val |= TSCR_RSTN; + pluto_write_tscr(pluto, val); + } +} + +static void pluto_set_dma_addr(struct pluto *pluto) +{ + pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); +} + +static int __devinit pluto_dma_map(struct pluto *pluto) +{ + pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); +} + +static void pluto_dma_unmap(struct pluto *pluto) +{ + pci_unmap_single(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static int pluto_start_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* enable PID filtering */ + if (pluto->users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); + else if (pluto->full_ts_users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); + + return 0; +} + +static int pluto_stop_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* disable PID filtering */ + if (--pluto->users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); + else if (--pluto->full_ts_users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); + + return 0; +} + +static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) +{ + /* synchronize the DMA transfer with the CPU + * first so that we see updated contents. */ + pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + /* Workaround for broken hardware: + * [1] On startup NBPACKETS seems to contain an uninitialized value, + * but no packets have been transferred. + * [2] Sometimes (actually very often) NBPACKETS stays at zero + * although one packet has been transferred. + * [3] Sometimes (actually rarely), the card gets into an erroneous + * mode where it continuously generates interrupts, claiming it + * has received nbpackets>TS_DMA_PACKETS packets, but no packet + * has been transferred. Only a reset seems to solve this + */ + if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { + unsigned int i = 0; + while (pluto->dma_buf[i] == 0x47) + i += 188; + nbpackets = i / 188; + if (i == 0) { + pluto_reset_ts(pluto, 1); + dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n"); + } + } + + dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); + + /* clear the dma buffer. this is needed to be able to identify + * new valid ts packets above */ + memset(pluto->dma_buf, 0, nbpackets * 188); + + /* reset the dma address */ + pluto_set_dma_addr(pluto); + + /* sync the buffer and give it back to the card */ + pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static irqreturn_t pluto_irq(int irq, void *dev_id) +{ + struct pluto *pluto = dev_id; + u32 tscr; + + /* check whether an interrupt occurred on this device */ + tscr = pluto_readreg(pluto, REG_TSCR); + if (!(tscr & (TSCR_DE | TSCR_OVR))) + return IRQ_NONE; + + if (tscr == 0xffffffff) { + if (pluto->dead == 0) + dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n"); + /* It's dead Jim */ + pluto->dead = 1; + return IRQ_HANDLED; + } + + /* dma end interrupt */ + if (tscr & TSCR_DE) { + pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); + /* overflow interrupt */ + if (tscr & TSCR_OVR) + pluto->overflow++; + if (pluto->overflow) { + dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", + pluto->overflow); + pluto_reset_ts(pluto, 1); + pluto->overflow = 0; + } + } else if (tscr & TSCR_OVR) { + pluto->overflow++; + } + + /* ACK the interrupt */ + pluto_write_tscr(pluto, tscr | TSCR_IACK); + + return IRQ_HANDLED; +} + +static void __devinit pluto_enable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* disable AFUL and LOCK interrupts */ + val |= (TSCR_MSKA | TSCR_MSKL); + /* enable DMA and OVERFLOW interrupts */ + val &= ~(TSCR_DEM | TSCR_MSKO); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_write_tscr(pluto, val); +} + +static void pluto_disable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* disable all interrupts */ + val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_write_tscr(pluto, val); +} + +static int __devinit pluto_hw_init(struct pluto *pluto) +{ + pluto_reset_frontend(pluto, 1); + + /* set automatic LED control by FPGA */ + pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); + + /* set data endianess */ +#ifdef __LITTLE_ENDIAN + pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); +#else + pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); +#endif + /* map DMA and set address */ + pluto_dma_map(pluto); + pluto_set_dma_addr(pluto); + + /* enable interrupts */ + pluto_enable_irqs(pluto); + + /* reset TS logic */ + pluto_reset_ts(pluto, 1); + + return 0; +} + +static void pluto_hw_exit(struct pluto *pluto) +{ + /* disable interrupts */ + pluto_disable_irqs(pluto); + + pluto_reset_ts(pluto, 0); + + /* LED: disable automatic control, enable yellow, disable green */ + pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); + + /* unmap DMA */ + pluto_dma_unmap(pluto); + + pluto_reset_frontend(pluto, 0); +} + +static inline u32 divide(u32 numerator, u32 denominator) +{ + if (denominator == 0) + return ~0; + + return DIV_ROUND_CLOSEST(numerator, denominator); +} + +/* LG Innotek TDTE-E001P (Infineon TUA6034) */ +static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct pluto *pluto = frontend_to_pluto(fe); + struct i2c_msg msg; + int ret; + u8 buf[4]; + u32 div; + + // Fref = 166.667 Hz + // Fref * 3 = 500.000 Hz + // IF = 36166667 + // IF / Fref = 217 + //div = divide(p->frequency + 36166667, 166667); + div = divide(p->frequency * 3, 500000) + 217; + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + + if (p->frequency < 611000000) + buf[2] = 0xb4; + else if (p->frequency < 811000000) + buf[2] = 0xbc; + else + buf[2] = 0xf4; + + // VHF: 174-230 MHz + // center: 350 MHz + // UHF: 470-862 MHz + if (p->frequency < 350000000) + buf[3] = 0x02; + else + buf[3] = 0x04; + + if (p->bandwidth_hz == 8000000) + buf[3] |= 0x08; + + msg.addr = I2C_ADDR_TUA6034 >> 1; + msg.flags = 0; + msg.buf = buf; + msg.len = sizeof(buf); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); + if (ret < 0) + return ret; + else if (ret == 0) + return -EREMOTEIO; + + return 0; +} + +static int pluto2_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct pluto *pluto = frontend_to_pluto(fe); + + return request_firmware(fw, name, &pluto->pdev->dev); +} + +static struct tda1004x_config pluto2_fe_config __devinitdata = { + .demod_address = I2C_ADDR_TDA10046 >> 1, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = pluto2_request_firmware, +}; + +static int __devinit frontend_init(struct pluto *pluto) +{ + int ret; + + pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); + if (!pluto->fe) { + dev_err(&pluto->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; + + ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); + if (ret < 0) { + if (pluto->fe->ops.release) + pluto->fe->ops.release(pluto->fe); + return ret; + } + + return 0; +} + +static void __devinit pluto_read_rev(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; + dev_info(&pluto->pdev->dev, "board revision %d.%d\n", + (val >> 12) & 0x0f, (val >> 4) & 0xff); +} + +static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) +{ + u32 val = pluto_readreg(pluto, REG_MMAC); + mac[0] = (val >> 8) & 0xff; + mac[1] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_IMAC); + mac[2] = (val >> 8) & 0xff; + mac[3] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_LMAC); + mac[4] = (val >> 8) & 0xff; + mac[5] = (val >> 0) & 0xff; + + dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); +} + +static int __devinit pluto_read_serial(struct pluto *pluto) +{ + struct pci_dev *pdev = pluto->pdev; + unsigned int i, j; + u8 __iomem *cis; + + cis = pci_iomap(pdev, 1, 0); + if (!cis) + return -EIO; + + dev_info(&pdev->dev, "S/N "); + + for (i = 0xe0; i < 0x100; i += 4) { + u32 val = readl(&cis[i]); + for (j = 0; j < 32; j += 8) { + if ((val & 0xff) == 0xff) + goto out; + printk("%c", val & 0xff); + val >>= 8; + } + } +out: + printk("\n"); + pci_iounmap(pdev, cis); + + return 0; +} + +static int __devinit pluto2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct pluto *pluto; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + + pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); + if (!pluto) + goto out; + + pluto->pdev = pdev; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + /* enable interrupts */ + pci_write_config_dword(pdev, 0x6c, 0x8000); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + 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; + + pluto->io_mem = pci_iomap(pdev, 0, 0x40); + if (!pluto->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(pdev, pluto); + + ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto); + if (ret < 0) + goto err_pci_iounmap; + + ret = pluto_hw_init(pluto); + if (ret < 0) + goto err_free_irq; + + /* i2c */ + i2c_set_adapdata(&pluto->i2c_adap, pluto); + strcpy(pluto->i2c_adap.name, DRIVER_NAME); + pluto->i2c_adap.owner = THIS_MODULE; + pluto->i2c_adap.dev.parent = &pdev->dev; + pluto->i2c_adap.algo_data = &pluto->i2c_bit; + pluto->i2c_bit.data = pluto; + pluto->i2c_bit.setsda = pluto_setsda; + pluto->i2c_bit.setscl = pluto_setscl; + pluto->i2c_bit.getsda = pluto_getsda; + pluto->i2c_bit.getscl = pluto_getscl; + pluto->i2c_bit.udelay = 10; + pluto->i2c_bit.timeout = 10; + + /* Raise SCL and SDA */ + pluto_setsda(pluto, 1); + pluto_setscl(pluto, 1); + + ret = i2c_bit_add_bus(&pluto->i2c_adap); + if (ret < 0) + goto err_pluto_hw_exit; + + /* dvb */ + ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, + THIS_MODULE, &pdev->dev, adapter_nr); + if (ret < 0) + goto err_i2c_del_adapter; + + dvb_adapter = &pluto->dvb_adapter; + + pluto_read_rev(pluto); + pluto_read_serial(pluto); + pluto_read_mac(pluto, dvb_adapter->proposed_mac); + + dvbdemux = &pluto->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = pluto_start_feed; + dvbdemux->stop_feed = pluto_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + pluto->hw_frontend.source = DMX_FRONTEND_0; + pluto->mem_frontend.source = DMX_MEMORY_FE; + pluto->dmxdev.filternum = NHWFILTERS; + pluto->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &pluto->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = frontend_init(pluto); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); +out: + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &pluto->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &pluto->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&pluto->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_i2c_del_adapter: + i2c_del_adapter(&pluto->i2c_adap); +err_pluto_hw_exit: + pluto_hw_exit(pluto); +err_free_irq: + free_irq(pdev->irq, pluto); +err_pci_iounmap: + pci_iounmap(pdev, pluto->io_mem); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(pluto); + goto out; +} + +static void __devexit pluto2_remove(struct pci_dev *pdev) +{ + struct pluto *pluto = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; + struct dvb_demux *dvbdemux = &pluto->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&pluto->dvbnet); + if (pluto->fe) + dvb_unregister_frontend(pluto->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &pluto->mem_frontend); + dmx->remove_frontend(dmx, &pluto->hw_frontend); + dvb_dmxdev_release(&pluto->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + i2c_del_adapter(&pluto->i2c_adap); + pluto_hw_exit(pluto); + free_irq(pdev->irq, pluto); + pci_iounmap(pdev, pluto->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(pluto); +} + +#ifndef PCI_VENDOR_ID_SCM +#define PCI_VENDOR_ID_SCM 0x0432 +#endif +#ifndef PCI_DEVICE_ID_PLUTO2 +#define PCI_DEVICE_ID_PLUTO2 0x0001 +#endif + +static struct pci_device_id pluto2_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SCM, + .device = PCI_DEVICE_ID_PLUTO2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, pluto2_id_table); + +static struct pci_driver pluto2_driver = { + .name = DRIVER_NAME, + .id_table = pluto2_id_table, + .probe = pluto2_probe, + .remove = __devexit_p(pluto2_remove), +}; + +static int __init pluto2_init(void) +{ + return pci_register_driver(&pluto2_driver); +} + +static void __exit pluto2_exit(void) +{ + pci_unregister_driver(&pluto2_driver); +} + +module_init(pluto2_init); +module_exit(pluto2_exit); + +MODULE_AUTHOR("Andreas Oberritter "); +MODULE_DESCRIPTION("Pluto2 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/pt1/Kconfig b/drivers/media/pci/pt1/Kconfig new file mode 100644 index 00000000000..24501d5bf70 --- /dev/null +++ b/drivers/media/pci/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/drivers/media/pci/pt1/Makefile b/drivers/media/pci/pt1/Makefile new file mode 100644 index 00000000000..98e391295af --- /dev/null +++ b/drivers/media/pci/pt1/Makefile @@ -0,0 +1,5 @@ +earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o + +obj-$(CONFIG_DVB_PT1) += earth-pt1.o + +ccflags-y += -Idrivers/media/dvb-core -Idrivers/media/dvb-frontends diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c new file mode 100644 index 00000000000..15b35c4725f --- /dev/null +++ b/drivers/media/pci/pt1/pt1.c @@ -0,0 +1,1246 @@ +/* + * driver for Earthsoft PT1/PT2 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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; + int table_index; + int buf_index; + + struct mutex lock; + int power; + int reset; +}; + +struct pt1_adapter { + struct pt1 *pt1; + int index; + + u8 *buf; + int upacket_count; + int packet_count; + int st_count; + + struct dvb_adapter adap; + struct dvb_demux demux; + int users; + struct dmxdev dmxdev; + struct dvb_frontend *fe; + int (*orig_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); + int (*orig_sleep)(struct dvb_frontend *fe); + int (*orig_init)(struct dvb_frontend *fe); + + fe_sec_voltage_t voltage; + int sleep; +}; + +#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 = 8; +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; + int phase; + schedule_timeout_uninterruptible((HZ + 999) / 1000); + phase = pt1->pdev->device == 0x211a ? 128 : 166; + for (i = 0; i < phase; 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; + int sc; + + 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; + + if (upacket >> 24 & 1) + printk_ratelimited(KERN_INFO "earth-pt1: device " + "buffer overflowing. table[%d] buf[%d]\n", + pt1->table_index, pt1->buf_index); + sc = upacket >> 26 & 0x7; + if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) + printk_ratelimited(KERN_INFO "earth-pt1: data loss" + " in streamID(adapter)[%d]\n", index); + adap->st_count = sc; + + 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; + struct pt1_buffer_page *page; + + pt1 = data; + set_freezable(); + + while (!kthread_should_stop()) { + try_to_freeze(); + + page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; + if (!pt1_filter(pt1, page)) { + schedule_timeout_interruptible((HZ + 999) / 1000); + continue; + } + + if (++pt1->buf_index >= PT1_NR_BUFS) { + pt1_increment_table_count(pt1); + pt1->buf_index = 0; + if (++pt1->table_index >= pt1_nr_tables) + pt1->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_polling(struct pt1 *pt1) +{ + int ret = 0; + + mutex_lock(&pt1->lock); + if (!pt1->kthread) { + pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); + if (IS_ERR(pt1->kthread)) { + ret = PTR_ERR(pt1->kthread); + pt1->kthread = NULL; + } + } + mutex_unlock(&pt1->lock); + 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++) { + int ret; + + ret = pt1_start_polling(adap->pt1); + if (ret) + return ret; + pt1_set_stream(adap->pt1, adap->index, 1); + } + return 0; +} + +static void pt1_stop_polling(struct pt1 *pt1) +{ + int i, count; + + mutex_lock(&pt1->lock); + for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) + count += pt1->adaps[i]->users; + + if (count == 0 && pt1->kthread) { + kthread_stop(pt1->kthread); + pt1->kthread = NULL; + } + mutex_unlock(&pt1->lock); +} + +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); + pt1_stop_polling(adap->pt1); + } + return 0; +} + +static void +pt1_update_power(struct pt1 *pt1) +{ + int bits; + int i; + struct pt1_adapter *adap; + static const int sleep_bits[] = { + 1 << 4, + 1 << 6 | 1 << 7, + 1 << 5, + 1 << 6 | 1 << 8, + }; + + bits = pt1->power | !pt1->reset << 3; + mutex_lock(&pt1->lock); + for (i = 0; i < PT1_NR_ADAPS; i++) { + adap = pt1->adaps[i]; + switch (adap->voltage) { + case SEC_VOLTAGE_13: /* actually 11V */ + bits |= 1 << 1; + break; + case SEC_VOLTAGE_18: /* actually 15V */ + bits |= 1 << 1 | 1 << 2; + break; + default: + break; + } + + /* XXX: The bits should be changed depending on adap->sleep. */ + bits |= sleep_bits[i]; + } + pt1_write_reg(pt1, 1, bits); + mutex_unlock(&pt1->lock); +} + +static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct pt1_adapter *adap; + + adap = container_of(fe->dvb, struct pt1_adapter, adap); + adap->voltage = voltage; + pt1_update_power(adap->pt1); + + if (adap->orig_set_voltage) + return adap->orig_set_voltage(fe, voltage); + else + return 0; +} + +static int pt1_sleep(struct dvb_frontend *fe) +{ + struct pt1_adapter *adap; + + adap = container_of(fe->dvb, struct pt1_adapter, adap); + adap->sleep = 1; + pt1_update_power(adap->pt1); + + if (adap->orig_sleep) + return adap->orig_sleep(fe); + else + return 0; +} + +static int pt1_wakeup(struct dvb_frontend *fe) +{ + struct pt1_adapter *adap; + + adap = container_of(fe->dvb, struct pt1_adapter, adap); + adap->sleep = 0; + pt1_update_power(adap->pt1); + schedule_timeout_uninterruptible((HZ + 999) / 1000); + + if (adap->orig_init) + return adap->orig_init(fe); + else + return 0; +} + +static void pt1_free_adapter(struct pt1_adapter *adap) +{ + 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 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->voltage = SEC_VOLTAGE_OFF; + adap->sleep = 1; + + 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; + adap->st_count = -1; + + 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; + + return adap; + +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]); +} + +static int pt1_init_adapters(struct pt1 *pt1) +{ + int i; + struct pt1_adapter *adap; + int ret; + + for (i = 0; i < PT1_NR_ADAPS; i++) { + adap = pt1_alloc_adapter(pt1); + if (IS_ERR(adap)) { + ret = PTR_ERR(adap); + goto err; + } + + adap->index = i; + pt1->adaps[i] = adap; + } + return 0; + +err: + while (i--) + pt1_free_adapter(pt1->adaps[i]); + + return ret; +} + +static void pt1_cleanup_frontend(struct pt1_adapter *adap) +{ + dvb_unregister_frontend(adap->fe); +} + +static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) +{ + int ret; + + adap->orig_set_voltage = fe->ops.set_voltage; + adap->orig_sleep = fe->ops.sleep; + adap->orig_init = fe->ops.init; + fe->ops.set_voltage = pt1_set_voltage; + fe->ops.sleep = pt1_sleep; + fe->ops.init = pt1_wakeup; + + ret = dvb_register_frontend(&adap->adap, fe); + if (ret < 0) + return ret; + + adap->fe = fe; + return 0; +} + +static void pt1_cleanup_frontends(struct pt1 *pt1) +{ + int i; + for (i = 0; i < PT1_NR_ADAPS; i++) + pt1_cleanup_frontend(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, + .frequency = VA1J5JF8007S_20MHZ, + }, + { + .demod_address = 0x1a, + .frequency = VA1J5JF8007T_20MHZ, + }, + }, { + { + .demod_address = 0x19, + .frequency = VA1J5JF8007S_20MHZ, + }, + { + .demod_address = 0x18, + .frequency = VA1J5JF8007T_20MHZ, + }, + }, +}; + +static const struct pt1_config pt2_configs[2] = { + { + { + .demod_address = 0x1b, + .frequency = VA1J5JF8007S_25MHZ, + }, + { + .demod_address = 0x1a, + .frequency = VA1J5JF8007T_25MHZ, + }, + }, { + { + .demod_address = 0x19, + .frequency = VA1J5JF8007S_25MHZ, + }, + { + .demod_address = 0x18, + .frequency = VA1J5JF8007T_25MHZ, + }, + }, +}; + +static int pt1_init_frontends(struct pt1 *pt1) +{ + int i, j; + struct i2c_adapter *i2c_adap; + const struct pt1_config *configs, *config; + struct dvb_frontend *fe[4]; + int ret; + + i = 0; + j = 0; + + i2c_adap = &pt1->i2c_adap; + configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs; + do { + config = &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 { + ret = pt1_init_frontend(pt1->adaps[j], fe[j]); + if (ret < 0) + goto err; + } while (++j < 4); + + return 0; + +err: + while (i-- > j) + fe[i]->ops.release(fe[i]); + + while (j--) + dvb_unregister_frontend(fe[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; + + if (pt1->kthread) + kthread_stop(pt1->kthread); + pt1_cleanup_tables(pt1); + pt1_cleanup_frontends(pt1); + pt1_disable_ram(pt1); + pt1->power = 0; + pt1->reset = 1; + pt1_update_power(pt1); + pt1_cleanup_adapters(pt1); + 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; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err; + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + 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; + } + + mutex_init(&pt1->lock); + pt1->pdev = pdev; + pt1->regs = regs; + pci_set_drvdata(pdev, pt1); + + ret = pt1_init_adapters(pt1); + if (ret < 0) + goto err_kfree; + + mutex_init(&pt1->lock); + + pt1->power = 0; + pt1->reset = 1; + pt1_update_power(pt1); + + i2c_adap = &pt1->i2c_adap; + i2c_adap->algo = &pt1_i2c_algo; + i2c_adap->algo_data = NULL; + i2c_adap->dev.parent = &pdev->dev; + strcpy(i2c_adap->name, DRIVER_NAME); + i2c_set_adapdata(i2c_adap, pt1); + ret = i2c_add_adapter(i2c_adap); + if (ret < 0) + goto err_pt1_cleanup_adapters; + + 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->power = 1; + pt1_update_power(pt1); + schedule_timeout_uninterruptible((HZ + 49) / 50); + + pt1->reset = 0; + pt1_update_power(pt1); + schedule_timeout_uninterruptible((HZ + 999) / 1000); + + ret = pt1_init_frontends(pt1); + if (ret < 0) + goto err_pt1_disable_ram; + + ret = pt1_init_tables(pt1); + if (ret < 0) + goto err_pt1_cleanup_frontends; + + return 0; + +err_pt1_cleanup_frontends: + pt1_cleanup_frontends(pt1); +err_pt1_disable_ram: + pt1_disable_ram(pt1); + pt1->power = 0; + pt1->reset = 1; + pt1_update_power(pt1); +err_i2c_del_adapter: + i2c_del_adapter(i2c_adap); +err_pt1_cleanup_adapters: + pt1_cleanup_adapters(pt1); +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) }, + { PCI_DEVICE(0x10ee, 0x222a) }, + { }, +}; +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 "); +MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/pt1/va1j5jf8007s.c b/drivers/media/pci/pt1/va1j5jf8007s.c new file mode 100644 index 00000000000..d980dfb21e5 --- /dev/null +++ b/drivers/media/pci/pt1/va1j5jf8007s.c @@ -0,0 +1,735 @@ +/* + * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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 +#include +#include +#include +#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_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct va1j5jf8007s_state *state; + u8 addr; + int i; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + s32 word, x1, x2, x3, x4, x5, y; + + state = fe->demodulator_priv; + addr = state->config->demod_address; + + word = 0; + for (i = 0; i < 2; i++) { + write_buf[0] = 0xbc + i; + + 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; + + word <<= 8; + word |= read_buf[0]; + } + + word -= 3000; + if (word < 0) + word = 0; + + x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000); + x2 = (s64)x1 * x1 >> 31; + x3 = (s64)x2 * x1 >> 31; + x4 = (s64)x2 * x2 >> 31; + x5 = (s64)x4 * x1 >> 31; + + y = (58857ll << 23) / 1000; + y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30; + y += (s64)x2 * ((88977ll << 24) / 1000) >> 28; + y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27; + y += (s64)x4 * ((14341ll << 27) / 1000) >> 27; + y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28; + + *snr = y < 0 ? 0 : y >> 15; + return 0; +} + +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, + bool re_tune, + unsigned int mode_flags, unsigned int *delay, + fe_status_t *status) +{ + struct va1j5jf8007s_state *state; + int ret; + int lock = 0; + + state = fe->demodulator_priv; + + if (re_tune) + 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 = { + .delsys = { SYS_ISDBS }, + .info = { + .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", + .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, + }, + + .read_snr = va1j5jf8007s_read_snr, + .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_20mhz_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 const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = { + {0x04, 0x02}, {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, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, +}; + +static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) +{ + const u8 (*bufs)[2]; + int size; + u8 addr; + u8 buf[2]; + struct i2c_msg msg; + int i; + + switch (state->config->frequency) { + case VA1J5JF8007S_20MHZ: + bufs = va1j5jf8007s_20mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs); + break; + case VA1J5JF8007S_25MHZ: + bufs = va1j5jf8007s_25mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs); + break; + default: + return -EINVAL; + } + + addr = state->config->demod_address; + + msg.addr = addr; + msg.flags = 0; + msg.len = 2; + msg.buf = buf; + for (i = 0; i < size; i++) { + memcpy(buf, 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/drivers/media/pci/pt1/va1j5jf8007s.h b/drivers/media/pci/pt1/va1j5jf8007s.h new file mode 100644 index 00000000000..b7d6f05a0e0 --- /dev/null +++ b/drivers/media/pci/pt1/va1j5jf8007s.h @@ -0,0 +1,46 @@ +/* + * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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 + +enum va1j5jf8007s_frequency { + VA1J5JF8007S_20MHZ, + VA1J5JF8007S_25MHZ, +}; + +struct va1j5jf8007s_config { + u8 demod_address; + enum va1j5jf8007s_frequency frequency; +}; + +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/drivers/media/pci/pt1/va1j5jf8007t.c b/drivers/media/pci/pt1/va1j5jf8007t.c new file mode 100644 index 00000000000..2db15159d51 --- /dev/null +++ b/drivers/media/pci/pt1/va1j5jf8007t.c @@ -0,0 +1,536 @@ +/* + * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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 +#include +#include +#include +#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_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct va1j5jf8007t_state *state; + u8 addr; + int i; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + s32 word, x, y; + + state = fe->demodulator_priv; + addr = state->config->demod_address; + + word = 0; + for (i = 0; i < 3; i++) { + write_buf[0] = 0x8b + i; + + 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; + + word <<= 8; + word |= read_buf[0]; + } + + if (!word) + return -EIO; + + x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24)); + y = (24ll << 46) / 1000000; + y = ((s64)y * x >> 30) - (16ll << 40) / 10000; + y = ((s64)y * x >> 29) + (398ll << 35) / 10000; + y = ((s64)y * x >> 30) + (5491ll << 29) / 10000; + y = ((s64)y * x >> 30) + (30965ll << 23) / 10000; + *snr = y >> 15; + return 0; +} + +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, + bool re_tune, + unsigned int mode_flags, unsigned int *delay, + fe_status_t *status) +{ + struct va1j5jf8007t_state *state; + int ret; + int lock = 0, retry = 0; + + state = fe->demodulator_priv; + + if (re_tune) + 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 = { + .delsys = { SYS_ISDBT }, + .info = { + .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", + .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, + }, + + .read_snr = va1j5jf8007t_read_snr, + .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_20mhz_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} +}; + +static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = { + {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, + {0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c}, + {0x77, 0x03}, {0xef, 0x01} +}; + +int va1j5jf8007t_prepare(struct dvb_frontend *fe) +{ + struct va1j5jf8007t_state *state; + const u8 (*bufs)[2]; + int size; + u8 buf[2]; + struct i2c_msg msg; + int i; + + state = fe->demodulator_priv; + + switch (state->config->frequency) { + case VA1J5JF8007T_20MHZ: + bufs = va1j5jf8007t_20mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs); + break; + case VA1J5JF8007T_25MHZ: + bufs = va1j5jf8007t_25mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs); + break; + default: + return -EINVAL; + } + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + for (i = 0; i < size; i++) { + memcpy(buf, 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/drivers/media/pci/pt1/va1j5jf8007t.h b/drivers/media/pci/pt1/va1j5jf8007t.h new file mode 100644 index 00000000000..2903be519ef --- /dev/null +++ b/drivers/media/pci/pt1/va1j5jf8007t.h @@ -0,0 +1,46 @@ +/* + * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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 + +enum va1j5jf8007t_frequency { + VA1J5JF8007T_20MHZ, + VA1J5JF8007T_25MHZ, +}; + +struct va1j5jf8007t_config { + u8 demod_address; + enum va1j5jf8007t_frequency frequency; +}; + +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/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig new file mode 100644 index 00000000000..9d83ced69dd --- /dev/null +++ b/drivers/media/pci/ttpci/Kconfig @@ -0,0 +1,159 @@ +config TTPCI_EEPROM + tristate + depends on I2C + default n + +config DVB_AV7110 + tristate "AV7110 cards" + depends on DVB_CORE && PCI && I2C + select TTPCI_EEPROM + select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV + select DVB_VES1820 if !DVB_FE_CUSTOMISE + select DVB_VES1X93 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_SP8870 if !DVB_FE_CUSTOMISE + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_L64781 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + help + Support for SAA7146 and AV7110 based DVB cards as produced + by Fujitsu-Siemens, Technotrend, Hauppauge and others. + + This driver only supports the fullfeatured cards with + onboard MPEG2 decoder. + + This driver needs an external firmware. Please use the script + "/Documentation/dvb/get_dvb_firmware av7110" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + + Alternatively, you can download the file and use the kernel's + EXTRA_FIRMWARE configuration option to build it into your + kernel image by adding the filename to the EXTRA_FIRMWARE + configuration option string. + + Say Y if you own such a card and want to use it. + +config DVB_AV7110_OSD + bool "AV7110 OSD support" + depends on DVB_AV7110 + default y if DVB_AV7110=y || DVB_AV7110=m + help + The AV7110 firmware provides some code to generate an OnScreenDisplay + on the video output. This is kind of nonstandard and not guaranteed to + be maintained. + + Anyway, some popular DVB software like VDR uses this OSD to render + its menus, so say Y if you want to use this software. + + All other people say N. + +config DVB_BUDGET_CORE + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" + depends on DVB_CORE && PCI && I2C + select VIDEO_SAA7146 + select TTPCI_EEPROM + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. + +config DVB_BUDGET + tristate "Budget cards" + depends on DVB_BUDGET_CORE && I2C + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_VES1X93 if !DVB_FE_CUSTOMISE + select DVB_VES1820 if !DVB_FE_CUSTOMISE + select DVB_L64781 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_S5H1420 if !DVB_FE_CUSTOMISE + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + help + Support for simple SAA7146 based DVB cards (so called Budget- + or Nova-PCI cards) without onboard MPEG2 decoder, and without + analog inputs or an onboard Common Interface connector. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget. + +config DVB_BUDGET_CI + tristate "Budget cards with onboard CI connector" + depends on DVB_BUDGET_CORE && I2C + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + depends on RC_CORE + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder, but with onboard Common Interface connector. + + Note: The Common Interface is not yet supported by this driver + due to lack of information from the vendor. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-ci. + +config DVB_BUDGET_AV + tristate "Budget cards with analog video inputs" + depends on DVB_BUDGET_CORE && I2C + select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_TDA10021 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_TDA8261 if !DVB_FE_CUSTOMISE + select DVB_TUA6100 if !DVB_FE_CUSTOMISE + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder, but with one or more analog video inputs. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-av. + +config DVB_BUDGET_PATCH + tristate "AV7110 cards with Budget Patch" + depends on DVB_BUDGET_CORE && I2C + depends on DVB_AV7110 + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_VES1X93 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + help + Support for Budget Patch (full TS) modification on + SAA7146+AV7110 based cards (DVB-S cards). This + driver doesn't use onboard MPEG2 decoder. The + card is driven in Budget-only mode. Card is + required to have loaded firmware to tune properly. + Firmware can be loaded by insertion and removal of + standard AV7110 driver prior to loading this + driver. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-patch. diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile new file mode 100644 index 00000000000..22a235f3cc4 --- /dev/null +++ b/drivers/media/pci/ttpci/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the kernel SAA7146 FULL TS DVB device driver +# and the AV7110 DVB device driver +# + +dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o + +ifdef CONFIG_INPUT_EVDEV +dvb-ttpci-objs += av7110_ir.o +endif + +obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o +obj-$(CONFIG_DVB_BUDGET) += budget.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o + +ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c new file mode 100644 index 00000000000..4bd8bd56bef --- /dev/null +++ b/drivers/media/pci/ttpci/av7110.c @@ -0,0 +1,2939 @@ +/* + * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) + * av7110.c: initialization and demux stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include "dvb_frontend.h" + +#include "ttpci-eeprom.h" +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" +#include "av7110_ca.h" +#include "av7110_ipack.h" + +#include "bsbe1.h" +#include "lnbp21.h" +#include "bsru6.h" + +#define TS_WIDTH 376 +#define TS_HEIGHT 512 +#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) +#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) + + +int av7110_debug; + +static int vidmode = CVBS_RGB_OUT; +static int pids_off; +static int adac = DVB_ADAC_TI; +static int hw_sections; +static int rgb_on; +static int volume = 255; +static int budgetpatch; +static int wss_cfg_4_3 = 0x4008; +static int wss_cfg_16_9 = 0x0007; +static int tv_standard; +static int full_ts; + +module_param_named(debug, av7110_debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); +module_param(vidmode, int, 0444); +MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC"); +module_param(pids_off, int, 0444); +MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed"); +module_param(adac, int, 0444); +MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)"); +module_param(hw_sections, int, 0444); +MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); +module_param(rgb_on, int, 0444); +MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control" + " signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); +module_param(volume, int, 0444); +MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); +module_param(budgetpatch, int, 0444); +MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); +module_param(full_ts, int, 0444); +MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); +module_param(wss_cfg_4_3, int, 0444); +MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(wss_cfg_16_9, int, 0444); +MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(tv_standard, int, 0444); +MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static void restart_feeds(struct av7110 *av7110); +static int budget_start_feed(struct dvb_demux_feed *feed); +static int budget_stop_feed(struct dvb_demux_feed *feed); + +static int av7110_num; + +#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ +{\ + if (fe_func != NULL) { \ + av7110_copy = fe_func; \ + fe_func = av7110_func; \ + } \ +} + + +static void init_av7110_av(struct av7110 *av7110) +{ + int ret; + struct saa7146_dev *dev = av7110->dev; + + /* set internal volume control to maximum */ + av7110->adac_type = DVB_ADAC_TI; + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret < 0) + printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, + 1, (u16) av7110->display_ar); + if (ret < 0) + printk("dvb-ttpci: unable to set aspect ratio\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + if (ret < 0) + printk("dvb-ttpci: unable to set pan scan\n"); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3); + if (ret < 0) + printk("dvb-ttpci: unable to configure 4:3 wss\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9); + if (ret < 0) + printk("dvb-ttpci: unable to configure 16:9 wss\n"); + + ret = av7710_set_video_mode(av7110, vidmode); + if (ret < 0) + printk("dvb-ttpci:cannot set video mode:%d\n",ret); + + /* handle different card types */ + /* remaining inits according to card and frontend type */ + av7110->analog_tuner_flags = 0; + av7110->current_input = 0; + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on + if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { + printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_CRYSTAL; + i2c_writereg(av7110, 0x20, 0x01, 0xd2); + i2c_writereg(av7110, 0x20, 0x02, 0x49); + i2c_writereg(av7110, 0x20, 0x03, 0x00); + i2c_writereg(av7110, 0x20, 0x04, 0x00); + + /** + * some special handling for the Siemens DVB-C cards... + */ + } else if (0 == av7110_init_analog_module(av7110)) { + /* done. */ + } + else if (dev->pci->subsystem_vendor == 0x110a) { + printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_NONE; + } + else { + av7110->adac_type = adac; + printk("dvb-ttpci: adac type set to %d @ card %d\n", + av7110->adac_type, av7110->dvb_adapter.num); + } + + if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { + // switch DVB SCART on + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); + if (ret < 0) + printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + if (ret < 0) + printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); + if (rgb_on && + ((av7110->dev->pci->subsystem_vendor == 0x110a) || + (av7110->dev->pci->subsystem_vendor == 0x13c2)) && + (av7110->dev->pci->subsystem_device == 0x0000)) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 + //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 + } + } + + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e) + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on + + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret < 0) + printk("dvb-ttpci:cannot set volume :%d\n",ret); +} + +static void recover_arm(struct av7110 *av7110) +{ + dprintk(4, "%p\n",av7110); + + av7110_bootarm(av7110); + msleep(100); + + init_av7110_av(av7110); + + /* card-specific recovery */ + if (av7110->recover) + av7110->recover(av7110); + + restart_feeds(av7110); + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_check_ir_config(av7110, true); +#endif +} + +static void av7110_arm_sync(struct av7110 *av7110) +{ + if (av7110->arm_thread) + kthread_stop(av7110->arm_thread); + + av7110->arm_thread = NULL; +} + +static int arm_thread(void *data) +{ + struct av7110 *av7110 = data; + u16 newloops = 0; + int timeout; + + dprintk(4, "%p\n",av7110); + + for (;;) { + timeout = wait_event_interruptible_timeout(av7110->arm_wait, + kthread_should_stop(), 5 * HZ); + + if (-ERESTARTSYS == timeout || kthread_should_stop()) { + /* got signal or told to quit*/ + break; + } + + if (!av7110->arm_ready) + continue; + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_check_ir_config(av7110, false); +#endif + + if (mutex_lock_interruptible(&av7110->dcomlock)) + break; + newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); + mutex_unlock(&av7110->dcomlock); + + if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { + printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", + av7110->dvb_adapter.num); + + recover_arm(av7110); + + if (mutex_lock_interruptible(&av7110->dcomlock)) + break; + newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; + mutex_unlock(&av7110->dcomlock); + } + av7110->arm_loops = newloops; + av7110->arm_errors = 0; + } + + return 0; +} + + +/**************************************************************************** + * IRQ handling + ****************************************************************************/ + +static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, + u8 *buffer2, size_t buffer2_len, + struct dvb_demux_filter *dvbdmxfilter, + enum dmx_success success, + struct av7110 *av7110) +{ + if (!dvbdmxfilter->feed->demux->dmx.frontend) + return 0; + if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE) + return 0; + + switch (dvbdmxfilter->type) { + case DMX_TYPE_SEC: + if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len) + return 0; + if (dvbdmxfilter->doneq) { + struct dmx_section_filter *filter = &dvbdmxfilter->filter; + int i; + u8 xor, neq = 0; + + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + xor = filter->filter_value[i] ^ buffer1[i]; + neq |= dvbdmxfilter->maskandnotmode[i] & xor; + } + if (!neq) + return 0; + } + return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, + buffer2, buffer2_len, + &dvbdmxfilter->filter, + DMX_OK); + case DMX_TYPE_TS: + if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) + return 0; + if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, + buffer2, buffer2_len, + &dvbdmxfilter->feed->feed.ts, + DMX_OK); + else + av7110_p2t_write(buffer1, buffer1_len, + dvbdmxfilter->feed->pid, + &av7110->p2t_filter[dvbdmxfilter->index]); + default: + return 0; + } +} + + +//#define DEBUG_TIMING +static inline void print_time(char *s) +{ +#ifdef DEBUG_TIMING + struct timeval tv; + do_gettimeofday(&tv); + printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec); +#endif +} + +#define DEBI_READ 0 +#define DEBI_WRITE 1 +static inline void start_debi_dma(struct av7110 *av7110, int dir, + unsigned long addr, unsigned int len) +{ + dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); + return; + } + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ + SAA7146_IER_ENABLE(av7110->dev, MASK_19); + if (len < 5) + len = 5; /* we want a real DEBI DMA */ + if (dir == DEBI_WRITE) + iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); + else + irdebi(av7110, DEBISWAB, addr, 0, len); +} + +static void debiirq(unsigned long cookie) +{ + struct av7110 *av7110 = (struct av7110 *)cookie; + int type = av7110->debitype; + int handle = (type >> 8) & 0x1f; + unsigned int xfer = 0; + + print_time("debi"); + dprintk(4, "type 0x%04x\n", type); + + if (type == -1) { + printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", + jiffies, saa7146_read(av7110->dev, PSR), + saa7146_read(av7110->dev, SSR)); + goto debi_done; + } + av7110->debitype = -1; + + switch (type & 0xff) { + + case DATA_TS_RECORD: + dvb_dmx_swfilter_packets(&av7110->demux, + (const u8 *) av7110->debi_virt, + av7110->debilen / 188); + xfer = RX_BUFF; + break; + + case DATA_PES_RECORD: + if (av7110->demux.recording) + av7110_record_cb(&av7110->p2t[handle], + (u8 *) av7110->debi_virt, + av7110->debilen); + xfer = RX_BUFF; + break; + + case DATA_IPMPE: + case DATA_FSECTION: + case DATA_PIPING: + if (av7110->handle2filter[handle]) + DvbDmxFilterCallback((u8 *)av7110->debi_virt, + av7110->debilen, NULL, 0, + av7110->handle2filter[handle], + DMX_OK, av7110); + xfer = RX_BUFF; + break; + + case DATA_CI_GET: + { + u8 *data = av7110->debi_virt; + + if ((data[0] < 2) && data[2] == 0xff) { + int flags = 0; + if (data[5] > 0) + flags |= CA_CI_MODULE_PRESENT; + if (data[5] > 5) + flags |= CA_CI_MODULE_READY; + av7110->ci_slot[data[0]].flags = flags; + } else + ci_get_data(&av7110->ci_rbuffer, + av7110->debi_virt, + av7110->debilen); + xfer = RX_BUFF; + break; + } + + case DATA_COMMON_INTERFACE: + CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen); +#if 0 + { + int i; + + printk("av7110%d: ", av7110->num); + printk("%02x ", *(u8 *)av7110->debi_virt); + printk("%02x ", *(1+(u8 *)av7110->debi_virt)); + for (i = 2; i < av7110->debilen; i++) + printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt))); + for (i = 2; i < av7110->debilen; i++) + printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt))); + + printk("\n"); + } +#endif + xfer = RX_BUFF; + break; + + case DATA_DEBUG_MESSAGE: + ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0; + printk("%s\n", (s8 *) av7110->debi_virt); + xfer = RX_BUFF; + break; + + case DATA_CI_PUT: + dprintk(4, "debi DATA_CI_PUT\n"); + case DATA_MPEG_PLAY: + dprintk(4, "debi DATA_MPEG_PLAY\n"); + case DATA_BMP_LOAD: + dprintk(4, "debi DATA_BMP_LOAD\n"); + xfer = TX_BUFF; + break; + default: + break; + } +debi_done: + spin_lock(&av7110->debilock); + if (xfer) + iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); + ARM_ClearMailBox(av7110); + spin_unlock(&av7110->debilock); +} + +/* irq from av7110 firmware writing the mailbox register in the DPRAM */ +static void gpioirq(unsigned long cookie) +{ + struct av7110 *av7110 = (struct av7110 *)cookie; + u32 rxbuf, txbuf; + int len; + + if (av7110->debitype != -1) + /* we shouldn't get any irq while a debi xfer is running */ + printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", + jiffies, saa7146_read(av7110->dev, PSR), + saa7146_read(av7110->dev, SSR)); + + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); + BUG(); /* maybe we should try resetting the debi? */ + } + + spin_lock(&av7110->debilock); + ARM_ClearIrq(av7110); + + /* see what the av7110 wants */ + av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); + av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + len = (av7110->debilen + 3) & ~3; + + print_time("gpio"); + dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); + + switch (av7110->debitype & 0xff) { + + case DATA_TS_PLAY: + case DATA_PES_PLAY: + break; + + case DATA_MPEG_VIDEO_EVENT: + { + u32 h_ar; + struct video_event event; + + av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2); + h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2); + + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + + av7110->video_size.h = h_ar & 0xfff; + + event.type = VIDEO_EVENT_SIZE_CHANGED; + event.u.size.w = av7110->video_size.w; + event.u.size.h = av7110->video_size.h; + switch ((h_ar >> 12) & 0xf) + { + case 3: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9; + event.u.size.aspect_ratio = VIDEO_FORMAT_16_9; + av7110->videostate.video_format = VIDEO_FORMAT_16_9; + break; + case 4: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1; + event.u.size.aspect_ratio = VIDEO_FORMAT_221_1; + av7110->videostate.video_format = VIDEO_FORMAT_221_1; + break; + default: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3; + event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; + av7110->videostate.video_format = VIDEO_FORMAT_4_3; + } + + dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", + av7110->video_size.w, av7110->video_size.h, + av7110->video_size.aspect_ratio); + + dvb_video_add_event(av7110, &event); + break; + } + + case DATA_CI_PUT: + { + int avail; + struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer; + + avail = dvb_ringbuffer_avail(cibuf); + if (avail <= 2) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= DVB_RINGBUFFER_PEEK(cibuf, 1); + if (avail < len + 2) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + DVB_RINGBUFFER_SKIP(cibuf, 2); + + dvb_ringbuffer_read(cibuf, av7110->debi_virt, len); + + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + dprintk(8, "DMA: CI\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); + spin_unlock(&av7110->debilock); + wake_up(&cibuf->queue); + return; + } + + case DATA_MPEG_PLAY: + if (!av7110->playing) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + len = 0; + if (av7110->debitype & 0x100) { + spin_lock(&av7110->aout.lock); + len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048); + spin_unlock(&av7110->aout.lock); + } + if (len <= 0 && (av7110->debitype & 0x200) + &&av7110->videostate.play_state != VIDEO_FREEZED) { + spin_lock(&av7110->avout.lock); + len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048); + spin_unlock(&av7110->avout.lock); + } + if (len <= 0) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + dprintk(8, "DMA: MPEG_PLAY\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_BMP_LOAD: + len = av7110->debilen; + dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); + if (!len) { + av7110->bmp_state = BMP_LOADED; + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + wake_up(&av7110->bmpq); + dprintk(8, "gpio DATA_BMP_LOAD done\n"); + break; + } + if (len > av7110->bmplen) + len = av7110->bmplen; + if (len > 2 * 1024) + len = 2 * 1024; + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); + av7110->bmpp += len; + av7110->bmplen -= len; + dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_CI_GET: + case DATA_COMMON_INTERFACE: + case DATA_FSECTION: + case DATA_IPMPE: + case DATA_PIPING: + if (!len || len > 4 * 1024) { + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + } + /* fall through */ + + case DATA_TS_RECORD: + case DATA_PES_RECORD: + dprintk(8, "DMA: TS_REC etc.\n"); + start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_DEBUG_MESSAGE: + if (!len || len > 0xff) { + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + } + start_debi_dma(av7110, DEBI_READ, Reserved, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_IRCOMMAND: + if (av7110->ir.ir_handler) + av7110->ir.ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + + default: + printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n", + av7110->debitype, av7110->debilen); + break; + } + av7110->debitype = -1; + ARM_ClearMailBox(av7110); + spin_unlock(&av7110->debilock); +} + + +#ifdef CONFIG_DVB_AV7110_OSD +static int dvb_osd_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(4, "%p\n", av7110); + + if (cmd == OSD_SEND_CMD) + return av7110_osd_cmd(av7110, (osd_cmd_t *) parg); + if (cmd == OSD_GET_CAPABILITY) + return av7110_osd_capability(av7110, (osd_cap_t *) parg); + + return -EINVAL; +} + + +static const struct file_operations dvb_osd_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_osd = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_osd_fops, + .kernel_ioctl = dvb_osd_ioctl, +}; +#endif /* CONFIG_DVB_AV7110_OSD */ + + +static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid) +{ + u16 aflags = 0; + + dprintk(4, "%p\n", av7110); + + if (vpid == 0x1fff || apid == 0x1fff || + ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) { + vpid = apid = ttpid = subpid = pcrpid = 0; + av7110->pids[DMX_PES_VIDEO] = 0; + av7110->pids[DMX_PES_AUDIO] = 0; + av7110->pids[DMX_PES_TELETEXT] = 0; + av7110->pids[DMX_PES_PCR] = 0; + } + + if (av7110->audiostate.bypass_mode) + aflags |= 0x8000; + + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, + pcrpid, vpid, apid, ttpid, subpid, aflags); +} + +int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid) +{ + int ret = 0; + dprintk(4, "%p\n", av7110); + + if (mutex_lock_interruptible(&av7110->pid_mutex)) + return -ERESTARTSYS; + + if (!(vpid & 0x8000)) + av7110->pids[DMX_PES_VIDEO] = vpid; + if (!(apid & 0x8000)) + av7110->pids[DMX_PES_AUDIO] = apid; + if (!(ttpid & 0x8000)) + av7110->pids[DMX_PES_TELETEXT] = ttpid; + if (!(pcrpid & 0x8000)) + av7110->pids[DMX_PES_PCR] = pcrpid; + + av7110->pids[DMX_PES_SUBTITLE] = 0; + + if (av7110->fe_synced) { + pcrpid = av7110->pids[DMX_PES_PCR]; + ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); + } + + mutex_unlock(&av7110->pid_mutex); + return ret; +} + + +/****************************************************************************** + * hardware filter functions + ******************************************************************************/ + +static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) +{ + struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed; + struct av7110 *av7110 = dvbdmxfeed->demux->priv; + u16 buf[20]; + int ret, i; + u16 handle; +// u16 mode = 0x0320; + u16 mode = 0xb96a; + + dprintk(4, "%p\n", av7110); + + if (av7110->full_ts) + return 0; + + if (dvbdmxfilter->type == DMX_TYPE_SEC) { + if (hw_sections) { + buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | + dvbdmxfilter->maskandmode[0]; + for (i = 3; i < 18; i++) + buf[i + 4 - 2] = + (dvbdmxfilter->filter.filter_value[i] << 8) | + dvbdmxfilter->maskandmode[i]; + mode = 4; + } + } else if ((dvbdmxfeed->ts_type & TS_PACKET) && + !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) { + av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed); + } + + buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter; + buf[1] = 16; + buf[2] = dvbdmxfeed->pid; + buf[3] = mode; + + ret = av7110_fw_request(av7110, buf, 20, &handle, 1); + if (ret != 0 || handle >= 32) { + printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " + "ret %d handle %04x\n", + __func__, buf[0], buf[1], buf[2], buf[3], + ret, handle); + dvbdmxfilter->hw_handle = 0xffff; + if (!ret) + ret = -1; + return ret; + } + + av7110->handle2filter[handle] = dvbdmxfilter; + dvbdmxfilter->hw_handle = handle; + + return ret; +} + +static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) +{ + struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv; + u16 buf[3]; + u16 answ[2]; + int ret; + u16 handle; + + dprintk(4, "%p\n", av7110); + + if (av7110->full_ts) + return 0; + + handle = dvbdmxfilter->hw_handle; + if (handle >= 32) { + printk("%s tried to stop invalid filter %04x, filter type = %x\n", + __func__, handle, dvbdmxfilter->type); + return -EINVAL; + } + + av7110->handle2filter[handle] = NULL; + + buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter; + buf[1] = 1; + buf[2] = handle; + ret = av7110_fw_request(av7110, buf, 3, answ, 2); + if (ret != 0 || answ[1] != handle) { + printk("dvb-ttpci: %s error cmd %04x %04x %04x ret %x " + "resp %04x %04x pid %d\n", + __func__, buf[0], buf[1], buf[2], ret, + answ[0], answ[1], dvbdmxfilter->feed->pid); + if (!ret) + ret = -1; + } + return ret; +} + + +static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct av7110 *av7110 = dvbdmx->priv; + u16 *pid = dvbdmx->pids, npids[5]; + int i; + int ret = 0; + + dprintk(4, "%p\n", av7110); + + npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; + i = dvbdmxfeed->pes_type; + npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; + if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { + npids[i] = 0; + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = StartHWFilter(dvbdmxfeed->filter); + return ret; + } + if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (ret) + return ret; + } + + if (dvbdmxfeed->pes_type < 2 && npids[0]) + if (av7110->fe_synced) + { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (ret) + return ret; + } + + if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { + if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) + ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); + if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) + ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); + } + return ret; +} + +static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct av7110 *av7110 = dvbdmx->priv; + u16 *pid = dvbdmx->pids, npids[5]; + int i; + + int ret = 0; + + dprintk(4, "%p\n", av7110); + + if (dvbdmxfeed->pes_type <= 1) { + ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + if (ret) + return ret; + if (!av7110->rec_mode) + dvbdmx->recording = 0; + if (!av7110->playing) + dvbdmx->playing = 0; + } + npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; + i = dvbdmxfeed->pes_type; + switch (i) { + case 2: //teletext + if (dvbdmxfeed->ts_type & TS_PACKET) + ret = StopHWFilter(dvbdmxfeed->filter); + npids[2] = 0; + break; + case 0: + case 1: + case 4: + if (!pids_off) + return 0; + npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; + break; + } + if (!ret) + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + return ret; +} + +static int av7110_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = demux->priv; + int ret = 0; + + dprintk(4, "%p\n", av7110); + + if (!demux->dmx.frontend) + return -EINVAL; + + if (!av7110->full_ts && feed->pid > 0x1fff) + return -EINVAL; + + if (feed->type == DMX_TYPE_TS) { + if ((feed->ts_type & TS_DECODER) && + (feed->pes_type <= DMX_TS_PES_PCR)) { + switch (demux->dmx.frontend->source) { + case DMX_MEMORY_FE: + if (feed->ts_type & TS_DECODER) + if (feed->pes_type < 2 && + !(demux->pids[0] & 0x8000) && + !(demux->pids[1] & 0x8000)) { + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + ret = av7110_av_start_play(av7110,RP_AV); + if (!ret) + demux->playing = 1; + } + break; + default: + ret = dvb_feed_start_pid(feed); + break; + } + } else if ((feed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE)) { + ret = StartHWFilter(feed->filter); + } + } + + if (av7110->full_ts) { + budget_start_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { + int i; + + for (i = 0; i < demux->filternum; i++) { + if (demux->filter[i].state != DMX_STATE_READY) + continue; + if (demux->filter[i].type != DMX_TYPE_SEC) + continue; + if (demux->filter[i].filter.parent != &feed->feed.sec) + continue; + demux->filter[i].state = DMX_STATE_GO; + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StartHWFilter(&demux->filter[i]); + if (ret) + break; + } + } + } + + return ret; +} + + +static int av7110_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = demux->priv; + int i, rc, ret = 0; + dprintk(4, "%p\n", av7110); + + if (feed->type == DMX_TYPE_TS) { + if (feed->ts_type & TS_DECODER) { + if (feed->pes_type >= DMX_TS_PES_OTHER || + !demux->pesfilter[feed->pes_type]) + return -EINVAL; + demux->pids[feed->pes_type] |= 0x8000; + demux->pesfilter[feed->pes_type] = NULL; + } + if (feed->ts_type & TS_DECODER && + feed->pes_type < DMX_TS_PES_OTHER) { + ret = dvb_feed_stop_pid(feed); + } else + if ((feed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE)) + ret = StopHWFilter(feed->filter); + } + + if (av7110->full_ts) { + budget_stop_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { + for (i = 0; ifilternum; i++) { + if (demux->filter[i].state == DMX_STATE_GO && + demux->filter[i].filter.parent == &feed->feed.sec) { + demux->filter[i].state = DMX_STATE_READY; + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + rc = StopHWFilter(&demux->filter[i]); + if (!ret) + ret = rc; + /* keep going, stop as many filters as possible */ + } + } + } + } + + return ret; +} + + +static void restart_feeds(struct av7110 *av7110) +{ + struct dvb_demux *dvbdmx = &av7110->demux; + struct dvb_demux_feed *feed; + int mode; + int feeding; + int i, j; + + dprintk(4, "%p\n", av7110); + + mode = av7110->playing; + av7110->playing = 0; + av7110->rec_mode = 0; + + feeding = av7110->feeding1; /* full_ts mod */ + + for (i = 0; i < dvbdmx->feednum; i++) { + feed = &dvbdmx->feed[i]; + if (feed->state == DMX_STATE_GO) { + if (feed->type == DMX_TYPE_SEC) { + for (j = 0; j < dvbdmx->filternum; j++) { + if (dvbdmx->filter[j].type != DMX_TYPE_SEC) + continue; + if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) + continue; + if (dvbdmx->filter[j].state == DMX_STATE_GO) + dvbdmx->filter[j].state = DMX_STATE_READY; + } + } + av7110_start_feed(feed); + } + } + + av7110->feeding1 = feeding; /* full_ts mod */ + + if (mode) + av7110_av_start_play(av7110, mode); +} + +static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, + uint64_t *stc, unsigned int *base) +{ + int ret; + u16 fwstc[4]; + u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC); + struct dvb_demux *dvbdemux; + struct av7110 *av7110; + + /* pointer casting paranoia... */ + BUG_ON(!demux); + dvbdemux = demux->priv; + BUG_ON(!dvbdemux); + av7110 = dvbdemux->priv; + + dprintk(4, "%p\n", av7110); + + if (num != 0) + return -EINVAL; + + ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); + if (ret) { + printk(KERN_ERR "%s: av7110_fw_request error\n", __func__); + return ret; + } + dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", + fwstc[0], fwstc[1], fwstc[2], fwstc[3]); + + *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) | + (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]); + *base = 1; + + dprintk(4, "stc = %lu\n", (unsigned long)*stc); + + return 0; +} + + +/****************************************************************************** + * SEC device file operations + ******************************************************************************/ + + +static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct av7110* av7110 = fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + return Set22K(av7110, 1); + + case SEC_TONE_OFF: + return Set22K(av7110, 0); + + default: + return -EINVAL; + } +} + +static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); +} + +static int av7110_diseqc_send_burst(struct dvb_frontend* fe, + fe_sec_mini_cmd_t minicmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + return av7110_diseqc_send(av7110, 0, NULL, minicmd); +} + +/* simplified code from budget-core.c */ +static int stop_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (--budget->feeding1) + return budget->feeding1; + saa7146_write(budget->dev, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(budget->dev, MASK_10); + SAA7146_ISR_CLEAR(budget->dev, MASK_10); + return 0; +} + +static int start_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (budget->feeding1) + return ++budget->feeding1; + memset(budget->grabbing, 0x00, TS_BUFLEN); + budget->ttbp = 0; + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ + return ++budget->feeding1; +} + +static int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = demux->priv; + int status; + + dprintk(2, "av7110: %p\n", budget); + + spin_lock(&budget->feedlock1); + feed->pusi_seen = 0; /* have a clean section start */ + status = start_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = demux->priv; + int status; + + dprintk(2, "budget: %p\n", budget); + + spin_lock(&budget->feedlock1); + status = stop_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static void vpeirq(unsigned long cookie) +{ + struct av7110 *budget = (struct av7110 *)cookie; + u8 *mem = (u8 *) (budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; + + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= TS_BUFLEN) + return; + + budget->ttbp = newdma; + + if (!budget->feeding1 || (newdma == olddma)) + return; + + /* Ensure streamed PCI data is synced to CPU */ + pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); + +#if 0 + /* track rps1 activity */ + printk("vpeirq: %02x Event Counter 1 0x%04x\n", + mem[olddma], + saa7146_read(budget->dev, EC1R) & 0x3fff); +#endif + + if (newdma > olddma) + /* no wraparound, dump olddma..newdma */ + dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); + else { + /* wraparound, dump olddma..buflen and 0..newdma */ + dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem, newdma / 188); + } +} + +static int av7110_register(struct av7110 *av7110) +{ + int ret, i; + struct dvb_demux *dvbdemux = &av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; + + dprintk(4, "%p\n", av7110); + + if (av7110->registered) + return -1; + + av7110->registered = 1; + + dvbdemux->priv = (void *) av7110; + + for (i = 0; i < 32; i++) + av7110->handle2filter[i] = NULL; + + dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; + dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; + dvbdemux->start_feed = av7110_start_feed; + dvbdemux->stop_feed = av7110_stop_feed; + dvbdemux->write_to_decoder = av7110_write_to_decoder; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux); + av7110->demux.dmx.get_stc = dvb_get_stc; + + av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; + av7110->dmxdev.demux = &dvbdemux->dmx; + av7110->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter); + + av7110->hw_frontend.source = DMX_FRONTEND_0; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend); + + if (ret < 0) + return ret; + + av7110->mem_frontend.source = DMX_MEMORY_FE; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend); + + if (ret < 0) + return ret; + + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, + &av7110->hw_frontend); + if (ret < 0) + return ret; + + av7110_av_register(av7110); + av7110_ca_register(av7110); + +#ifdef CONFIG_DVB_AV7110_OSD + dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, + &dvbdev_osd, av7110, DVB_DEVICE_OSD); +#endif + + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); + + if (budgetpatch) { + /* initialize software demux1 without its own frontend + * demux1 hardware is connected to frontend0 of demux0 + */ + dvbdemux1->priv = (void *) av7110; + + dvbdemux1->filternum = 256; + dvbdemux1->feednum = 256; + dvbdemux1->start_feed = budget_start_feed; + dvbdemux1->stop_feed = budget_stop_feed; + dvbdemux1->write_to_decoder = NULL; + + dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux1); + + av7110->dmxdev1.filternum = 256; + av7110->dmxdev1.demux = &dvbdemux1->dmx; + av7110->dmxdev1.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter); + + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); + printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); + } + return 0; +} + + +static void dvb_unregister(struct av7110 *av7110) +{ + struct dvb_demux *dvbdemux = &av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; + + dprintk(4, "%p\n", av7110); + + if (!av7110->registered) + return; + + if (budgetpatch) { + dvb_net_release(&av7110->dvb_net1); + dvbdemux->dmx.close(&dvbdemux1->dmx); + dvb_dmxdev_release(&av7110->dmxdev1); + dvb_dmx_release(&av7110->demux1); + } + + dvb_net_release(&av7110->dvb_net); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend); + + dvb_dmxdev_release(&av7110->dmxdev); + dvb_dmx_release(&av7110->demux); + + if (av7110->fe != NULL) { + dvb_unregister_frontend(av7110->fe); + dvb_frontend_detach(av7110->fe); + } + dvb_unregister_device(av7110->osd_dev); + av7110_av_unregister(av7110); + av7110_ca_unregister(av7110); +} + + +/**************************************************************************** + * I2C client commands + ****************************************************************************/ + +int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + struct i2c_msg msgs; + + msgs.flags = 0; + msgs.addr = id / 2; + msgs.len = 2; + msgs.buf = msg; + return i2c_transfer(&av7110->i2c_adap, &msgs, 1); +} + +u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) +{ + u8 mm1[] = {0x00}; + u8 mm2[] = {0x00}; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = id / 2; + mm1[0] = reg; + msgs[0].len = 1; msgs[1].len = 1; + msgs[0].buf = mm1; msgs[1].buf = mm2; + i2c_transfer(&av7110->i2c_adap, msgs, 2); + + return mm2[0]; +} + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + + +static int check_firmware(struct av7110* av7110) +{ + u32 crc = 0, len = 0; + unsigned char *ptr; + + /* check for firmware magic */ + ptr = av7110->bin_fw; + if (ptr[0] != 'A' || ptr[1] != 'V' || + ptr[2] != 'F' || ptr[3] != 'W') { + printk("dvb-ttpci: this is not an av7110 firmware\n"); + return -EINVAL; + } + ptr += 4; + + /* check dpram file */ + crc = get_unaligned_be32(ptr); + ptr += 4; + len = get_unaligned_be32(ptr); + ptr += 4; + if (len >= 512) { + printk("dvb-ttpci: dpram file is way too big.\n"); + return -EINVAL; + } + if (crc != crc32_le(0, ptr, len)) { + printk("dvb-ttpci: crc32 of dpram file does not match.\n"); + return -EINVAL; + } + av7110->bin_dpram = ptr; + av7110->size_dpram = len; + ptr += len; + + /* check root file */ + crc = get_unaligned_be32(ptr); + ptr += 4; + len = get_unaligned_be32(ptr); + ptr += 4; + + if (len <= 200000 || len >= 300000 || + len > ((av7110->bin_fw + av7110->size_fw) - ptr)) { + printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len); + return -EINVAL; + } + if( crc != crc32_le(0, ptr, len)) { + printk("dvb-ttpci: crc32 of root file does not match.\n"); + return -EINVAL; + } + av7110->bin_root = ptr; + av7110->size_root = len; + return 0; +} + +static void put_firmware(struct av7110* av7110) +{ + vfree(av7110->bin_fw); +} + +static int get_firmware(struct av7110* av7110) +{ + int ret; + const struct firmware *fw; + + /* request the av7110 firmware, this will block until someone uploads it */ + ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev); + if (ret) { + if (ret == -ENOENT) { + printk(KERN_ERR "dvb-ttpci: could not load firmware," + " file not found: dvb-ttpci-01.fw\n"); + printk(KERN_ERR "dvb-ttpci: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + printk(KERN_ERR "dvb-ttpci: and can be downloaded from" + " http://www.linuxtv.org/download/dvb/firmware/\n"); + } else + printk(KERN_ERR "dvb-ttpci: cannot request firmware" + " (error %i)\n", ret); + return -EINVAL; + } + + if (fw->size <= 200000) { + printk("dvb-ttpci: this firmware is way too small.\n"); + release_firmware(fw); + return -EINVAL; + } + + /* check if the firmware is available */ + av7110->bin_fw = vmalloc(fw->size); + if (NULL == av7110->bin_fw) { + dprintk(1, "out of memory\n"); + release_firmware(fw); + return -ENOMEM; + } + + memcpy(av7110->bin_fw, fw->data, fw->size); + av7110->size_fw = fw->size; + if ((ret = check_firmware(av7110))) + vfree(av7110->bin_fw); + + release_firmware(fw); + return ret; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (p->frequency + 479500) / 125; + + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; + else + pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (p->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + + + + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = p->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + + + +static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u32 f = p->frequency; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (f + 36125000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config philips_cd1516_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + + + +static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div, pwr; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (p->frequency + 36200000) / 166666; + + if (p->frequency <= 782000000) + pwr = 1; + else + pwr = 2; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + data[3] = pwr << 6; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ +#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE) + struct av7110* av7110 = fe->dvb->priv; + + return request_firmware(fw, name, &av7110->dev->pci->dev); +#else + return -EINVAL; +#endif +} + +static struct sp8870_config alps_tdlb7_config = { + + .demod_address = 0x71, + .request_firmware = alps_tdlb7_request_firmware, +}; + + +static u8 nexusca_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; + +static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) }; + struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; + int i; + + div = (p->frequency + 36150000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; + + if (p->frequency < 45000000) + return -EINVAL; + else if (p->frequency < 137000000) + data[3] = 0x01; + else if (p->frequency < 403000000) + data[3] = 0x02; + else if (p->frequency < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) { + printk("nexusca: pll transfer failed!\n"); + return -EIO; + } + + // wait for PLL lock + for(i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1) + if (data[0] & 0x40) break; + msleep(10); + } + + return 0; +} + +static struct stv0297_config nexusca_stv0297_config = { + + .demod_address = 0x1C, + .inittab = nexusca_stv0297_inittab, + .invert = 1, + .stop_during_read = 1, +}; + + + +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 cfg, cpump, band_select; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36125000 + p->frequency) / 166666; + + cfg = 0x88; + + if (p->frequency < 175000000) + cpump = 2; + else if (p->frequency < 390000000) + cpump = 1; + else if (p->frequency < 470000000) + cpump = 2; + else if (p->frequency < 750000000) + cpump = 1; + else + cpump = 3; + + if (p->frequency < 175000000) + band_select = 0x0e; + else if (p->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct l64781_config grundig_29504_401_config = { + .demod_address = 0x55, +}; + + + +static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +{ + int ret = 0; + int synced = (status & FE_HAS_LOCK) ? 1 : 0; + + av7110->fe_status = status; + + if (av7110->fe_synced == synced) + return 0; + + if (av7110->playing) { + av7110->fe_synced = synced; + return 0; + } + + if (mutex_lock_interruptible(&av7110->pid_mutex)) + return -ERESTARTSYS; + + if (synced) { + ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], 0, + av7110->pids[DMX_PES_PCR]); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } else { + ret = SetPIDs(av7110, 0, 0, 0, 0, 0); + if (!ret) { + ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); + if (!ret) + ret = av7110_wait_msgstate(av7110, GPMQBusy); + } + } + + if (!ret) + av7110->fe_synced = synced; + + mutex_unlock(&av7110->pid_mutex); + return ret; +} + +static int av7110_fe_set_frontend(struct dvb_frontend *fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_frontend(fe); + + return ret; +} + +static int av7110_fe_init(struct dvb_frontend* fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_init(fe); + return ret; +} + +static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct av7110* av7110 = fe->dvb->priv; + + /* call the real implementation */ + int ret = av7110->fe_read_status(fe, status); + if (!ret) + if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) + ret = av7110_fe_lock_fix(av7110, *status); + return ret; +} + +static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_reset_overload(fe); + return ret; +} + +static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_master_cmd = *cmd; + ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + } + return ret; +} + +static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_minicmd = minicmd; + ret = av7110->fe_diseqc_send_burst(fe, minicmd); + } + return ret; +} + +static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_tone = tone; + ret = av7110->fe_set_tone(fe, tone); + } + return ret; +} + +static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_voltage = voltage; + ret = av7110->fe_set_voltage(fe, voltage); + } + return ret; +} + +static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + return ret; +} + +static void dvb_s_recover(struct av7110* av7110) +{ + av7110_fe_init(av7110->fe); + + av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); + if (av7110->saved_master_cmd.msg_len) { + msleep(20); + av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); + } + msleep(20); + av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); + msleep(20); + av7110_fe_set_tone(av7110->fe, av7110->saved_tone); + + av7110_fe_set_frontend(av7110->fe); +} + +static u8 read_pwm(struct av7110* av7110) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int frontend_init(struct av7110 *av7110) +{ + int ret; + + if (av7110->dev->pci->subsystem_vendor == 0x110a) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) + av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, + &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } + break; + } + + } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X + case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE + + // try the ALPS BSRV2 first of all + av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + // try the ALPS BSRU6 now + av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + // Try the grundig 29504-451 + av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + /* Try DVB-C cards */ + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: + /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ + av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, + read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } + break; + case 0x0003: + /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ + av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, + read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } + break; + } + break; + + case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X + // try ALPS TDLB7 first, then Grundig 29504-401 + av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; + break; + } + /* fall-thru */ + + case 0x0008: // Hauppauge/TT DVB-T + // Grundig 29504-401 + av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap); + if (av7110->fe) + av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + break; + + case 0x0002: // Hauppauge/TT DVB-C premium rev2.X + + av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } + break; + + case 0x0004: // Galaxis DVB-S rev1.3 + /* ALPS BSRV2 */ + av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + } + break; + + case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ + /* Grundig 29504-451 */ + av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + } + break; + + case 0x000A: // Hauppauge/TT Nexus-CA rev1.X + + av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; + + /* set TDA9819 into DVB mode */ + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + + /* tuner on this needs a slower i2c bus speed */ + av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + break; + } + break; + + case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ + /* ALPS BSBE1 */ + av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) { + printk("dvb-ttpci: LNBP21 not found!\n"); + if (av7110->fe->ops.release) + av7110->fe->ops.release(av7110->fe); + av7110->fe = NULL; + } else { + av7110->fe->ops.dishnetwork_send_legacy_command = NULL; + av7110->recover = dvb_s_recover; + } + } + break; + } + } + + if (!av7110->fe) { + /* FIXME: propagate the failure code from the lower layers */ + ret = -ENOMEM; + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + av7110->dev->pci->vendor, + av7110->dev->pci->device, + av7110->dev->pci->subsystem_vendor, + av7110->dev->pci->subsystem_device); + } else { + FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); + FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage); + FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); + + ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); + if (ret < 0) { + printk("av7110: Frontend registration failed!\n"); + dvb_frontend_detach(av7110->fe); + av7110->fe = NULL; + } + } + return ret; +} + +/* Budgetpatch note: + * Original hardware design by Roberto Deza: + * There is a DVB_Wiki at + * http://www.linuxtv.org/ + * + * New software triggering design by Emard that works on + * original Roberto Deza's hardware: + * + * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. + * GPIO3 is in budget-patch hardware connectd to port B VSYNC + * HS is an internal event of 7146, accessible with RPS + * and temporarily raised high every n lines + * (n in defined in the RPS_THRESH1 counter threshold) + * I think HS is raised high on the beginning of the n-th line + * and remains high until this n-th line that triggered + * it is completely received. When the receiption of n-th line + * ends, HS is lowered. + * + * To transmit data over DMA, 7146 needs changing state at + * port B VSYNC pin. Any changing of port B VSYNC will + * cause some DMA data transfer, with more or less packets loss. + * It depends on the phase and frequency of VSYNC and + * the way of 7146 is instructed to trigger on port B (defined + * in DD1_INIT register, 3rd nibble from the right valid + * numbers are 0-7, see datasheet) + * + * The correct triggering can minimize packet loss, + * dvbtraffic should give this stable bandwidths: + * 22k transponder = 33814 kbit/s + * 27.5k transponder = 38045 kbit/s + * by experiment it is found that the best results + * (stable bandwidths and almost no packet loss) + * are obtained using DD1_INIT triggering number 2 + * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) + * and a VSYNC phase that occurs in the middle of DMA transfer + * (about byte 188*512=96256 in the DMA window). + * + * Phase of HS is still not clear to me how to control, + * It just happens to be so. It can be seen if one enables + * RPS_IRQ and print Event Counter 1 in vpeirq(). Every + * time RPS_INTERRUPT is called, the Event Counter 1 will + * increment. That's how the 7146 is programmed to do event + * counting in this budget-patch.c + * I *think* HPS setting has something to do with the phase + * of HS but I can't be 100% sure in that. + * + * hardware debug note: a working budget card (including budget patch) + * with vpeirq() interrupt setup in mode "0x90" (every 64K) will + * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes + * and that means 3*25=75 Hz of interrupt freqency, as seen by + * watch cat /proc/interrupts + * + * If this frequency is 3x lower (and data received in the DMA + * buffer don't start with 0x47, but in the middle of packets, + * whose lengths appear to be like 188 292 188 104 etc. + * this means VSYNC line is not connected in the hardware. + * (check soldering pcb and pins) + * The same behaviour of missing VSYNC can be duplicated on budget + * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. + */ +static int __devinit av7110_attach(struct saa7146_dev* dev, + struct saa7146_pci_extension_data *pci_ext) +{ + const int length = TS_WIDTH * TS_HEIGHT; + struct pci_dev *pdev = dev->pci; + struct av7110 *av7110; + struct task_struct *thread; + int ret, count = 0; + + dprintk(4, "dev: %p\n", dev); + + /* Set RPS_IRQ to 1 to track rps1 activity. + * Enabling this won't send any interrupt to PC CPU. + */ +#define RPS_IRQ 0 + + if (budgetpatch == 1) { + budgetpatch = 0; + /* autodetect the presence of budget patch + * this only works if saa7146 has been recently + * reset with with MASK_31 to MC1 + * + * will wait for VBI_B event (vertical blank at port B) + * and will reset GPIO3 after VBI_B is detected. + * (GPIO3 should be raised high by CPU to + * test if GPIO3 will generate vertical blank signal + * in budget patch GPIO3 is connected to VSYNC_B + */ + + /* RESET SAA7146 */ + saa7146_write(dev, MC1, MASK_31); + /* autodetection success seems to be time-dependend after reset */ + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* set vsync_b triggering */ + saa7146_write(dev, DD1_STREAM_B, 0); + /* port B VSYNC at rising edge */ + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + saa7146_write(dev, MC2, + 1 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 1 * (MASK_10 | MASK_26) | // b + 0 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 0 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); + + /* start writing RPS1 code from beginning */ + count = 0; + /* Disable RPS1 */ + saa7146_write(dev, MC1, MASK_29); + /* RPS1 timeout disable */ + saa7146_write(dev, RPS_TOV1, 0); + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + /* issue RPS1 interrupt to increment counter */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + WRITE_RPS1(CMD_STOP); + /* Jump to begin of RPS program as safety measure (p37) */ + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 threshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Enable RPS1, (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + mdelay(10); + /* now send VSYNC_B to rps1 by rising GPIO3 */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(10); + /* if rps1 responded by lowering the GPIO3, + * then we have budgetpatch hardware + */ + if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) { + budgetpatch = 1; + printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n"); + } + /* Disable RPS1 */ + saa7146_write(dev, MC1, ( MASK_29 )); +#if RPS_IRQ + printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + } + + /* prepare the av7110 device struct */ + av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL); + if (!av7110) { + dprintk(1, "out of memory\n"); + return -ENOMEM; + } + + av7110->card_name = (char*) pci_ext->ext_priv; + av7110->dev = dev; + dev->ext_priv = av7110; + + ret = get_firmware(av7110); + if (ret < 0) + goto err_kfree_0; + + ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, + THIS_MODULE, &dev->pci->dev, adapter_nr); + if (ret < 0) + goto err_put_firmware_1; + + /* the Siemens DVB needs this if you want to have the i2c chips + get recognized before the main driver is fully loaded */ + saa7146_write(dev, GPIO_CTRL, 0x500000); + + strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name)); + + saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ + + ret = i2c_add_adapter(&av7110->i2c_adap); + if (ret < 0) + goto err_dvb_unregister_adapter_2; + + ttpci_eeprom_parse_mac(&av7110->i2c_adap, + av7110->dvb_adapter.proposed_mac); + ret = -ENOMEM; + + /* full-ts mod? */ + if (full_ts) + av7110->full_ts = true; + + /* check for full-ts flag in eeprom */ + if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { + u8 flags = i2c_readreg(av7110, 0xaa, 2); + if (flags != 0xff && (flags & 0x01)) + av7110->full_ts = true; + } + + if (av7110->full_ts) { + printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, MC2, MASK_08 | MASK_24); + + /* dma3 */ + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + saa7146_write(dev, MC2, MASK_04 | MASK_20); + + tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + + } else if (budgetpatch) { + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, PCI_BT_V1, 0x1c1f101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 threshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */ + count = 0; + + /* Wait Source Line Counter Threshold (p36) */ + WRITE_RPS1(CMD_PAUSE | EVT_HS); + /* Set GPIO3=1 (p42) */ + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + /* Wait reset Source Line Counter Threshold (p36) */ + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); + /* Set GPIO3=0 (p42) */ + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + /* Jump to begin of RPS program (p37) */ + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Set Source Line Counter Threshold, using BRS (rCC p43) + * It generates HS event every TS_HEIGHT lines + * this is related to TS_WIDTH set in register + * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits + * are set to TS_WIDTH bytes (TS_WIDTH=2*188), + * then RPS_THRESH1 should be set to trigger + * every TS_HEIGHT (512) lines. + */ + saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); + + /* Enable RPS1 (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + /* end of budgetpatch register initialization */ + tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + } else { + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); + } + + tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110); + tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110); + + mutex_init(&av7110->pid_mutex); + + /* locks for data transfers from/to AV7110 */ + spin_lock_init(&av7110->debilock); + mutex_init(&av7110->dcomlock); + av7110->debitype = -1; + + /* default OSD window */ + av7110->osdwin = 1; + mutex_init(&av7110->osd_mutex); + + /* TV standard */ + av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC + : AV7110_VIDEO_MODE_PAL; + + /* ARM "watchdog" */ + init_waitqueue_head(&av7110->arm_wait); + av7110->arm_thread = NULL; + + /* allocate and init buffers */ + av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus); + if (!av7110->debi_virt) + goto err_saa71466_vfree_4; + + + av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS); + if (!av7110->iobuf) + goto err_pci_free_5; + + ret = av7110_av_init(av7110); + if (ret < 0) + goto err_iobuf_vfree_6; + + /* init BMP buffer */ + av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN; + init_waitqueue_head(&av7110->bmpq); + + ret = av7110_ca_init(av7110); + if (ret < 0) + goto err_av7110_av_exit_7; + + /* load firmware into AV7110 cards */ + ret = av7110_bootarm(av7110); + if (ret < 0) + goto err_av7110_ca_exit_8; + + ret = av7110_firmversion(av7110); + if (ret < 0) + goto err_stop_arm_9; + + if (FW_VERSION(av7110->arm_app)<0x2501) + printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. " + "System might be unstable!\n", FW_VERSION(av7110->arm_app)); + + thread = kthread_run(arm_thread, (void *) av7110, "arm_mon"); + if (IS_ERR(thread)) { + ret = PTR_ERR(thread); + goto err_stop_arm_9; + } + av7110->arm_thread = thread; + + /* set initial volume in mixer struct */ + av7110->mixer.volume_left = volume; + av7110->mixer.volume_right = volume; + + ret = av7110_register(av7110); + if (ret < 0) + goto err_arm_thread_stop_10; + + init_av7110_av(av7110); + + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + ret = av7110_init_v4l(av7110); + if (ret < 0) + goto err_av7110_unregister_11; + + av7110->dvb_adapter.priv = av7110; + ret = frontend_init(av7110); + if (ret < 0) + goto err_av7110_exit_v4l_12; + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_ir_init(av7110); +#endif + printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); + av7110_num++; +out: + return ret; + +err_av7110_exit_v4l_12: + av7110_exit_v4l(av7110); +err_av7110_unregister_11: + dvb_unregister(av7110); +err_arm_thread_stop_10: + av7110_arm_sync(av7110); +err_stop_arm_9: + /* Nothing to do. Rejoice. */ +err_av7110_ca_exit_8: + av7110_ca_exit(av7110); +err_av7110_av_exit_7: + av7110_av_exit(av7110); +err_iobuf_vfree_6: + vfree(av7110->iobuf); +err_pci_free_5: + pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); +err_saa71466_vfree_4: + if (av7110->grabbing) + saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); +err_i2c_del_3: + i2c_del_adapter(&av7110->i2c_adap); +err_dvb_unregister_adapter_2: + dvb_unregister_adapter(&av7110->dvb_adapter); +err_put_firmware_1: + put_firmware(av7110); +err_kfree_0: + kfree(av7110); + goto out; +} + +static int __devexit av7110_detach(struct saa7146_dev* saa) +{ + struct av7110 *av7110 = saa->ext_priv; + dprintk(4, "%p\n", av7110); + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_ir_exit(av7110); +#endif + if (budgetpatch || av7110->full_ts) { + if (budgetpatch) { + /* Disable RPS1 */ + saa7146_write(saa, MC1, MASK_29); + /* VSYNC LOW (inactive) */ + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } + saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(saa, MASK_10); + SAA7146_ISR_CLEAR(saa, MASK_10); + msleep(50); + tasklet_kill(&av7110->vpe_tasklet); + saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt); + } + av7110_exit_v4l(av7110); + + av7110_arm_sync(av7110); + + tasklet_kill(&av7110->debi_tasklet); + tasklet_kill(&av7110->gpio_tasklet); + + dvb_unregister(av7110); + + SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03); + SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03); + + av7110_ca_exit(av7110); + av7110_av_exit(av7110); + + vfree(av7110->iobuf); + pci_free_consistent(saa->pci, 8192, av7110->debi_virt, + av7110->debi_bus); + + i2c_del_adapter(&av7110->i2c_adap); + + dvb_unregister_adapter (&av7110->dvb_adapter); + + av7110_num--; + + put_firmware(av7110); + + kfree(av7110); + + saa->ext_priv = NULL; + + return 0; +} + + +static void av7110_irq(struct saa7146_dev* dev, u32 *isr) +{ + struct av7110 *av7110 = dev->ext_priv; + + //print_time("av7110_irq"); + + /* Note: Don't try to handle the DEBI error irq (MASK_18), in + * intel mode the timeout is asserted all the time... + */ + + if (*isr & MASK_19) { + //printk("av7110_irq: DEBI\n"); + /* Note 1: The DEBI irq is level triggered: We must enable it + * only after we started a DMA xfer, and disable it here + * immediately, or it will be signalled all the time while + * DEBI is idle. + * Note 2: You would think that an irq which is masked is + * not signalled by the hardware. Not so for the SAA7146: + * An irq is signalled as long as the corresponding bit + * in the ISR is set, and disabling irqs just prevents the + * hardware from setting the ISR bit. This means a) that we + * must clear the ISR *after* disabling the irq (which is why + * we must do it here even though saa7146_core did it already), + * and b) that if we were to disable an edge triggered irq + * (like the gpio irqs sadly are) temporarily we would likely + * loose some. This sucks :-( + */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); + tasklet_schedule(&av7110->debi_tasklet); + } + + if (*isr & MASK_03) { + //printk("av7110_irq: GPIO\n"); + tasklet_schedule(&av7110->gpio_tasklet); + } + + if (*isr & MASK_10) + tasklet_schedule(&av7110->vpe_tasklet); +} + + +static struct saa7146_extension av7110_extension_driver; + +#define MAKE_AV7110_INFO(x_var,x_name) \ +static struct saa7146_pci_extension_data x_var = { \ + .ext_priv = x_name, \ + .ext = &av7110_extension_driver } + +MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); +MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); +MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); +MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); +MAKE_AV7110_INFO(tts_2_3, "Technotrend/Hauppauge WinTV Nexus-S rev2.3"); +MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); +MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T"); +MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); +MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), + MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), + MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), + MAKE_EXTENSION_PCI(gxs_1_3, 0x13c2, 0x0004), + MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), + MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), + +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? + + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + + +static struct saa7146_extension av7110_extension_driver = { + .name = "av7110", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = &pci_tbl[0], + .attach = av7110_attach, + .detach = __devexit_p(av7110_detach), + + .irq_mask = MASK_19 | MASK_03 | MASK_10, + .irq_func = av7110_irq, +}; + + +static int __init av7110_init(void) +{ + int retval; + retval = saa7146_register_extension(&av7110_extension_driver); + return retval; +} + + +static void __exit av7110_exit(void) +{ + saa7146_unregister_extension(&av7110_extension_driver); +} + +module_init(av7110_init); +module_exit(av7110_exit); + +MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by " + "Siemens, Technotrend, Hauppauge"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h new file mode 100644 index 00000000000..88b3b2d6cc0 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110.h @@ -0,0 +1,314 @@ +#ifndef _AV7110_H_ +#define _AV7110_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "dvbdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "dvb_ringbuffer.h" +#include "dvb_frontend.h" +#include "ves1820.h" +#include "ves1x93.h" +#include "stv0299.h" +#include "tda8083.h" +#include "sp8870.h" +#include "stv0297.h" +#include "l64781.h" + +#include + + +#define ANALOG_TUNER_VES1820 1 +#define ANALOG_TUNER_STV0297 2 + +extern int av7110_debug; + +#define dprintk(level,args...) \ + do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0) + +#define MAXFILT 32 + +enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; + +enum av7110_video_mode { + AV7110_VIDEO_MODE_PAL = 0, + AV7110_VIDEO_MODE_NTSC = 1 +}; + +struct av7110_p2t { + u8 pes[TS_SIZE]; + u8 counter; + long int pos; + int frags; + struct dvb_demux_feed *feed; +}; + +/* video MPEG decoder events: */ +/* (code copied from dvb_frontend.c, should maybe be factored out...) */ +#define MAX_VIDEO_EVENT 8 +struct dvb_video_events { + struct video_event events[MAX_VIDEO_EVENT]; + int eventw; + int eventr; + int overflow; + wait_queue_head_t wait_queue; + spinlock_t lock; +}; + + +struct av7110; + +/* infrared remote control */ +struct infrared { + u16 key_map[256]; + struct input_dev *input_dev; + char input_phys[32]; + struct timer_list keyup_timer; + struct tasklet_struct ir_tasklet; + void (*ir_handler)(struct av7110 *av7110, u32 ircom); + u32 ir_command; + u32 ir_config; + u32 device_mask; + u8 protocol; + u8 inversion; + u16 last_key; + u16 last_toggle; + u8 delay_timer_finished; +}; + + +/* place to store all the necessary device information */ +struct av7110 { + + /* devices */ + + struct dvb_device dvb_dev; + struct dvb_net dvb_net; + + struct video_device *v4l_dev; + struct video_device *vbi_dev; + + struct saa7146_dev *dev; + + struct i2c_adapter i2c_adap; + + char *card_name; + + /* support for analog module of dvb-c */ + int analog_tuner_flags; + int current_input; + u32 current_freq; + + struct tasklet_struct debi_tasklet; + struct tasklet_struct gpio_tasklet; + + int adac_type; /* audio DAC type */ +#define DVB_ADAC_TI 0 +#define DVB_ADAC_CRYSTAL 1 +#define DVB_ADAC_MSP34x0 2 +#define DVB_ADAC_MSP34x5 3 +#define DVB_ADAC_NONE -1 + + + /* buffers */ + + void *iobuf; /* memory for all buffers */ + struct dvb_ringbuffer avout; /* buffer for video or A/V mux */ +#define AVOUTLEN (128*1024) + struct dvb_ringbuffer aout; /* buffer for audio */ +#define AOUTLEN (64*1024) + void *bmpbuf; +#define BMPLEN (8*32768+1024) + + /* bitmap buffers and states */ + + int bmpp; + int bmplen; + volatile int bmp_state; +#define BMP_NONE 0 +#define BMP_LOADING 1 +#define BMP_LOADED 2 + wait_queue_head_t bmpq; + + + /* DEBI and polled command interface */ + + spinlock_t debilock; + struct mutex dcomlock; + volatile int debitype; + volatile int debilen; + + + /* Recording and playback flags */ + + int rec_mode; + int playing; +#define RP_NONE 0 +#define RP_VIDEO 1 +#define RP_AUDIO 2 +#define RP_AV 3 + + + /* OSD */ + + int osdwin; /* currently active window */ + u16 osdbpp[8]; + struct mutex osd_mutex; + + /* CA */ + + ca_slot_info_t ci_slot[2]; + + enum av7110_video_mode vidmode; + struct dmxdev dmxdev; + struct dvb_demux demux; + + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + + /* for budget mode demux1 */ + struct dmxdev dmxdev1; + struct dvb_demux demux1; + struct dvb_net dvb_net1; + spinlock_t feedlock1; + int feeding1; + u32 ttbp; + unsigned char *grabbing; + struct saa7146_pgtable pt; + struct tasklet_struct vpe_tasklet; + bool full_ts; + + int fe_synced; + struct mutex pid_mutex; + + int video_blank; + struct video_status videostate; + u16 display_panscan; + int display_ar; + int trickmode; +#define TRICK_NONE 0 +#define TRICK_FAST 1 +#define TRICK_SLOW 2 +#define TRICK_FREEZE 3 + struct audio_status audiostate; + + struct dvb_demux_filter *handle2filter[32]; + struct av7110_p2t p2t_filter[MAXFILT]; + struct dvb_filter_pes2ts p2t[2]; + struct ipack ipack[2]; + u8 *kbuf[2]; + + int sinfo; + int feeding; + + int arm_errors; + int registered; + + + /* AV711X */ + + u32 arm_fw; + u32 arm_rtsl; + u32 arm_vid; + u32 arm_app; + u32 avtype; + int arm_ready; + struct task_struct *arm_thread; + wait_queue_head_t arm_wait; + u16 arm_loops; + + void *debi_virt; + dma_addr_t debi_bus; + + u16 pids[DMX_PES_OTHER]; + + struct dvb_ringbuffer ci_rbuffer; + struct dvb_ringbuffer ci_wbuffer; + + struct audio_mixer mixer; + + struct dvb_adapter dvb_adapter; + struct dvb_device *video_dev; + struct dvb_device *audio_dev; + struct dvb_device *ca_dev; + struct dvb_device *osd_dev; + + struct dvb_video_events video_events; + video_size_t video_size; + + u16 wssMode; + u16 wssData; + + struct infrared ir; + + /* firmware stuff */ + unsigned char *bin_fw; + unsigned long size_fw; + + unsigned char *bin_dpram; + unsigned long size_dpram; + + unsigned char *bin_root; + unsigned long size_root; + + struct dvb_frontend* fe; + fe_status_t fe_status; + + /* crash recovery */ + void (*recover)(struct av7110* av7110); + fe_sec_voltage_t saved_voltage; + fe_sec_tone_mode_t saved_tone; + struct dvb_diseqc_master_cmd saved_master_cmd; + fe_sec_mini_cmd_t saved_minicmd; + + int (*fe_init)(struct dvb_frontend* fe); + int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); + int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); + int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); + int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); + int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); + int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); + int (*fe_set_frontend)(struct dvb_frontend *fe); +}; + + +extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid); + +extern int av7110_check_ir_config(struct av7110 *av7110, int force); +extern int av7110_ir_init(struct av7110 *av7110); +extern void av7110_ir_exit(struct av7110 *av7110); + +/* msp3400 i2c subaddresses */ +#define MSP_WR_DEM 0x10 +#define MSP_RD_DEM 0x11 +#define MSP_WR_DSP 0x12 +#define MSP_RD_DSP 0x13 + +extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val); +extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg); +extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val); + + +extern int av7110_init_analog_module(struct av7110 *av7110); +extern int av7110_init_v4l(struct av7110 *av7110); +extern int av7110_exit_v4l(struct av7110 *av7110); + +#endif /* _AV7110_H_ */ diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c new file mode 100644 index 00000000000..952b33dbac4 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_av.c @@ -0,0 +1,1626 @@ +/* + * av7110_av.c: audio and video MPEG decoder stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" +#include "av7110_ipack.h" + +/* MPEG-2 (ISO 13818 / H.222.0) stream types */ +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define PTS_DTS_FLAGS 0xC0 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +static void p_to_t(u8 const *buf, long int length, u16 pid, + u8 *counter, struct dvb_demux_feed *feed); +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); + + +int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv; + + if (!(dvbdmxfeed->ts_type & TS_PACKET)) + return 0; + if (buf[3] == 0xe0) // video PES do not have a length in TS + buf[4] = buf[5] = 0; + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfeed->cb.ts(buf, len, NULL, 0, + &dvbdmxfeed->feed.ts, DMX_OK); + else + return dvb_filter_pes2ts(p2t, buf, len, 1); +} + +static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; + + dvbdmxfeed->cb.ts(data, 188, NULL, 0, + &dvbdmxfeed->feed.ts, DMX_OK); + return 0; +} + +int av7110_av_start_record(struct av7110 *av7110, int av, + struct dvb_demux_feed *dvbdmxfeed) +{ + int ret = 0; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); + + if (av7110->playing || (av7110->rec_mode & av)) + return -EBUSY; + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + dvbdmx->recording = 1; + av7110->rec_mode |= av; + + switch (av7110->rec_mode) { + case RP_AUDIO: + dvb_filter_pes2ts_init(&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[0]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + break; + + case RP_VIDEO: + dvb_filter_pes2ts_init(&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[1]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + break; + + case RP_AV: + dvb_filter_pes2ts_init(&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[0]); + dvb_filter_pes2ts_init(&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[1]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); + break; + } + return ret; +} + +int av7110_av_start_play(struct av7110 *av7110, int av) +{ + int ret = 0; + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->rec_mode) + return -EBUSY; + if (av7110->playing & av) + return -EBUSY; + + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + + if (av7110->playing == RP_NONE) { + av7110_ipack_reset(&av7110->ipack[0]); + av7110_ipack_reset(&av7110->ipack[1]); + } + + av7110->playing |= av; + switch (av7110->playing) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + av7110->sinfo = 0; + break; + case RP_AV: + av7110->sinfo = 0; + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + break; + } + return ret; +} + +int av7110_av_stop(struct av7110 *av7110, int av) +{ + int ret = 0; + dprintk(2, "av7110:%p, \n", av7110); + + if (!(av7110->playing & av) && !(av7110->rec_mode & av)) + return 0; + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (av7110->playing) { + av7110->playing &= ~av; + switch (av7110->playing) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + break; + case RP_NONE: + ret = av7110_set_vidmode(av7110, av7110->vidmode); + break; + } + } else { + av7110->rec_mode &= ~av; + switch (av7110->rec_mode) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + break; + case RP_NONE: + break; + } + } + return ret; +} + + +int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) +{ + int len; + u32 sync; + u16 blen; + + if (!dlen) { + wake_up(&buf->queue); + return -1; + } + while (1) { + len = dvb_ringbuffer_avail(buf); + if (len < 6) { + wake_up(&buf->queue); + return -1; + } + sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; + sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; + sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; + sync |= DVB_RINGBUFFER_PEEK(buf, 3); + + if (((sync &~ 0x0f) == 0x000001e0) || + ((sync &~ 0x1f) == 0x000001c0) || + (sync == 0x000001bd)) + break; + printk("resync\n"); + DVB_RINGBUFFER_SKIP(buf, 1); + } + blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; + blen |= DVB_RINGBUFFER_PEEK(buf, 5); + blen += 6; + if (len < blen || blen > dlen) { + //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); + wake_up(&buf->queue); + return -1; + } + + dvb_ringbuffer_read(buf, dest, (size_t) blen); + + dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", + (unsigned long) buf->pread, (unsigned long) buf->pwrite); + wake_up(&buf->queue); + return blen; +} + + +int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) +{ + int err, vol, val, balance = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + av7110->mixer.volume_left = volleft; + av7110->mixer.volume_right = volright; + + switch (av7110->adac_type) { + case DVB_ADAC_TI: + volleft = (volleft * 256) / 1036; + volright = (volright * 256) / 1036; + if (volleft > 0x3f) + volleft = 0x3f; + if (volright > 0x3f) + volright = 0x3f; + if ((err = SendDAC(av7110, 3, 0x80 + volleft))) + return err; + return SendDAC(av7110, 4, volright); + + case DVB_ADAC_CRYSTAL: + volleft = 127 - volleft / 2; + volright = 127 - volright / 2; + i2c_writereg(av7110, 0x20, 0x03, volleft); + i2c_writereg(av7110, 0x20, 0x04, volright); + return 0; + + case DVB_ADAC_MSP34x0: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ + return 0; + + case DVB_ADAC_MSP34x5: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + return 0; + } + + return 0; +} + +int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) +{ + int ret; + dprintk(2, "av7110:%p, \n", av7110); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); + + if (!ret && !av7110->playing) { + ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], + 0, av7110->pids[DMX_PES_PCR]); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } + return ret; +} + + +static enum av7110_video_mode sw2mode[16] = { + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, +}; + +static int get_video_format(struct av7110 *av7110, u8 *buf, int count) +{ + int i; + int hsize, vsize; + int sw; + u8 *p; + int ret = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->sinfo) + return 0; + for (i = 7; i < count - 10; i++) { + p = buf + i; + if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) + continue; + p += 4; + hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); + vsize = ((p[1] &0x0F) << 8) | (p[2]); + sw = (p[3] & 0x0F); + ret = av7110_set_vidmode(av7110, sw2mode[sw]); + if (!ret) { + dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); + av7110->sinfo = 1; + } + break; + } + return ret; +} + + +/**************************************************************************** + * I/O buffer management and control + ****************************************************************************/ + +static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, + const u8 *buf, unsigned long count) +{ + unsigned long todo = count; + int free; + + while (todo > 0) { + if (dvb_ringbuffer_free(rbuf) < 2048) { + if (wait_event_interruptible(rbuf->queue, + (dvb_ringbuffer_free(rbuf) >= 2048))) + return count - todo; + } + free = dvb_ringbuffer_free(rbuf); + if (free > todo) + free = todo; + dvb_ringbuffer_write(rbuf, buf, free); + todo -= free; + buf += free; + } + + return count - todo; +} + +static void play_video_cb(u8 *buf, int count, void *priv) +{ + struct av7110 *av7110 = (struct av7110 *) priv; + dprintk(2, "av7110:%p, \n", av7110); + + if ((buf[3] & 0xe0) == 0xe0) { + get_video_format(av7110, buf, count); + aux_ring_buffer_write(&av7110->avout, buf, count); + } else + aux_ring_buffer_write(&av7110->aout, buf, count); +} + +static void play_audio_cb(u8 *buf, int count, void *priv) +{ + struct av7110 *av7110 = (struct av7110 *) priv; + dprintk(2, "av7110:%p, \n", av7110); + + aux_ring_buffer_write(&av7110->aout, buf, count); +} + + +#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) + +static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + struct dvb_ringbuffer *rb; + u8 *kb; + unsigned long todo = count; + + dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); + + rb = (type) ? &av7110->avout : &av7110->aout; + kb = av7110->kbuf[type]; + + if (!kb) + return -ENOBUFS; + + if (nonblock && !FREE_COND_TS) + return -EWOULDBLOCK; + + while (todo >= TS_SIZE) { + if (!FREE_COND_TS) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(rb->queue, FREE_COND_TS)) + return count - todo; + } + if (copy_from_user(kb, buf, TS_SIZE)) + return -EFAULT; + write_ts_to_decoder(av7110, type, kb, TS_SIZE); + todo -= TS_SIZE; + buf += TS_SIZE; + } + + return count - todo; +} + + +#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ + dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) + +static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) + return -EWOULDBLOCK; + + while (todo > 0) { + if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->aout.queue, + (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024))) + return count-todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed) +{ + memset(p->pes, 0, TS_SIZE); + p->counter = 0; + p->pos = 0; + p->frags = 0; + if (feed) + p->feed = feed; +} + +static void clear_p2t(struct av7110_p2t *p) +{ + memset(p->pes, 0, TS_SIZE); +// p->counter = 0; + p->pos = 0; + p->frags = 0; +} + + +static int find_pes_header(u8 const *buf, long int length, int *frags) +{ + int c = 0; + int found = 0; + + *frags = 0; + + while (c < length - 3 && !found) { + if (buf[c] == 0x00 && buf[c + 1] == 0x00 && + buf[c + 2] == 0x01) { + switch ( buf[c + 3] ) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + + default: + c++; + break; + } + } else + c++; + } + if (c == length - 3 && !found) { + if (buf[length - 1] == 0x00) + *frags = 1; + if (buf[length - 2] == 0x00 && + buf[length - 1] == 0x00) + *frags = 2; + if (buf[length - 3] == 0x00 && + buf[length - 2] == 0x00 && + buf[length - 1] == 0x01) + *frags = 3; + return -1; + } + + return c; +} + +void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p) +{ + int c, c2, l, add; + int check, rest; + + c = 0; + c2 = 0; + if (p->frags){ + check = 0; + switch(p->frags) { + case 1: + if (buf[c] == 0x00 && buf[c + 1] == 0x01) { + check = 1; + c += 2; + } + break; + case 2: + if (buf[c] == 0x01) { + check = 1; + c++; + } + break; + case 3: + check = 1; + } + if (check) { + switch (buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + p->pes[0] = 0x00; + p->pes[1] = 0x00; + p->pes[2] = 0x01; + p->pes[3] = buf[c]; + p->pos = 4; + memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos); + c += (TS_SIZE - 4) - p->pos; + p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed); + clear_p2t(p); + break; + + default: + c = 0; + break; + } + } + p->frags = 0; + } + + if (p->pos) { + c2 = find_pes_header(buf + c, length - c, &p->frags); + if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos) + l = c2+c; + else + l = (TS_SIZE - 4) - p->pos; + memcpy(p->pes + p->pos, buf, l); + c += l; + p->pos += l; + p_to_t(p->pes, p->pos, pid, &p->counter, p->feed); + clear_p2t(p); + } + + add = 0; + while (c < length) { + c2 = find_pes_header(buf + c + add, length - c - add, &p->frags); + if (c2 >= 0) { + c2 += c + add; + if (c2 > c){ + p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed); + c = c2; + clear_p2t(p); + add = 0; + } else + add = 1; + } else { + l = length - c; + rest = l % (TS_SIZE - 4); + l -= rest; + p_to_t(buf + c, l, pid, &p->counter, p->feed); + memcpy(p->pes, buf + c + l, rest); + p->pos = rest; + c = length; + } + } +} + + +static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) +{ + int i; + int c = 0; + int fill; + u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 }; + + fill = (TS_SIZE - 4) - length; + if (pes_start) + tshead[1] = 0x40; + if (fill) + tshead[3] = 0x30; + tshead[1] |= (u8)((pid & 0x1F00) >> 8); + tshead[2] |= (u8)(pid & 0x00FF); + tshead[3] |= ((*counter)++ & 0x0F); + memcpy(buf, tshead, 4); + c += 4; + + if (fill) { + buf[4] = fill - 1; + c++; + if (fill > 1) { + buf[5] = 0x00; + c++; + } + for (i = 6; i < fill + 4; i++) { + buf[i] = 0xFF; + c++; + } + } + + return c; +} + + +static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, + struct dvb_demux_feed *feed) +{ + int l, pes_start; + u8 obuf[TS_SIZE]; + long c = 0; + + pes_start = 0; + if (length > 3 && + buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) + switch (buf[3]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + pes_start = 1; + break; + + default: + break; + } + + while (c < length) { + memset(obuf, 0, TS_SIZE); + if (length - c >= (TS_SIZE - 4)){ + l = write_ts_header2(pid, counter, pes_start, + obuf, (TS_SIZE - 4)); + memcpy(obuf + l, buf + c, TS_SIZE - l); + c += TS_SIZE - l; + } else { + l = write_ts_header2(pid, counter, pes_start, + obuf, length - c); + memcpy(obuf + l, buf + c, TS_SIZE - l); + c = length; + } + feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK); + pes_start = 0; + } +} + + +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) +{ + struct ipack *ipack = &av7110->ipack[type]; + + if (buf[1] & TRANS_ERROR) { + av7110_ipack_reset(ipack); + return -1; + } + + if (!(buf[3] & PAYLOAD)) + return -1; + + if (buf[1] & PAY_START) + av7110_ipack_flush(ipack); + + if (buf[3] & ADAPT_FIELD) { + len -= buf[4] + 1; + buf += buf[4] + 1; + if (!len) + return 0; + } + + av7110_ipack_instant_repack(buf + 4, len - 4, ipack); + return 0; +} + + +int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = (struct av7110 *) demux->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) + return 0; + + switch (feed->pes_type) { + case 0: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + return -EINVAL; + break; + case 1: + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) + return -EINVAL; + break; + default: + return -1; + } + + return write_ts_to_decoder(av7110, feed->pes_type, buf, len); +} + + + +/****************************************************************************** + * Video MPEG decoder events + ******************************************************************************/ +void dvb_video_add_event(struct av7110 *av7110, struct video_event *event) +{ + struct dvb_video_events *events = &av7110->video_events; + int wp; + + spin_lock_bh(&events->lock); + + wp = (events->eventw + 1) % MAX_VIDEO_EVENT; + if (wp == events->eventr) { + events->overflow = 1; + events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; + } + + //FIXME: timestamp? + memcpy(&events->events[events->eventw], event, sizeof(struct video_event)); + events->eventw = wp; + + spin_unlock_bh(&events->lock); + + wake_up_interruptible(&events->wait_queue); +} + + +static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags) +{ + struct dvb_video_events *events = &av7110->video_events; + + if (events->overflow) { + events->overflow = 0; + return -EOVERFLOW; + } + if (events->eventw == events->eventr) { + int ret; + + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + + ret = wait_event_interruptible(events->wait_queue, + events->eventw != events->eventr); + if (ret < 0) + return ret; + } + + spin_lock_bh(&events->lock); + + memcpy(event, &events->events[events->eventr], + sizeof(struct video_event)); + events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; + + spin_unlock_bh(&events->lock); + + return 0; +} + + +/****************************************************************************** + * DVB device file operations + ******************************************************************************/ + +static unsigned int dvb_video_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned int mask = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) + poll_wait(file, &av7110->avout.queue, wait); + + poll_wait(file, &av7110->video_events.wait_queue, wait); + + if (av7110->video_events.eventw != av7110->video_events.eventr) + mask = POLLPRI; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (av7110->playing) { + if (FREE_COND) + mask |= (POLLOUT | POLLWRNORM); + } else /* if not playing: may play if asked for */ + mask |= (POLLOUT | POLLWRNORM); + } + + return mask; +} + +static ssize_t dvb_video_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned char c; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EPERM; + + if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) + return -EPERM; + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + else + return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); +} + +static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned int mask = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + poll_wait(file, &av7110->aout.queue, wait); + + if (av7110->playing) { + if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) + mask |= (POLLOUT | POLLWRNORM); + } else /* if not playing: may play if asked for */ + mask = (POLLOUT | POLLWRNORM); + + return mask; +} + +static ssize_t dvb_audio_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned char c; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) { + printk(KERN_ERR "not audio source memory\n"); + return -EPERM; + } + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + else + return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); +} + +static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; + +#define MIN_IFRAME 400000 + +static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) +{ + unsigned i, n; + int progressive = 0; + int match = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if (!(av7110->playing & RP_VIDEO)) { + if (av7110_av_start_play(av7110, RP_VIDEO) < 0) + return -EBUSY; + } + + /* search in buf for instances of 00 00 01 b5 1? */ + for (i = 0; i < len; i++) { + unsigned char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (match == 5) { + progressive = c & 0x08; + match = 0; + } + if (c == 0x00) { + match = (match == 1 || match == 2) ? 2 : 1; + continue; + } + switch (match++) { + case 2: if (c == 0x01) + continue; + break; + case 3: if (c == 0xb5) + continue; + break; + case 4: if ((c & 0xf0) == 0x10) + continue; + break; + } + match = 0; + } + + /* setting n always > 1, fixes problems when playing stillframes + consisting of I- and P-Frames */ + n = MIN_IFRAME / len + 1; + + /* FIXME: nonblock? */ + dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); + + for (i = 0; i < n; i++) + dvb_play(av7110, buf, len, 0, 1); + + av7110_ipack_flush(&av7110->ipack[1]); + + if (progressive) + return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + else + return 0; +} + + +static int dvb_video_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && + cmd != VIDEO_GET_SIZE ) { + return -EPERM; + } + } + + switch (cmd) { + case VIDEO_STOP: + av7110->videostate.play_state = VIDEO_STOPPED; + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) + ret = av7110_av_stop(av7110, RP_VIDEO); + else + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, + av7110->videostate.video_blank ? 0 : 1); + if (!ret) + av7110->trickmode = TRICK_NONE; + break; + + case VIDEO_PLAY: + av7110->trickmode = TRICK_NONE; + if (av7110->videostate.play_state == VIDEO_FREEZED) { + av7110->videostate.play_state = VIDEO_PLAYING; + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (ret) + break; + } + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { + if (av7110->playing == RP_AV) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (ret) + break; + av7110->playing &= ~RP_VIDEO; + } + ret = av7110_av_start_play(av7110, RP_VIDEO); + } + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) + av7110->videostate.play_state = VIDEO_PLAYING; + break; + + case VIDEO_FREEZE: + av7110->videostate.play_state = VIDEO_FREEZED; + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); + else + ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + if (!ret) + av7110->trickmode = TRICK_FREEZE; + break; + + case VIDEO_CONTINUE: + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) { + av7110->videostate.play_state = VIDEO_PLAYING; + av7110->trickmode = TRICK_NONE; + } + break; + + case VIDEO_SELECT_SOURCE: + av7110->videostate.stream_source = (video_stream_source_t) arg; + break; + + case VIDEO_SET_BLANK: + av7110->videostate.video_blank = (int) arg; + break; + + case VIDEO_GET_STATUS: + memcpy(parg, &av7110->videostate, sizeof(struct video_status)); + break; + + case VIDEO_GET_EVENT: + ret = dvb_video_get_event(av7110, parg, file->f_flags); + break; + + case VIDEO_GET_SIZE: + memcpy(parg, &av7110->video_size, sizeof(video_size_t)); + break; + + case VIDEO_SET_DISPLAY_FORMAT: + { + video_displayformat_t format = (video_displayformat_t) arg; + switch (format) { + case VIDEO_PAN_SCAN: + av7110->display_panscan = VID_PAN_SCAN_PREF; + break; + case VIDEO_LETTER_BOX: + av7110->display_panscan = VID_VC_AND_PS_PREF; + break; + case VIDEO_CENTER_CUT_OUT: + av7110->display_panscan = VID_CENTRE_CUT_PREF; + break; + default: + ret = -EINVAL; + } + if (ret < 0) + break; + av7110->videostate.display_format = format; + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + break; + } + + case VIDEO_SET_FORMAT: + if (arg > 1) { + ret = -EINVAL; + break; + } + av7110->display_ar = arg; + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, + 1, (u16) arg); + break; + + case VIDEO_STILLPICTURE: + { + struct video_still_picture *pic = + (struct video_still_picture *) parg; + av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + ret = play_iframe(av7110, pic->iFrame, pic->size, + file->f_flags & O_NONBLOCK); + break; + } + + case VIDEO_FAST_FORWARD: + //note: arg is ignored by firmware + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Scan_I, 2, AV_PES, 0); + else + ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); + if (!ret) { + av7110->trickmode = TRICK_FAST; + av7110->videostate.play_state = VIDEO_PLAYING; + } + break; + + case VIDEO_SLOWMOTION: + if (av7110->playing&RP_VIDEO) { + if (av7110->trickmode != TRICK_SLOW) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } else { + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } + if (!ret) { + av7110->trickmode = TRICK_SLOW; + av7110->videostate.play_state = VIDEO_PLAYING; + } + break; + + case VIDEO_GET_CAPABILITIES: + *(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 | + VIDEO_CAP_SYS | VIDEO_CAP_PROG; + break; + + case VIDEO_CLEAR_BUFFER: + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + av7110_ipack_reset(&av7110->ipack[1]); + if (av7110->playing == RP_AV) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Play, 2, AV_PES, 0); + if (ret) + break; + if (av7110->trickmode == TRICK_FAST) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Scan_I, 2, AV_PES, 0); + if (av7110->trickmode == TRICK_SLOW) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } + if (av7110->trickmode == TRICK_FREEZE) + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); + } + break; + + case VIDEO_SET_STREAMTYPE: + break; + + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +static int dvb_audio_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); + + if (((file->f_flags & O_ACCMODE) == O_RDONLY) && + (cmd != AUDIO_GET_STATUS)) + return -EPERM; + + switch (cmd) { + case AUDIO_STOP: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + ret = av7110_av_stop(av7110, RP_AUDIO); + else + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_STOPPED; + break; + + case AUDIO_PLAY: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + ret = av7110_av_start_play(av7110, RP_AUDIO); + if (!ret) + ret = audcom(av7110, AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PLAYING; + break; + + case AUDIO_PAUSE: + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PAUSED; + break; + + case AUDIO_CONTINUE: + if (av7110->audiostate.play_state == AUDIO_PAUSED) { + av7110->audiostate.play_state = AUDIO_PLAYING; + ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); + } + break; + + case AUDIO_SELECT_SOURCE: + av7110->audiostate.stream_source = (audio_stream_source_t) arg; + break; + + case AUDIO_SET_MUTE: + { + ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.mute_state = (int) arg; + break; + } + + case AUDIO_SET_AV_SYNC: + av7110->audiostate.AV_sync_state = (int) arg; + ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); + break; + + case AUDIO_SET_BYPASS_MODE: + if (FW_VERSION(av7110->arm_app) < 0x2621) + ret = -EINVAL; + av7110->audiostate.bypass_mode = (int)arg; + break; + + case AUDIO_CHANNEL_SELECT: + av7110->audiostate.channel_select = (audio_channel_select_t) arg; + switch(av7110->audiostate.channel_select) { + case AUDIO_STEREO: + ret = audcom(av7110, AUDIO_CMD_STEREO); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x49); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); + } + break; + case AUDIO_MONO_LEFT: + ret = audcom(av7110, AUDIO_CMD_MONO_L); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x4a); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); + } + break; + case AUDIO_MONO_RIGHT: + ret = audcom(av7110, AUDIO_CMD_MONO_R); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x45); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); + } + break; + default: + ret = -EINVAL; + break; + } + break; + + case AUDIO_GET_STATUS: + memcpy(parg, &av7110->audiostate, sizeof(struct audio_status)); + break; + + case AUDIO_GET_CAPABILITIES: + if (FW_VERSION(av7110->arm_app) < 0x2621) + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + else + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | + AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + break; + + case AUDIO_CLEAR_BUFFER: + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + av7110_ipack_reset(&av7110->ipack[0]); + if (av7110->playing == RP_AV) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Play, 2, AV_PES, 0); + break; + + case AUDIO_SET_ID: + break; + + case AUDIO_SET_MIXER: + { + struct audio_mixer *amix = (struct audio_mixer *)parg; + ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); + break; + } + + case AUDIO_SET_STREAMTYPE: + break; + + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} + + +static int dvb_video_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((err = dvb_generic_open(inode, file)) < 0) + return err; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + av7110->video_blank = 1; + av7110->audiostate.AV_sync_state = 1; + av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; + + /* empty event queue */ + av7110->video_events.eventr = av7110->video_events.eventw = 0; + } + + return 0; +} + +static int dvb_video_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + av7110_av_stop(av7110, RP_VIDEO); + } + + return dvb_generic_release(inode, file); +} + +static int dvb_audio_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err = dvb_generic_open(inode, file); + + dprintk(2, "av7110:%p, \n", av7110); + + if (err < 0) + return err; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; + return 0; +} + +static int dvb_audio_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + av7110_av_stop(av7110, RP_AUDIO); + return dvb_generic_release(inode, file); +} + + + +/****************************************************************************** + * driver registration + ******************************************************************************/ + +static const struct file_operations dvb_video_fops = { + .owner = THIS_MODULE, + .write = dvb_video_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_video_open, + .release = dvb_video_release, + .poll = dvb_video_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_video = { + .priv = NULL, + .users = 6, + .readers = 5, /* arbitrary */ + .writers = 1, + .fops = &dvb_video_fops, + .kernel_ioctl = dvb_video_ioctl, +}; + +static const struct file_operations dvb_audio_fops = { + .owner = THIS_MODULE, + .write = dvb_audio_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_audio_open, + .release = dvb_audio_release, + .poll = dvb_audio_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_audio = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_audio_fops, + .kernel_ioctl = dvb_audio_ioctl, +}; + + +int av7110_av_register(struct av7110 *av7110) +{ + av7110->audiostate.AV_sync_state = 0; + av7110->audiostate.mute_state = 0; + av7110->audiostate.play_state = AUDIO_STOPPED; + av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; + av7110->audiostate.channel_select = AUDIO_STEREO; + av7110->audiostate.bypass_mode = 0; + + av7110->videostate.video_blank = 0; + av7110->videostate.play_state = VIDEO_STOPPED; + av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; + av7110->videostate.video_format = VIDEO_FORMAT_4_3; + av7110->videostate.display_format = VIDEO_LETTER_BOX; + av7110->display_ar = VIDEO_FORMAT_4_3; + av7110->display_panscan = VID_VC_AND_PS_PREF; + + init_waitqueue_head(&av7110->video_events.wait_queue); + spin_lock_init(&av7110->video_events.lock); + av7110->video_events.eventw = av7110->video_events.eventr = 0; + av7110->video_events.overflow = 0; + memset(&av7110->video_size, 0, sizeof (video_size_t)); + + dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, + &dvbdev_video, av7110, DVB_DEVICE_VIDEO); + + dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, + &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); + + return 0; +} + +void av7110_av_unregister(struct av7110 *av7110) +{ + dvb_unregister_device(av7110->audio_dev); + dvb_unregister_device(av7110->video_dev); +} + +int av7110_av_init(struct av7110 *av7110) +{ + void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; + int i, ret; + + for (i = 0; i < 2; i++) { + struct ipack *ipack = av7110->ipack + i; + + ret = av7110_ipack_init(ipack, IPACKS, play[i]); + if (ret < 0) { + if (i) + av7110_ipack_free(--ipack); + goto out; + } + ipack->data = av7110; + } + + dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN); + dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN); + + av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN); + av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS; +out: + return ret; +} + +void av7110_av_exit(struct av7110 *av7110) +{ + av7110_ipack_free(&av7110->ipack[0]); + av7110_ipack_free(&av7110->ipack[1]); +} diff --git a/drivers/media/pci/ttpci/av7110_av.h b/drivers/media/pci/ttpci/av7110_av.h new file mode 100644 index 00000000000..5f02ef85e47 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_av.h @@ -0,0 +1,30 @@ +#ifndef _AV7110_AV_H_ +#define _AV7110_AV_H_ + +struct av7110; + +extern int av7110_set_vidmode(struct av7110 *av7110, + enum av7110_video_mode mode); + +extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); +extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); +extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); + +extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); +extern int av7110_av_stop(struct av7110 *av7110, int av); +extern int av7110_av_start_record(struct av7110 *av7110, int av, + struct dvb_demux_feed *dvbdmxfeed); +extern int av7110_av_start_play(struct av7110 *av7110, int av); + +extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event); + +extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed); +extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p); + +extern int av7110_av_register(struct av7110 *av7110); +extern void av7110_av_unregister(struct av7110 *av7110); +extern int av7110_av_init(struct av7110 *av7110); +extern void av7110_av_exit(struct av7110 *av7110); + + +#endif /* _AV7110_AV_H_ */ diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c new file mode 100644 index 00000000000..9fc1dd0ba4c --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_ca.c @@ -0,0 +1,387 @@ +/* + * av7110_ca.c: CA and CI stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_ca.h" + + +void CI_handle(struct av7110 *av7110, u8 *data, u16 len) +{ + dprintk(8, "av7110:%p\n",av7110); + + if (len < 3) + return; + switch (data[0]) { + case CI_MSG_CI_INFO: + if (data[2] != 1 && data[2] != 2) + break; + switch (data[1]) { + case 0: + av7110->ci_slot[data[2] - 1].flags = 0; + break; + case 1: + av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT; + break; + case 2: + av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY; + break; + } + break; + case CI_SWITCH_PRG_REPLY: + //av7110->ci_stat=data[1]; + break; + default: + break; + } +} + + +void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len) +{ + if (dvb_ringbuffer_free(cibuf) < len + 2) + return; + + DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8); + DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); + dvb_ringbuffer_write(cibuf, data, len); + wake_up_interruptible(&cibuf->queue); +} + + +/****************************************************************************** + * CI link layer file ops + ******************************************************************************/ + +static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) +{ + struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p; + void *data; + + for (p = tab; *p; p++) { + data = vmalloc(size); + if (!data) { + while (p-- != tab) { + vfree(p[0]->data); + p[0]->data = NULL; + } + return -ENOMEM; + } + dvb_ringbuffer_init(*p, data, size); + } + return 0; +} + +static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +{ + dvb_ringbuffer_flush_spinlock_wakeup(cirbuf); + dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf); +} + +static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +{ + vfree(cirbuf->data); + cirbuf->data = NULL; + vfree(ciwbuf->data); + ciwbuf->data = NULL; +} + +static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, + int slots, ca_slot_info_t *slot) +{ + int i; + int len = 0; + u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 }; + + for (i = 0; i < 2; i++) { + if (slots & (1 << i)) + len += 8; + } + + if (dvb_ringbuffer_free(cibuf) < len) + return -EBUSY; + + for (i = 0; i < 2; i++) { + if (slots & (1 << i)) { + msg[2] = i; + dvb_ringbuffer_write(cibuf, msg, 8); + slot[i].flags = 0; + } + } + + return 0; +} + +static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + int free; + int non_blocking = file->f_flags & O_NONBLOCK; + u8 *page = (u8 *)__get_free_page(GFP_USER); + int res; + + if (!page) + return -ENOMEM; + + res = -EINVAL; + if (count > 2048) + goto out; + + res = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + free = dvb_ringbuffer_free(cibuf); + if (count + 2 > free) { + res = -EWOULDBLOCK; + if (non_blocking) + goto out; + res = -ERESTARTSYS; + if (wait_event_interruptible(cibuf->queue, + (dvb_ringbuffer_free(cibuf) >= count + 2))) + goto out; + } + + DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); + DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); + + res = dvb_ringbuffer_write(cibuf, page, count); +out: + free_page((unsigned long)page); + return res; +} + +static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + int avail; + int non_blocking = file->f_flags & O_NONBLOCK; + ssize_t len; + + if (!cibuf->data || !count) + return 0; + if (non_blocking && (dvb_ringbuffer_empty(cibuf))) + return -EWOULDBLOCK; + if (wait_event_interruptible(cibuf->queue, + !dvb_ringbuffer_empty(cibuf))) + return -ERESTARTSYS; + avail = dvb_ringbuffer_avail(cibuf); + if (avail < 4) + return 0; + len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= DVB_RINGBUFFER_PEEK(cibuf, 1); + if (avail < len + 2 || count < len) + return -EINVAL; + DVB_RINGBUFFER_SKIP(cibuf, 2); + + return dvb_ringbuffer_read_user(cibuf, buf, len); +} + +static int dvb_ca_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err = dvb_generic_open(inode, file); + + dprintk(8, "av7110:%p\n",av7110); + + if (err < 0) + return err; + ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer); + return 0; +} + +static unsigned int dvb_ca_poll (struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer; + struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer; + unsigned int mask = 0; + + dprintk(8, "av7110:%p\n",av7110); + + poll_wait(file, &rbuf->queue, wait); + poll_wait(file, &wbuf->queue, wait); + + if (!dvb_ringbuffer_empty(rbuf)) + mask |= (POLLIN | POLLRDNORM); + + if (dvb_ringbuffer_free(wbuf) > 1024) + mask |= (POLLOUT | POLLWRNORM); + + return mask; +} + +static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + + dprintk(8, "av7110:%p\n",av7110); + + switch (cmd) { + case CA_RESET: + return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]); + break; + case CA_GET_CAP: + { + ca_caps_t cap; + + cap.slot_num = 2; + cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? + CA_CI_LINK : CA_CI) | CA_DESCR; + cap.descr_num = 16; + cap.descr_type = CA_ECD; + memcpy(parg, &cap, sizeof(cap)); + break; + } + + case CA_GET_SLOT_INFO: + { + ca_slot_info_t *info=(ca_slot_info_t *)parg; + + if (info->num < 0 || info->num > 1) + return -EINVAL; + av7110->ci_slot[info->num].num = info->num; + av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? + CA_CI_LINK : CA_CI; + memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); + break; + } + + case CA_GET_MSG: + break; + + case CA_SEND_MSG: + break; + + case CA_GET_DESCR_INFO: + { + ca_descr_info_t info; + + info.num = 16; + info.type = CA_ECD; + memcpy(parg, &info, sizeof (info)); + break; + } + + case CA_SET_DESCR: + { + ca_descr_t *descr = (ca_descr_t*) parg; + + if (descr->index >= 16) + return -EINVAL; + if (descr->parity > 1) + return -EINVAL; + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5, + (descr->index<<8)|descr->parity, + (descr->cw[0]<<8)|descr->cw[1], + (descr->cw[2]<<8)|descr->cw[3], + (descr->cw[4]<<8)|descr->cw[5], + (descr->cw[6]<<8)|descr->cw[7]); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +static ssize_t dvb_ca_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(8, "av7110:%p\n",av7110); + return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); +} + +static ssize_t dvb_ca_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(8, "av7110:%p\n",av7110); + return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos); +} + +static const struct file_operations dvb_ca_fops = { + .owner = THIS_MODULE, + .read = dvb_ca_read, + .write = dvb_ca_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_ca_open, + .release = dvb_generic_release, + .poll = dvb_ca_poll, + .llseek = default_llseek, +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_ca_fops, + .kernel_ioctl = dvb_ca_ioctl, +}; + + +int av7110_ca_register(struct av7110 *av7110) +{ + return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, + &dvbdev_ca, av7110, DVB_DEVICE_CA); +} + +void av7110_ca_unregister(struct av7110 *av7110) +{ + dvb_unregister_device(av7110->ca_dev); +} + +int av7110_ca_init(struct av7110* av7110) +{ + return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192); +} + +void av7110_ca_exit(struct av7110* av7110) +{ + ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer); +} diff --git a/drivers/media/pci/ttpci/av7110_ca.h b/drivers/media/pci/ttpci/av7110_ca.h new file mode 100644 index 00000000000..70ee855ece1 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_ca.h @@ -0,0 +1,14 @@ +#ifndef _AV7110_CA_H_ +#define _AV7110_CA_H_ + +struct av7110; + +extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len); +extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len); + +extern int av7110_ca_register(struct av7110 *av7110); +extern void av7110_ca_unregister(struct av7110 *av7110); +extern int av7110_ca_init(struct av7110* av7110); +extern void av7110_ca_exit(struct av7110* av7110); + +#endif /* _AV7110_CA_H_ */ diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c new file mode 100644 index 00000000000..f1cbfe52698 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -0,0 +1,1208 @@ +/* + * av7110_hw.c: av7110 low level hardware access and firmware interface + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * the project's page is at http://www.linuxtv.org/ + */ + +/* for debugging ARM communication: */ +//#define COM_DEBUG + +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" + +#define _NOHANDSHAKE + +/**************************************************************************** + * DEBI functions + ****************************************************************************/ + +/* This DEBI code is based on the Stradis driver + by Nathan Laredo */ + +int av7110_debiwrite(struct av7110 *av7110, u32 config, + int addr, u32 val, int count) +{ + struct saa7146_dev *dev = av7110->dev; + + if (count <= 0 || count > 32764) { + printk("%s: invalid count %d\n", __func__, count); + return -1; + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done failed\n", __func__); + return -1; + } + saa7146_write(dev, DEBI_CONFIG, config); + if (count <= 4) /* immediate transfer */ + saa7146_write(dev, DEBI_AD, val); + else /* block transfer */ + saa7146_write(dev, DEBI_AD, av7110->debi_bus); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); + saa7146_write(dev, MC2, (2 << 16) | 2); + return 0; +} + +u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count) +{ + struct saa7146_dev *dev = av7110->dev; + u32 result = 0; + + if (count > 32764 || count <= 0) { + printk("%s: invalid count %d\n", __func__, count); + return 0; + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #1 failed\n", __func__); + return 0; + } + saa7146_write(dev, DEBI_AD, av7110->debi_bus); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); + + saa7146_write(dev, DEBI_CONFIG, config); + saa7146_write(dev, MC2, (2 << 16) | 2); + if (count > 4) + return count; + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #2 failed\n", __func__); + return 0; + } + + result = saa7146_read(dev, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + return result; +} + + + +/* av7110 ARM core boot stuff */ +#if 0 +void av7110_reset_arm(struct av7110 *av7110) +{ + saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); + + /* Disable DEBI and GPIO irq */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + + saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI); + msleep(30); /* the firmware needs some time to initialize */ + + ARM_ResetMailBox(av7110); + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + SAA7146_IER_ENABLE(av7110->dev, MASK_03); + + av7110->arm_ready = 1; + dprintk(1, "reset ARM\n"); +} +#endif /* 0 */ + +static int waitdebi(struct av7110 *av7110, int adr, int state) +{ + int k; + + dprintk(4, "%p\n", av7110); + + for (k = 0; k < 100; k++) { + if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state) + return 0; + udelay(5); + } + return -ETIMEDOUT; +} + +static int load_dram(struct av7110 *av7110, u32 *data, int len) +{ + int i; + int blocks, rest; + u32 base, bootblock = AV7110_BOOT_BLOCK; + + dprintk(4, "%p\n", av7110); + + blocks = len / AV7110_BOOT_MAX_SIZE; + rest = len % AV7110_BOOT_MAX_SIZE; + base = DRAM_START_CODE; + + for (i = 0; i < blocks; i++) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); + return -ETIMEDOUT; + } + dprintk(4, "writing DRAM block %d\n", i); + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); + bootblock ^= 0x1400; + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + base += AV7110_BOOT_MAX_SIZE; + } + + if (rest > 0) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); + return -ETIMEDOUT; + } + if (rest > 4) + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); + else + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); + + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + } + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); + return -ETIMEDOUT; + } + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); + return -ETIMEDOUT; + } + return 0; +} + + +/* we cannot write av7110 DRAM directly, so load a bootloader into + * the DPRAM which implements a simple boot protocol */ +int av7110_bootarm(struct av7110 *av7110) +{ + const struct firmware *fw; + const char *fw_name = "av7110/bootcode.bin"; + struct saa7146_dev *dev = av7110->dev; + u32 ret; + int i; + + dprintk(4, "%p\n", av7110); + + av7110->arm_ready = 0; + + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); + + /* Disable DEBI and GPIO irq */ + SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + + /* enable DEBI */ + saa7146_write(av7110->dev, MC1, 0x08800880); + saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); + saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* test DEBI */ + iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); + /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */ + iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); + + if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { + printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: " + "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", + ret, 0x10325476); + return -1; + } + for (i = 0; i < 8192; i += 4) + iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4); + dprintk(2, "debi test OK\n"); + + /* boot */ + dprintk(1, "load boot code\n"); + saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO); + //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT); + //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); + + ret = request_firmware(&fw, fw_name, &dev->pci->dev); + if (ret) { + printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n", + fw_name); + return ret; + } + + mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size); + release_firmware(fw); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "saa7146_wait_for_debi_done() timed out\n"); + return -ETIMEDOUT; + } + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); + mdelay(1); + + dprintk(1, "load dram code\n"); + if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "load_dram() failed\n"); + return -1; + } + + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); + mdelay(1); + + dprintk(1, "load dpram code\n"); + mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); + + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); + return -ETIMEDOUT; + } + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); + msleep(30); /* the firmware needs some time to initialize */ + + //ARM_ClearIrq(av7110); + ARM_ResetMailBox(av7110); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + SAA7146_IER_ENABLE(av7110->dev, MASK_03); + + av7110->arm_errors = 0; + av7110->arm_ready = 1; + return 0; +} +MODULE_FIRMWARE("av7110/bootcode.bin"); + +/**************************************************************************** + * DEBI command polling + ****************************************************************************/ + +int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) +{ + unsigned long start; + u32 stat; + int err; + + if (FW_VERSION(av7110->arm_app) <= 0x261c) { + /* not supported by old firmware */ + msleep(50); + return 0; + } + + /* new firmware */ + start = jiffies; + for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + mutex_unlock(&av7110->dcomlock); + if ((stat & flags) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", + __func__, stat & flags); + return -ETIMEDOUT; + } + msleep(1); + } + return 0; +} + +static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +{ + int i; + unsigned long start; + char *type = NULL; + u16 flags[2] = {0, 0}; + u32 stat; + int err; + +// dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -ENXIO; + } + + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__); + av7110->arm_errors++; + return -ETIMEDOUT; + } + msleep(1); + } + + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); + +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + + switch ((buf[0] >> 8) & 0xff) { + case COMTYPE_PIDFILTER: + case COMTYPE_ENCODER: + case COMTYPE_REC_PLAY: + case COMTYPE_MPEGDECODER: + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQFull; + break; + case COMTYPE_OSD: + type = "OSD"; + flags[0] = OSDQOver; + flags[1] = OSDQFull; + break; + case COMTYPE_MISC: + if (FW_VERSION(av7110->arm_app) >= 0x261d) { + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQBusy; + } + break; + default: + break; + } + + if (type != NULL) { + /* non-immediate COMMAND type */ + start = jiffies; + for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & flags[0]) { + printk(KERN_ERR "%s: %s QUEUE overflow\n", + __func__, type); + return -1; + } + if ((stat & flags[1]) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", + __func__, type); + av7110->arm_errors++; + return -ETIMEDOUT; + } + msleep(1); + } + } + + for (i = 2; i < length; i++) + wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2); + + if (length) + wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); + else + wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); + + wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); + + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); + +#ifdef COM_DEBUG + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", + __func__, (buf[0] >> 8) & 0xff); + return -ETIMEDOUT; + } + msleep(1); + } + + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & GPMQOver) { + printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__); + return -ENOSPC; + } + else if (stat & OSDQOver) { + printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__); + return -ENOSPC; + } +#endif + + return 0; +} + +static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +{ + int ret; + +// dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -1; + } + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + ret = __av7110_send_fw_cmd(av7110, buf, length); + mutex_unlock(&av7110->dcomlock); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", + __func__, ret); + return ret; +} + +int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) +{ + va_list args; + u16 buf[num + 2]; + int i, ret; + +// dprintk(4, "%p\n", av7110); + + buf[0] = ((type << 8) | com); + buf[1] = num; + + if (num) { + va_start(args, num); + for (i = 0; i < num; i++) + buf[i + 2] = va_arg(args, u32); + va_end(args); + } + + ret = av7110_send_fw_cmd(av7110, buf, num + 2); + if (ret && ret != -ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); + return ret; +} + +#if 0 +int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) +{ + int i, ret; + u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(4, "%p\n", av7110); + + for(i = 0; i < len && i < 32; i++) + { + if(i % 2 == 0) + cmd[(i / 2) + 2] = (u16)(buf[i]) << 8; + else + cmd[(i / 2) + 2] |= buf[i]; + } + + ret = av7110_send_fw_cmd(av7110, cmd, 18); + if (ret && ret != -ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); + return ret; +} +#endif /* 0 */ + +int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, + int request_buf_len, u16 *reply_buf, int reply_buf_len) +{ + int err; + s16 i; + unsigned long start; +#ifdef COM_DEBUG + u32 stat; +#endif + + dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -1; + } + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { + mutex_unlock(&av7110->dcomlock); + printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); + return err; + } + + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } +#ifdef _NOHANDSHAKE + msleep(1); +#endif + } + +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + +#ifdef COM_DEBUG + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & GPMQOver) { + printk(KERN_ERR "%s: GPMQOver\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -1; + } + else if (stat & OSDQOver) { + printk(KERN_ERR "%s: OSDQOver\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -1; + } +#endif + + for (i = 0; i < reply_buf_len; i++) + reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2); + + mutex_unlock(&av7110->dcomlock); + return 0; +} + +static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) +{ + int ret; + ret = av7110_fw_request(av7110, &tag, 0, buf, length); + if (ret) + printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); + return ret; +} + + +/**************************************************************************** + * Firmware commands + ****************************************************************************/ + +/* get version of the firmware ROM, RTSL, video ucode and ARM application */ +int av7110_firmversion(struct av7110 *av7110) +{ + u16 buf[20]; + u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion); + + dprintk(4, "%p\n", av7110); + + if (av7110_fw_query(av7110, tag, buf, 16)) { + printk("dvb-ttpci: failed to boot firmware @ card %d\n", + av7110->dvb_adapter.num); + return -EIO; + } + + av7110->arm_fw = (buf[0] << 16) + buf[1]; + av7110->arm_rtsl = (buf[2] << 16) + buf[3]; + av7110->arm_vid = (buf[4] << 16) + buf[5]; + av7110->arm_app = (buf[6] << 16) + buf[7]; + av7110->avtype = (buf[8] << 16) + buf[9]; + + printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", + av7110->dvb_adapter.num, av7110->arm_fw, + av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); + + /* print firmware capabilities */ + if (FW_CI_LL_SUPPORT(av7110->arm_app)) + printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", + av7110->dvb_adapter.num); + else + printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", + av7110->dvb_adapter.num); + + return 0; +} + + +int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) +{ + int i, ret; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(4, "%p\n", av7110); + + if (len > 10) + len = 10; + + buf[1] = len + 2; + buf[2] = len; + + if (burst != -1) + buf[3] = burst ? 0x01 : 0x00; + else + buf[3] = 0xffff; + + for (i = 0; i < len; i++) + buf[i + 4] = msg[i]; + + ret = av7110_send_fw_cmd(av7110, buf, 18); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); + return ret; +} + + +#ifdef CONFIG_DVB_AV7110_OSD + +static inline int SetColorBlend(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr); +} + +static inline int SetBlend_(struct av7110 *av7110, u8 windownr, + enum av7110_osd_palette_type colordepth, u16 index, u8 blending) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4, + windownr, colordepth, index, blending); +} + +static inline int SetColor_(struct av7110 *av7110, u8 windownr, + enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5, + windownr, colordepth, index, colorhi, colorlo); +} + +static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, + u16 colorfg, u16 colorbg) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4, + windownr, fontsize, colorfg, colorbg); +} + +static int FlushText(struct av7110 *av7110) +{ + unsigned long start; + int err; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } + mutex_unlock(&av7110->dcomlock); + return 0; +} + +static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) +{ + int i, ret; + unsigned long start; + int length = strlen(buf) + 1; + u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y }; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + start = jiffies; + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (ret) { + printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (ret) { + printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + for (i = 0; i < length / 2; i++) + wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, + swab16(*(u16 *)(buf + 2 * i)), 2); + if (length & 1) + wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); + ret = __av7110_send_fw_cmd(av7110, cbuf, 5); + mutex_unlock(&av7110->dcomlock); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); + return ret; +} + +static inline int DrawLine(struct av7110 *av7110, u8 windownr, + u16 x, u16 y, u16 dx, u16 dy, u16 color) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6, + windownr, x, y, dx, dy, color); +} + +static inline int DrawBlock(struct av7110 *av7110, u8 windownr, + u16 x, u16 y, u16 dx, u16 dy, u16 color) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6, + windownr, x, y, dx, dy, color); +} + +static inline int HideWindow(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr); +} + +static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y); +} + +static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y); +} + +static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr); +} + +static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr, + osd_raw_window_t disptype, + u16 width, u16 height) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4, + windownr, disptype, width, height); +} + + +static enum av7110_osd_palette_type bpp2pal[8] = { + Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit +}; +static osd_raw_window_t bpp2bit[8] = { + OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 +}; + +static inline int WaitUntilBmpLoaded(struct av7110 *av7110) +{ + int ret = wait_event_timeout(av7110->bmpq, + av7110->bmp_state != BMP_LOADING, 10*HZ); + if (ret == 0) { + printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", + ret, av7110->bmp_state); + av7110->bmp_state = BMP_NONE; + return -ETIMEDOUT; + } + return 0; +} + +static inline int LoadBitmap(struct av7110 *av7110, + u16 dx, u16 dy, int inc, u8 __user * data) +{ + u16 format; + int bpp; + int i; + int d, delta; + u8 c; + int ret; + + dprintk(4, "%p\n", av7110); + + format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; + + av7110->bmp_state = BMP_LOADING; + if (format == OSD_BITMAP8) { + bpp=8; delta = 1; + } else if (format == OSD_BITMAP4) { + bpp=4; delta = 2; + } else if (format == OSD_BITMAP2) { + bpp=2; delta = 4; + } else if (format == OSD_BITMAP1) { + bpp=1; delta = 8; + } else { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; + av7110->bmpp = 0; + if (av7110->bmplen > 32768) { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + for (i = 0; i < dy; i++) { + if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + } + if (format != OSD_BITMAP8) { + for (i = 0; i < dx * dy / delta; i++) { + c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1]; + for (d = delta - 2; d >= 0; d--) { + c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d] + << ((delta - d - 1) * bpp)); + ((u8 *)av7110->bmpbuf)[1024 + i] = c; + } + } + } + av7110->bmplen += 1024; + dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); + ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + if (!ret) + ret = WaitUntilBmpLoaded(av7110); + return ret; +} + +static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) +{ + dprintk(4, "%p\n", av7110); + + return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); +} + +static inline int ReleaseBitmap(struct av7110 *av7110) +{ + dprintk(4, "%p\n", av7110); + + if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) + return -1; + if (av7110->bmp_state == BMP_LOADING) + dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); + av7110->bmp_state = BMP_NONE; + return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); +} + +static u32 RGB2YUV(u16 R, u16 G, u16 B) +{ + u16 y, u, v; + u16 Y, Cr, Cb; + + y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */ + u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */ + v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */ + + Y = y / 256; + Cb = u / 16; + Cr = v / 16; + + return Cr | (Cb << 16) | (Y << 8); +} + +static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) +{ + int ret; + + u16 ch, cl; + u32 yuv; + + yuv = blend ? RGB2YUV(r,g,b) : 0; + cl = (yuv & 0xffff); + ch = ((yuv >> 16) & 0xffff); + ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ch, cl); + if (!ret) + ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ((blend >> 4) & 0x0f)); + return ret; +} + +static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) +{ + int i; + int length = last - first + 1; + + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; + + for (i = 0; i < length; i++) { + u32 color, blend, yuv; + + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + (color >> 16) & 0xFF) | blend : 0; + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + av7110->osdwin, + bpp2pal[av7110->osdbpp[av7110->osdwin]], + first, last); +} + +static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, + int x1, int y1, int inc, u8 __user * data) +{ + uint w, h, bpp, bpl, size, lpb, bnum, brest; + int i; + int rc,release_rc; + + w = x1 - x0 + 1; + h = y1 - y0 + 1; + if (inc <= 0) + inc = w; + if (w <= 0 || w > 720 || h <= 0 || h > 576) + return -EINVAL; + bpp = av7110->osdbpp[av7110->osdwin] + 1; + bpl = ((w * bpp + 7) & ~7) / 8; + size = h * bpl; + lpb = (32 * 1024) / bpl; + bnum = size / (lpb * bpl); + brest = size - bnum * lpb * bpl; + + if (av7110->bmp_state == BMP_LOADING) { + /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ + BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); + rc = WaitUntilBmpLoaded(av7110); + if (rc) + return rc; + /* just continue. This should work for all fw versions + * if bnum==1 && !brest && LoadBitmap was successful + */ + } + + rc = 0; + for (i = 0; i < bnum; i++) { + rc = LoadBitmap(av7110, w, lpb, inc, data); + if (rc) + break; + rc = BlitBitmap(av7110, x0, y0 + i * lpb); + if (rc) + break; + data += lpb * inc; + } + if (!rc && brest) { + rc = LoadBitmap(av7110, w, brest / bpl, inc, data); + if (!rc) + rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); + } + release_rc = ReleaseBitmap(av7110); + if (!rc) + rc = release_rc; + if (rc) + dprintk(1,"returns %d\n",rc); + return rc; +} + +int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) +{ + int ret; + + if (mutex_lock_interruptible(&av7110->osd_mutex)) + return -ERESTARTSYS; + + switch (dc->cmd) { + case OSD_Close: + ret = DestroyOSDWindow(av7110, av7110->osdwin); + break; + case OSD_Open: + av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; + ret = CreateOSDWindow(av7110, av7110->osdwin, + bpp2bit[av7110->osdbpp[av7110->osdwin]], + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; + if (!dc->data) { + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (ret) + break; + ret = SetColorBlend(av7110, av7110->osdwin); + } + break; + case OSD_Show: + ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); + break; + case OSD_Hide: + ret = HideWindow(av7110, av7110->osdwin); + break; + case OSD_Clear: + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); + break; + case OSD_Fill: + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); + break; + case OSD_SetColor: + ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); + break; + case OSD_SetPalette: + if (FW_VERSION(av7110->arm_app) >= 0x2618) + ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); + else { + int i, len = dc->x0-dc->color+1; + u8 __user *colors = (u8 __user *)dc->data; + u8 r, g = 0, b = 0, blend = 0; + ret = 0; + for (i = 0; icolor + i, r, g, b, blend); + if (ret) + break; + } + } + break; + case OSD_SetPixel: + ret = DrawLine(av7110, av7110->osdwin, + dc->x0, dc->y0, 0, 0, dc->color); + break; + case OSD_SetRow: + dc->y1 = dc->y0; + /* fall through */ + case OSD_SetBlock: + ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); + break; + case OSD_FillRow: + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + dc->x1-dc->x0+1, dc->y1, dc->color); + break; + case OSD_FillBlock: + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); + break; + case OSD_Line: + ret = DrawLine(av7110, av7110->osdwin, + dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); + break; + case OSD_Text: + { + char textbuf[240]; + + if (strncpy_from_user(textbuf, dc->data, 240) < 0) { + ret = -EFAULT; + break; + } + textbuf[239] = 0; + if (dc->x1 > 3) + dc->x1 = 3; + ret = SetFont(av7110, av7110->osdwin, dc->x1, + (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); + if (!ret) + ret = FlushText(av7110); + if (!ret) + ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); + break; + } + case OSD_SetWindow: + if (dc->x0 < 1 || dc->x0 > 7) + ret = -EINVAL; + else { + av7110->osdwin = dc->x0; + ret = 0; + } + break; + case OSD_MoveWindow: + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + break; + case OSD_OpenRaw: + if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { + ret = -EINVAL; + break; + } + if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) + av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; + else + av7110->osdbpp[av7110->osdwin] = 0; + ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; + if (!dc->data) { + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + } + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&av7110->osd_mutex); + if (ret==-ERESTARTSYS) + dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); + else if (ret) + dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); + + return ret; +} + +int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) +{ + switch (cap->cmd) { + case OSD_CAP_MEMSIZE: + if (FW_4M_SDRAM(av7110->arm_app)) + cap->val = 1000000; + else + cap->val = 92000; + return 0; + default: + return -EINVAL; + } +} +#endif /* CONFIG_DVB_AV7110_OSD */ diff --git a/drivers/media/pci/ttpci/av7110_hw.h b/drivers/media/pci/ttpci/av7110_hw.h new file mode 100644 index 00000000000..1634aba5cb8 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_hw.h @@ -0,0 +1,495 @@ +#ifndef _AV7110_HW_H_ +#define _AV7110_HW_H_ + +#include "av7110.h" + +/* DEBI transfer mode defs */ + +#define DEBINOSWAP 0x000e0000 +#define DEBISWAB 0x001e0000 +#define DEBISWAP 0x002e0000 + +#define ARM_WAIT_FREE (HZ) +#define ARM_WAIT_SHAKE (HZ/5) +#define ARM_WAIT_OSD (HZ) + + +enum av7110_bootstate +{ + BOOTSTATE_BUFFER_EMPTY = 0, + BOOTSTATE_BUFFER_FULL = 1, + BOOTSTATE_AV7110_BOOT_COMPLETE = 2 +}; + +enum av7110_type_rec_play_format +{ RP_None, + AudioPES, + AudioMp2, + AudioPCM, + VideoPES, + AV_PES +}; + +enum av7110_osd_palette_type +{ + NoPalet = 0, /* No palette */ + Pal1Bit = 2, /* 2 colors for 1 Bit Palette */ + Pal2Bit = 4, /* 4 colors for 2 bit palette */ + Pal4Bit = 16, /* 16 colors for 4 bit palette */ + Pal8Bit = 256 /* 256 colors for 16 bit palette */ +}; + +/* switch defines */ +#define SB_GPIO 3 +#define SB_OFF SAA7146_GPIO_OUTLO /* SlowBlank off (TV-Mode) */ +#define SB_ON SAA7146_GPIO_INPUT /* SlowBlank on (AV-Mode) */ +#define SB_WIDE SAA7146_GPIO_OUTHI /* SlowBlank 6V (16/9-Mode) (not implemented) */ + +#define FB_GPIO 1 +#define FB_OFF SAA7146_GPIO_LO /* FastBlank off (CVBS-Mode) */ +#define FB_ON SAA7146_GPIO_OUTHI /* FastBlank on (RGB-Mode) */ +#define FB_LOOP SAA7146_GPIO_INPUT /* FastBlank loop-through (PC graphics ???) */ + +enum av7110_video_output_mode +{ + NO_OUT = 0, /* disable analog output */ + CVBS_RGB_OUT = 1, + CVBS_YC_OUT = 2, + YC_OUT = 3 +}; + +/* firmware internal msg q status: */ +#define GPMQFull 0x0001 /* Main Message Queue Full */ +#define GPMQOver 0x0002 /* Main Message Queue Overflow */ +#define HPQFull 0x0004 /* High Priority Msg Queue Full */ +#define HPQOver 0x0008 +#define OSDQFull 0x0010 /* OSD Queue Full */ +#define OSDQOver 0x0020 +#define GPMQBusy 0x0040 /* Queue not empty, FW >= 261d */ +#define HPQBusy 0x0080 +#define OSDQBusy 0x0100 + +/* hw section filter flags */ +#define SECTION_EIT 0x01 +#define SECTION_SINGLE 0x00 +#define SECTION_CYCLE 0x02 +#define SECTION_CONTINUOS 0x04 +#define SECTION_MODE 0x06 +#define SECTION_IPMPE 0x0C /* size up to 4k */ +#define SECTION_HIGH_SPEED 0x1C /* larger buffer */ +#define DATA_PIPING_FLAG 0x20 /* for Data Piping Filter */ + +#define PBUFSIZE_NONE 0x0000 +#define PBUFSIZE_1P 0x0100 +#define PBUFSIZE_2P 0x0200 +#define PBUFSIZE_1K 0x0300 +#define PBUFSIZE_2K 0x0400 +#define PBUFSIZE_4K 0x0500 +#define PBUFSIZE_8K 0x0600 +#define PBUFSIZE_16K 0x0700 +#define PBUFSIZE_32K 0x0800 + + +/* firmware command codes */ +enum av7110_osd_command { + WCreate, + WDestroy, + WMoveD, + WMoveA, + WHide, + WTop, + DBox, + DLine, + DText, + Set_Font, + SetColor, + SetBlend, + SetWBlend, + SetCBlend, + SetNonBlend, + LoadBmp, + BlitBmp, + ReleaseBmp, + SetWTrans, + SetWNoTrans, + Set_Palette +}; + +enum av7110_pid_command { + MultiPID, + VideoPID, + AudioPID, + InitFilt, + FiltError, + NewVersion, + CacheError, + AddPIDFilter, + DelPIDFilter, + Scan, + SetDescr, + SetIR, + FlushTSQueue +}; + +enum av7110_mpeg_command { + SelAudChannels +}; + +enum av7110_audio_command { + AudioDAC, + CabADAC, + ON22K, + OFF22K, + MainSwitch, + ADSwitch, + SendDiSEqC, + SetRegister, + SpdifSwitch +}; + +enum av7110_request_command { + AudioState, + AudioBuffState, + VideoState1, + VideoState2, + VideoState3, + CrashCounter, + ReqVersion, + ReqVCXO, + ReqRegister, + ReqSecFilterError, + ReqSTC +}; + +enum av7110_encoder_command { + SetVidMode, + SetTestMode, + LoadVidCode, + SetMonitorType, + SetPanScanType, + SetFreezeMode, + SetWSSConfig +}; + +enum av7110_rec_play_state { + __Record, + __Stop, + __Play, + __Pause, + __Slow, + __FF_IP, + __Scan_I, + __Continue +}; + +enum av7110_fw_cmd_misc { + AV7110_FW_VIDEO_ZOOM = 1, + AV7110_FW_VIDEO_COMMAND, + AV7110_FW_AUDIO_COMMAND +}; + +enum av7110_command_type { + COMTYPE_NOCOM, + COMTYPE_PIDFILTER, + COMTYPE_MPEGDECODER, + COMTYPE_OSD, + COMTYPE_BMP, + COMTYPE_ENCODER, + COMTYPE_AUDIODAC, + COMTYPE_REQUEST, + COMTYPE_SYSTEM, + COMTYPE_REC_PLAY, + COMTYPE_COMMON_IF, + COMTYPE_PID_FILTER, + COMTYPE_PES, + COMTYPE_TS, + COMTYPE_VIDEO, + COMTYPE_AUDIO, + COMTYPE_CI_LL, + COMTYPE_MISC = 0x80 +}; + +#define VID_NONE_PREF 0x00 /* No aspect ration processing preferred */ +#define VID_PAN_SCAN_PREF 0x01 /* Pan and Scan Display preferred */ +#define VID_VERT_COMP_PREF 0x02 /* Vertical compression display preferred */ +#define VID_VC_AND_PS_PREF 0x03 /* PanScan and vertical Compression if allowed */ +#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ + +/* MPEG video decoder commands */ +#define AV_VIDEO_CMD_STOP 0x000e +#define AV_VIDEO_CMD_PLAY 0x000d +#define AV_VIDEO_CMD_FREEZE 0x0102 +#define AV_VIDEO_CMD_FFWD 0x0016 +#define AV_VIDEO_CMD_SLOW 0x0022 + +/* MPEG audio decoder commands */ +#define AUDIO_CMD_MUTE 0x0001 +#define AUDIO_CMD_UNMUTE 0x0002 +#define AUDIO_CMD_PCM16 0x0010 +#define AUDIO_CMD_STEREO 0x0080 +#define AUDIO_CMD_MONO_L 0x0100 +#define AUDIO_CMD_MONO_R 0x0200 +#define AUDIO_CMD_SYNC_OFF 0x000e +#define AUDIO_CMD_SYNC_ON 0x000f + +/* firmware data interface codes */ +#define DATA_NONE 0x00 +#define DATA_FSECTION 0x01 +#define DATA_IPMPE 0x02 +#define DATA_MPEG_RECORD 0x03 +#define DATA_DEBUG_MESSAGE 0x04 +#define DATA_COMMON_INTERFACE 0x05 +#define DATA_MPEG_PLAY 0x06 +#define DATA_BMP_LOAD 0x07 +#define DATA_IRCOMMAND 0x08 +#define DATA_PIPING 0x09 +#define DATA_STREAMING 0x0a +#define DATA_CI_GET 0x0b +#define DATA_CI_PUT 0x0c +#define DATA_MPEG_VIDEO_EVENT 0x0d + +#define DATA_PES_RECORD 0x10 +#define DATA_PES_PLAY 0x11 +#define DATA_TS_RECORD 0x12 +#define DATA_TS_PLAY 0x13 + +/* ancient CI command codes, only two are actually still used + * by the link level CI firmware */ +#define CI_CMD_ERROR 0x00 +#define CI_CMD_ACK 0x01 +#define CI_CMD_SYSTEM_READY 0x02 +#define CI_CMD_KEYPRESS 0x03 +#define CI_CMD_ON_TUNED 0x04 +#define CI_CMD_ON_SWITCH_PROGRAM 0x05 +#define CI_CMD_SECTION_ARRIVED 0x06 +#define CI_CMD_SECTION_TIMEOUT 0x07 +#define CI_CMD_TIME 0x08 +#define CI_CMD_ENTER_MENU 0x09 +#define CI_CMD_FAST_PSI 0x0a +#define CI_CMD_GET_SLOT_INFO 0x0b + +#define CI_MSG_NONE 0x00 +#define CI_MSG_CI_INFO 0x01 +#define CI_MSG_MENU 0x02 +#define CI_MSG_LIST 0x03 +#define CI_MSG_TEXT 0x04 +#define CI_MSG_REQUEST_INPUT 0x05 +#define CI_MSG_INPUT_COMPLETE 0x06 +#define CI_MSG_LIST_MORE 0x07 +#define CI_MSG_MENU_MORE 0x08 +#define CI_MSG_CLOSE_MMI_IMM 0x09 +#define CI_MSG_SECTION_REQUEST 0x0a +#define CI_MSG_CLOSE_FILTER 0x0b +#define CI_PSI_COMPLETE 0x0c +#define CI_MODULE_READY 0x0d +#define CI_SWITCH_PRG_REPLY 0x0e +#define CI_MSG_TEXT_MORE 0x0f + +#define CI_MSG_CA_PMT 0xe0 +#define CI_MSG_ERROR 0xf0 + + +/* base address of the dual ported RAM which serves as communication + * area between PCI bus and av7110, + * as seen by the DEBI bus of the saa7146 */ +#define DPRAM_BASE 0x4000 + +/* boot protocol area */ +#define AV7110_BOOT_STATE (DPRAM_BASE + 0x3F8) +#define AV7110_BOOT_SIZE (DPRAM_BASE + 0x3FA) +#define AV7110_BOOT_BASE (DPRAM_BASE + 0x3FC) +#define AV7110_BOOT_BLOCK (DPRAM_BASE + 0x400) +#define AV7110_BOOT_MAX_SIZE 0xc00 + +/* firmware command protocol area */ +#define IRQ_STATE (DPRAM_BASE + 0x0F4) +#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) +#define MSGSTATE (DPRAM_BASE + 0x0F8) +#define COMMAND (DPRAM_BASE + 0x0FC) +#define COM_BUFF (DPRAM_BASE + 0x100) +#define COM_BUFF_SIZE 0x20 + +/* various data buffers */ +#define BUFF1_BASE (DPRAM_BASE + 0x120) +#define BUFF1_SIZE 0xE0 + +#define DATA_BUFF0_BASE (DPRAM_BASE + 0x200) +#define DATA_BUFF0_SIZE 0x0800 + +#define DATA_BUFF1_BASE (DATA_BUFF0_BASE+DATA_BUFF0_SIZE) +#define DATA_BUFF1_SIZE 0x0800 + +#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE) +#define DATA_BUFF2_SIZE 0x0800 + +#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE) +#define DATA_BUFF3_SIZE 0x0400 + +#define Reserved (DPRAM_BASE + 0x1E00) +#define Reserved_SIZE 0x1C0 + + +/* firmware status area */ +#define STATUS_BASE (DPRAM_BASE + 0x1FC0) +#define STATUS_LOOPS (STATUS_BASE + 0x08) + +#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) +/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */ +#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E) + +/* firmware data protocol area */ +#define RX_TYPE (DPRAM_BASE + 0x1FE8) +#define RX_LEN (DPRAM_BASE + 0x1FEA) +#define TX_TYPE (DPRAM_BASE + 0x1FEC) +#define TX_LEN (DPRAM_BASE + 0x1FEE) + +#define RX_BUFF (DPRAM_BASE + 0x1FF4) +#define TX_BUFF (DPRAM_BASE + 0x1FF6) + +#define HANDSHAKE_REG (DPRAM_BASE + 0x1FF8) +#define COM_IF_LOCK (DPRAM_BASE + 0x1FFA) + +#define IRQ_RX (DPRAM_BASE + 0x1FFC) +#define IRQ_TX (DPRAM_BASE + 0x1FFE) + +/* used by boot protocol to load firmware into av7110 DRAM */ +#define DRAM_START_CODE 0x2e000404 +#define DRAM_MAX_CODE_SIZE 0x00100000 + +/* saa7146 gpio lines */ +#define RESET_LINE 2 +#define DEBI_DONE_LINE 1 +#define ARM_IRQ_LINE 0 + + + +extern int av7110_bootarm(struct av7110 *av7110); +extern int av7110_firmversion(struct av7110 *av7110); +#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) +#define FW_4M_SDRAM(arm_app) ((arm_app) & 0x40000000) +#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF) + +extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags); +extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...); +extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, + int request_buf_len, u16 *reply_buf, int reply_buf_len); + + +/* DEBI (saa7146 data extension bus interface) access */ +extern int av7110_debiwrite(struct av7110 *av7110, u32 config, + int addr, u32 val, int count); +extern u32 av7110_debiread(struct av7110 *av7110, u32 config, + int addr, int count); + + +/* DEBI during interrupt */ +/* single word writes */ +static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + av7110_debiwrite(av7110, config, addr, val, count); +} + +/* buffer writes */ +static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, + const u8 *val, int count) +{ + memcpy(av7110->debi_virt, val, count); + av7110_debiwrite(av7110, config, addr, 0, count); +} + +static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + u32 res; + + res=av7110_debiread(av7110, config, addr, count); + if (count<=4) + memcpy(av7110->debi_virt, (char *) &res, count); + return res; +} + +/* DEBI outside interrupts, only for count <= 4! */ +static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + unsigned long flags; + + spin_lock_irqsave(&av7110->debilock, flags); + av7110_debiwrite(av7110, config, addr, val, count); + spin_unlock_irqrestore(&av7110->debilock, flags); +} + +static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + unsigned long flags; + u32 res; + + spin_lock_irqsave(&av7110->debilock, flags); + res=av7110_debiread(av7110, config, addr, count); + spin_unlock_irqrestore(&av7110->debilock, flags); + return res; +} + +/* handle mailbox registers of the dual ported RAM */ +static inline void ARM_ResetMailBox(struct av7110 *av7110) +{ + unsigned long flags; + + spin_lock_irqsave(&av7110->debilock, flags); + av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2); + av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2); + spin_unlock_irqrestore(&av7110->debilock, flags); +} + +static inline void ARM_ClearMailBox(struct av7110 *av7110) +{ + iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); +} + +static inline void ARM_ClearIrq(struct av7110 *av7110) +{ + irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); +} + +/**************************************************************************** + * Firmware commands + ****************************************************************************/ + +static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) +{ + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); +} + +static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) +{ + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); +} + +static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) +{ + return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, + (com>>16), (com&0xffff), + (arg>>16), (arg&0xffff)); +} + +static inline int audcom(struct av7110 *av7110, u32 com) +{ + return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, + (com>>16), (com&0xffff)); +} + +static inline int Set22K(struct av7110 *av7110, int state) +{ + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); +} + + +extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst); + + +#ifdef CONFIG_DVB_AV7110_OSD +extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc); +extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap); +#endif /* CONFIG_DVB_AV7110_OSD */ + + + +#endif /* _AV7110_HW_H_ */ diff --git a/drivers/media/pci/ttpci/av7110_ipack.c b/drivers/media/pci/ttpci/av7110_ipack.c new file mode 100644 index 00000000000..699ef8b5b99 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_ipack.c @@ -0,0 +1,403 @@ +#include "dvb_filter.h" +#include "av7110_ipack.h" +#include /* for memcpy() */ +#include + + +void av7110_ipack_reset(struct ipack *p) +{ + p->found = 0; + p->cid = 0; + p->plength = 0; + p->flag1 = 0; + p->flag2 = 0; + p->hlength = 0; + p->mpeg = 0; + p->check = 0; + p->which = 0; + p->done = 0; + p->count = 0; +} + + +int av7110_ipack_init(struct ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)) +{ + if (!(p->buf = vmalloc(size*sizeof(u8)))) { + printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); + return -ENOMEM; + } + p->size = size; + p->func = func; + p->repack_subids = 0; + av7110_ipack_reset(p); + return 0; +} + + +void av7110_ipack_free(struct ipack *p) +{ + vfree(p->buf); +} + + +static void send_ipack(struct ipack *p) +{ + int off; + struct dvb_audio_info ai; + int ac3_off = 0; + int streamid = 0; + int nframes = 0; + int f = 0; + + switch (p->mpeg) { + case 2: + if (p->count < 10) + return; + p->buf[3] = p->cid; + p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); + p->buf[5] = (u8)((p->count - 6) & 0x00ff); + if (p->repack_subids && p->cid == PRIVATE_STREAM1) { + off = 9 + p->buf[8]; + streamid = p->buf[off]; + if ((streamid & 0xf8) == 0x80) { + ai.off = 0; + ac3_off = ((p->buf[off + 2] << 8)| + p->buf[off + 3]); + if (ac3_off < p->count) + f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off, + p->count - ac3_off, &ai, 0); + if (!f) { + nframes = (p->count - off - 3 - ac3_off) / + ai.framesize + 1; + p->buf[off + 2] = (ac3_off >> 8) & 0xff; + p->buf[off + 3] = (ac3_off) & 0xff; + p->buf[off + 1] = nframes; + ac3_off += nframes * ai.framesize - p->count; + } + } + } + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x80; + p->buf[7] = 0x00; + p->buf[8] = 0x00; + p->count = 9; + if (p->repack_subids && p->cid == PRIVATE_STREAM1 + && (streamid & 0xf8) == 0x80) { + p->count += 4; + p->buf[9] = streamid; + p->buf[10] = (ac3_off >> 8) & 0xff; + p->buf[11] = (ac3_off) & 0xff; + p->buf[12] = 0; + } + break; + + case 1: + if (p->count < 8) + return; + p->buf[3] = p->cid; + p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); + p->buf[5] = (u8)((p->count - 6) & 0x00ff); + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x0f; + p->count = 7; + break; + } +} + + +void av7110_ipack_flush(struct ipack *p) +{ + if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6) + return; + p->plength = p->found - 6; + p->found = 0; + send_ipack(p); + av7110_ipack_reset(p); +} + + +static void write_ipack(struct ipack *p, const u8 *data, int count) +{ + u8 headr[3] = { 0x00, 0x00, 0x01 }; + + if (p->count < 6) { + memcpy(p->buf, headr, 3); + p->count = 6; + } + + if (p->count + count < p->size){ + memcpy(p->buf+p->count, data, count); + p->count += count; + } else { + int rest = p->size - p->count; + memcpy(p->buf+p->count, data, rest); + p->count += rest; + send_ipack(p); + if (count - rest > 0) + write_ipack(p, data + rest, count - rest); + } +} + + +int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p) +{ + int l; + int c = 0; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)) { + switch (p->found) { + case 0: + case 1: + if (buf[c] == 0x00) + p->found++; + else + p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) + p->found++; + else if (buf[c] == 0) + p->found = 2; + else + p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + /* fall through */ + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; + + case 4: + if (count-c > 1) { + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found += 2; + p->plength = (p->plen[0] << 8) | p->plen[1]; + } else { + p->plen[0] = buf[c]; + p->found++; + return count; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + p->found++; + p->plength = (p->plen[0] << 8) | p->plen[1]; + break; + case 6: + if (!p->done) { + p->flag1 = buf[c]; + c++; + p->found++; + if ((p->flag1 & 0xc0) == 0x80) + p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if (!p->done && p->mpeg == 2) { + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if (!p->done && p->mpeg == 2) { + p->hlength = buf[c]; + c++; + p->found++; + } + break; + } + } + + if (c == count) + return count; + + if (!p->plength) + p->plength = MMAX_PLENGTH - 6; + + if (p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7))) { + switch (p->cid) { + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + if (p->mpeg == 2 && p->found == 9) { + write_ipack(p, &p->flag1, 1); + write_ipack(p, &p->flag2, 1); + write_ipack(p, &p->hlength, 1); + } + + if (p->mpeg == 1 && p->found == 7) + write_ipack(p, &p->flag1, 1); + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14) { + while (c < count && p->found < 14) { + p->pts[p->found - 9] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + } + if (c == count) + return count; + } + + if (p->mpeg == 1 && p->which < 2000) { + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xff){ + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + } + + if (c == count) + return count; + + if ((p->check & 0xc0) == 0x40 && !p->which) { + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + + p->which = 1; + if (c == count) + return count; + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if (c == count) + return count; + } + + if (p->which == 1) { + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if (c == count) + return count; + } + + if ((p->check & 0x30) && p->check != 0xff) { + p->flag2 = (p->check & 0xf0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if (c == count) + return count; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) { + while (c < count && p->which < 7) { + p->pts[p->which - 2] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if (c == count) + return count; + } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) { + while (c < count && p->which < 12) { + if (p->which < 7) + p->pts[p->which - 2] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if (c == count) + return count; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength + 6) { + l = count - c; + if (l + p->found > p->plength + 6) + l = p->plength + 6 - p->found; + write_ipack(p, buf + c, l); + p->found += l; + c += l; + } + break; + } + + + if (p->done) { + if (p->found + count - c < p->plength + 6) { + p->found += count - c; + c = count; + } else { + c += p->plength + 6 - p->found; + p->found = p->plength + 6; + } + } + + if (p->plength && p->found == p->plength + 6) { + send_ipack(p); + av7110_ipack_reset(p); + if (c < count) + av7110_ipack_instant_repack(buf + c, count - c, p); + } + } + return count; +} diff --git a/drivers/media/pci/ttpci/av7110_ipack.h b/drivers/media/pci/ttpci/av7110_ipack.h new file mode 100644 index 00000000000..becf94d3fdf --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_ipack.h @@ -0,0 +1,12 @@ +#ifndef _AV7110_IPACK_H_ +#define _AV7110_IPACK_H_ + +extern int av7110_ipack_init(struct ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)); + +extern void av7110_ipack_reset(struct ipack *p); +extern int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p); +extern void av7110_ipack_free(struct ipack * p); +extern void av7110_ipack_flush(struct ipack *p); + +#endif diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c new file mode 100644 index 00000000000..908f272fe26 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_ir.c @@ -0,0 +1,415 @@ +/* + * Driver for the remote control of SAA7146 based AV7110 cards + * + * Copyright (C) 1999-2003 Holger Waechtler + * Copyright (C) 2003-2007 Oliver Endriss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + + +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" + + +#define AV_CNT 4 + +#define IR_RC5 0 +#define IR_RCMM 1 +#define IR_RC5_EXT 2 /* internal only */ + +#define IR_ALL 0xffffffff + +#define UP_TIMEOUT (HZ*7/25) + + +/* Note: enable ir debugging by or'ing debug with 16 */ + +static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; +module_param_array(ir_protocol, int, NULL, 0644); +MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); + +static int ir_inversion[AV_CNT]; +module_param_array(ir_inversion, int, NULL, 0644); +MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); + +static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; +module_param_array(ir_device_mask, uint, NULL, 0644); +MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); + + +static int av_cnt; +static struct av7110 *av_list[AV_CNT]; + +static u16 default_key_map [256] = { + KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, + KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0, + 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0, + KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, + KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW, + KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN, + 0, 0, 0, 0, KEY_EPG, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR +}; + + +/* key-up timer */ +static void av7110_emit_keyup(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + + if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) + return; + + input_report_key(ir->input_dev, ir->last_key, 0); + input_sync(ir->input_dev); +} + + +/* tasklet */ +static void av7110_emit_key(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + u32 ircom = ir->ir_command; + u8 data; + u8 addr; + u16 toggle; + u16 keycode; + + /* extract device address and data */ + switch (ir->protocol) { + case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ + data = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + toggle = ircom & 0x0800; + break; + + case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ + data = ircom & 0xff; + addr = (ircom >> 8) & 0x1f; + toggle = ircom & 0x8000; + break; + + case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ + data = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + /* invert 7th data bit for backward compatibility with RC5 keymaps */ + if (!(ircom & 0x1000)) + data |= 0x40; + toggle = ircom & 0x0800; + break; + + default: + printk("%s invalid protocol %x\n", __func__, ir->protocol); + return; + } + + input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); + input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); + + keycode = ir->key_map[data]; + + dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", + __func__, ircom, addr, data, keycode); + + /* check device address */ + if (!(ir->device_mask & (1 << addr))) + return; + + if (!keycode) { + printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", + __func__, ircom, addr, data); + return; + } + + if (timer_pending(&ir->keyup_timer)) { + del_timer(&ir->keyup_timer); + if (ir->last_key != keycode || toggle != ir->last_toggle) { + ir->delay_timer_finished = 0; + input_event(ir->input_dev, EV_KEY, ir->last_key, 0); + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + } else if (ir->delay_timer_finished) { + input_event(ir->input_dev, EV_KEY, keycode, 2); + input_sync(ir->input_dev); + } + } else { + ir->delay_timer_finished = 0; + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + } + + ir->last_key = keycode; + ir->last_toggle = toggle; + + ir->keyup_timer.expires = jiffies + UP_TIMEOUT; + add_timer(&ir->keyup_timer); + +} + + +/* register with input layer */ +static void input_register_keys(struct infrared *ir) +{ + int i; + + set_bit(EV_KEY, ir->input_dev->evbit); + set_bit(EV_REP, ir->input_dev->evbit); + set_bit(EV_MSC, ir->input_dev->evbit); + + set_bit(MSC_RAW, ir->input_dev->mscbit); + set_bit(MSC_SCAN, ir->input_dev->mscbit); + + memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); + + for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { + if (ir->key_map[i] > KEY_MAX) + ir->key_map[i] = 0; + else if (ir->key_map[i] > KEY_RESERVED) + set_bit(ir->key_map[i], ir->input_dev->keybit); + } + + ir->input_dev->keycode = ir->key_map; + ir->input_dev->keycodesize = sizeof(ir->key_map[0]); + ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); +} + + +/* called by the input driver after rep[REP_DELAY] ms */ +static void input_repeat_key(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + + ir->delay_timer_finished = 1; +} + + +/* check for configuration changes */ +int av7110_check_ir_config(struct av7110 *av7110, int force) +{ + int i; + int modified = force; + int ret = -ENODEV; + + for (i = 0; i < av_cnt; i++) + if (av7110 == av_list[i]) + break; + + if (i < av_cnt && av7110) { + if ((av7110->ir.protocol & 1) != ir_protocol[i] || + av7110->ir.inversion != ir_inversion[i]) + modified = true; + + if (modified) { + /* protocol */ + if (ir_protocol[i]) { + ir_protocol[i] = 1; + av7110->ir.protocol = IR_RCMM; + av7110->ir.ir_config = 0x0001; + } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { + av7110->ir.protocol = IR_RC5_EXT; + av7110->ir.ir_config = 0x0002; + } else { + av7110->ir.protocol = IR_RC5; + av7110->ir.ir_config = 0x0000; + } + /* inversion */ + if (ir_inversion[i]) { + ir_inversion[i] = 1; + av7110->ir.ir_config |= 0x8000; + } + av7110->ir.inversion = ir_inversion[i]; + /* update ARM */ + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, + av7110->ir.ir_config); + } else + ret = 0; + + /* address */ + if (av7110->ir.device_mask != ir_device_mask[i]) + av7110->ir.device_mask = ir_device_mask[i]; + } + + return ret; +} + + +/* /proc/av7110_ir interface */ +static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char *page; + u32 ir_config; + int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; + int i; + + if (count < size) + return -EINVAL; + + page = vmalloc(size); + if (!page) + return -ENOMEM; + + if (copy_from_user(page, buffer, size)) { + vfree(page); + return -EFAULT; + } + + memcpy(&ir_config, page, sizeof ir_config); + + for (i = 0; i < av_cnt; i++) { + /* keymap */ + memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, + sizeof(av_list[i]->ir.key_map)); + /* protocol, inversion, address */ + ir_protocol[i] = ir_config & 0x0001; + ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; + if (ir_config & 0x4000) + ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); + else + ir_device_mask[i] = IR_ALL; + /* update configuration */ + av7110_check_ir_config(av_list[i], false); + input_register_keys(&av_list[i]->ir); + } + vfree(page); + return count; +} + +static const struct file_operations av7110_ir_proc_fops = { + .owner = THIS_MODULE, + .write = av7110_ir_proc_write, + .llseek = noop_llseek, +}; + +/* interrupt handler */ +static void ir_handler(struct av7110 *av7110, u32 ircom) +{ + dprintk(4, "ir command = %08x\n", ircom); + av7110->ir.ir_command = ircom; + tasklet_schedule(&av7110->ir.ir_tasklet); +} + + +int __devinit av7110_ir_init(struct av7110 *av7110) +{ + struct input_dev *input_dev; + static struct proc_dir_entry *e; + int err; + + if (av_cnt >= ARRAY_SIZE(av_list)) + return -ENOSPC; + + av_list[av_cnt++] = av7110; + av7110_check_ir_config(av7110, true); + + init_timer(&av7110->ir.keyup_timer); + av7110->ir.keyup_timer.function = av7110_emit_keyup; + av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + av7110->ir.input_dev = input_dev; + snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), + "pci-%s/ir0", pci_name(av7110->dev->pci)); + + input_dev->name = "DVB on-card IR receiver"; + + input_dev->phys = av7110->ir.input_phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 2; + if (av7110->dev->pci->subsystem_vendor) { + input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; + input_dev->id.product = av7110->dev->pci->subsystem_device; + } else { + input_dev->id.vendor = av7110->dev->pci->vendor; + input_dev->id.product = av7110->dev->pci->device; + } + input_dev->dev.parent = &av7110->dev->pci->dev; + /* initial keymap */ + memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); + input_register_keys(&av7110->ir); + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + input_dev->timer.function = input_repeat_key; + input_dev->timer.data = (unsigned long) &av7110->ir; + + if (av_cnt == 1) { + e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); + if (e) + e->size = 4 + 256 * sizeof(u16); + } + + tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); + av7110->ir.ir_handler = ir_handler; + + return 0; +} + + +void __devexit av7110_ir_exit(struct av7110 *av7110) +{ + int i; + + if (av_cnt == 0) + return; + + del_timer_sync(&av7110->ir.keyup_timer); + av7110->ir.ir_handler = NULL; + tasklet_kill(&av7110->ir.ir_tasklet); + + for (i = 0; i < av_cnt; i++) + if (av_list[i] == av7110) { + av_list[i] = av_list[av_cnt-1]; + av_list[av_cnt-1] = NULL; + break; + } + + if (av_cnt == 1) + remove_proc_entry("av7110_ir", NULL); + + input_unregister_device(av7110->ir.input_dev); + + av_cnt--; +} + +//MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); +//MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c new file mode 100644 index 00000000000..1b2d15140a1 --- /dev/null +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -0,0 +1,966 @@ +/* + * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * the project's page is at http://www.linuxtv.org/ + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" + +int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) +{ + u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; + struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs.addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs.addr = 0x42; + break; + default: + return 0; + } + + if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { + dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", + av7110->dvb_adapter.num, reg, val); + return -EIO; + } + return 0; +} + +static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) +{ + u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; + u8 msg2[2]; + struct i2c_msg msgs[2] = { + { .flags = 0 , .len = 3, .buf = msg1 }, + { .flags = I2C_M_RD, .len = 2, .buf = msg2 } + }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs[0].addr = 0x40; + msgs[1].addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs[0].addr = 0x42; + msgs[1].addr = 0x42; + break; + default: + return 0; + } + + if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { + dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", + av7110->dvb_adapter.num, reg); + return -EIO; + } + *val = (msg2[0] << 8) | msg2[1]; + return 0; +} + +static struct v4l2_input inputs[4] = { + { + .index = 0, + .name = "DVB", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, /* ignored */ + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 1, + .name = "Television", + .type = V4L2_INPUT_TYPE_TUNER, + .audioset = 1, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 2, + .name = "Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 3, + .name = "Y/C", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + } +}; + +static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) +{ + struct av7110 *av7110 = dev->ext_priv; + u8 buf[] = { 0x00, reg, data }; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; + + dprintk(4, "dev: %p\n", dev); + + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) + return -1; + return 0; +} + +static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) +{ + struct av7110 *av7110 = dev->ext_priv; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; + + dprintk(4, "dev: %p\n", dev); + + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) + return -1; + return 0; +} + +static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq) +{ + u32 div; + u8 config; + u8 buf[4]; + + dprintk(4, "freq: 0x%08x\n", freq); + + /* magic number: 614. tuning with the frequency given by v4l2 + is always off by 614*62.5 = 38375 kHz...*/ + div = freq + 614; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + + if (freq < (u32) (16 * 168.25)) + config = 0xa0; + else if (freq < (u32) (16 * 447.25)) + config = 0x90; + else + config = 0x30; + config &= ~0x02; + + buf[3] = config; + + return tuner_write(dev, 0x61, buf); +} + +static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq) +{ + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u32 div; + u8 data[4]; + + div = (freq + 38900000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; + + if (freq < 45000000) + return -EINVAL; + else if (freq < 137000000) + data[3] = 0x01; + else if (freq < 403000000) + data[3] = 0x02; + else if (freq < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + if (av7110->fe->ops.i2c_gate_ctrl) + av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1); + return tuner_write(dev, 0x63, data); +} + + + +static struct saa7146_standard analog_standard[]; +static struct saa7146_standard dvb_standard[]; +static struct saa7146_standard standard[]; + +static struct v4l2_audio msp3400_v4l2_audio = { + .index = 0, + .name = "Television", + .capability = V4L2_AUDCAP_STEREO +}; + +static int av7110_dvb_c_switch(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u16 adswitch; + int source, sync, err; + + dprintk(4, "%p\n", av7110); + + if ((vv->video_status & STATUS_OVERLAY) != 0) { + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (err != 0) { + dprintk(2, "suspending video failed\n"); + vv->ov_suspend = NULL; + } + } + + if (0 != av7110->current_input) { + dprintk(1, "switching to analog TV:\n"); + adswitch = 1; + source = SAA7146_HPS_SOURCE_PORT_B; + sync = SAA7146_HPS_SYNC_PORT_B; + memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); + + switch (av7110->current_input) { + case 1: + dprintk(1, "switching SAA7113 to Analog Tuner Input\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) + dprintk(1, "setting band in demodulator failed\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) + } + if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 2: + dprintk(1, "switching SAA7113 to Video AV CVBS Input\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 3: + dprintk(1, "switching SAA7113 to Video AV Y/C Input\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + default: + dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n"); + } + } else { + adswitch = 0; + source = SAA7146_HPS_SOURCE_PORT_A; + sync = SAA7146_HPS_SYNC_PORT_A; + memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); + dprintk(1, "switching DVB mode\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) + dprintk(1, "setting band in demodulator failed\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + } + } + + /* hmm, this does not do anything!? */ + if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch)) + dprintk(1, "ADSwitch error\n"); + + saa7146_set_hps_source_and_sync(dev, source, sync); + + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 stereo_det; + s8 stereo; + + dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); + + if (!av7110->analog_tuner_flags || t->index != 0) + return -EINVAL; + + memset(t, 0, sizeof(*t)); + strcpy((char *)t->name, "Television"); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ + t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ + /* FIXME: add the real signal strength here */ + t->signal = 0xffff; + t->afc = 0; + + /* FIXME: standard / stereo detection is still broken */ + msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); + msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); + stereo = (s8)(stereo_det >> 8); + if (stereo > 0x10) { + /* stereo */ + t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + t->audmode = V4L2_TUNER_MODE_STEREO; + } else if (stereo < -0x10) { + /* bilingual */ + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1; + } else /* mono */ + t->rxsubchans = V4L2_TUNER_SUB_MONO; + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 fm_matrix, src; + dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + switch (t->audmode) { + case V4L2_TUNER_MODE_STEREO: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); + fm_matrix = 0x3001; /* stereo */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); + fm_matrix = 0x3000; /* bilingual */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0000; + break; + case V4L2_TUNER_MODE_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0010; + break; + default: /* case V4L2_TUNER_MODE_MONO: */ + dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0030; + break; + } + msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); + msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); + msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = av7110->current_freq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); + + /* tune in desired frequency */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) + ves1820_set_tv_freq(dev, f->frequency); + else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) + stv0297_set_tv_freq(dev, f->frequency); + av7110->current_freq = f->frequency; + + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); + + if (av7110->analog_tuner_flags) { + if (i->index >= 4) + return -EINVAL; + } else { + if (i->index != 0) + return -EINVAL; + } + + memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); + + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + *input = av7110->current_input; + dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_INPUT: %d\n", input); + + if (!av7110->analog_tuner_flags) + return input ? -EINVAL : 0; + + if (input >= 4) + return -EINVAL; + + av7110->current_input = input; + return av7110_dvb_c_switch(fh); +} + +static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + *a = msp3400_v4l2_audio; + return 0; +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + if (av7110->current_input >= 2) + return -EINVAL; + *a = msp3400_v4l2_audio; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); + if (av7110->current_input >= 2) + return -EINVAL; + return a->index ? -EINVAL : 0; +} + +static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); + if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) + return -EINVAL; + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + cap->service_set = V4L2_SLICED_WSS_625; + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + } + return 0; +} + +static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FMT:\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + if (av7110->wssMode) { + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + } + return 0; +} + +static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FMT\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && + f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + /* WSS controlled by firmware */ + av7110->wssMode = 0; + av7110->wssData = 0; + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, + SetWSSConfig, 1, 0); + } else { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + /* WSS controlled by userspace */ + av7110->wssMode = 1; + av7110->wssData = 0; + } + return 0; +} + +static int av7110_vbi_reset(struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + dprintk(2, "%s\n", __func__); + av7110->wssMode = 0; + av7110->wssData = 0; + if (FW_VERSION(av7110->arm_app) < 0x2623) + return 0; + else + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); +} + +static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + struct v4l2_sliced_vbi_data d; + int rc; + + dprintk(2, "%s\n", __func__); + if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d) + return -EINVAL; + if (copy_from_user(&d, data, count)) + return -EFAULT; + if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23) + return -EINVAL; + if (d.id) + av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0]; + else + av7110->wssData = 0x8000; + rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData); + return (rc < 0) ? rc : count; +} + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + +static u8 saa7113_init_regs[] = { + 0x02, 0xd0, + 0x03, 0x23, + 0x04, 0x00, + 0x05, 0x00, + 0x06, 0xe9, + 0x07, 0x0d, + 0x08, 0x98, + 0x09, 0x02, + 0x0a, 0x80, + 0x0b, 0x40, + 0x0c, 0x40, + 0x0d, 0x00, + 0x0e, 0x01, + 0x0f, 0x7c, + 0x10, 0x48, + 0x11, 0x0c, + 0x12, 0x8b, + 0x13, 0x1a, + 0x14, 0x00, + 0x15, 0x00, + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1b, 0x00, + 0x1c, 0x00, + 0x1d, 0x00, + 0x1e, 0x00, + + 0x41, 0x77, + 0x42, 0x77, + 0x43, 0x77, + 0x44, 0x77, + 0x45, 0x77, + 0x46, 0x77, + 0x47, 0x77, + 0x48, 0x77, + 0x49, 0x77, + 0x4a, 0x77, + 0x4b, 0x77, + 0x4c, 0x77, + 0x4d, 0x77, + 0x4e, 0x77, + 0x4f, 0x77, + 0x50, 0x77, + 0x51, 0x77, + 0x52, 0x77, + 0x53, 0x77, + 0x54, 0x77, + 0x55, 0x77, + 0x56, 0x77, + 0x57, 0xff, + + 0xff +}; + + +static struct saa7146_ext_vv av7110_vv_data_st; +static struct saa7146_ext_vv av7110_vv_data_c; + +int av7110_init_analog_module(struct av7110 *av7110) +{ + u16 version1, version2; + + if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { + pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x0; + } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { + pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x5; + } else + return -ENODEV; + + msleep(100); // the probing above resets the msp... + msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); + msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); + dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", + av7110->dvb_adapter.num, version1, version2); + msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume + msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART + + if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { + pr_info("saa7113 not accessible\n"); + } else { + u8 *i = saa7113_init_regs; + + if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { + /* Fujitsu/Siemens DVB-Cable */ + av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; + } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) { + /* Hauppauge/TT DVB-C premium */ + av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; + } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) { + /* Hauppauge/TT DVB-C premium */ + av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297; + } + + /* setup for DVB by default */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) + dprintk(1, "setting band in demodulator failed\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + } + + /* init the saa7113 */ + while (*i != 0xff) { + if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { + dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num); + break; + } + i += 2; + } + /* setup msp for analog sound: B/G Dual-FM */ + msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG + msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz + msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI + msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz + msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI + msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2 + } + + memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); + /* set dd1 stream a & b */ + saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); + saa7146_write(av7110->dev, DD1_INIT, 0x03000700); + saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + return 0; +} + +int av7110_init_v4l(struct av7110 *av7110) +{ + struct saa7146_dev* dev = av7110->dev; + struct saa7146_ext_vv *vv_data; + int ret; + + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + if (av7110->analog_tuner_flags) + vv_data = &av7110_vv_data_c; + else + vv_data = &av7110_vv_data_st; + ret = saa7146_vv_init(dev, vv_data); + + if (ret) { + ERR("cannot init capture device. skipping\n"); + return -ENODEV; + } + vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input; + vv_data->vid_ops.vidioc_g_input = vidioc_g_input; + vv_data->vid_ops.vidioc_s_input = vidioc_s_input; + vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio; + vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio; + vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio; + vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL; + + vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL; + vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; + vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; + vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; + + if (FW_VERSION(av7110->arm_app) < 0x2623) + vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT; + + if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { + ERR("cannot register capture device. skipping\n"); + saa7146_vv_release(dev); + return -ENODEV; + } + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) + ERR("cannot register vbi v4l2 device. skipping\n"); + } + return 0; +} + +int av7110_exit_v4l(struct av7110 *av7110) +{ + struct saa7146_dev* dev = av7110->dev; + + saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); + saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); + + saa7146_vv_release(dev); + + return 0; +} + + + +/* FIXME: these values are experimental values that look better than the + values from the latest "official" driver -- at least for me... (MiHu) */ +static struct saa7146_standard standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x15, .v_field = 288, + .h_offset = 0x48, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static struct saa7146_standard analog_standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x1b, .v_field = 288, + .h_offset = 0x08, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static struct saa7146_standard dvb_standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x14, .v_field = 288, + .h_offset = 0x48, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +{ + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + if (std->id & V4L2_STD_PAL) { + av7110->vidmode = AV7110_VIDEO_MODE_PAL; + av7110_set_vidmode(av7110, av7110->vidmode); + } + else if (std->id & V4L2_STD_NTSC) { + av7110->vidmode = AV7110_VIDEO_MODE_NTSC; + av7110_set_vidmode(av7110, av7110->vidmode); + } + else + return -1; + + return 0; +} + + +static struct saa7146_ext_vv av7110_vv_data_st = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, + .flags = 0, + + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), + .std_callback = &std_callback, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, +}; + +static struct saa7146_ext_vv av7110_vv_data_c = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, + .flags = SAA7146_USE_PORT_B_FOR_VBI, + + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), + .std_callback = &std_callback, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, +}; + diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c new file mode 100644 index 00000000000..12ddb53c58d --- /dev/null +++ b/drivers/media/pci/ttpci/budget-av.c @@ -0,0 +1,1640 @@ +/* + * budget-av.c: driver for the SAA7146 based Budget DVB cards + * with analog video in + * + * Compiled from various sources by Michael Hunold + * + * CI interface support (c) 2004 Olivier Gournet & + * Andrew de Quincey + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "budget.h" +#include "stv0299.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "tda8261.h" +#include "tda8261_cfg.h" +#include "tda1002x.h" +#include "tda1004x.h" +#include "tua6100.h" +#include "dvb-pll.h" +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_ca_en50221.h" + +#define DEBICICAM 0x02420000 + +#define SLOTSTATUS_NONE 1 +#define SLOTSTATUS_PRESENT 2 +#define SLOTSTATUS_RESET 4 +#define SLOTSTATUS_READY 8 +#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct budget_av { + struct budget budget; + struct video_device *vd; + int cur_input; + int has_saa7113; + struct tasklet_struct ciintf_irq_tasklet; + int slot_status; + struct dvb_ca_en50221 ca; + u8 reinitialise_demod:1; +}; + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); + + +/* GPIO Connections: + * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! + * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory + * 2 - CI Card Enable (Active Low) + * 3 - CI Card Detect + */ + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + +static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg) +{ + u8 mm1[] = { 0x00 }; + u8 mm2[] = { 0x00 }; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = id / 2; + mm1[0] = reg; + msgs[0].len = 1; + msgs[1].len = 1; + msgs[0].buf = mm1; + msgs[1].buf = mm2; + + i2c_transfer(i2c, msgs, 2); + + return mm2[0]; +} + +static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len) +{ + u8 mm1[] = { reg }; + struct i2c_msg msgs[2] = { + {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, + {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} + }; + + if (i2c_transfer(i2c, msgs, 2) != 2) + return -EIO; + + return 0; +} + +static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + struct i2c_msg msgs; + + msgs.flags = 0; + msgs.addr = id / 2; + msgs.len = 2; + msgs.buf = msg; + return i2c_transfer(i2c, &msgs, 1); +} + +static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); + udelay(1); + + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + pr_info("cam ejected 1\n"); + } + return result; +} + +static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); + udelay(1); + + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + pr_info("cam ejected 2\n"); + } + return result; +} + +static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + udelay(1); + + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + pr_info("cam ejected 3\n"); + return -ETIMEDOUT; + } + return result; +} + +static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + udelay(1); + + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + pr_info("cam ejected 5\n"); + } + return result; +} + +static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_reset\n"); + budget_av->slot_status = SLOTSTATUS_RESET; + + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ + + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ + msleep(2); + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ + msleep(20); /* 20 ms Vcc settling time */ + + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + msleep(20); + + /* reinitialise the frontend if necessary */ + if (budget_av->reinitialise_demod) + dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + + return 0; +} + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_shutdown\n"); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + budget_av->slot_status = SLOTSTATUS_NONE; + + return 0; +} + +static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + + return 0; +} + +static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + int result; + + if (slot != 0) + return -EINVAL; + + /* test the card detect line - needs to be done carefully + * since it never goes high for some CAMs on this interface (e.g. topuptv) */ + if (budget_av->slot_status == SLOTSTATUS_NONE) { + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + udelay(1); + if (saa7146_read(saa, PSR) & MASK_06) { + if (budget_av->slot_status == SLOTSTATUS_NONE) { + budget_av->slot_status = SLOTSTATUS_PRESENT; + pr_info("cam inserted A\n"); + } + } + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } + + /* We also try and read from IO memory to work round the above detection bug. If + * there is no CAM, we will get a timeout. Only done if there is no cam + * present, since this test actually breaks some cams :( + * + * if the CI interface is not open, we also do the above test since we + * don't care if the cam has problems - we'll be resetting it on open() anyway */ + if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); + if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { + budget_av->slot_status = SLOTSTATUS_PRESENT; + pr_info("cam inserted B\n"); + } else if (result < 0) { + if (budget_av->slot_status != SLOTSTATUS_NONE) { + ciintf_slot_shutdown(ca, slot); + pr_info("cam ejected 5\n"); + return 0; + } + } + } + + /* read from attribute memory in reset/ready state to know when the CAM is ready */ + if (budget_av->slot_status == SLOTSTATUS_RESET) { + result = ciintf_read_attribute_mem(ca, slot, 0); + if (result == 0x1d) { + budget_av->slot_status = SLOTSTATUS_READY; + } + } + + /* work out correct return code */ + if (budget_av->slot_status != SLOTSTATUS_NONE) { + if (budget_av->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } + return 0; +} + +static int ciintf_init(struct budget_av *budget_av) +{ + struct saa7146_dev *saa = budget_av->budget.dev; + int result; + + memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); + + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + + /* Enable DEBI pins */ + saa7146_write(saa, MC1, MASK_27 | MASK_11); + + /* register CI interface */ + budget_av->ca.owner = THIS_MODULE; + budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; + budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; + budget_av->ca.read_cam_control = ciintf_read_cam_control; + budget_av->ca.write_cam_control = ciintf_write_cam_control; + budget_av->ca.slot_reset = ciintf_slot_reset; + budget_av->ca.slot_shutdown = ciintf_slot_shutdown; + budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; + budget_av->ca.poll_slot_status = ciintf_poll_slot_status; + budget_av->ca.data = budget_av; + budget_av->budget.ci_present = 1; + budget_av->slot_status = SLOTSTATUS_NONE; + + if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, + &budget_av->ca, 0, 1)) != 0) { + pr_err("ci initialisation failed\n"); + goto error; + } + + pr_info("ci interface initialised\n"); + return 0; + +error: + saa7146_write(saa, MC1, MASK_27); + return result; +} + +static void ciintf_deinit(struct budget_av *budget_av) +{ + struct saa7146_dev *saa = budget_av->budget.dev; + + saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + + /* release the CA device */ + dvb_ca_en50221_release(&budget_av->ca); + + /* disable DEBI pins */ + saa7146_write(saa, MC1, MASK_27); +} + + +static const u8 saa7113_tab[] = { + 0x01, 0x08, + 0x02, 0xc0, + 0x03, 0x33, + 0x04, 0x00, + 0x05, 0x00, + 0x06, 0xeb, + 0x07, 0xe0, + 0x08, 0x28, + 0x09, 0x00, + 0x0a, 0x80, + 0x0b, 0x47, + 0x0c, 0x40, + 0x0d, 0x00, + 0x0e, 0x01, + 0x0f, 0x44, + + 0x10, 0x08, + 0x11, 0x0c, + 0x12, 0x7b, + 0x13, 0x00, + 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, + + 0x57, 0xff, + 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, + 0x5b, 0x83, 0x5e, 0x00, + 0xff +}; + +static int saa7113_init(struct budget_av *budget_av) +{ + struct budget *budget = &budget_av->budget; + struct saa7146_dev *saa = budget->dev; + const u8 *data = saa7113_tab; + + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); + msleep(200); + + if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { + dprintk(1, "saa7113 not found on KNC card\n"); + return -ENODEV; + } + + dprintk(1, "saa7113 detected and initializing\n"); + + while (*data != 0xff) { + i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); + data += 2; + } + + dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); + + return 0; +} + +static int saa7113_setinput(struct budget_av *budget_av, int input) +{ + struct budget *budget = &budget_av->budget; + + if (1 != budget_av->has_saa7113) + return -ENODEV; + + if (input == 1) { + i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); + i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); + } else if (input == 0) { + i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); + i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); + } else + return -EINVAL; + + budget_av->cur_input = input; + return 0; +} + + +static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + + aclk = 0xb5; + if (srate < 2000000) + bclk = 0x86; + else if (srate < 5000000) + bclk = 0x89; + else if (srate < 15000000) + bclk = 0x8f; + else if (srate < 45000000) + bclk = 0x95; + + m1 = 0x14; + if (srate < 4000000) + m1 = 0x10; + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + stv0299_writereg(fe, 0x0f, 0x80 | m1); + + return 0; +} + +static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 div; + u8 buf[4]; + struct budget *budget = (struct budget *) fe->dvb->priv; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((c->frequency < 950000) || (c->frequency > 2150000)) + return -EINVAL; + + div = (c->frequency + (125 - 1)) / 125; /* round correctly */ + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0x20; + + if (c->symbol_rate < 4000000) + buf[3] |= 1; + + if (c->frequency < 1250000) + buf[3] |= 0; + else if (c->frequency < 1550000) + buf[3] |= 0x40; + else if (c->frequency < 2050000) + buf[3] |= 0x80; + else if (c->frequency < 2150000) + buf[3] |= 0xC0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static u8 typhoon_cinergy1200s_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, + 0xff, 0xff +}; + +static struct stv0299_config typhoon_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, +}; + + +static struct stv0299_config cinergy_1200s_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, +}; + +static struct stv0299_config cinergy_1200s_1894_0010_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, +}; + +static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget *budget = (struct budget *) fe->dvb->priv; + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (c->frequency < 150000000 ? 0x01 : + c->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static struct tda1002x_config philips_cu1216_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static struct tda1002x_config philips_cu1216_config_altaddress = { + .demod_address = 0x0d, + .invert = 0, +}; + +static struct tda10023_config philips_cu1216_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static int philips_tu1216_tuner_init(struct dvb_frontend *fe) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; + + // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + return 0; +} + +static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget *budget = (struct budget *) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = c->frequency + 36166000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + // determine band + if (c->frequency < 49000000) + return -EINVAL; + else if (c->frequency < 161000000) + band = 1; + else if (c->frequency < 444000000) + band = 2; + else if (c->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter + switch (c->bandwidth_hz) { + case 6000000: + filter = 0; + break; + + case 7000000: + filter = 0; + break; + + case 8000000: + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; + + // setup tuner buffer + tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tu1216_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + +static struct tda1004x_config philips_tu1216_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 1, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = philips_tu1216_request_firmware, +}; + +static u8 philips_sd1878_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, + 0x05, 0x35, + 0x06, 0x40, + 0x07, 0x00, + 0x08, 0x43, + 0x09, 0x02, + 0x0C, 0x51, + 0x0D, 0x82, + 0x0E, 0x23, + 0x10, 0x3f, + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, + 0x16, 0x19, + 0x17, 0x8c, + 0x18, 0x59, + 0x19, 0xf8, + 0x1a, 0xfe, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x09, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x93, + 0xff, 0xff +}; + +static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + + aclk = 0xb5; + if (srate < 2000000) + bclk = 0x86; + else if (srate < 5000000) + bclk = 0x89; + else if (srate < 15000000) + bclk = 0x8f; + else if (srate < 45000000) + bclk = 0x95; + + m1 = 0x14; + if (srate < 4000000) + m1 = 0x10; + + stv0299_writereg(fe, 0x0e, 0x23); + stv0299_writereg(fe, 0x0f, 0x94); + stv0299_writereg(fe, 0x10, 0x39); + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x15, 0xc9); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + stv0299_writereg(fe, 0x0f, 0x80 | m1); + + return 0; +} + +static struct stv0299_config philips_sd1878_config = { + .demod_address = 0x68, + .inittab = philips_sd1878_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, +}; + +/* KNC1 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x08 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x33 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xee }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +/* STB0899 demodulator config for the KNC1 and clones */ +static struct stb0899_config knc1_dvbs2_config = { + .init_dev = knc1_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = knc1_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, +// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ + .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ +// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_OFF, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 90000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = tda8261_get_frequency, + .tuner_set_frequency = tda8261_set_frequency, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = tda8261_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +/* + * SD1878/SHA tuner config + * 1F, Single I/P, Horizontal mount, High Sensitivity + */ +static const struct tda8261_config sd1878c_config = { +// .name = "SD1878/SHA", + .addr = 0x60, + .step_size = TDA8261_STEP_1000 /* kHz */ +}; + +static u8 read_pwm(struct budget_av *budget_av) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, + {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} + }; + + if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +#define SUBID_DVBS_KNC1 0x0010 +#define SUBID_DVBS_KNC1_PLUS 0x0011 +#define SUBID_DVBS_TYPHOON 0x4f56 +#define SUBID_DVBS_CINERGY1200 0x1154 +#define SUBID_DVBS_CYNERGY1200N 0x1155 +#define SUBID_DVBS_TV_STAR 0x0014 +#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 +#define SUBID_DVBS_TV_STAR_CI 0x0016 +#define SUBID_DVBS2_KNC1 0x0018 +#define SUBID_DVBS2_KNC1_OEM 0x0019 +#define SUBID_DVBS_EASYWATCH_1 0x001a +#define SUBID_DVBS_EASYWATCH_2 0x001b +#define SUBID_DVBS2_EASYWATCH 0x001d +#define SUBID_DVBS_EASYWATCH 0x001e + +#define SUBID_DVBC_EASYWATCH 0x002a +#define SUBID_DVBC_EASYWATCH_MK3 0x002c +#define SUBID_DVBC_KNC1 0x0020 +#define SUBID_DVBC_KNC1_PLUS 0x0021 +#define SUBID_DVBC_KNC1_MK3 0x0022 +#define SUBID_DVBC_KNC1_TDA10024 0x0028 +#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 +#define SUBID_DVBC_CINERGY1200 0x1156 +#define SUBID_DVBC_CINERGY1200_MK3 0x1176 + +#define SUBID_DVBT_EASYWATCH 0x003a +#define SUBID_DVBT_KNC1_PLUS 0x0031 +#define SUBID_DVBT_KNC1 0x0030 +#define SUBID_DVBT_CINERGY1200 0x1157 + +static void frontend_init(struct budget_av *budget_av) +{ + struct saa7146_dev * saa = budget_av->budget.dev; + struct dvb_frontend * fe = NULL; + + /* Enable / PowerON Frontend */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + + /* Wait for PowerON */ + msleep(100); + + /* additional setup necessary for the PLUS cards */ + switch (saa->pci->subsystem_device) { + case SUBID_DVBS_KNC1_PLUS: + case SUBID_DVBC_KNC1_PLUS: + case SUBID_DVBT_KNC1_PLUS: + case SUBID_DVBC_EASYWATCH: + case SUBID_DVBC_KNC1_PLUS_MK3: + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); + break; + } + + switch (saa->pci->subsystem_device) { + + case SUBID_DVBS_KNC1: + /* + * maybe that setting is needed for other dvb-s cards as well, + * but so far it has been only confirmed for this type + */ + budget_av->reinitialise_demod = 1; + /* fall through */ + case SUBID_DVBS_KNC1_PLUS: + case SUBID_DVBS_EASYWATCH_1: + if (saa->pci->subsystem_vendor == 0x1894) { + fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config, + &budget_av->budget.i2c_adap); + if (fe) { + dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap); + } + } else { + fe = dvb_attach(stv0299_attach, &typhoon_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } + } + break; + + case SUBID_DVBS_TV_STAR: + case SUBID_DVBS_TV_STAR_PLUS_X4: + case SUBID_DVBS_TV_STAR_CI: + case SUBID_DVBS_CYNERGY1200N: + case SUBID_DVBS_EASYWATCH: + case SUBID_DVBS_EASYWATCH_2: + fe = dvb_attach(stv0299_attach, &philips_sd1878_config, + &budget_av->budget.i2c_adap); + if (fe) { + dvb_attach(dvb_pll_attach, fe, 0x60, + &budget_av->budget.i2c_adap, + DVB_PLL_PHILIPS_SD1878_TDA8261); + } + break; + + case SUBID_DVBS_TYPHOON: + fe = dvb_attach(stv0299_attach, &typhoon_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } + break; + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: + budget_av->reinitialise_demod = 1; + if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) + dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); + + break; + case SUBID_DVBS_CINERGY1200: + fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } + break; + + case SUBID_DVBC_KNC1: + case SUBID_DVBC_KNC1_PLUS: + case SUBID_DVBC_CINERGY1200: + case SUBID_DVBC_EASYWATCH: + budget_av->reinitialise_demod = 1; + budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + fe = dvb_attach(tda10021_attach, &philips_cu1216_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); + if (fe == NULL) + fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); + if (fe) { + fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; + } + break; + + case SUBID_DVBC_EASYWATCH_MK3: + case SUBID_DVBC_CINERGY1200_MK3: + case SUBID_DVBC_KNC1_MK3: + case SUBID_DVBC_KNC1_TDA10024: + case SUBID_DVBC_KNC1_PLUS_MK3: + budget_av->reinitialise_demod = 1; + budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + fe = dvb_attach(tda10023_attach, + &philips_cu1216_tda10023_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); + if (fe) { + fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; + } + break; + + case SUBID_DVBT_EASYWATCH: + case SUBID_DVBT_KNC1: + case SUBID_DVBT_KNC1_PLUS: + case SUBID_DVBT_CINERGY1200: + budget_av->reinitialise_demod = 1; + fe = dvb_attach(tda10046_attach, &philips_tu1216_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.init = philips_tu1216_tuner_init; + fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; + } + break; + } + + if (fe == NULL) { + pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + saa->pci->vendor, + saa->pci->device, + saa->pci->subsystem_vendor, + saa->pci->subsystem_device); + return; + } + + budget_av->budget.dvb_frontend = fe; + + if (dvb_register_frontend(&budget_av->budget.dvb_adapter, + budget_av->budget.dvb_frontend)) { + pr_err("Frontend registration failed!\n"); + dvb_frontend_detach(budget_av->budget.dvb_frontend); + budget_av->budget.dvb_frontend = NULL; + } +} + + +static void budget_av_irq(struct saa7146_dev *dev, u32 * isr) +{ + struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; + + dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); + + if (*isr & MASK_10) + ttpci_budget_irq10_handler(dev, isr); +} + +static int budget_av_detach(struct saa7146_dev *dev) +{ + struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; + int err; + + dprintk(2, "dev: %p\n", dev); + + if (1 == budget_av->has_saa7113) { + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); + + msleep(200); + + saa7146_unregister_device(&budget_av->vd, dev); + + saa7146_vv_release(dev); + } + + if (budget_av->budget.ci_present) + ciintf_deinit(budget_av); + + if (budget_av->budget.dvb_frontend != NULL) { + dvb_unregister_frontend(budget_av->budget.dvb_frontend); + dvb_frontend_detach(budget_av->budget.dvb_frontend); + } + err = ttpci_budget_deinit(&budget_av->budget); + + kfree(budget_av); + + return err; +} + +#define KNC1_INPUTS 2 +static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { + { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, + V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, + V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, +}; + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index); + if (i->index >= KNC1_INPUTS) + return -EINVAL; + memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; + + *i = budget_av->cur_input; + + dprintk(1, "VIDIOC_G_INPUT %d\n", *i); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; + + dprintk(1, "VIDIOC_S_INPUT %d\n", input); + return saa7113_setinput(budget_av, input); +} + +static struct saa7146_ext_vv vv_data; + +static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct budget_av *budget_av; + u8 *mac; + int err; + + dprintk(2, "dev: %p\n", dev); + + if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) + return -ENOMEM; + + budget_av->has_saa7113 = 0; + budget_av->budget.ci_present = 0; + + dev->ext_priv = budget_av; + + err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, + adapter_nr); + if (err) { + kfree(budget_av); + return err; + } + + /* knc1 initialization */ + saa7146_write(dev, DD1_STREAM_B, 0x04000000); + saa7146_write(dev, DD1_INIT, 0x07000600); + saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); + + if (saa7113_init(budget_av) == 0) { + budget_av->has_saa7113 = 1; + + if (0 != saa7146_vv_init(dev, &vv_data)) { + /* fixme: proper cleanup here */ + ERR("cannot init vv subsystem\n"); + return err; + } + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; + vv_data.vid_ops.vidioc_g_input = vidioc_g_input; + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; + + if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { + /* fixme: proper cleanup here */ + ERR("cannot register capture v4l2 device\n"); + saa7146_vv_release(dev); + return err; + } + + /* beware: this modifies dev->vv ... */ + saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, + SAA7146_HPS_SYNC_PORT_A); + + saa7113_setinput(budget_av, 0); + } + + /* fixme: find some sane values here... */ + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + + mac = budget_av->budget.dvb_adapter.proposed_mac; + if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { + pr_err("KNC1-%d: Could not read MAC from KNC1 card\n", + budget_av->budget.dvb_adapter.num); + memset(mac, 0, 6); + } else { + pr_info("KNC1-%d: MAC addr = %pM\n", + budget_av->budget.dvb_adapter.num, mac); + } + + budget_av->budget.dvb_adapter.priv = budget_av; + frontend_init(budget_av); + ciintf_init(budget_av); + + ttpci_budget_init_hooks(&budget_av->budget); + + return 0; +} + +static struct saa7146_standard standard[] = { + {.name = "PAL",.id = V4L2_STD_PAL, + .v_offset = 0x17,.v_field = 288, + .h_offset = 0x14,.h_pixels = 680, + .v_max_out = 576,.h_max_out = 768 }, + + {.name = "NTSC",.id = V4L2_STD_NTSC, + .v_offset = 0x16,.v_field = 240, + .h_offset = 0x06,.h_pixels = 708, + .v_max_out = 480,.h_max_out = 640, }, +}; + +static struct saa7146_ext_vv vv_data = { + .inputs = 2, + .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 + .flags = 0, + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), +}; + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); +MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); +MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); +MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); +MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); +MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); +MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); +MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); +MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); +MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); +MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); +MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); +MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024); +MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); +MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); +MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); +MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); +MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); +MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); +MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), + MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), + MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), + MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), + MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), + MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), + MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), + MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), + MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), + MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), + MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), + MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), + MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), + MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), + MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), + MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), + MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), + MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), + MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028), + MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), + MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), + MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), + MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), + MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), + MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), + MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), + MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_extension budget_extension = { + .name = "budget_av", + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = pci_tbl, + + .module = THIS_MODULE, + .attach = budget_av_attach, + .detach = budget_av_detach, + + .irq_mask = MASK_10, + .irq_func = budget_av_irq, +}; + +static int __init budget_av_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_av_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_av_init); +module_exit(budget_av_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c new file mode 100644 index 00000000000..98e52417876 --- /dev/null +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -0,0 +1,1591 @@ +/* + * budget-ci.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold + * + * msp430 IR support contributed by Jack Thomasson + * partially based on the Siemens DVB driver by Ralph+Marcus Metzler + * + * CI interface support (c) 2004 Andrew de Quincey + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include +#include + +#include "budget.h" + +#include "dvb_ca_en50221.h" +#include "stv0299.h" +#include "stv0297.h" +#include "tda1004x.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "stb6100.h" +#include "stb6100_cfg.h" +#include "lnbp21.h" +#include "bsbe1.h" +#include "bsru6.h" +#include "tda1002x.h" +#include "tda827x.h" +#include "bsbe1-d01a.h" + +#define MODULE_NAME "budget_ci" + +/* + * Regarding DEBIADDR_IR: + * Some CI modules hang if random addresses are read. + * Using address 0x4000 for the IR read means that we + * use the same address as for CI version, which should + * be a safe default. + */ +#define DEBIADDR_IR 0x4000 +#define DEBIADDR_CICONTROL 0x0000 +#define DEBIADDR_CIVERSION 0x4000 +#define DEBIADDR_IO 0x1000 +#define DEBIADDR_ATTR 0x3000 + +#define CICONTROL_RESET 0x01 +#define CICONTROL_ENABLETS 0x02 +#define CICONTROL_CAMDETECT 0x08 + +#define DEBICICTL 0x00420000 +#define DEBICICAM 0x02420000 + +#define SLOTSTATUS_NONE 1 +#define SLOTSTATUS_PRESENT 2 +#define SLOTSTATUS_RESET 4 +#define SLOTSTATUS_READY 8 +#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) + +/* RC5 device wildcard */ +#define IR_DEVICE_ANY 255 + +static int rc5_device = -1; +module_param(rc5_device, int, 0644); +MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); + +static int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct budget_ci_ir { + struct rc_dev *dev; + struct tasklet_struct msp430_irq_tasklet; + char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ + char phys[32]; + int rc5_device; + u32 ir_key; + bool have_command; + bool full_rc5; /* Outputs a full RC5 code */ +}; + +struct budget_ci { + struct budget budget; + struct tasklet_struct ciintf_irq_tasklet; + int slot_status; + int ci_irq; + struct dvb_ca_en50221 ca; + struct budget_ci_ir ir; + u8 tuner_pll_address; /* used for philips_tdm1316l configs */ +}; + +static void msp430_ir_interrupt(unsigned long data) +{ + struct budget_ci *budget_ci = (struct budget_ci *) data; + struct rc_dev *dev = budget_ci->ir.dev; + u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; + + /* + * The msp430 chip can generate two different bytes, command and device + * + * type1: X1CCCCCC, C = command bits (0 - 63) + * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit + * + * Each signal from the remote control can generate one or more command + * bytes and one or more device bytes. For the repeated bytes, the + * highest bit (X) is set. The first command byte is always generated + * before the first device byte. Other than that, no specific order + * seems to apply. To make life interesting, bytes can also be lost. + * + * Only when we have a command and device byte, a keypress is + * generated. + */ + + if (ir_debug) + printk("budget_ci: received byte 0x%02x\n", command); + + /* Remove repeat bit, we use every command */ + command = command & 0x7f; + + /* Is this a RC5 command byte? */ + if (command & 0x40) { + budget_ci->ir.have_command = true; + budget_ci->ir.ir_key = command & 0x3f; + return; + } + + /* It's a RC5 device byte */ + if (!budget_ci->ir.have_command) + return; + budget_ci->ir.have_command = false; + + if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && + budget_ci->ir.rc5_device != (command & 0x1f)) + return; + + if (budget_ci->ir.full_rc5) { + rc_keydown(dev, + budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key, + (command & 0x20) ? 1 : 0); + return; + } + + /* FIXME: We should generate complete scancodes for all devices */ + rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0); +} + +static int msp430_ir_init(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + struct rc_dev *dev; + int error; + + dev = rc_allocate_device(); + if (!dev) { + printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); + return -ENOMEM; + } + + snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), + "Budget-CI dvb ir receiver %s", saa->name); + snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys), + "pci-%s/ir0", pci_name(saa->pci)); + + dev->driver_name = MODULE_NAME; + dev->input_name = budget_ci->ir.name; + dev->input_phys = budget_ci->ir.phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.version = 1; + if (saa->pci->subsystem_vendor) { + dev->input_id.vendor = saa->pci->subsystem_vendor; + dev->input_id.product = saa->pci->subsystem_device; + } else { + dev->input_id.vendor = saa->pci->vendor; + dev->input_id.product = saa->pci->device; + } + dev->dev.parent = &saa->pci->dev; + + if (rc5_device < 0) + budget_ci->ir.rc5_device = IR_DEVICE_ANY; + else + budget_ci->ir.rc5_device = rc5_device; + + /* Select keymap and address */ + switch (budget_ci->budget.dev->pci->subsystem_device) { + case 0x100c: + case 0x100f: + case 0x1011: + case 0x1012: + /* The hauppauge keymap is a superset of these remotes */ + dev->map_name = RC_MAP_HAUPPAUGE; + budget_ci->ir.full_rc5 = true; + + if (rc5_device < 0) + budget_ci->ir.rc5_device = 0x1f; + break; + case 0x1010: + case 0x1017: + case 0x1019: + case 0x101a: + case 0x101b: + /* for the Technotrend 1500 bundled remote */ + dev->map_name = RC_MAP_TT_1500; + break; + default: + /* unknown remote */ + dev->map_name = RC_MAP_BUDGET_CI_OLD; + break; + } + if (!budget_ci->ir.full_rc5) + dev->scanmask = 0xff; + + error = rc_register_device(dev); + if (error) { + printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); + rc_free_device(dev); + return error; + } + + budget_ci->ir.dev = dev; + + tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, + (unsigned long) budget_ci); + + SAA7146_IER_ENABLE(saa, MASK_06); + saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); + + return 0; +} + +static void msp430_ir_deinit(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + + SAA7146_IER_DISABLE(saa, MASK_06); + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); + + rc_unregister_device(budget_ci->ir.dev); +} + +static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, + DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); +} + +static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, + DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); +} + +static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, + DEBIADDR_IO | (address & 3), 1, 1, 0); +} + +static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, + DEBIADDR_IO | (address & 3), 1, value, 1, 0); +} + +static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + struct saa7146_dev *saa = budget_ci->budget.dev; + + if (slot != 0) + return -EINVAL; + + if (budget_ci->ci_irq) { + // trigger on RISING edge during reset so we know when READY is re-asserted + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + } + budget_ci->slot_status = SLOTSTATUS_RESET; + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); + msleep(1); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); + + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + return 0; +} + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + struct saa7146_dev *saa = budget_ci->budget.dev; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + return 0; +} + +static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + struct saa7146_dev *saa = budget_ci->budget.dev; + int tmp; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); + + tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + tmp | CICONTROL_ENABLETS, 1, 0); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + return 0; +} + +static void ciintf_interrupt(unsigned long data) +{ + struct budget_ci *budget_ci = (struct budget_ci *) data; + struct saa7146_dev *saa = budget_ci->budget.dev; + unsigned int flags; + + // ensure we don't get spurious IRQs during initialisation + if (!budget_ci->budget.ci_present) + return; + + // read the CAM status + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + if (flags & CICONTROL_CAMDETECT) { + + // GPIO should be set to trigger on falling edge if a CAM is present + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); + + if (budget_ci->slot_status & SLOTSTATUS_NONE) { + // CAM insertion IRQ + budget_ci->slot_status = SLOTSTATUS_PRESENT; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + + } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { + // CAM ready (reset completed) + budget_ci->slot_status = SLOTSTATUS_READY; + dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); + + } else if (budget_ci->slot_status & SLOTSTATUS_READY) { + // FR/DA IRQ + dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); + } + } else { + + // trigger on rising edge if a CAM is not present - when a CAM is inserted, we + // only want to get the IRQ when it sets READY. If we trigger on the falling edge, + // the CAM might not actually be ready yet. + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + + // generate a CAM removal IRQ if we haven't already + if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { + // CAM removal IRQ + budget_ci->slot_status = SLOTSTATUS_NONE; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + } +} + +static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + unsigned int flags; + + // ensure we don't get spurious IRQs during initialisation + if (!budget_ci->budget.ci_present) + return -EINVAL; + + // read the CAM status + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + if (flags & CICONTROL_CAMDETECT) { + // mark it as present if it wasn't before + if (budget_ci->slot_status & SLOTSTATUS_NONE) { + budget_ci->slot_status = SLOTSTATUS_PRESENT; + } + + // during a RESET, we check if we can read from IO memory to see when CAM is ready + if (budget_ci->slot_status & SLOTSTATUS_RESET) { + if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { + budget_ci->slot_status = SLOTSTATUS_READY; + } + } + } else { + budget_ci->slot_status = SLOTSTATUS_NONE; + } + + if (budget_ci->slot_status != SLOTSTATUS_NONE) { + if (budget_ci->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } + + return 0; +} + +static int ciintf_init(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + int flags; + int result; + int ci_version; + int ca_flags; + + memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); + + // enable DEBI pins + saa7146_write(saa, MC1, MASK_27 | MASK_11); + + // test if it is there + ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); + if ((ci_version & 0xa0) != 0xa0) { + result = -ENODEV; + goto error; + } + + // determine whether a CAM is present or not + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + budget_ci->slot_status = SLOTSTATUS_NONE; + if (flags & CICONTROL_CAMDETECT) + budget_ci->slot_status = SLOTSTATUS_PRESENT; + + // version 0xa2 of the CI firmware doesn't generate interrupts + if (ci_version == 0xa2) { + ca_flags = 0; + budget_ci->ci_irq = 0; + } else { + ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | + DVB_CA_EN50221_FLAG_IRQ_FR | + DVB_CA_EN50221_FLAG_IRQ_DA; + budget_ci->ci_irq = 1; + } + + // register CI interface + budget_ci->ca.owner = THIS_MODULE; + budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; + budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; + budget_ci->ca.read_cam_control = ciintf_read_cam_control; + budget_ci->ca.write_cam_control = ciintf_write_cam_control; + budget_ci->ca.slot_reset = ciintf_slot_reset; + budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; + budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; + budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; + budget_ci->ca.data = budget_ci; + if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, + &budget_ci->ca, + ca_flags, 1)) != 0) { + printk("budget_ci: CI interface detected, but initialisation failed.\n"); + goto error; + } + + // Setup CI slot IRQ + if (budget_ci->ci_irq) { + tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); + if (budget_ci->slot_status != SLOTSTATUS_NONE) { + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); + } else { + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + } + SAA7146_IER_ENABLE(saa, MASK_03); + } + + // enable interface + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); + + // success! + printk("budget_ci: CI interface initialised\n"); + budget_ci->budget.ci_present = 1; + + // forge a fake CI IRQ so the CAM state is setup correctly + if (budget_ci->ci_irq) { + flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; + if (budget_ci->slot_status != SLOTSTATUS_NONE) + flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); + } + + return 0; + +error: + saa7146_write(saa, MC1, MASK_27); + return result; +} + +static void ciintf_deinit(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + + // disable CI interrupts + if (budget_ci->ci_irq) { + SAA7146_IER_DISABLE(saa, MASK_03); + saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); + tasklet_kill(&budget_ci->ciintf_irq_tasklet); + } + + // reset interface + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); + msleep(1); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); + + // disable TS data stream to CI interface + saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); + + // release the CA device + dvb_ca_en50221_release(&budget_ci->ca); + + // disable DEBI pins + saa7146_write(saa, MC1, MASK_27); +} + +static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) +{ + struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; + + dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); + + if (*isr & MASK_06) + tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); + + if (*isr & MASK_10) + ttpci_budget_irq10_handler(dev, isr); + + if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) + tasklet_schedule(&budget_ci->ciintf_irq_tasklet); +} + +static u8 philips_su1278_tt_inittab[] = { + 0x01, 0x0f, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x5b, + 0x05, 0x85, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x02, + 0x09, 0x00, + 0x0C, 0x01, + 0x0D, 0x81, + 0x0E, 0x44, + 0x0f, 0x14, + 0x10, 0x3c, + 0x11, 0x84, + 0x12, 0xda, + 0x13, 0x97, + 0x14, 0x95, + 0x15, 0xc9, + 0x16, 0x19, + 0x17, 0x8c, + 0x18, 0x59, + 0x19, 0xf8, + 0x1a, 0xfe, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x09, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x93, + 0xff, 0xff +}; + +static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + stv0299_writereg(fe, 0x0e, 0x44); + if (srate >= 10000000) { + stv0299_writereg(fe, 0x13, 0x97); + stv0299_writereg(fe, 0x14, 0x95); + stv0299_writereg(fe, 0x15, 0xc9); + stv0299_writereg(fe, 0x17, 0x8c); + stv0299_writereg(fe, 0x1a, 0xfe); + stv0299_writereg(fe, 0x1c, 0x7f); + stv0299_writereg(fe, 0x2d, 0x09); + } else { + stv0299_writereg(fe, 0x13, 0x99); + stv0299_writereg(fe, 0x14, 0x8d); + stv0299_writereg(fe, 0x15, 0xce); + stv0299_writereg(fe, 0x17, 0x43); + stv0299_writereg(fe, 0x1a, 0x1d); + stv0299_writereg(fe, 0x1c, 0x12); + stv0299_writereg(fe, 0x2d, 0x05); + } + stv0299_writereg(fe, 0x0e, 0x23); + stv0299_writereg(fe, 0x0f, 0x94); + stv0299_writereg(fe, 0x10, 0x39); + stv0299_writereg(fe, 0x15, 0xc9); + + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u32 div; + u8 buf[4]; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((p->frequency < 950000) || (p->frequency > 2150000)) + return -EINVAL; + + div = (p->frequency + (500 - 1)) / 500; /* round correctly */ + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; + buf[3] = 0x20; + + if (p->symbol_rate < 4000000) + buf[3] |= 1; + + if (p->frequency < 1250000) + buf[3] |= 0; + else if (p->frequency < 1550000) + buf[3] |= 0x40; + else if (p->frequency < 2050000) + buf[3] |= 0x80; + else if (p->frequency < 2150000) + buf[3] |= 0xC0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct stv0299_config philips_su1278_tt_config = { + + .demod_address = 0x68, + .inittab = philips_su1278_tt_inittab, + .mclk = 64000000UL, + .invert = 0, + .skip_reinit = 1, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 50, + .set_symbol_rate = philips_su1278_tt_set_symbol_rate, +}; + + + +static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = + sizeof(td1316_init) }; + + // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); + } + + return 0; +} + +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = p->frequency + 36130000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + // determine band + if (p->frequency < 49000000) + return -EINVAL; + else if (p->frequency < 159000000) + band = 1; + else if (p->frequency < 444000000) + band = 2; + else if (p->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter and TDA9889 + switch (p->bandwidth_hz) { + case 6000000: + tda1004x_writereg(fe, 0x0C, 0x14); + filter = 0; + break; + + case 7000000: + tda1004x_writereg(fe, 0x0C, 0x80); + filter = 0; + break; + + case 8000000: + tda1004x_writereg(fe, 0x0C, 0x14); + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + + return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); +} + +static struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 0, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = philips_tdm1316l_request_firmware, +}; + +static struct tda1004x_config philips_tdm1316l_config_invert = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = philips_tdm1316l_request_firmware, +}; + +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[5]; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, + .flags = 0, + .buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = p->frequency + 36125000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) { + cp = 3; + band = 1; + } else if (tuner_frequency < 160000000) { + cp = 5; + band = 1; + } else if (tuner_frequency < 200000000) { + cp = 6; + band = 1; + } else if (tuner_frequency < 290000000) { + cp = 3; + band = 2; + } else if (tuner_frequency < 420000000) { + cp = 5; + band = 2; + } else if (tuner_frequency < 480000000) { + cp = 6; + band = 2; + } else if (tuner_frequency < 620000000) { + cp = 3; + band = 4; + } else if (tuner_frequency < 830000000) { + cp = 5; + band = 4; + } else if (tuner_frequency < 895000000) { + cp = 7; + band = 4; + } else + return -EINVAL; + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(50); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, + .stop_during_read = 1, +}; + +static struct tda10023_config tda10023_config = { + .demod_address = 0xc, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; + +static struct tda827x_config tda827x_config = { + .config = 0, +}; + +/* TT S2-3200 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xc7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +static struct stb0899_config tt3200_config = { + .init_dev = tt3200_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = tt3200_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +static struct stb6100_config tt3200_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static void frontend_init(struct budget_ci *budget_ci) +{ + switch (budget_ci->budget.dev->pci->subsystem_device) { + case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) + budget_ci->budget.dvb_frontend = + dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; + break; + } + break; + + case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) + budget_ci->budget.dvb_frontend = + dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; + break; + } + break; + + case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) + budget_ci->tuner_pll_address = 0x61; + budget_ci->budget.dvb_frontend = + dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->tuner_pll_address = 0x63; + budget_ci->budget.dvb_frontend = + dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) + budget_ci->tuner_pll_address = 0x60; + budget_ci->budget.dvb_frontend = + dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1017: // TT S-1500 PCI + budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; + + budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { + printk("%s: No LNBP21 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ + budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */ + budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) { + if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { + printk(KERN_ERR "%s: No LNBP21 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } else { + printk(KERN_ERR "%s: No STB6000 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + case 0x1019: // TT S2-3200 PCI + /* + * NOTE! on some STB0899 versions, the internal PLL takes a longer time + * to settle, aka LOCK. On the older revisions of the chip, we don't see + * this, as a result on the newer chips the entire clock tree, will not + * be stable after a freshly POWER 'ed up situation. + * In this case, we should RESET the STB0899 (Active LOW) and wait for + * PLL stabilization. + * + * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is + * connected to the SAA7146 GPIO, GPIO2, Pin 142 + */ + /* Reset Demodulator */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); + /* Wait for everything to die */ + msleep(50); + /* Pull it up out of Reset state */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); + /* Wait for PLL to stabilize */ + msleep(250); + /* + * PLL state should be stable now. Ideally, we should check + * for PLL LOCK status. But well, never mind! + */ + budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { + if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { + printk("%s: No LNBP21 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } else { + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + } + + if (budget_ci->budget.dvb_frontend == NULL) { + printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget_ci->budget.dev->pci->vendor, + budget_ci->budget.dev->pci->device, + budget_ci->budget.dev->pci->subsystem_vendor, + budget_ci->budget.dev->pci->subsystem_device); + } else { + if (dvb_register_frontend + (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { + printk("budget-ci: Frontend registration failed!\n"); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } +} + +static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct budget_ci *budget_ci; + int err; + + budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL); + if (!budget_ci) { + err = -ENOMEM; + goto out1; + } + + dprintk(2, "budget_ci: %p\n", budget_ci); + + dev->ext_priv = budget_ci; + + err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, + adapter_nr); + if (err) + goto out2; + + err = msp430_ir_init(budget_ci); + if (err) + goto out3; + + ciintf_init(budget_ci); + + budget_ci->budget.dvb_adapter.priv = budget_ci; + frontend_init(budget_ci); + + ttpci_budget_init_hooks(&budget_ci->budget); + + return 0; + +out3: + ttpci_budget_deinit(&budget_ci->budget); +out2: + kfree(budget_ci); +out1: + return err; +} + +static int budget_ci_detach(struct saa7146_dev *dev) +{ + struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; + struct saa7146_dev *saa = budget_ci->budget.dev; + int err; + + if (budget_ci->budget.ci_present) + ciintf_deinit(budget_ci); + msp430_ir_deinit(budget_ci); + if (budget_ci->budget.dvb_frontend) { + dvb_unregister_frontend(budget_ci->budget.dvb_frontend); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + } + err = ttpci_budget_deinit(&budget_ci->budget); + + // disable frontend and CI interface + saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); + + kfree(budget_ci); + + return err; +} + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); +MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), + MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), + MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), + MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), + MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), + MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), + MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), + MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), + MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_extension budget_extension = { + .name = "budget_ci dvb", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = &pci_tbl[0], + .attach = budget_ci_attach, + .detach = budget_ci_detach, + + .irq_mask = MASK_03 | MASK_06 | MASK_10, + .irq_func = budget_ci_irq, +}; + +static int __init budget_ci_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_ci_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_ci_init); +module_exit(budget_ci_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB cards w/ CI-module produced by " + "Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c new file mode 100644 index 00000000000..37d02fe0913 --- /dev/null +++ b/drivers/media/pci/ttpci/budget-core.c @@ -0,0 +1,602 @@ +/* + * budget-core.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 26feb2004 Support for FS Activy Card (Grundig tuner) by + * Michael Dreher , + * Oliver Endriss , + * Andreas 'randy' Weinberger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + + +#include "budget.h" +#include "ttpci-eeprom.h" + +#define TS_WIDTH (2 * TS_SIZE) +#define TS_WIDTH_ACTIVY TS_SIZE +#define TS_WIDTH_DVBC TS_SIZE +#define TS_HEIGHT_MASK 0xf00 +#define TS_HEIGHT_MASK_ACTIVY 0xc00 +#define TS_HEIGHT_MASK_DVBC 0xe00 +#define TS_MIN_BUFSIZE_K 188 +#define TS_MAX_BUFSIZE_K 1410 +#define TS_MAX_BUFSIZE_K_ACTIVY 564 +#define TS_MAX_BUFSIZE_K_DVBC 1316 +#define BUFFER_WARNING_WAIT (30*HZ) + +int budget_debug; +static int dma_buffer_size = TS_MIN_BUFSIZE_K; +module_param_named(debug, budget_debug, int, 0644); +module_param_named(bufsize, dma_buffer_size, int, 0444); +MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); +MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); + +/**************************************************************************** + * TT budget / WinTV Nova + ****************************************************************************/ + +static int stop_ts_capture(struct budget *budget) +{ + dprintk(2, "budget: %p\n", budget); + + saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off + SAA7146_IER_DISABLE(budget->dev, MASK_10); + return 0; +} + +static int start_ts_capture(struct budget *budget) +{ + struct saa7146_dev *dev = budget->dev; + + dprintk(2, "budget: %p\n", budget); + + if (!budget->feeding || !budget->fe_synced) + return 0; + + saa7146_write(dev, MC1, MASK_20); // DMA3 off + + memset(budget->grabbing, 0x00, budget->buffer_size); + + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + + budget->ttbp = 0; + + /* + * Signal path on the Activy: + * + * tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory + * + * Since the tuner feeds 204 bytes packets into the SAA7146, + * DMA3 is configured to strip the trailing 16 FEC bytes: + * Pitch: 188, NumBytes3: 188, NumLines3: 1024 + */ + + switch(budget->card->type) { + case BUDGET_FS_ACTIVY: + saa7146_write(dev, DD1_INIT, 0x04000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25)); + saa7146_write(dev, BRS_CTRL, 0x00000000); + break; + case BUDGET_PATCH: + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + break; + case BUDGET_CIN1200C_MK3: + case BUDGET_KNC1C_MK3: + case BUDGET_KNC1C_TDA10024: + case BUDGET_KNC1CP_MK3: + if (budget->video_port == BUDGET_VIDEO_PORTA) { + saa7146_write(dev, DD1_INIT, 0x06000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x00000000); + } else { + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + } + break; + default: + if (budget->video_port == BUDGET_VIDEO_PORTA) { + saa7146_write(dev, DD1_INIT, 0x06000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x00000000); + } else { + saa7146_write(dev, DD1_INIT, 0x02000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + } + } + + saa7146_write(dev, MC2, (MASK_08 | MASK_24)); + mdelay(10); + + saa7146_write(dev, BASE_ODD3, 0); + if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { + // using odd/even buffers + saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); + } else { + // using a single buffer + saa7146_write(dev, BASE_EVEN3, 0); + } + saa7146_write(dev, PROT_ADDR3, budget->buffer_size); + saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); + + saa7146_write(dev, PITCH3, budget->buffer_width); + saa7146_write(dev, NUM_LINE_BYTE3, + (budget->buffer_height << 16) | budget->buffer_width); + + saa7146_write(dev, MC2, (MASK_04 | MASK_20)); + + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ + + return 0; +} + +static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + int synced; + int ret; + + if (budget->read_fe_status) + ret = budget->read_fe_status(fe, status); + else + ret = -EINVAL; + + if (!ret) { + synced = (*status & FE_HAS_LOCK); + if (synced != budget->fe_synced) { + budget->fe_synced = synced; + spin_lock(&budget->feedlock); + if (synced) + start_ts_capture(budget); + else + stop_ts_capture(budget); + spin_unlock(&budget->feedlock); + } + } + return ret; +} + +static void vpeirq(unsigned long data) +{ + struct budget *budget = (struct budget *) data; + u8 *mem = (u8 *) (budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + u32 count; + + /* Ensure streamed PCI data is synced to CPU */ + pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); + + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= budget->buffer_size) + return; + + budget->ttbp = newdma; + + if (budget->feeding == 0 || newdma == olddma) + return; + + if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ + count = newdma - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); + } else { /* wraparound, dump olddma..buflen and 0..newdma */ + count = budget->buffer_size - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); + count += newdma; + dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); + } + + if (count > budget->buffer_warning_threshold) + budget->buffer_warnings++; + + if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { + printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", + budget->dev->name, __func__, budget->buffer_warnings, count); + budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; + budget->buffer_warnings = 0; + } +} + + +int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + int result = 0; + unsigned long flags = 0; + + if (count > 4 || count <= 0) + return 0; + + if (uselocks) + spin_lock_irqsave(&budget->debilock, flags); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, DEBI_PAGE, 0); + saa7146_write(saa, MC2, (2 << 16) | 2); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + result = saa7146_read(saa, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + + return result; +} + +int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, + int count, u32 value, int uselocks, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + unsigned long flags = 0; + int result; + + if (count > 4 || count <= 0) + return 0; + + if (uselocks) + spin_lock_irqsave(&budget->debilock, flags); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, DEBI_PAGE, 0); + saa7146_write(saa, DEBI_AD, value); + saa7146_write(saa, MC2, (2 << 16) | 2); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return 0; +} + + +/**************************************************************************** + * DVB API SECTION + ****************************************************************************/ + +static int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct budget *budget = (struct budget *) demux->priv; + int status = 0; + + dprintk(2, "budget: %p\n", budget); + + if (!demux->dmx.frontend) + return -EINVAL; + + spin_lock(&budget->feedlock); + feed->pusi_seen = 0; /* have a clean section start */ + if (budget->feeding++ == 0) + status = start_ts_capture(budget); + spin_unlock(&budget->feedlock); + return status; +} + +static int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct budget *budget = (struct budget *) demux->priv; + int status = 0; + + dprintk(2, "budget: %p\n", budget); + + spin_lock(&budget->feedlock); + if (--budget->feeding == 0) + status = stop_ts_capture(budget); + spin_unlock(&budget->feedlock); + return status; +} + +static int budget_register(struct budget *budget) +{ + struct dvb_demux *dvbdemux = &budget->demux; + int ret; + + dprintk(2, "budget: %p\n", budget); + + dvbdemux->priv = (void *) budget; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = budget_start_feed; + dvbdemux->stop_feed = budget_stop_feed; + dvbdemux->write_to_decoder = NULL; + + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&budget->demux); + + budget->dmxdev.filternum = 256; + budget->dmxdev.demux = &dvbdemux->dmx; + budget->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter); + + budget->hw_frontend.source = DMX_FRONTEND_0; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); + + if (ret < 0) + return ret; + + budget->mem_frontend.source = DMX_MEMORY_FE; + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); + if (ret < 0) + return ret; + + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); + if (ret < 0) + return ret; + + dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); + + return 0; +} + +static void budget_unregister(struct budget *budget) +{ + struct dvb_demux *dvbdemux = &budget->demux; + + dprintk(2, "budget: %p\n", budget); + + dvb_net_release(&budget->dvb_net); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend); + + dvb_dmxdev_release(&budget->dmxdev); + dvb_dmx_release(&budget->demux); +} + +int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, + struct saa7146_pci_extension_data *info, + struct module *owner, short *adapter_nums) +{ + int ret = 0; + struct budget_info *bi = info->ext_priv; + int max_bufsize; + int height_mask; + + memset(budget, 0, sizeof(struct budget)); + + dprintk(2, "dev: %p, budget: %p\n", dev, budget); + + budget->card = bi; + budget->dev = (struct saa7146_dev *) dev; + + switch(budget->card->type) { + case BUDGET_FS_ACTIVY: + budget->buffer_width = TS_WIDTH_ACTIVY; + max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; + height_mask = TS_HEIGHT_MASK_ACTIVY; + break; + + case BUDGET_KNC1C: + case BUDGET_KNC1CP: + case BUDGET_CIN1200C: + case BUDGET_KNC1C_MK3: + case BUDGET_KNC1C_TDA10024: + case BUDGET_KNC1CP_MK3: + case BUDGET_CIN1200C_MK3: + budget->buffer_width = TS_WIDTH_DVBC; + max_bufsize = TS_MAX_BUFSIZE_K_DVBC; + height_mask = TS_HEIGHT_MASK_DVBC; + break; + + default: + budget->buffer_width = TS_WIDTH; + max_bufsize = TS_MAX_BUFSIZE_K; + height_mask = TS_HEIGHT_MASK; + } + + if (dma_buffer_size < TS_MIN_BUFSIZE_K) + dma_buffer_size = TS_MIN_BUFSIZE_K; + else if (dma_buffer_size > max_bufsize) + dma_buffer_size = max_bufsize; + + budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; + if (budget->buffer_height > 0xfff) { + budget->buffer_height /= 2; + budget->buffer_height &= height_mask; + budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; + } else { + budget->buffer_height &= height_mask; + budget->buffer_size = budget->buffer_height * budget->buffer_width; + } + budget->buffer_warning_threshold = budget->buffer_size * 80/100; + budget->buffer_warnings = 0; + budget->buffer_warning_time = jiffies; + + dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", + budget->dev->name, + budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", + budget->buffer_width, budget->buffer_height); + printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); + + ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, + owner, &budget->dev->pci->dev, adapter_nums); + if (ret < 0) + return ret; + + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25)); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + saa7146_write(dev, DD1_INIT, 0x02000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + if (bi->type != BUDGET_FS_ACTIVY) + budget->video_port = BUDGET_VIDEO_PORTB; + else + budget->video_port = BUDGET_VIDEO_PORTA; + spin_lock_init(&budget->feedlock); + spin_lock_init(&budget->debilock); + + /* the Siemens DVB needs this if you want to have the i2c chips + get recognized before the main driver is loaded */ + if (bi->type != BUDGET_FS_ACTIVY) + saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ + + strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name)); + + saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); + strcpy(budget->i2c_adap.name, budget->card->name); + + if (i2c_add_adapter(&budget->i2c_adap) < 0) { + ret = -ENOMEM; + goto err_dvb_unregister; + } + + ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); + + budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt); + if (NULL == budget->grabbing) { + ret = -ENOMEM; + goto err_del_i2c; + } + + saa7146_write(dev, PCI_BT_V1, 0x001c0000); + /* upload all */ + saa7146_write(dev, GPIO_CTRL, 0x000000); + + tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); + + /* frontend power on */ + if (bi->type != BUDGET_FS_ACTIVY) + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + if ((ret = budget_register(budget)) == 0) + return 0; /* Everything OK */ + + /* An error occurred, cleanup resources */ + saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); + +err_del_i2c: + i2c_del_adapter(&budget->i2c_adap); + +err_dvb_unregister: + dvb_unregister_adapter(&budget->dvb_adapter); + + return ret; +} + +void ttpci_budget_init_hooks(struct budget *budget) +{ + if (budget->dvb_frontend && !budget->read_fe_status) { + budget->read_fe_status = budget->dvb_frontend->ops.read_status; + budget->dvb_frontend->ops.read_status = budget_read_fe_status; + } +} + +int ttpci_budget_deinit(struct budget *budget) +{ + struct saa7146_dev *dev = budget->dev; + + dprintk(2, "budget: %p\n", budget); + + budget_unregister(budget); + + tasklet_kill(&budget->vpe_tasklet); + + saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); + + i2c_del_adapter(&budget->i2c_adap); + + dvb_unregister_adapter(&budget->dvb_adapter); + + return 0; +} + +void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr) +{ + struct budget *budget = (struct budget *) dev->ext_priv; + + dprintk(8, "dev: %p, budget: %p\n", dev, budget); + + if (*isr & MASK_10) + tasklet_schedule(&budget->vpe_tasklet); +} + +void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) +{ + struct budget *budget = (struct budget *) dev->ext_priv; + + spin_lock(&budget->feedlock); + budget->video_port = video_port; + if (budget->feeding) { + stop_ts_capture(budget); + start_ts_capture(budget); + } + spin_unlock(&budget->feedlock); +} + +EXPORT_SYMBOL_GPL(ttpci_budget_debiread); +EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); +EXPORT_SYMBOL_GPL(ttpci_budget_init); +EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks); +EXPORT_SYMBOL_GPL(ttpci_budget_deinit); +EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); +EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); +EXPORT_SYMBOL_GPL(budget_debug); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c new file mode 100644 index 00000000000..2cb35c23d2a --- /dev/null +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -0,0 +1,680 @@ +/* + * budget-patch.c: driver for Budget Patch, + * hardware modification of DVB-S cards enabling full TS + * + * Written by Emard + * + * Original idea by Roberto Deza + * + * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic + * and Metzlerbros + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include "av7110.h" +#include "av7110_hw.h" +#include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "tda8083.h" + +#include "bsru6.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define budget_patch budget + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); +//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), +// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + { + .vendor = 0, + } +}; + +/* those lines are for budget-patch to be tried +** on a true budget card and observe the +** behaviour of VSYNC generated by rps1. +** this code was shamelessly copy/pasted from budget.c +*/ +static void gpio_Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler */ + +static void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + +static void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + dprintk(2, "budget: %p\n", budget); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + +static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) +{ + struct saa7146_dev *dev=budget->dev; + int i; + + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; idvb->priv; + + switch (tone) { + case SEC_TONE_ON: + gpio_Set22K (budget, 1); + break; + + case SEC_TONE_OFF: + gpio_Set22K (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, 0, NULL, minicmd); + + return 0; +} + +static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) +{ + int i; + + dprintk(2, "budget: %p\n", budget); + + for (i = 2; i < length; i++) + { + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); + msleep(5); + } + if (length) + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); + else + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); + msleep(5); + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); + msleep(5); + return 0; +} + +static void av7110_set22k(struct budget_patch *budget, int state) +{ + u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; + + dprintk(2, "budget: %p\n", budget); + budget_av7110_send_fw_cmd(budget, buf, 2); +} + +static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) +{ + int i; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(2, "budget: %p\n", budget); + + if (len>10) + len=10; + + buf[1] = len+2; + buf[2] = len; + + if (burst != -1) + buf[3]=burst ? 0x01 : 0x00; + else + buf[3]=0xffff; + + for (i=0; idvb->priv; + + switch (tone) { + case SEC_TONE_ON: + av7110_set22k (budget, 1); + break; + + case SEC_TONE_OFF: + av7110_set22k (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, 0, NULL, minicmd); + + return 0; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (p->frequency + 479500) / 125; + + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = p->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + +static void frontend_init(struct budget_patch* budget) +{ + switch(budget->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x1013: // SATELCO Multimedia PCI + + // try the ALPS BSRV2 first of all + budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + + // Try the grundig 29504-451 + budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { + printk("budget-av: Frontend registration failed!\n"); + dvb_frontend_detach(budget->dvb_frontend); + budget->dvb_frontend = NULL; + } + } +} + +/* written by Emard */ +static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget_patch *budget; + int err; + int count = 0; + int detected = 0; + +#define PATCH_RESET 0 +#define RPS_IRQ 0 +#define HPS_SETUP 0 +#if PATCH_RESET + saa7146_write(dev, MC1, MASK_31); + msleep(40); +#endif +#if HPS_SETUP + // initialize registers. Better to have it like this + // than leaving something unconfigured + saa7146_write(dev, DD1_STREAM_B, 0); + // port B VSYNC at rising edge + saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + + // debi config + // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); + + // zero all HPS registers + saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 + saa7146_write(dev, HPS_H_SCALE, 0); // r6c + saa7146_write(dev, BCS_CTRL, 0); // r70 + saa7146_write(dev, HPS_V_SCALE, 0); // r60 + saa7146_write(dev, HPS_V_GAIN, 0); // r64 + saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 + saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 + // Set HPS prescaler for port B input + saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); + saa7146_write(dev, MC2, + 0 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 0 * (MASK_10 | MASK_26) | // b + 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); +#endif + // Disable RPS1 and RPS0 + saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); + // RPS1 timeout disable + saa7146_write(dev, RPS_TOV1, 0); + + // code for autodetection + // will wait for VBI_B event (vertical blank at port B) + // and will reset GPIO3 after VBI_B is detected. + // (GPIO3 should be raised high by CPU to + // test if GPIO3 will generate vertical blank signal + // in budget patch GPIO3 is connected to VSYNC_B + count = 0; +#if 0 + WRITE_RPS1(CMD_UPLOAD | + MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); +#endif + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + // issue RPS1 interrupt to increment counter + WRITE_RPS1(CMD_INTERRUPT); + // at least a NOP is neede between two interrupts + WRITE_RPS1(CMD_NOP); + // interrupt again + WRITE_RPS1(CMD_INTERRUPT); +#endif + WRITE_RPS1(CMD_STOP); + +#if RPS_IRQ + // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + // set event counter 1 threshold to maximum allowed value (rEC p55) + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + // Enable RPS1, (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + + mdelay(50); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(150); + + + if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) + detected = 1; + +#if RPS_IRQ + printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + // Disable RPS1 + saa7146_write(dev, MC1, ( MASK_29 )); + + if(detected == 0) + printk("budget-patch not detected or saa7146 in non-default state.\n" + "try enabling ressetting of 7146 with MASK_31 in MC1 register\n"); + + else + printk("BUDGET-PATCH DETECTED.\n"); + + +/* OLD (Original design by Roberto Deza): +** This code will setup the SAA7146_RPS1 to generate a square +** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of +** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; +** then, this GPIO3 output which is connected to the D1B_VSYNC +** input, will trigger the acquisition of the alternate field +** and so on. +** Currently, the TT_budget / WinTV_Nova cards have two ICs +** (74HCT4040, LVC74) for the generation of this VSYNC signal, +** which seems that can be done perfectly without this :-)). +*/ + +/* New design (By Emard) +** this rps1 code will copy internal HS event to GPIO3 pin. +** GPIO3 is in budget-patch hardware connected to port B VSYNC + +** HS is an internal event of 7146, accessible with RPS +** and temporarily raised high every n lines +** (n in defined in the RPS_THRESH1 counter threshold) +** I think HS is raised high on the beginning of the n-th line +** and remains high until this n-th line that triggered +** it is completely received. When the reception of n-th line +** ends, HS is lowered. + +** To transmit data over DMA, 7146 needs changing state at +** port B VSYNC pin. Any changing of port B VSYNC will +** cause some DMA data transfer, with more or less packets loss. +** It depends on the phase and frequency of VSYNC and +** the way of 7146 is instructed to trigger on port B (defined +** in DD1_INIT register, 3rd nibble from the right valid +** numbers are 0-7, see datasheet) +** +** The correct triggering can minimize packet loss, +** dvbtraffic should give this stable bandwidths: +** 22k transponder = 33814 kbit/s +** 27.5k transponder = 38045 kbit/s +** by experiment it is found that the best results +** (stable bandwidths and almost no packet loss) +** are obtained using DD1_INIT triggering number 2 +** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) +** and a VSYNC phase that occurs in the middle of DMA transfer +** (about byte 188*512=96256 in the DMA window). +** +** Phase of HS is still not clear to me how to control, +** It just happens to be so. It can be seen if one enables +** RPS_IRQ and print Event Counter 1 in vpeirq(). Every +** time RPS_INTERRUPT is called, the Event Counter 1 will +** increment. That's how the 7146 is programmed to do event +** counting in this budget-patch.c +** I *think* HPS setting has something to do with the phase +** of HS but I can't be 100% sure in that. + +** hardware debug note: a working budget card (including budget patch) +** with vpeirq() interrupt setup in mode "0x90" (every 64K) will +** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes +** and that means 3*25=75 Hz of interrupt frequency, as seen by +** watch cat /proc/interrupts +** +** If this frequency is 3x lower (and data received in the DMA +** buffer don't start with 0x47, but in the middle of packets, +** whose lengths appear to be like 188 292 188 104 etc. +** this means VSYNC line is not connected in the hardware. +** (check soldering pcb and pins) +** The same behaviour of missing VSYNC can be duplicated on budget +** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. +*/ + + // Setup RPS1 "program" (p35) + count = 0; + + + // Wait Source Line Counter Threshold (p36) + WRITE_RPS1(CMD_PAUSE | EVT_HS); + // Set GPIO3=1 (p42) + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(CMD_INTERRUPT); +#endif + // Wait reset Source Line Counter Threshold (p36) + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); + // Set GPIO3=0 (p42) + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(CMD_INTERRUPT); +#endif + // Jump to begin of RPS program (p37) + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + + if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) + return -ENOMEM; + + dprintk(2, "budget: %p\n", budget); + + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { + kfree(budget); + return err; + } + + // Set Source Line Counter Threshold, using BRS (rCC p43) + // It generates HS event every TS_HEIGHT lines + // this is related to TS_WIDTH set in register + // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE + // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 + //,then RPS_THRESH1 + // should be set to trigger every TS_HEIGHT (512) lines. + // + saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); + + // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); + // Enable RPS1 (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + + dev->ext_priv = budget; + + budget->dvb_adapter.priv = budget; + frontend_init(budget); + + ttpci_budget_init_hooks(budget); + + return 0; +} + +static int budget_patch_detach (struct saa7146_dev* dev) +{ + struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; + int err; + + if (budget->dvb_frontend) { + dvb_unregister_frontend(budget->dvb_frontend); + dvb_frontend_detach(budget->dvb_frontend); + } + err = ttpci_budget_deinit (budget); + + kfree (budget); + + return err; +} + +static int __init budget_patch_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_patch_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +static struct saa7146_extension budget_extension = { + .name = "budget_patch dvb", + .flags = 0, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_patch_attach, + .detach = budget_patch_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + +module_init(budget_patch_init); +module_exit(budget_patch_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); +MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 " + "based so-called Budget Patch cards"); diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c new file mode 100644 index 00000000000..7e6e43ae5c5 --- /dev/null +++ b/drivers/media/pci/ttpci/budget.c @@ -0,0 +1,871 @@ +/* + * budget.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 26feb2004 Support for FS Activy Card (Grundig tuner) by + * Michael Dreher , + * Oliver Endriss and + * Andreas 'randy' Weinberger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "ves1820.h" +#include "l64781.h" +#include "tda8083.h" +#include "s5h1420.h" +#include "tda10086.h" +#include "tda826x.h" +#include "lnbp21.h" +#include "bsru6.h" +#include "bsbe1.h" +#include "tdhd1.h" +#include "stv6110x.h" +#include "stv090x.h" +#include "isl6423.h" +#include "lnbh24.h" + + +static int diseqc_method; +module_param(diseqc_method, int, 0444); +MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static void Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler */ + +static void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + +static void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + dprintk(2, "budget: %p\n", budget); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + +static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) +{ + struct saa7146_dev *dev=budget->dev; + int i; + + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; idev; + + dprintk(2, "budget: %p\n", budget); + + switch (voltage) { + case SEC_VOLTAGE_13: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); + break; + case SEC_VOLTAGE_18: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + break; + case SEC_VOLTAGE_OFF: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + return SetVoltage_Activy (budget, voltage); +} + +static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + Set22K (budget, 1); + break; + + case SEC_TONE_OFF: + Set22K (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, 0, NULL, minicmd); + + return 0; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (c->frequency + 479500) / 125; + + if (c->frequency > 2000000) + pwr = 3; + else if (c->frequency > 1800000) + pwr = 2; + else if (c->frequency > 1600000) + pwr = 1; + else if (c->frequency > 1200000) + pwr = 0; + else if (c->frequency >= 1100000) + pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = +{ + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (c->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget *budget = fe->dvb->priv; + u8 *tuner_addr = fe->tuner_priv; + u32 div; + u8 cfg, cpump, band_select; + u8 data[4]; + struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) }; + + if (tuner_addr) + msg.addr = *tuner_addr; + else + msg.addr = 0x61; + + div = (36125000 + c->frequency) / 166666; + + cfg = 0x88; + + if (c->frequency < 175000000) + cpump = 2; + else if (c->frequency < 390000000) + cpump = 1; + else if (c->frequency < 470000000) + cpump = 2; + else if (c->frequency < 750000000) + cpump = 1; + else + cpump = 3; + + if (c->frequency < 175000000) + band_select = 0x0e; + else if (c->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct l64781_config grundig_29504_401_config = { + .demod_address = 0x55, +}; + +static struct l64781_config grundig_29504_401_config_activy = { + .demod_address = 0x54, +}; + +static u8 tuner_address_grundig_29504_401_activy = 0x60; + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = c->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + +static int s5h1420_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = c->frequency / 1000; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xc2; + + if (div < 1450) + data[3] = 0x00; + else if (div < 1850) + data[3] = 0x40; + else if (div < 2000) + data[3] = 0x80; + else + data[3] = 0xc0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + return 0; +} + +static struct s5h1420_config s5h1420_config = { + .demod_address = 0x53, + .invert = 1, + .cdclk_polarity = 1, +}; + +static struct tda10086_config tda10086_config = { + .demod_address = 0x0e, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct stv0299_config alps_bsru6_config_activy = { + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .op0_off = 1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, +}; + +static struct stv0299_config alps_bsbe1_config_activy = { + .demod_address = 0x68, + .inittab = alps_bsbe1_inittab, + .mclk = 88000000UL, + .invert = 1, + .op0_off = 1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsbe1_set_symbol_rate, +}; + +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *)fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + + +static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) +{ + u8 val; + struct i2c_msg msg[] = { + { .addr = adr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 } + }; + + return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val; +} + +static u8 read_pwm(struct budget* budget) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static struct stv090x_config tt1600_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 13500000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, + + .repeater_level = STV090x_RPTLEVEL_16, + + .tuner_init = NULL, + .tuner_sleep = NULL, + .tuner_set_mode = NULL, + .tuner_set_frequency = NULL, + .tuner_get_frequency = NULL, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = NULL, + .tuner_set_bbgain = NULL, + .tuner_get_bbgain = NULL, + .tuner_set_refclk = NULL, + .tuner_get_status = NULL, +}; + +static struct stv6110x_config tt1600_stv6110x_config = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 2, +}; + +static struct isl6423_config tt1600_isl6423_config = { + .current_max = SEC_CURRENT_515m, + .curlim = SEC_CURRENT_LIM_ON, + .mod_extern = 1, + .addr = 0x08, +}; + +static void frontend_init(struct budget *budget) +{ + (void)alps_bsbe1_config; /* avoid warning */ + + switch(budget->dev->pci->subsystem_device) { + case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) + case 0x1013: + // try the ALPS BSRV2 first of all + budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) { + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + } + break; + } + break; + + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + + budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + break; + } + break; + + case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) + + budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + budget->dvb_frontend->tuner_priv = NULL; + break; + } + break; + + case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ + { + int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); + + if (subtype < 0) + break; + /* fixme: find a better way to identify the card */ + if (subtype < 0x36) { + /* assume ALPS BSRU6 */ + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap); + if (budget->dvb_frontend) { + printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n"); + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + break; + } + } else { + /* assume ALPS BSBE1 */ + /* reset tuner */ + saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO); + msleep(50); + saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI); + msleep(250); + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap); + if (budget->dvb_frontend) { + printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n"); + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + break; + } + } + break; + } + + case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) + budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + } + break; + + case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ + budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + } + break; + + case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ + budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy; + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + } + break; + + case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) + budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params; + if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { + printk("%s: No LNBP21 found!\n", __func__); + goto error_out; + } + break; + } + + case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262) + // gpio2 is connected to CLB - reset it + leave it high + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); + msleep(1); + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); + msleep(1); + + budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL) + printk("%s: No tda826x found!\n", __func__); + if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { + printk("%s: No LNBP21 found!\n", __func__); + goto error_out; + } + break; + } + + case 0x101c: { /* TT S2-1600 */ + struct stv6110x_devctl *ctl; + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); + msleep(50); + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); + msleep(250); + + budget->dvb_frontend = dvb_attach(stv090x_attach, + &tt1600_stv090x_config, + &budget->i2c_adap, + STV090x_DEMODULATOR_0); + + if (budget->dvb_frontend) { + + ctl = dvb_attach(stv6110x_attach, + budget->dvb_frontend, + &tt1600_stv6110x_config, + &budget->i2c_adap); + + if (ctl) { + tt1600_stv090x_config.tuner_init = ctl->tuner_init; + tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; + tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (budget->dvb_frontend->ops.init) + budget->dvb_frontend->ops.init(budget->dvb_frontend); + + if (dvb_attach(isl6423_attach, + budget->dvb_frontend, + &budget->i2c_adap, + &tt1600_isl6423_config) == NULL) { + printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__); + goto error_out; + } + } else { + printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); + goto error_out; + } + } + } + break; + + case 0x1020: { /* Omicom S2 */ + struct stv6110x_devctl *ctl; + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); + msleep(50); + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); + msleep(250); + + budget->dvb_frontend = dvb_attach(stv090x_attach, + &tt1600_stv090x_config, + &budget->i2c_adap, + STV090x_DEMODULATOR_0); + + if (budget->dvb_frontend) { + printk(KERN_INFO "budget: Omicom S2 detected\n"); + + ctl = dvb_attach(stv6110x_attach, + budget->dvb_frontend, + &tt1600_stv6110x_config, + &budget->i2c_adap); + + if (ctl) { + tt1600_stv090x_config.tuner_init = ctl->tuner_init; + tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; + tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (budget->dvb_frontend->ops.init) + budget->dvb_frontend->ops.init(budget->dvb_frontend); + + if (dvb_attach(lnbh24_attach, + budget->dvb_frontend, + &budget->i2c_adap, + LNBH24_PCL | LNBH24_TTX, + LNBH24_TEN, 0x14>>1) == NULL) { + printk(KERN_ERR + "No LNBH24 found!\n"); + goto error_out; + } + } else { + printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); + goto error_out; + } + } + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) + goto error_out; + } + return; + +error_out: + printk("budget: Frontend registration failed!\n"); + dvb_frontend_detach(budget->dvb_frontend); + budget->dvb_frontend = NULL; + return; +} + +static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget *budget = NULL; + int err; + + budget = kmalloc(sizeof(struct budget), GFP_KERNEL); + if( NULL == budget ) { + return -ENOMEM; + } + + dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget); + + dev->ext_priv = budget; + + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { + printk("==> failed\n"); + kfree (budget); + return err; + } + + budget->dvb_adapter.priv = budget; + frontend_init(budget); + + ttpci_budget_init_hooks(budget); + + return 0; +} + +static int budget_detach (struct saa7146_dev* dev) +{ + struct budget *budget = (struct budget*) dev->ext_priv; + int err; + + if (budget->dvb_frontend) { + dvb_unregister_frontend(budget->dvb_frontend); + dvb_frontend_detach(budget->dvb_frontend); + } + + err = ttpci_budget_deinit (budget); + + kfree (budget); + dev->ext_priv = NULL; + + return err; +} + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); +MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), + MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), + MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), + MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), + MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), + MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), + MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), + MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), + MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), + MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), + MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_extension budget_extension = { + .name = "budget dvb", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_attach, + .detach = budget_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + +static int __init budget_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_init); +module_exit(budget_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h new file mode 100644 index 00000000000..3d8a806c20b --- /dev/null +++ b/drivers/media/pci/ttpci/budget.h @@ -0,0 +1,124 @@ + +#ifndef __BUDGET_DVB__ +#define __BUDGET_DVB__ + +#include "dvb_frontend.h" +#include "dvbdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#include "dvb_net.h" + +#include +#include + +#include + +extern int budget_debug; + +#ifdef dprintk +#undef dprintk +#endif + +#define dprintk(level,args...) \ + do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0) + +struct budget_info { + char *name; + int type; +}; + +/* place to store all the necessary device information */ +struct budget { + + /* devices */ + struct dvb_device dvb_dev; + struct dvb_net dvb_net; + + struct saa7146_dev *dev; + + struct i2c_adapter i2c_adap; + struct budget_info *card; + + unsigned char *grabbing; + struct saa7146_pgtable pt; + + struct tasklet_struct fidb_tasklet; + struct tasklet_struct vpe_tasklet; + + struct dmxdev dmxdev; + struct dvb_demux demux; + + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + + int ci_present; + int video_port; + + u32 buffer_width; + u32 buffer_height; + u32 buffer_size; + u32 buffer_warning_threshold; + u32 buffer_warnings; + unsigned long buffer_warning_time; + + u32 ttbp; + int feeding; + + spinlock_t feedlock; + + spinlock_t debilock; + + struct dvb_adapter dvb_adapter; + struct dvb_frontend *dvb_frontend; + int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); + int fe_synced; + + void *priv; +}; + +#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \ +static struct budget_info x_var ## _info = { \ + .name=x_name, \ + .type=x_type }; \ +static struct saa7146_pci_extension_data x_var = { \ + .ext_priv = &x_var ## _info, \ + .ext = &budget_extension }; + +#define BUDGET_TT 0 +#define BUDGET_TT_HW_DISEQC 1 +#define BUDGET_PATCH 3 +#define BUDGET_FS_ACTIVY 4 +#define BUDGET_CIN1200S 5 +#define BUDGET_CIN1200C 6 +#define BUDGET_CIN1200T 7 +#define BUDGET_KNC1S 8 +#define BUDGET_KNC1C 9 +#define BUDGET_KNC1T 10 +#define BUDGET_KNC1SP 11 +#define BUDGET_KNC1CP 12 +#define BUDGET_KNC1TP 13 +#define BUDGET_TVSTAR 14 +#define BUDGET_CIN1200C_MK3 15 +#define BUDGET_KNC1C_MK3 16 +#define BUDGET_KNC1CP_MK3 17 +#define BUDGET_KNC1S2 18 +#define BUDGET_KNC1C_TDA10024 19 + +#define BUDGET_VIDEO_PORTA 0 +#define BUDGET_VIDEO_PORTB 1 + +extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, + struct saa7146_pci_extension_data *info, + struct module *owner, short *adapter_nums); +extern void ttpci_budget_init_hooks(struct budget *budget); +extern int ttpci_budget_deinit(struct budget *budget); +extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); +extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port); +extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop); +extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value, + int uselocks, int nobusyloop); + +#endif diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c new file mode 100644 index 00000000000..32d43156c54 --- /dev/null +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -0,0 +1,176 @@ +/* + Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, + decode it and store it in the associated adapter struct for + use by dvb_net.c + + This card appear to have the 24C16 write protect held to ground, + thus permitting normal read/write operation. Theoretically it + would be possible to write routines to burn a different (encoded) + MAC address into the EEPROM. + + Robert Schlabbach GMX + Michael Glaum KVH Industries + Holger Waechtler Convergence + + Copyright (C) 2002-2003 Ralph Metzler + Metzler Brothers Systementwicklung GbR + + 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 +#include +#include +#include +#include + +#include "ttpci-eeprom.h" + +#if 1 +#define dprintk(x...) do { printk(x); } while (0) +#else +#define dprintk(x...) do { } while (0) +#endif + + +static int check_mac_tt(u8 *buf) +{ + int i; + u16 tmp = 0xffff; + + for (i = 0; i < 8; i++) { + tmp = (tmp << 8) | ((tmp >> 8) ^ buf[i]); + tmp ^= (tmp >> 4) & 0x0f; + tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5); + } + tmp ^= 0xffff; + return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9])); +} + +static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) +{ + u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, + 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, + 0x1d, 0x36, 0x64, 0x78}; + u8 data[20]; + int i; + + /* In case there is a sig check failure have the orig contents available */ + memcpy(data, encodedMAC, 20); + + for (i = 0; i < 20; i++) + data[i] ^= xor[i]; + for (i = 0; i < 10; i++) + data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) + >> ((data[2 * i + 1] >> 6) & 3); + + if (check_mac_tt(data)) + return -ENODEV; + + decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0]; + decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4]; + return 0; +} + +int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC) +{ + u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, + 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, + 0x1d, 0x36, 0x64, 0x78}; + u8 data[20]; + int i; + + memcpy(data, encodedMAC, 20); + + for (i = 0; i < 20; i++) + data[i] ^= xor[i]; + for (i = 0; i < 10; i++) + data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) + >> ((data[2 * i + 1] >> 6) & 3); + + if (check_mac_tt(data)) + return -ENODEV; + + decodedMAC[0] = data[2]; + decodedMAC[1] = data[1]; + decodedMAC[2] = data[0]; + decodedMAC[3] = data[6]; + decodedMAC[4] = data[5]; + decodedMAC[5] = data[4]; + return 0; +} +EXPORT_SYMBOL(ttpci_eeprom_decode_mac); + +static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) +{ + int ret; + u8 b0[] = { 0xcc }; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, .buf = b0, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 } + }; + + /* dprintk("%s\n", __func__); */ + + ret = i2c_transfer(adapter, msg, 2); + + if (ret != 2) /* Assume EEPROM isn't there */ + return (-ENODEV); + + return 0; +} + + +int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) +{ + int ret, i; + u8 encodedMAC[20]; + u8 decodedMAC[6]; + + ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC); + + if (ret != 0) { /* Will only be -ENODEV */ + dprintk("Couldn't read from EEPROM: not there?\n"); + memset(proposed_mac, 0, 6); + return ret; + } + + ret = getmac_tt(decodedMAC, encodedMAC); + if( ret != 0 ) { + dprintk("adapter failed MAC signature check\n"); + dprintk("encoded MAC from EEPROM was " ); + for(i=0; i<19; i++) { + dprintk( "%.2x:", encodedMAC[i]); + } + dprintk("%.2x\n", encodedMAC[19]); + memset(proposed_mac, 0, 6); + return ret; + } + + memcpy(proposed_mac, decodedMAC, 6); + dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + decodedMAC[0], decodedMAC[1], decodedMAC[2], + decodedMAC[3], decodedMAC[4], decodedMAC[5]); + return 0; +} + +EXPORT_SYMBOL(ttpci_eeprom_parse_mac); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); +MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards " + "made by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.h b/drivers/media/pci/ttpci/ttpci-eeprom.h new file mode 100644 index 00000000000..dcc33d5a5cb --- /dev/null +++ b/drivers/media/pci/ttpci/ttpci-eeprom.h @@ -0,0 +1,34 @@ +/* + Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM, + decode it and store it in associated adapter net device + + Robert Schlabbach GMX + Michael Glaum KVH Industries + Holger Waechtler Convergence + + 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 __TTPCI_EEPROM_H__ +#define __TTPCI_EEPROM_H__ + +#include +#include + +extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC); +extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac); + +#endif diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index a5630e30ead..94bdf4d5171 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile @@ -79,4 +79,4 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/ # due to tuner-xc3028 ccflags-y += -I$(srctree)/drivers/media/common/tuners -ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci +ccflags-y += -I$(srctree)/drivers/media/pci/ttpci -- cgit v1.2.3-70-g09d2 From 1511288620bd4ea794bae08871f9e108ca034b2d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Aug 2012 00:07:39 -0300 Subject: ioctl-number.txt: Remove legacy private ioctl's from media drivers None of those drivers use private ioctl's, as they all got converted to the standard V4L2 ones. Signed-off-by: Mauro Carvalho Chehab --- Documentation/ioctl/ioctl-number.txt | 5 ----- 1 file changed, 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 849b771c5e0..2152b0e7237 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -178,7 +178,6 @@ Code Seq#(hex) Include File Comments 'V' C0 linux/ivtv.h conflict! 'V' C0 media/davinci/vpfe_capture.h conflict! 'V' C0 media/si4713.h conflict! -'V' C0-CF drivers/media/video/mxb.h conflict! 'W' 00-1F linux/watchdog.h conflict! 'W' 00-1F linux/wanrouter.h conflict! 'W' 00-3F sound/asound.h conflict! @@ -204,8 +203,6 @@ Code Seq#(hex) Include File Comments 'c' A0-AF arch/x86/include/asm/msr.h conflict! 'd' 00-FF linux/char/drm/drm/h conflict! 'd' 02-40 pcmcia/ds.h conflict! -'d' 10-3F drivers/media/video/dabusb.h conflict! -'d' C0-CF drivers/media/video/saa7191.h conflict! 'd' F0-FF linux/digi1.h 'e' all linux/digi1.h conflict! 'e' 00-1F drivers/net/irda/irtty-sir.h conflict! @@ -267,9 +264,7 @@ Code Seq#(hex) Include File Comments 'v' 00-1F linux/ext2_fs.h conflict! 'v' 00-1F linux/fs.h conflict! 'v' 00-0F linux/sonypi.h conflict! -'v' C0-DF media/pwc-ioctl.h conflict! 'v' C0-FF linux/meye.h conflict! -'v' D0-DF drivers/media/video/cpia2/cpia2dev.h conflict! 'w' all CERN SCI driver 'y' 00-1F packet based user level communications -- cgit v1.2.3-70-g09d2 From e3c399ee4afebda7fd0a96a748e665a26853c246 Mon Sep 17 00:00:00 2001 From: Przemo Firszt Date: Tue, 31 Jul 2012 18:27:56 +0100 Subject: HID: wacom: OLEDs control over sysfs for Intuos4 Thsi patch adds ability to control OLED micro displays on Wacom Intuos4 Wireless. The OLEDS are exposed as /sys/class/hidraw/hidraw*/device/oled{No]_img where No. is 0 to 7 Setting an image: dd bs=256 if=img_file of=/sys/class/hidraw/hidraw{No}/device/oled0_img The image has to contain 256 bytes (64x32px 1 bit). More detailed description in Documentation/ABI/testing/sysfs-driver-wacom Signed-off-by: Przemo Firszt Acked-by: Ping Cheng Signed-off-by: Jiri Kosina --- Documentation/ABI/testing/sysfs-driver-wacom | 13 +++ drivers/hid/hid-wacom.c | 143 +++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index 8d55a83d692..7fc781048b7 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -1,3 +1,16 @@ +WWhat: /sys/class/hidraw/hidraw*/device/oled*_img +Date: June 2012 +Contact: linux-bluetooth@vger.kernel.org +Description: + The /sys/class/hidraw/hidraw*/device/oled*_img files control + OLED mocro displays on Intuos4 Wireless tablet. Accepted image + has to contain 256 bytes (64x32 px 1 bit colour). The format + is the same as PBM image 62x32px without header (64 bits per + horizontal line, 32 lines). An example of setting OLED No. 0: + dd bs=256 count=1 if=img_file of=[path to oled0_img]/oled0_img + The attribute is read only and no local copy of the image is + stored. + What: /sys/class/hidraw/hidraw*/device/speed Date: April 2010 Kernel Version: 2.6.35 diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 848842e0df1..0f02358888a 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -33,6 +33,8 @@ #define PAD_DEVICE_ID 0x0F #define WAC_CMD_LED_CONTROL 0x20 +#define WAC_CMD_ICON_START_STOP 0x21 +#define WAC_CMD_ICON_TRANSFER 0x26 struct wacom_data { __u16 tool; @@ -69,6 +71,91 @@ static enum power_supply_property wacom_ac_props[] = { POWER_SUPPLY_PROP_SCOPE, }; +static void wacom_scramble(__u8 *image) +{ + __u16 mask; + __u16 s1; + __u16 s2; + __u16 r1 ; + __u16 r2 ; + __u16 r; + __u8 buf[256]; + int i, w, x, y, z; + + for (x = 0; x < 32; x++) { + for (y = 0; y < 8; y++) + buf[(8 * x) + (7 - y)] = image[(8 * x) + y]; + } + + /* Change 76543210 into GECA6420 as required by Intuos4 WL + * HGFEDCBA HFDB7531 + */ + for (x = 0; x < 4; x++) { + for (y = 0; y < 4; y++) { + for (z = 0; z < 8; z++) { + mask = 0x0001; + r1 = 0; + r2 = 0; + i = (x << 6) + (y << 4) + z; + s1 = buf[i]; + s2 = buf[i+8]; + for (w = 0; w < 8; w++) { + r1 |= (s1 & mask); + r2 |= (s2 & mask); + s1 <<= 1; + s2 <<= 1; + mask <<= 2; + } + r = r1 | (r2 << 1); + i = (x << 6) + (y << 4) + (z << 1); + image[i] = 0xFF & r; + image[i+1] = (0xFF00 & r) >> 8; + } + } + } +} + +static void wacom_set_image(struct hid_device *hdev, const char *image, + __u8 icon_no) +{ + __u8 rep_data[68]; + __u8 p[256]; + int ret, i, j; + + for (i = 0; i < 256; i++) + p[i] = image[i]; + + rep_data[0] = WAC_CMD_ICON_START_STOP; + rep_data[1] = 0; + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + if (ret < 0) + goto err; + + rep_data[0] = WAC_CMD_ICON_TRANSFER; + rep_data[1] = icon_no & 0x07; + + wacom_scramble(p); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 64; j++) + rep_data[j + 3] = p[(i << 6) + j]; + + rep_data[2] = i; + ret = hdev->hid_output_raw_report(hdev, rep_data, 67, + HID_FEATURE_REPORT); + } + + rep_data[0] = WAC_CMD_ICON_START_STOP; + rep_data[1] = 0; + + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + +err: + return; +} + static void wacom_leds_set_brightness(struct led_classdev *led_dev, enum led_brightness value) { @@ -93,6 +180,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev, buf[1] = led; buf[2] = value >> 2; buf[3] = value; + /* use fixed brightness for OLEDs */ + buf[4] = 0x08; hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); kfree(buf); } @@ -318,6 +407,34 @@ static ssize_t wacom_store_speed(struct device *dev, static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, wacom_show_speed, wacom_store_speed); +#define WACOM_STORE(OLED_ID) \ +static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct hid_device *hdev = container_of(dev, struct hid_device, \ + dev); \ + \ + if (count != 256) \ + return -EINVAL; \ + \ + wacom_set_image(hdev, buf, OLED_ID); \ + \ + return count; \ +} \ + \ +static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \ + wacom_oled##OLED_ID##_store) + +WACOM_STORE(0); +WACOM_STORE(1); +WACOM_STORE(2); +WACOM_STORE(3); +WACOM_STORE(4); +WACOM_STORE(5); +WACOM_STORE(6); +WACOM_STORE(7); + static int wacom_gr_parse_report(struct hid_device *hdev, struct wacom_data *wdata, struct input_dev *input, unsigned char *data) @@ -718,6 +835,24 @@ static int wacom_probe(struct hid_device *hdev, hid_warn(hdev, "can't create sysfs speed attribute err: %d\n", ret); +#define OLED_INIT(OLED_ID) \ + do { \ + ret = device_create_file(&hdev->dev, \ + &dev_attr_oled##OLED_ID##_img); \ + if (ret) \ + hid_warn(hdev, \ + "can't create sysfs oled attribute, err: %d\n", ret);\ + } while (0) + +OLED_INIT(0); +OLED_INIT(1); +OLED_INIT(2); +OLED_INIT(3); +OLED_INIT(4); +OLED_INIT(5); +OLED_INIT(6); +OLED_INIT(7); + wdata->features = 0; wacom_set_features(hdev, 1); @@ -782,6 +917,14 @@ static void wacom_remove(struct hid_device *hdev) struct wacom_data *wdata = hid_get_drvdata(hdev); wacom_destroy_leds(hdev); + device_remove_file(&hdev->dev, &dev_attr_oled0_img); + device_remove_file(&hdev->dev, &dev_attr_oled1_img); + device_remove_file(&hdev->dev, &dev_attr_oled2_img); + device_remove_file(&hdev->dev, &dev_attr_oled3_img); + device_remove_file(&hdev->dev, &dev_attr_oled4_img); + device_remove_file(&hdev->dev, &dev_attr_oled5_img); + device_remove_file(&hdev->dev, &dev_attr_oled6_img); + device_remove_file(&hdev->dev, &dev_attr_oled7_img); device_remove_file(&hdev->dev, &dev_attr_speed); hid_hw_stop(hdev); -- cgit v1.2.3-70-g09d2 From 1c86845268dc91fa6a53de9a4479b407cd4ee903 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Aug 2012 11:09:35 +0200 Subject: ALSA: hda - Add 3stack-automute model to AD1882 codec Added a simple support of automute for the front HP jack to AD1882 stack model. Such an addition is basically an exception -- we really want to avoid the static quirk codes, but AD1882 parser isn't still ready for moving to the BIOS auto-parser yet. So, as a quick fix, I merged it for now. In near future, we really need the big clean up of patch_analog.c to move on to the auto-parser... Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 3 ++- sound/pci/hda/patch_analog.c | 40 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a92bba81684..16dfe57f173 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -74,7 +74,8 @@ CMI9880 AD1882 / AD1882A ================ - 3stack 3-stack mode (default) + 3stack 3-stack mode + 3stack-automute 3-stack with automute front HP (default) 6stack 6-stack mode AD1884A / AD1883 / AD1984A / AD1984B diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0208fa121e5..21218853366 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -4814,6 +4814,32 @@ static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { { } /* end */ }; +/* simple auto-mute control for AD1882 3-stack board */ +#define AD1882_HP_EVENT 0x01 + +static void ad1882_3stack_automute(struct hda_codec *codec) +{ + bool mute = snd_hda_jack_detect(codec, 0x11); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + mute ? 0 : PIN_OUT); +} + +static int ad1882_3stack_automute_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1882_3stack_automute(codec); + return 0; +} + +static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) +{ + switch (res >> 26) { + case AD1882_HP_EVENT: + ad1882_3stack_automute(codec); + break; + } +} + static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), @@ -4928,6 +4954,11 @@ static const struct hda_verb ad1882_init_verbs[] = { { } /* end */ }; +static const struct hda_verb ad1882_3stack_automute_verbs[] = { + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, + { } /* end */ +}; + #ifdef CONFIG_SND_HDA_POWER_SAVE static const struct hda_amp_list ad1882_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ @@ -4942,12 +4973,14 @@ static const struct hda_amp_list ad1882_loopbacks[] = { enum { AD1882_3STACK, AD1882_6STACK, + AD1882_3STACK_AUTOMUTE, AD1882_MODELS }; static const char * const ad1882_models[AD1986A_MODELS] = { [AD1882_3STACK] = "3stack", [AD1882_6STACK] = "6stack", + [AD1882_3STACK_AUTOMUTE] = "3stack-automute", }; @@ -5002,6 +5035,7 @@ static int patch_ad1882(struct hda_codec *codec) switch (board_config) { default: case AD1882_3STACK: + case AD1882_3STACK_AUTOMUTE: spec->num_mixers = 3; spec->mixers[2] = ad1882_3stack_mixers; spec->channel_mode = ad1882_modes; @@ -5009,6 +5043,12 @@ static int patch_ad1882(struct hda_codec *codec) spec->need_dac_fix = 1; spec->multiout.max_channels = 2; spec->multiout.num_dacs = 1; + if (board_config != AD1882_3STACK) { + spec->init_verbs[spec->num_init_verbs++] = + ad1882_3stack_automute_verbs; + codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; + codec->patch_ops.init = ad1882_3stack_automute_init; + } break; case AD1882_6STACK: spec->num_mixers = 3; -- cgit v1.2.3-70-g09d2 From fff8491c8b8cce5fc9190e025d1a665f2ee71a4f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 14 Aug 2012 12:07:56 +0300 Subject: ASoC: omap-twl4030: Simple machine driver for TI SoC with twl4030 codec Machine driver to handle simple devices using twl4030 as audio codec. The driver supports the following boards: - Beagleboard or Devkit8000 - Gumstix Overo or CompuLab CM-T35/CM-T3730 - IGEP v2 - OMAP3EVM All of these boards can be switched to use this driver since their setup is identical. Devicetree support for the omap-twl4030 machine driver also implemented. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/omap-twl4030.txt | 17 ++ include/linux/platform_data/omap-twl4030.h | 32 ++++ sound/soc/omap/Kconfig | 13 ++ sound/soc/omap/Makefile | 2 + sound/soc/omap/omap-twl4030.c | 188 +++++++++++++++++++++ 5 files changed, 252 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/omap-twl4030.txt create mode 100644 include/linux/platform_data/omap-twl4030.h create mode 100644 sound/soc/omap/omap-twl4030.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/Documentation/devicetree/bindings/sound/omap-twl4030.txt new file mode 100644 index 00000000000..6fae51c7f76 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-twl4030.txt @@ -0,0 +1,17 @@ +* Texas Instruments SoC with twl4030 based audio setups + +Required properties: +- compatible: "ti,omap-twl4030" +- ti,model: Name of the sound card (for example "omap3beagle") +- ti,mcbsp: phandle for the McBSP node +- ti,codec: phandle for the twl4030 audio node + +Example: + +sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3beagle"; + + ti,mcbsp = <&mcbsp2>; + ti,codec = <&twl_audio>; +}; diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h new file mode 100644 index 00000000000..c7bef788daa --- /dev/null +++ b/include/linux/platform_data/omap-twl4030.h @@ -0,0 +1,32 @@ +/** + * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030 + * codec, header. + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * All rights reserved. + * + * Author: Peter Ujfalusi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef _OMAP_TWL4030_H_ +#define _OMAP_TWL4030_H_ + +struct omap_tw4030_pdata { + const char *card_name; +}; + +#endif /* _OMAP_TWL4030_H_ */ diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 57a2fa75108..fc83d748625 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -95,6 +95,19 @@ config SND_OMAP_SOC_SDP3430 Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. +config SND_OMAP_SOC_OMAP_TWL4030 + tristate "SoC Audio support for TI SoC based boards with twl4030 codec" + depends on TWL4030_CORE && SND_OMAP_SOC + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on TI SoC based boards + using twl4030 as c codec. This driver currently supports: + - Beagleboard or Devkit8000 + - Gumstix Overo or CompuLab CM-T35/CM-T3730 + - IGEP v2 + - OMAP3EVM + config SND_OMAP_SOC_OMAP_ABE_TWL6040 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4 diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 0e14dd32256..861e640e2be 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -21,6 +21,7 @@ snd-soc-omap3evm-objs := omap3evm.o snd-soc-am3517evm-objs := am3517evm.o snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o +snd-soc-omap-twl4030-objs := omap-twl4030.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o @@ -37,6 +38,7 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c new file mode 100644 index 00000000000..3b97b87971f --- /dev/null +++ b/sound/soc/omap/omap-twl4030.c @@ -0,0 +1,188 @@ +/* + * omap-twl4030.c -- SoC audio for TI SoC based boards with twl4030 codec + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * All rights reserved. + * + * Author: Peter Ujfalusi + * + * This driver replaces the following machine drivers: + * omap3beagle (Author: Steve Sakoman ) + * omap3evm (Author: Anuj Aggarwal ) + * overo (Author: Steve Sakoman ) + * igep0020 (Author: Enric Balletbo i Serra ) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" + +static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + unsigned int fmt; + int ret; + + switch (params_channels(params)) { + case 2: /* Stereo I2S mode */ + fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + break; + case 4: /* Four channel TDM mode */ + fmt = SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBM_CFM; + break; + default: + return -EINVAL; + } + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(card->dev, "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + dev_err(card->dev, "can't set cpu DAI configuration\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap_twl4030_ops = { + .hw_params = omap_twl4030_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap_twl4030_dai_links[] = { + { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai_name = "omap-mcbsp.2", + .codec_dai_name = "twl4030-hifi", + .platform_name = "omap-pcm-audio", + .codec_name = "twl4030-codec", + .ops = &omap_twl4030_ops, + }, +}; + +/* Audio machine driver */ +static struct snd_soc_card omap_twl4030_card = { + .owner = THIS_MODULE, + .dai_link = omap_twl4030_dai_links, + .num_links = ARRAY_SIZE(omap_twl4030_dai_links), +}; + +static __devinit int omap_twl4030_probe(struct platform_device *pdev) +{ + struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); + struct device_node *node = pdev->dev.of_node; + struct snd_soc_card *card = &omap_twl4030_card; + int ret = 0; + + card->dev = &pdev->dev; + + if (node) { + struct device_node *dai_node; + + if (snd_soc_of_parse_card_name(card, "ti,model")) { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + dai_node = of_parse_phandle(node, "ti,mcbsp", 0); + if (!dai_node) { + dev_err(&pdev->dev, "McBSP node is not provided\n"); + return -EINVAL; + } + omap_twl4030_dai_links[0].cpu_dai_name = NULL; + omap_twl4030_dai_links[0].cpu_of_node = dai_node; + + } else if (pdata) { + if (pdata->card_name) { + card->name = pdata->card_name; + } else { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + } else { + dev_err(&pdev->dev, "Missing pdata\n"); + return -ENODEV; + } + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + return ret; + } + + return 0; +} + +static int __devexit omap_twl4030_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static const struct of_device_id omap_twl4030_of_match[] = { + {.compatible = "ti,omap-twl4030", }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_twl4030_of_match); + +static struct platform_driver omap_twl4030_driver = { + .driver = { + .name = "omap-twl4030", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = omap_twl4030_of_match, + }, + .probe = omap_twl4030_probe, + .remove = __devexit_p(omap_twl4030_remove), +}; + +module_platform_driver(omap_twl4030_driver); + +MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_DESCRIPTION("ALSA SoC for TI SoC based boards with twl4030 codec"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-twl4030"); -- cgit v1.2.3-70-g09d2 From 34affc6a5c75ce6523d7282d56c51bb36c183da7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Aug 2012 06:10:02 -0300 Subject: [media] DocBook: update RDS references to the latest RDS standards Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/biblio.xml | 12 ++++++------ Documentation/DocBook/media/v4l/controls.xml | 6 +++--- Documentation/DocBook/media/v4l/dev-rds.xml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml index 1078e45f189..18b6fc9ff58 100644 --- a/Documentation/DocBook/media/v4l/biblio.xml +++ b/Documentation/DocBook/media/v4l/biblio.xml @@ -178,23 +178,23 @@ Signal - NTSC for Studio Applications" 1125-Line High-Definition Production" - - EN 50067 + + IEC 62106 - European Committee for Electrotechnical Standardization -(http://www.cenelec.eu) + International Electrotechnical Commission +(http://www.iec.ch) Specification of the radio data system (RDS) for VHF/FM sound broadcasting in the frequency range from 87,5 to 108,0 MHz - NRSC-4 + NRSC-4-B National Radio Systems Committee (http://www.nrscstandards.org) - NRSC-4: United States RBDS Standard + NRSC-4-B: United States RBDS Standard diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index b0964fb4e83..41cd801f0f0 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3505,7 +3505,7 @@ This encodes up to 31 pre-defined programme types. Sets the Programme Service name (PS_NAME) for transmission. It is intended for static display on a receiver. It is the primary aid to listeners in programme service -identification and selection. In Annex E of , the RDS specification, +identification and selection. In Annex E of , the RDS specification, there is a full description of the correct character encoding for Programme Service name strings. Also from RDS specification, PS is usually a single eight character text. However, it is also possible to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured @@ -3519,7 +3519,7 @@ with steps of 8 characters. The result is it must always contain a string with s what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names, programme-related information or any other text. In these cases, RadioText should be used in addition to V4L2_CID_RDS_TX_PS_NAME. The encoding for Radio Text strings is also fully described -in Annex E of . The length of Radio Text strings depends on which RDS Block is being +in Annex E of . The length of Radio Text strings depends on which RDS Block is being used to transmit it, either 32 (2A block) or 64 (2B block). However, it is also possible to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. @@ -3650,7 +3650,7 @@ manually or automatically if set to zero. Unit, range and step are driver-specif For more details about RDS specification, refer to - document, from CENELEC. + document, from CENELEC.
diff --git a/Documentation/DocBook/media/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml index 38883a419e6..be2f3373732 100644 --- a/Documentation/DocBook/media/v4l/dev-rds.xml +++ b/Documentation/DocBook/media/v4l/dev-rds.xml @@ -6,7 +6,7 @@ information, on an inaudible audio subcarrier of a radio program. This interface is aimed at devices capable of receiving and/or transmitting RDS information. - For more information see the core RDS standard + For more information see the core RDS standard and the RBDS standard . Note that the RBDS standard as is used in the USA is almost identical -- cgit v1.2.3-70-g09d2 From 071408b6dcc1cb29150699621e13b0ddb81e3cf1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Aug 2012 06:10:01 -0300 Subject: [media] DocBook validation fixes More validation fixes as reported by xmllint. There are still three xmllint errors after this remaining regarding SVG file support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/Makefile | 2 +- Documentation/DocBook/media/dvb/dvbproperty.xml | 22 +- Documentation/DocBook/media/dvb/frontend.xml | 20 +- Documentation/DocBook/media/v4l/controls.xml | 447 ++++++++++----------- Documentation/DocBook/media/v4l/dev-subdev.xml | 20 +- .../DocBook/media/v4l/pixfmt-srggb10dpcm8.xml | 3 +- Documentation/DocBook/media/v4l/selection-api.xml | 22 +- .../DocBook/media/v4l/vidioc-g-selection.xml | 9 +- Documentation/DocBook/media/v4l/vidioc-qbuf.xml | 2 + .../media/v4l/vidioc-subdev-g-selection.xml | 8 +- 10 files changed, 278 insertions(+), 277 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile index 362520992ce..9b7e4c55792 100644 --- a/Documentation/DocBook/media/Makefile +++ b/Documentation/DocBook/media/Makefile @@ -300,7 +300,7 @@ $(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml @( \ for ident in $(IOCTLS) ; do \ entity=`echo $$ident | tr _ -` ; \ - id=`grep "$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \ + id=`grep "$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml $(MEDIA_OBJ_DIR)/media-ioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \ echo "$$ident\">" \ >>$@ ; \ diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index eddfe6f9a75..d188be963a4 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -569,33 +569,33 @@ typedef enum fe_delivery_system { <constant>DTV_ATSCMH_RS_FRAME_MODE</constant> RS frame mode. Possible values are: -
+ typedef enum atscmh_rs_frame_mode { ATSCMH_RSFRAME_PRI_ONLY = 0, ATSCMH_RSFRAME_PRI_SEC = 1, } atscmh_rs_frame_mode_t; -
+
<constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant> RS frame ensemble. Possible values are: -
+ typedef enum atscmh_rs_frame_ensemble { ATSCMH_RSFRAME_ENS_PRI = 0, ATSCMH_RSFRAME_ENS_SEC = 1, } atscmh_rs_frame_ensemble_t; -
+
<constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant> RS code mode (primary). Possible values are: -
+ typedef enum atscmh_rs_code_mode { ATSCMH_RSCODE_211_187 = 0, @@ -603,7 +603,7 @@ typedef enum atscmh_rs_code_mode { ATSCMH_RSCODE_235_187 = 2, } atscmh_rs_code_mode_t; -
+
<constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant> @@ -621,27 +621,27 @@ typedef enum atscmh_rs_code_mode { <constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant> Series Concatenated Convolutional Code Block Mode. Possible values are: -
+ typedef enum atscmh_sccc_block_mode { ATSCMH_SCCC_BLK_SEP = 0, ATSCMH_SCCC_BLK_COMB = 1, } atscmh_sccc_block_mode_t; -
+
<constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant> Series Concatenated Convolutional Code Rate. Possible values are: -
+ typedef enum atscmh_sccc_code_mode { ATSCMH_SCCC_CODE_HLF = 0, ATSCMH_SCCC_CODE_QTR = 1, } atscmh_sccc_code_mode_t; -
+
<constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant> @@ -817,7 +817,7 @@ typedef enum fe_hierarchy {
<constant>DTV_INTERLEAVING</constant> - Interleaving mode + Interleaving mode enum fe_interleaving { INTERLEAVING_NONE, diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml index 1ab2e1af81f..950bdfb4504 100644 --- a/Documentation/DocBook/media/dvb/frontend.xml +++ b/Documentation/DocBook/media/dvb/frontend.xml @@ -264,7 +264,7 @@ and to add newer delivery systems. FE_GET_PROPERTY/FE_SET_PROPERTY instead, in order to be able to support the newer System Delivery like DVB-S2, DVB-T2, DVB-C2, ISDB, etc. -All kinds of parameters are combined as an union in the FrontendParameters structure: +All kinds of parameters are combined as an union in the FrontendParameters structure: struct dvb_frontend_parameters { uint32_t frequency; /⋆ (absolute) frequency in Hz for QAM/OFDM ⋆/ @@ -277,12 +277,13 @@ struct dvb_frontend_parameters { struct dvb_vsb_parameters vsb; } u; }; - + In the case of QPSK frontends the frequency field specifies the intermediate frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and OFDM frontends the frequency specifies the absolute frequency and is given in Hz. +
QPSK parameters For satellite QPSK frontends you have to use the dvb_qpsk_parameters structure: @@ -347,8 +348,8 @@ itself.
frontend code rate The possible values for the fec_inner field used on -struct dvb_qpsk_parameters and -struct dvb_qam_parameters are: +struct dvb_qpsk_parameters and +struct dvb_qam_parameters are: typedef enum fe_code_rate { @@ -373,9 +374,9 @@ detection.
frontend modulation type for QAM, OFDM and VSB For cable and terrestrial frontends, e. g. for -struct dvb_qpsk_parameters, -struct dvb_qam_parameters and -struct dvb_qam_parameters, +struct dvb_qpsk_parameters, +struct dvb_qam_parameters and +struct dvb_qam_parameters, it needs to specify the quadrature modulation mode which can be one of the following: @@ -396,8 +397,8 @@ it needs to specify the quadrature modulation mode which can be one of the follo } fe_modulation_t;
-Finally, there are several more parameters for OFDM: - +
+More OFDM parameters
Number of carriers per channel @@ -453,6 +454,7 @@ typedef enum fe_hierarchy { } fe_hierarchy_t;
+
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 41cd801f0f0..93b9c6872e5 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3717,232 +3717,231 @@ interface and may change in the future. use case involving camera or individually. -
+ + Flash Control IDs + + + + + + + + + + + ID + Type + Description + + + + + + V4L2_CID_FLASH_CLASS + class + + + The FLASH class descriptor. + + + V4L2_CID_FLASH_LED_MODE + menu + + + Defines the mode of the flash LED, + the high-power white LED attached to the flash controller. + Setting this control may not be possible in presence of + some faults. See V4L2_CID_FLASH_FAULT. + + + + + + V4L2_FLASH_LED_MODE_NONE + Off. + + + V4L2_FLASH_LED_MODE_FLASH + Flash mode. + + + V4L2_FLASH_LED_MODE_TORCH + Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY. + + + + + + V4L2_CID_FLASH_STROBE_SOURCE + menu + + Defines the source of the flash LED + strobe. + + + + + + V4L2_FLASH_STROBE_SOURCE_SOFTWARE + The flash strobe is triggered by using + the V4L2_CID_FLASH_STROBE control. + + + V4L2_FLASH_STROBE_SOURCE_EXTERNAL + The flash strobe is triggered by an + external source. Typically this is a sensor, + which makes it possible to synchronises the + flash strobe start to exposure start. + + + + + + V4L2_CID_FLASH_STROBE + button + + + Strobe flash. Valid when + V4L2_CID_FLASH_LED_MODE is set to + V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE + is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this + control may not be possible in presence of some faults. + See V4L2_CID_FLASH_FAULT. + + + V4L2_CID_FLASH_STROBE_STOP + button + + Stop flash strobe immediately. + + + V4L2_CID_FLASH_STROBE_STATUS + boolean + + + Strobe status: whether the flash + is strobing at the moment or not. This is a read-only + control. + + + V4L2_CID_FLASH_TIMEOUT + integer + + + Hardware timeout for flash. The + flash strobe is stopped after this period of time has + passed from the start of the strobe. + + + V4L2_CID_FLASH_INTENSITY + integer + + + Intensity of the flash strobe when + the flash LED is in flash mode + (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps + (mA) if possible. + + + V4L2_CID_FLASH_TORCH_INTENSITY + integer + + + Intensity of the flash LED in + torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be + milliamps (mA) if possible. Setting this control may not + be possible in presence of some faults. See + V4L2_CID_FLASH_FAULT. + + + V4L2_CID_FLASH_INDICATOR_INTENSITY + integer + + + Intensity of the indicator LED. + The indicator LED may be fully independent of the flash + LED. The unit should be microamps (uA) if possible. + + + V4L2_CID_FLASH_FAULT + bitmask + + + Faults related to the flash. The + faults tell about specific problems in the flash chip + itself or the LEDs attached to it. Faults may prevent + further use of some of the flash controls. In particular, + V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE + if the fault affects the flash LED. Exactly which faults + have such an effect is chip dependent. Reading the faults + resets the control and returns the chip to a usable state + if possible. + + + + + + V4L2_FLASH_FAULT_OVER_VOLTAGE + Flash controller voltage to the flash LED + has exceeded the limit specific to the flash + controller. + + + V4L2_FLASH_FAULT_TIMEOUT + The flash strobe was still on when + the timeout set by the user --- + V4L2_CID_FLASH_TIMEOUT control --- has expired. + Not all flash controllers may set this in all + such conditions. + + + V4L2_FLASH_FAULT_OVER_TEMPERATURE + The flash controller has overheated. + + + V4L2_FLASH_FAULT_SHORT_CIRCUIT + The short circuit protection of the flash + controller has been triggered. + + + V4L2_FLASH_FAULT_OVER_CURRENT + Current in the LED power supply has exceeded the limit + specific to the flash controller. + + + V4L2_FLASH_FAULT_INDICATOR + The flash controller has detected a short or open + circuit condition on the indicator LED. + + + + + + V4L2_CID_FLASH_CHARGE + boolean + + Enable or disable charging of the xenon + flash capacitor. + + + V4L2_CID_FLASH_READY + boolean + + + Is the flash ready to strobe? + Xenon flashes require their capacitors charged before + strobing. LED flashes often require a cooldown period + after strobe during which another strobe will not be + possible. This is a read-only control. + + + + +
+
- - - Flash Control IDs - - - - - - - - - - - ID - Type - Description - - - - - - V4L2_CID_FLASH_CLASS - class - - - The FLASH class descriptor. - - - V4L2_CID_FLASH_LED_MODE - menu - - - Defines the mode of the flash LED, - the high-power white LED attached to the flash controller. - Setting this control may not be possible in presence of - some faults. See V4L2_CID_FLASH_FAULT. - - - - - - V4L2_FLASH_LED_MODE_NONE - Off. - - - V4L2_FLASH_LED_MODE_FLASH - Flash mode. - - - V4L2_FLASH_LED_MODE_TORCH - Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY. - - - - - - V4L2_CID_FLASH_STROBE_SOURCE - menu - - Defines the source of the flash LED - strobe. - - - - - - V4L2_FLASH_STROBE_SOURCE_SOFTWARE - The flash strobe is triggered by using - the V4L2_CID_FLASH_STROBE control. - - - V4L2_FLASH_STROBE_SOURCE_EXTERNAL - The flash strobe is triggered by an - external source. Typically this is a sensor, - which makes it possible to synchronises the - flash strobe start to exposure start. - - - - - - V4L2_CID_FLASH_STROBE - button - - - Strobe flash. Valid when - V4L2_CID_FLASH_LED_MODE is set to - V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE - is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this - control may not be possible in presence of some faults. - See V4L2_CID_FLASH_FAULT. - - - V4L2_CID_FLASH_STROBE_STOP - button - - Stop flash strobe immediately. - - - V4L2_CID_FLASH_STROBE_STATUS - boolean - - - Strobe status: whether the flash - is strobing at the moment or not. This is a read-only - control. - - - V4L2_CID_FLASH_TIMEOUT - integer - - - Hardware timeout for flash. The - flash strobe is stopped after this period of time has - passed from the start of the strobe. - - - V4L2_CID_FLASH_INTENSITY - integer - - - Intensity of the flash strobe when - the flash LED is in flash mode - (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps - (mA) if possible. - - - V4L2_CID_FLASH_TORCH_INTENSITY - integer - - - Intensity of the flash LED in - torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be - milliamps (mA) if possible. Setting this control may not - be possible in presence of some faults. See - V4L2_CID_FLASH_FAULT. - - - V4L2_CID_FLASH_INDICATOR_INTENSITY - integer - - - Intensity of the indicator LED. - The indicator LED may be fully independent of the flash - LED. The unit should be microamps (uA) if possible. - - - V4L2_CID_FLASH_FAULT - bitmask - - - Faults related to the flash. The - faults tell about specific problems in the flash chip - itself or the LEDs attached to it. Faults may prevent - further use of some of the flash controls. In particular, - V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE - if the fault affects the flash LED. Exactly which faults - have such an effect is chip dependent. Reading the faults - resets the control and returns the chip to a usable state - if possible. - - - - - - V4L2_FLASH_FAULT_OVER_VOLTAGE - Flash controller voltage to the flash LED - has exceeded the limit specific to the flash - controller. - - - V4L2_FLASH_FAULT_TIMEOUT - The flash strobe was still on when - the timeout set by the user --- - V4L2_CID_FLASH_TIMEOUT control --- has expired. - Not all flash controllers may set this in all - such conditions. - - - V4L2_FLASH_FAULT_OVER_TEMPERATURE - The flash controller has overheated. - - - V4L2_FLASH_FAULT_SHORT_CIRCUIT - The short circuit protection of the flash - controller has been triggered. - - - V4L2_FLASH_FAULT_OVER_CURRENT - Current in the LED power supply has exceeded the limit - specific to the flash controller. - - - V4L2_FLASH_FAULT_INDICATOR - The flash controller has detected a short or open - circuit condition on the indicator LED. - - - - - - V4L2_CID_FLASH_CHARGE - boolean - - Enable or disable charging of the xenon - flash capacitor. - - - V4L2_CID_FLASH_READY - boolean - - - Is the flash ready to strobe? - Xenon flashes require their capacitors charged before - strobing. LED flashes often require a cooldown period - after strobe during which another strobe will not be - possible. This is a read-only control. - - - - -
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml index a3d9dd09326..d15aaf83f56 100644 --- a/Documentation/DocBook/media/v4l/dev-subdev.xml +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml @@ -374,29 +374,29 @@ rectangle --- if it is supported by the hardware. - Sink pad format. The user configures the sink pad + Sink pad format. The user configures the sink pad format. This format defines the parameters of the image the - entity receives through the pad for further processing. + entity receives through the pad for further processing. - Sink pad actual crop selection. The sink pad crop - defines the crop performed to the sink pad format. + Sink pad actual crop selection. The sink pad crop + defines the crop performed to the sink pad format. - Sink pad actual compose selection. The size of the + Sink pad actual compose selection. The size of the sink pad compose rectangle defines the scaling ratio compared to the size of the sink pad crop rectangle. The location of the compose rectangle specifies the location of the actual sink compose rectangle in the sink compose bounds - rectangle. + rectangle. - Source pad actual crop selection. Crop on the source + Source pad actual crop selection. Crop on the source pad defines crop performed to the image in the sink compose - bounds rectangle. + bounds rectangle. - Source pad format. The source pad format defines the + Source pad format. The source pad format defines the output pixel format of the subdev, as well as the other parameters with the exception of the image width and height. Width and height are defined by the size of the source pad - actual crop selection. + actual crop selection. Accessing any of the above rectangles not supported by the diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml index 8eace3e2e7d..2d3f0b1aefe 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml @@ -22,8 +22,7 @@ with 10 bits per colour compressed to 8 bits each, using DPCM compression. DPCM, differential pulse-code modulation, is lossy. Each colour component consumes 8 bits of memory. In other respects - this format is similar to . + this format is similar to . diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml index e7ed5077834..4c238ce068b 100644 --- a/Documentation/DocBook/media/v4l/selection-api.xml +++ b/Documentation/DocBook/media/v4l/selection-api.xml @@ -40,6 +40,7 @@ cropping and composing rectangles have the same size.
Selection targets +
Cropping and composing targets @@ -52,12 +53,12 @@ cropping and composing rectangles have the same size.
+
+ See for more + information.
- See for more - information. -
Configuration @@ -216,18 +217,17 @@ composing and cropping operations by setting the appropriate targets. The V4L2 API lacks any support for composing to and cropping from an image inside a memory buffer. The application could configure a capture device to fill only a part of an image by abusing V4L2 API. Cropping a smaller image from a larger -one is achieved by setting the field -&v4l2-pix-format;::bytesperline . Introducing an image offsets -could be done by modifying field &v4l2-buffer;::m:userptr - before calling VIDIOC_QBUF . Those +one is achieved by setting the field +&v4l2-pix-format;::bytesperline. Introducing an image offsets +could be done by modifying field &v4l2-buffer;::m_userptr +before calling VIDIOC_QBUF . Those operations should be avoided because they are not portable (endianness), and do not work for macroblock and Bayer formats and mmap buffers. The selection API deals with configuration of buffer cropping/composing in a clear, intuitive and portable way. Next, with the selection API the concepts of the padded target -and constraints flags are introduced. Finally, &v4l2-crop; - and &v4l2-cropcap; have no reserved -fields. Therefore there is no way to extend their functionality. The new - &v4l2-selection; provides a lot of place for future +and constraints flags are introduced. Finally, &v4l2-crop; and &v4l2-cropcap; +have no reserved fields. Therefore there is no way to extend their functionality. +The new &v4l2-selection; provides a lot of place for future extensions. Driver developers are encouraged to implement only selection API. The former cropping API would be simulated using the new one. diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml index f76d8a6d9b9..b11ec75e21a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml @@ -152,12 +152,10 @@ satisfactory parameters have been negotiated. If constraints flags have to be violated at then ERANGE is returned. The error indicates that there exist no rectangle that satisfies the constraints. - - Selection targets and flags are documented in . -
+
Size adjustments with constraint flags. @@ -170,9 +168,9 @@ exist no rectangle that satisfies the constraints.
-
+ - + struct <structname>v4l2_selection</structname> @@ -208,6 +206,7 @@ exist no rectangle that satisfies the constraints.
+
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml index 77ff5be0809..6a821a65a5a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml @@ -155,6 +155,8 @@ or no buffers have been allocated yet, or the userptr or length are invalid. + + EIO VIDIOC_DQBUF failed due to an diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml index f33cc814a01..1ba9e999af3 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml @@ -69,23 +69,22 @@ more information on how each selection target affects the image processing pipeline inside the subdevice. -
+ Types of selection targets There are two types of selection targets: actual and bounds. The actual targets are the targets which configure the hardware. The BOUNDS target will return a rectangle that contain all possible actual rectangles. -
+ -
+ Discovering supported features To discover which targets are supported, the user can perform VIDIOC_SUBDEV_G_SELECTION on them. Any unsupported target will return EINVAL. -
Selection targets and flags are documented in . @@ -132,6 +131,7 @@ +
-- cgit v1.2.3-70-g09d2 From 9020b7cc27439e23a0e993f79ef8632fea5e88d5 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 19 Jul 2012 19:58:39 +0200 Subject: RTC: add DT bindings to pxa-rtc This patch adds generic device tree bindings to the PXA RTC driver. Documentation for bindings were also added. Signed-off-by: Daniel Mack Cc: Robert Jarzmik Cc: Alessandro Zummo Acked-by: Arnd Bergmann Signed-off-by: Haojian Zhuang --- Documentation/devicetree/bindings/rtc/pxa-rtc.txt | 14 ++++++++++++++ drivers/rtc/rtc-pxa.c | 11 +++++++++++ 2 files changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/pxa-rtc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/pxa-rtc.txt b/Documentation/devicetree/bindings/rtc/pxa-rtc.txt new file mode 100644 index 00000000000..8c6672a1b7d --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/pxa-rtc.txt @@ -0,0 +1,14 @@ +* PXA RTC + +PXA specific RTC driver. + +Required properties: +- compatible : Should be "marvell,pxa-rtc" + +Examples: + +rtc@40900000 { + compatible = "marvell,pxa-rtc"; + reg = <0x40900000 0x3c>; + interrupts = <30 31>; +}; diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 0075c8fd93d..f771b2ee4b1 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include @@ -396,6 +398,14 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static struct of_device_id pxa_rtc_dt_ids[] = { + { .compatible = "marvell,pxa-rtc" }, + {} +}; +MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids); +#endif + #ifdef CONFIG_PM static int pxa_rtc_suspend(struct device *dev) { @@ -425,6 +435,7 @@ static struct platform_driver pxa_rtc_driver = { .remove = __exit_p(pxa_rtc_remove), .driver = { .name = "pxa-rtc", + .of_match_table = of_match_ptr(pxa_rtc_dt_ids), #ifdef CONFIG_PM .pm = &pxa_rtc_pm_ops, #endif -- cgit v1.2.3-70-g09d2 From 1e7ba630d4aeabef8e022a4099b20ab9f660d37d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 22 Jul 2012 19:51:02 +0200 Subject: MTD: pxa3xx-nand: add devicetree bindings This patch contains a hack to get the DMA resources of the device when probed from a devicetree node. This can be removed once a generic DMA controller framework lands. A mtd_part_parser_data is passed mtd_device_parse_register which contains a reference to the device node, so MTD partitions can be added as children. Signed-off-by: Daniel Mack Cc: David Woodhouse Acked-by: Arnd Bergmann Signed-off-by: Haojian Zhuang --- .../devicetree/bindings/mtd/pxa3xx-nand.txt | 31 ++++++++ drivers/mtd/nand/pxa3xx_nand.c | 85 ++++++++++++++++++---- 2 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt new file mode 100644 index 00000000000..f1421e2bbab --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -0,0 +1,31 @@ +PXA3xx NAND DT bindings + +Required properties: + + - compatible: Should be "marvell,pxa3xx-nand" + - reg: The register base for the controller + - interrupts: The interrupt to map + - #address-cells: Set to <1> if the node includes partitions + +Optional properties: + + - marvell,nand-enable-arbiter: Set to enable the bus arbiter + - marvell,nand-keep-config: Set to keep the NAND controller config as set + by the bootloader + - num-cs: Number of chipselect lines to usw + +Example: + + nand0: nand@43100000 { + compatible = "marvell,pxa3xx-nand"; + reg = <0x43100000 90>; + interrupts = <45>; + #address-cells = <1>; + + marvell,nand-enable-arbiter; + marvell,nand-keep-config; + num-cs = <1>; + + /* partitions (optional) */ + }; + diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 252aaefcacf..b0319d8934a 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -1081,21 +1083,31 @@ static int alloc_nand_resource(struct platform_device *pdev) } clk_enable(info->clk); - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no resource defined for data DMA\n"); - ret = -ENXIO; - goto fail_put_clk; - } - info->drcmr_dat = r->start; + /* + * This is a dirty hack to make this driver work from devicetree + * bindings. It can be removed once we have a prober DMA controller + * framework for DT. + */ + if (pdev->dev.of_node && cpu_is_pxa3xx()) { + info->drcmr_dat = 97; + info->drcmr_cmd = 99; + } else { + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r == NULL) { + dev_err(&pdev->dev, "no resource defined for data DMA\n"); + ret = -ENXIO; + goto fail_put_clk; + } + info->drcmr_dat = r->start; - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (r == NULL) { - dev_err(&pdev->dev, "no resource defined for command DMA\n"); - ret = -ENXIO; - goto fail_put_clk; + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r == NULL) { + dev_err(&pdev->dev, "no resource defined for command DMA\n"); + ret = -ENXIO; + goto fail_put_clk; + } + info->drcmr_cmd = r->start; } - info->drcmr_cmd = r->start; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -1200,12 +1212,55 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static struct of_device_id pxa3xx_nand_dt_ids[] = { + { .compatible = "marvell,pxa3xx-nand" }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); + +static int pxa3xx_nand_probe_dt(struct platform_device *pdev) +{ + struct pxa3xx_nand_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "marvell,nand-enable-arbiter", NULL)) + pdata->enable_arbiter = 1; + if (of_get_property(np, "marvell,nand-keep-config", NULL)) + pdata->keep_config = 1; + of_property_read_u32(np, "num-cs", &pdata->num_cs); + + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static inline int pxa3xx_nand_probe_dt(struct platform_device *) +{ + return 0; +} +#endif + static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; + struct mtd_part_parser_data ppdata = {}; struct pxa3xx_nand_info *info; int ret, cs, probe_success; + ret = pxa3xx_nand_probe_dt(pdev); + if (ret) + return ret; + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); @@ -1229,8 +1284,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) continue; } + ppdata.of_node = pdev->dev.of_node; ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, - NULL, pdata->parts[cs], + &ppdata, pdata->parts[cs], pdata->nr_parts[cs]); if (!ret) probe_success = 1; @@ -1306,6 +1362,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) static struct platform_driver pxa3xx_nand_driver = { .driver = { .name = "pxa3xx-nand", + .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids), }, .probe = pxa3xx_nand_probe, .remove = pxa3xx_nand_remove, -- cgit v1.2.3-70-g09d2 From c2b7e05c753156dfba3240c59c400d557c5c8746 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Tue, 31 Jul 2012 14:13:14 +0800 Subject: ARM: cache: add dt support for tauros2 cache Signed-off-by: Chao Xie Signed-off-by: Haojian Zhuang --- .../devicetree/bindings/arm/mrvl/tauros2.txt | 17 +++++++++++ arch/arm/mm/cache-tauros2.c | 35 +++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/mrvl/tauros2.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt b/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt new file mode 100644 index 00000000000..31af1cbb60b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt @@ -0,0 +1,17 @@ +* Marvell Tauros2 Cache + +Required properties: +- compatible : Should be "marvell,tauros2-cache". +- marvell,tauros2-cache-features : Specify the features supported for the + tauros2 cache. + The features including + CACHE_TAUROS2_PREFETCH_ON (1 << 0) + CACHE_TAUROS2_LINEFILL_BURST8 (1 << 1) + The definition can be found at + arch/arm/include/asm/hardware/cache-tauros2.h + +Example: + L2: l2-cache { + compatible = "marvell,tauros2-cache"; + marvell,tauros2-cache-features = <0x3>; + }; diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c index e9f054fc7e8..1be0f4e5e6e 100644 --- a/arch/arm/mm/cache-tauros2.c +++ b/arch/arm/mm/cache-tauros2.c @@ -15,6 +15,8 @@ */ #include +#include +#include #include #include #include @@ -198,7 +200,7 @@ static void enable_extra_feature(unsigned int features) write_extra_features(u); } -void __init tauros2_init(unsigned int features) +static void __init tauros2_internal_init(unsigned int features) { char *mode = NULL; @@ -294,3 +296,34 @@ void __init tauros2_init(unsigned int features) printk(KERN_INFO "Tauros2: L2 cache support initialised " "in %s mode.\n", mode); } + +#ifdef CONFIG_OF +static const struct of_device_id tauros2_ids[] __initconst = { + { .compatible = "marvell,tauros2-cache"}, + {} +}; +#endif + +void __init tauros2_init(unsigned int features) +{ +#ifdef CONFIG_OF + struct device_node *node; + int ret; + unsigned int f; + + node = of_find_matching_node(NULL, tauros2_ids); + if (!node) { + pr_info("Not found marvell,tauros2-cache, disable it\n"); + return; + } + + ret = of_property_read_u32(node, "marvell,tauros2-cache-features", &f); + if (ret) { + pr_info("Not found marvell,tauros-cache-features property, " + "disable extra features\n"); + features = 0; + } else + features = f; +#endif + tauros2_internal_init(features); +} -- cgit v1.2.3-70-g09d2 From 5f3d1382e3ca39a54032784414f0ad4e7078b37e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 23 Jul 2012 16:36:35 +0200 Subject: onewire: w1-gpio: add DT bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch add DT bindings to the w1-gpio driver, along with some documentation on how to use them. Signed-off-by: Daniel Mack Acked-by: Evgeniy Polyakov Acked-by: Ville Syrjälä Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/w1/w1-gpio.txt | 22 +++++++++++ drivers/w1/masters/w1-gpio.c | 48 +++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/w1/w1-gpio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/w1/w1-gpio.txt b/Documentation/devicetree/bindings/w1/w1-gpio.txt new file mode 100644 index 00000000000..6e09c35d9f1 --- /dev/null +++ b/Documentation/devicetree/bindings/w1/w1-gpio.txt @@ -0,0 +1,22 @@ +w1-gpio devicetree bindings + +Required properties: + + - compatible: "w1-gpio" + - gpios: one or two GPIO specs: + - the first one is used as data I/O pin + - the second one is optional. If specified, it is used as + enable pin for an external pin pullup. + +Optional properties: + + - linux,open-drain: if specified, the data pin is considered in + open-drain mode. + +Examples: + + onewire@0 { + compatible = "w1-gpio"; + gpios = <&gpio 126 0>, <&gpio 105 0>; + }; + diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index df600d14974..f01c336233d 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "../w1.h" #include "../w1_int.h" @@ -42,12 +44,55 @@ static u8 w1_gpio_read_bit(void *data) return gpio_get_value(pdata->pin) ? 1 : 0; } +#ifdef CONFIG_OF +static struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); + +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(w1_gpio_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "linux,open-drain", NULL)) + pdata->is_open_drain = 1; + + pdata->pin = of_get_gpio(np, 0); + pdata->ext_pullup_enable_pin = of_get_gpio(np, 1); + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ + return 0; +} +#endif + static int __init w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; - struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + struct w1_gpio_platform_data *pdata; int err; + err = w1_gpio_probe_dt(pdev); + if (err < 0) + return err; + + pdata = pdev->dev.platform_data; + if (!pdata) return -ENXIO; @@ -135,6 +180,7 @@ static struct platform_driver w1_gpio_driver = { .driver = { .name = "w1-gpio", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(w1_gpio_dt_ids), }, .remove = __exit_p(w1_gpio_remove), .suspend = w1_gpio_suspend, -- cgit v1.2.3-70-g09d2 From bc2c90c974a0ed390327bbd94f49269e9f24e280 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Aug 2012 16:21:00 +0100 Subject: IIO: Add basic MXS LRADC driver This driver is very basic. It supports userland trigger, buffer and raw access to channels. The support for delay channels is missing altogether. Signed-off-by: Marek Vasut Signed-off-by: Jonathan Cameron Cc: Jonathan Cameron Cc: Juergen Beisert Cc: Lars-Peter Clausen Cc: Shawn Guo Cc: Wolfgang Denk --- .../bindings/staging/iio/adc/mxs-lradc.txt | 15 + drivers/staging/iio/adc/Kconfig | 12 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/mxs-lradc.c | 590 +++++++++++++++++++++ 4 files changed, 618 insertions(+) create mode 100644 Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt create mode 100644 drivers/staging/iio/adc/mxs-lradc.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt new file mode 100644 index 00000000000..801d58cb6d4 --- /dev/null +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -0,0 +1,15 @@ +* Freescale i.MX28 LRADC device driver + +Required properties: +- compatible: Should be "fsl,imx28-lradc" +- reg: Address and length of the register set for the device +- interrupts: Should contain the LRADC interrupts + +Examples: + + lradc@80050000 { + compatible = "fsl,imx28-lradc"; + reg = <0x80050000 0x2000>; + interrupts = <10 14 15 16 17 18 19 + 20 21 22 23 24 25>; + }; diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 67711b7d718..845fb6c70ca 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -200,6 +200,18 @@ config LPC32XX_ADC activate only one via device tree selection. Provides direct access via sysfs. +config MXS_LRADC + tristate "Freescale i.MX28 LRADC" + depends on ARCH_MXS + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for i.MX28 LRADC convertor + built into these chips. + + To compile this driver as a module, choose M here: the + module will be called mxs-lradc. + config SPEAR_ADC tristate "ST SPEAr ADC" depends on PLAT_SPEAR diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 14e98b62b70..ecac9a0bb35 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -38,4 +38,5 @@ obj-$(CONFIG_ADT7310) += adt7310.o obj-$(CONFIG_ADT7410) += adt7410.o obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o +obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c new file mode 100644 index 00000000000..ae549e572e5 --- /dev/null +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -0,0 +1,590 @@ +/* + * Freescale i.MX28 LRADC driver + * + * Copyright (c) 2012 DENX Software Engineering, GmbH. + * Marek Vasut + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define DRIVER_NAME "mxs-lradc" + +#define LRADC_MAX_DELAY_CHANS 4 +#define LRADC_MAX_MAPPED_CHANS 8 +#define LRADC_MAX_TOTAL_CHANS 16 + +#define LRADC_DELAY_TIMER_HZ 2000 + +/* + * Make this runtime configurable if necessary. Currently, if the buffered mode + * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before + * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000) + * seconds. The result is that the samples arrive every 500mS. + */ +#define LRADC_DELAY_TIMER_PER 200 +#define LRADC_DELAY_TIMER_LOOP 5 + +static const char * const mxs_lradc_irq_name[] = { + "mxs-lradc-touchscreen", + "mxs-lradc-thresh0", + "mxs-lradc-thresh1", + "mxs-lradc-channel0", + "mxs-lradc-channel1", + "mxs-lradc-channel2", + "mxs-lradc-channel3", + "mxs-lradc-channel4", + "mxs-lradc-channel5", + "mxs-lradc-channel6", + "mxs-lradc-channel7", + "mxs-lradc-button0", + "mxs-lradc-button1", +}; + +struct mxs_lradc_chan { + uint8_t slot; + uint8_t flags; +}; + +struct mxs_lradc { + struct device *dev; + void __iomem *base; + int irq[13]; + + uint32_t *buffer; + struct iio_trigger *trig; + + struct mutex lock; + + uint8_t enable; + + struct completion completion; +}; + +#define LRADC_CTRL0 0x00 +#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23) +#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22) + +#define LRADC_CTRL1 0x10 +#define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n)) +#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_LRADC_IRQ_EN(n) (1 << ((n) + 16)) +#define LRADC_CTRL1_LRADC_IRQ_EN_MASK (0x1fff << 16) + +#define LRADC_CTRL2 0x20 +#define LRADC_CTRL2_TEMPSENSE_PWD (1 << 15) + +#define LRADC_CH(n) (0x50 + (0x10 * (n))) +#define LRADC_CH_ACCUMULATE (1 << 29) +#define LRADC_CH_NUM_SAMPLES_MASK (0x1f << 24) +#define LRADC_CH_NUM_SAMPLES_OFFSET 24 +#define LRADC_CH_VALUE_MASK 0x3ffff +#define LRADC_CH_VALUE_OFFSET 0 + +#define LRADC_DELAY(n) (0xd0 + (0x10 * (n))) +#define LRADC_DELAY_TRIGGER_LRADCS_MASK (0xff << 24) +#define LRADC_DELAY_TRIGGER_LRADCS_OFFSET 24 +#define LRADC_DELAY_KICK (1 << 20) +#define LRADC_DELAY_TRIGGER_DELAYS_MASK (0xf << 16) +#define LRADC_DELAY_TRIGGER_DELAYS_OFFSET 16 +#define LRADC_DELAY_LOOP_COUNT_MASK (0x1f << 11) +#define LRADC_DELAY_LOOP_COUNT_OFFSET 11 +#define LRADC_DELAY_DELAY_MASK 0x7ff +#define LRADC_DELAY_DELAY_OFFSET 0 + +#define LRADC_CTRL4 0x140 +#define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4)) +#define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4) + +/* + * Raw I/O operations + */ +static int mxs_lradc_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long m) +{ + struct mxs_lradc *lradc = iio_priv(iio_dev); + int ret; + + if (m != IIO_CHAN_INFO_RAW) + return -EINVAL; + + /* Check for invalid channel */ + if (chan->channel > LRADC_MAX_TOTAL_CHANS) + return -EINVAL; + + /* + * See if there is no buffered operation in progess. If there is, simply + * bail out. This can be improved to support both buffered and raw IO at + * the same time, yet the code becomes horribly complicated. Therefore I + * applied KISS principle here. + */ + ret = mutex_trylock(&lradc->lock); + if (!ret) + return -EBUSY; + + INIT_COMPLETION(lradc->completion); + + /* + * No buffered operation in progress, map the channel and trigger it. + * Virtual channel 0 is always used here as the others are always not + * used if doing raw sampling. + */ + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + + writel(chan->channel, lradc->base + LRADC_CTRL4); + writel(0, lradc->base + LRADC_CH(0)); + + /* Enable the IRQ and start sampling the channel. */ + writel(LRADC_CTRL1_LRADC_IRQ_EN(0), + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); + writel(1 << 0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + + /* Wait for completion on the channel, 1 second max. */ + ret = wait_for_completion_killable_timeout(&lradc->completion, HZ); + if (!ret) + ret = -ETIMEDOUT; + if (ret < 0) + goto err; + + /* Read the data. */ + *val = readl(lradc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK; + ret = IIO_VAL_INT; + +err: + writel(LRADC_CTRL1_LRADC_IRQ_EN(0), + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + mutex_unlock(&lradc->lock); + + return ret; +} + +static const struct iio_info mxs_lradc_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = mxs_lradc_read_raw, +}; + +/* + * IRQ Handling + */ +static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) +{ + struct iio_dev *iio = data; + struct mxs_lradc *lradc = iio_priv(iio); + unsigned long reg = readl(lradc->base + LRADC_CTRL1); + + if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK)) + return IRQ_NONE; + + /* + * Touchscreen IRQ handling code shall probably have priority + * and therefore shall be placed here. + */ + + if (iio_buffer_enabled(iio)) + iio_trigger_poll(iio->trig, iio_get_time_ns()); + else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) + complete(&lradc->completion); + + writel(reg & LRADC_CTRL1_LRADC_IRQ_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + return IRQ_HANDLED; +} + +/* + * Trigger handling + */ +static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *iio = pf->indio_dev; + struct mxs_lradc *lradc = iio_priv(iio); + struct iio_buffer *buffer = iio->buffer; + const uint32_t chan_value = LRADC_CH_ACCUMULATE | + ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); + int i, j = 0; + + for_each_set_bit(i, iio->active_scan_mask, iio->masklength) { + lradc->buffer[j] = readl(lradc->base + LRADC_CH(j)); + writel(chan_value, lradc->base + LRADC_CH(j)); + lradc->buffer[j] &= LRADC_CH_VALUE_MASK; + lradc->buffer[j] /= LRADC_DELAY_TIMER_LOOP; + j++; + } + + if (iio->scan_timestamp) { + s64 *timestamp = (s64 *)((u8 *)lradc->buffer + + ALIGN(j, sizeof(s64))); + *timestamp = pf->timestamp; + } + + iio_push_to_buffer(buffer, (u8 *)lradc->buffer, pf->timestamp); + + iio_trigger_notify_done(iio->trig); + + return IRQ_HANDLED; +} + +static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state) +{ + struct iio_dev *iio = trig->private_data; + struct mxs_lradc *lradc = iio_priv(iio); + const uint32_t st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR; + + writel(LRADC_DELAY_KICK, lradc->base + LRADC_DELAY(0) + st); + + return 0; +} + +static const struct iio_trigger_ops mxs_lradc_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = &mxs_lradc_configure_trigger, +}; + +static int mxs_lradc_trigger_init(struct iio_dev *iio) +{ + int ret; + struct iio_trigger *trig; + + trig = iio_trigger_alloc("%s-dev%i", iio->name, iio->id); + if (trig == NULL) + return -ENOMEM; + + trig->dev.parent = iio->dev.parent; + trig->private_data = iio; + trig->ops = &mxs_lradc_trigger_ops; + + ret = iio_trigger_register(trig); + if (ret) { + iio_trigger_free(trig); + return ret; + } + + iio->trig = trig; + + return 0; +} + +static void mxs_lradc_trigger_remove(struct iio_dev *iio) +{ + iio_trigger_unregister(iio->trig); + iio_trigger_free(iio->trig); +} + +static int mxs_lradc_buffer_preenable(struct iio_dev *iio) +{ + struct mxs_lradc *lradc = iio_priv(iio); + struct iio_buffer *buffer = iio->buffer; + int ret = 0, chan, ofs = 0, enable = 0; + uint32_t ctrl4 = 0; + uint32_t ctrl1_irq = 0; + const uint32_t chan_value = LRADC_CH_ACCUMULATE | + ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); + const int len = bitmap_weight(buffer->scan_mask, LRADC_MAX_TOTAL_CHANS); + + if (!len) + return -EINVAL; + + /* + * Lock the driver so raw access can not be done during buffered + * operation. This simplifies the code a lot. + */ + ret = mutex_trylock(&lradc->lock); + if (!ret) + return -EBUSY; + + lradc->buffer = kmalloc(len * sizeof(*lradc->buffer), GFP_KERNEL); + if (!lradc->buffer) { + ret = -ENOMEM; + goto err_mem; + } + + ret = iio_sw_buffer_preenable(iio); + if (ret < 0) + goto err_buf; + + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + + for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) { + ctrl4 |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); + ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs); + writel(chan_value, lradc->base + LRADC_CH(ofs)); + enable |= 1 << ofs; + ofs++; + }; + + writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, + lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); + + writel(ctrl4, lradc->base + LRADC_CTRL4); + writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); + + writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET, + lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET); + + return 0; + +err_buf: + kfree(lradc->buffer); +err_mem: + mutex_unlock(&lradc->lock); + return ret; +} + +static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) +{ + struct mxs_lradc *lradc = iio_priv(iio); + + writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, + lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); + + writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + kfree(lradc->buffer); + mutex_unlock(&lradc->lock); + + return 0; +} + +static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio, + const unsigned long *mask) +{ + const int mw = bitmap_weight(mask, iio->masklength); + + return mw <= LRADC_MAX_MAPPED_CHANS; +} + +static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { + .preenable = &mxs_lradc_buffer_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &mxs_lradc_buffer_postdisable, + .validate_scan_mask = &mxs_lradc_validate_scan_mask, +}; + +/* + * Driver initialization + */ + +#define MXS_ADC_CHAN(idx, chan_type) { \ + .type = (chan_type), \ + .indexed = 1, \ + .scan_index = (idx), \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .channel = (idx), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 18, \ + .storagebits = 32, \ + }, \ +} + +static const struct iio_chan_spec mxs_lradc_chan_spec[] = { + MXS_ADC_CHAN(0, IIO_VOLTAGE), + MXS_ADC_CHAN(1, IIO_VOLTAGE), + MXS_ADC_CHAN(2, IIO_VOLTAGE), + MXS_ADC_CHAN(3, IIO_VOLTAGE), + MXS_ADC_CHAN(4, IIO_VOLTAGE), + MXS_ADC_CHAN(5, IIO_VOLTAGE), + MXS_ADC_CHAN(6, IIO_VOLTAGE), + MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */ + MXS_ADC_CHAN(8, IIO_TEMP), /* Temp sense 0 */ + MXS_ADC_CHAN(9, IIO_TEMP), /* Temp sense 1 */ + MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */ + MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */ + MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */ + MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */ + MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */ + MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */ +}; + +static void mxs_lradc_hw_init(struct mxs_lradc *lradc) +{ + int i; + const uint32_t cfg = + (LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET); + + stmp_reset_block(lradc->base); + + for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) + writel(cfg | (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + i)), + lradc->base + LRADC_DELAY(i)); + + /* Start internal temperature sensing. */ + writel(0, lradc->base + LRADC_CTRL2); +} + +static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) +{ + int i; + + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) + writel(0, lradc->base + LRADC_DELAY(i)); +} + +static int __devinit mxs_lradc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mxs_lradc *lradc; + struct iio_dev *iio; + struct resource *iores; + int ret = 0; + int i; + + /* Allocate the IIO device. */ + iio = iio_device_alloc(sizeof(*lradc)); + if (!iio) { + dev_err(dev, "Failed to allocate IIO device\n"); + return -ENOMEM; + } + + lradc = iio_priv(iio); + + /* Grab the memory area */ + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lradc->dev = &pdev->dev; + lradc->base = devm_request_and_ioremap(dev, iores); + if (!lradc->base) { + ret = -EADDRNOTAVAIL; + goto err_addr; + } + + /* Grab all IRQ sources */ + for (i = 0; i < 13; i++) { + lradc->irq[i] = platform_get_irq(pdev, i); + if (lradc->irq[i] < 0) { + ret = -EINVAL; + goto err_addr; + } + + ret = devm_request_irq(dev, lradc->irq[i], + mxs_lradc_handle_irq, 0, + mxs_lradc_irq_name[i], iio); + if (ret) + goto err_addr; + } + + platform_set_drvdata(pdev, iio); + + init_completion(&lradc->completion); + mutex_init(&lradc->lock); + + iio->name = pdev->name; + iio->dev.parent = &pdev->dev; + iio->info = &mxs_lradc_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = mxs_lradc_chan_spec; + iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec); + + ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time, + &mxs_lradc_trigger_handler, + &mxs_lradc_buffer_ops); + if (ret) + goto err_addr; + + ret = mxs_lradc_trigger_init(iio); + if (ret) + goto err_trig; + + /* Register IIO device. */ + ret = iio_device_register(iio); + if (ret) { + dev_err(dev, "Failed to register IIO device\n"); + goto err_dev; + } + + /* Configure the hardware. */ + mxs_lradc_hw_init(lradc); + + return 0; + +err_dev: + mxs_lradc_trigger_remove(iio); +err_trig: + iio_triggered_buffer_cleanup(iio); +err_addr: + iio_device_free(iio); + return ret; +} + +static int __devexit mxs_lradc_remove(struct platform_device *pdev) +{ + struct iio_dev *iio = platform_get_drvdata(pdev); + struct mxs_lradc *lradc = iio_priv(iio); + + mxs_lradc_hw_stop(lradc); + + iio_device_unregister(iio); + iio_triggered_buffer_cleanup(iio); + mxs_lradc_trigger_remove(iio); + iio_device_free(iio); + + return 0; +} + +static const struct of_device_id mxs_lradc_dt_ids[] = { + { .compatible = "fsl,imx28-lradc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids); + +static struct platform_driver mxs_lradc_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = mxs_lradc_dt_ids, + }, + .probe = mxs_lradc_probe, + .remove = __devexit_p(mxs_lradc_remove), +}; + +module_platform_driver(mxs_lradc_driver); + +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 63d486964cbd0d8556f28bf215c37b0d63f6bbba Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Tue, 14 Aug 2012 16:18:32 -0700 Subject: firmware: remove computone driver firmware and documentation The only Computone support left in the kernel is in drivers/tty/serial/8250/8250_pci.c. CONFIG_COMPUTONE is no longer a valid option. Therefore, remove firmware, documentation, and the last vestiges of this driver. Cc: Rob Landley Cc: Paul Gortmaker Cc: Ben Hutchings Cc: James Bottomley Cc: Dan Williams Signed-off-by: Tim Gardner Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- Documentation/serial/00-INDEX | 2 - Documentation/serial/computone.txt | 520 --------- firmware/Makefile | 1 - firmware/intelliport2.bin.ihex | 2147 ------------------------------------ 4 files changed, 2670 deletions(-) delete mode 100644 Documentation/serial/computone.txt delete mode 100644 firmware/intelliport2.bin.ihex (limited to 'Documentation') diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX index e09468ad3cb..f7b0c7dc25e 100644 --- a/Documentation/serial/00-INDEX +++ b/Documentation/serial/00-INDEX @@ -2,8 +2,6 @@ - this file. README.cycladesZ - info on Cyclades-Z firmware loading. -computone.txt - - info on Computone Intelliport II/Plus Multiport Serial Driver. digiepca.txt - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. hayes-esp.txt diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt deleted file mode 100644 index a6a1158ea2b..00000000000 --- a/Documentation/serial/computone.txt +++ /dev/null @@ -1,520 +0,0 @@ -NOTE: This is an unmaintained driver. It is not guaranteed to work due to -changes made in the tty layer in 2.6. If you wish to take over maintenance of -this driver, contact Michael Warfield . - -Changelog: ----------- -11-01-2001: Original Document - -10-29-2004: Minor misspelling & format fix, update status of driver. - James Nelson - -Computone Intelliport II/Plus Multiport Serial Driver ------------------------------------------------------ - -Release Notes For Linux Kernel 2.2 and higher. -These notes are for the drivers which have already been integrated into the -kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4. - -Version: 1.2.14 -Date: 11/01/2001 -Historical Author: Andrew Manison -Primary Author: Doug McNash - -This file assumes that you are using the Computone drivers which are -integrated into the kernel sources. For updating the drivers or installing -drivers into kernels which do not already have Computone drivers, please -refer to the instructions in the README.computone file in the driver patch. - - -1. INTRODUCTION - -This driver supports the entire family of Intelliport II/Plus controllers -with the exception of the MicroChannel controllers. It does not support -products previous to the Intelliport II. - -This driver was developed on the v2.0.x Linux tree and has been tested up -to v2.4.14; it will probably not work with earlier v1.X kernels,. - - -2. QUICK INSTALLATION - -Hardware - If you have an ISA card, find a free interrupt and io port. - List those in use with `cat /proc/interrupts` and - `cat /proc/ioports`. Set the card dip switches to a free - address. You may need to configure your BIOS to reserve an - irq for an ISA card. PCI and EISA parameters are set - automagically. Insert card into computer with the power off - before or after drivers installation. - - Note the hardware address from the Computone ISA cards installed into - the system. These are required for editing ip2.c or editing - /etc/modprobe.d/*.conf, or for specification on the modprobe - command line. - - Note that the /etc/modules.conf should be used for older (pre-2.6) - kernels. - -Software - - -Module installation: - -a) Determine free irq/address to use if any (configure BIOS if need be) -b) Run "make config" or "make menuconfig" or "make xconfig" - Select (m) module for CONFIG_COMPUTONE under character - devices. CONFIG_PCI and CONFIG_MODULES also may need to be set. -c) Set address on ISA cards then: - edit /usr/src/linux/drivers/char/ip2.c if needed - or - edit config file in /etc/modprobe.d/ if needed (module). - or both to match this setting. -d) Run "make modules" -e) Run "make modules_install" -f) Run "/sbin/depmod -a" -g) install driver using `modprobe ip2 ` (options listed below) -h) run ip2mkdev (either the script below or the binary version) - - -Kernel installation: - -a) Determine free irq/address to use if any (configure BIOS if need be) -b) Run "make config" or "make menuconfig" or "make xconfig" - Select (y) kernel for CONFIG_COMPUTONE under character - devices. CONFIG_PCI may need to be set if you have PCI bus. -c) Set address on ISA cards then: - edit /usr/src/linux/drivers/char/ip2.c - (Optional - may be specified on kernel command line now) -d) Run "make zImage" or whatever target you prefer. -e) mv /usr/src/linux/arch/x86/boot/zImage to /boot. -f) Add new config for this kernel into /etc/lilo.conf, run "lilo" - or copy to a floppy disk and boot from that floppy disk. -g) Reboot using this kernel -h) run ip2mkdev (either the script below or the binary version) - -Kernel command line options: - -When compiling the driver into the kernel, io and irq may be -compiled into the driver by editing ip2.c and setting the values for -io and irq in the appropriate array. An alternative is to specify -a command line parameter to the kernel at boot up. - - ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 - -Note that this order is very different from the specifications for the -modload parameters which have separate IRQ and IO specifiers. - -The io port also selects PCI (1) and EISA (2) boards. - - io=0 No board - io=1 PCI board - io=2 EISA board - else ISA board io address - -You only need to specify the boards which are present. - - Examples: - - 2 PCI boards: - - ip2=1,0,1,0 - - 1 ISA board at 0x310 irq 5: - - ip2=0x310,5 - -This can be added to and "append" option in lilo.conf similar to this: - - append="ip2=1,0,1,0" - - -3. INSTALLATION - -Previously, the driver sources were packaged with a set of patch files -to update the character drivers' makefile and configuration file, and other -kernel source files. A build script (ip2build) was included which applies -the patches if needed, and build any utilities needed. -What you receive may be a single patch file in conventional kernel -patch format build script. That form can also be applied by -running patch -p1 < ThePatchFile. Otherwise run ip2build. - -The driver can be installed as a module (recommended) or built into the -kernel. This is selected as for other drivers through the `make config` -command from the root of the Linux source tree. If the driver is built -into the kernel you will need to edit the file ip2.c to match the boards -you are installing. See that file for instructions. If the driver is -installed as a module the configuration can also be specified on the -modprobe command line as follows: - - modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4 - -where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11, -12,15) and addr1-4 are the base addresses for up to four controllers. If -the irqs are not specified the driver uses the default in ip2.c (which -selects polled mode). If no base addresses are specified the defaults in -ip2.c are used. If you are autoloading the driver module with kerneld or -kmod the base addresses and interrupt number must also be set in ip2.c -and recompile or just insert and options line in /etc/modprobe.d/*.conf or both. -The options line is equivalent to the command line and takes precedence over -what is in ip2.c. - -config sample to put /etc/modprobe.d/*.conf: - options ip2 io=1,0x328 irq=1,10 - alias char-major-71 ip2 - alias char-major-72 ip2 - alias char-major-73 ip2 - -The equivalent in ip2.c: - -static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 }; -static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 }; - -The equivalent for the kernel command line (in lilo.conf): - - append="ip2=1,1,0x328,10" - - -Note: Both io and irq should be updated to reflect YOUR system. An "io" - address of 1 or 2 indicates a PCI or EISA card in the board table. - The PCI or EISA irq will be assigned automatically. - -Specifying an invalid or in-use irq will default the driver into -running in polled mode for that card. If all irq entries are 0 then -all cards will operate in polled mode. - -If you select the driver as part of the kernel run : - - make zlilo (or whatever you do to create a bootable kernel) - -If you selected a module run : - - make modules && make modules_install - -The utility ip2mkdev (see 5 and 7 below) creates all the device nodes -required by the driver. For a device to be created it must be configured -in the driver and the board must be installed. Only devices corresponding -to real IntelliPort II ports are created. With multiple boards and expansion -boxes this will leave gaps in the sequence of device names. ip2mkdev uses -Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and -cuf0 - cuf255 for callout devices. - - -4. USING THE DRIVERS - -As noted above, the driver implements the ports in accordance with Linux -conventions, and the devices should be interchangeable with the standard -serial devices. (This is a key point for problem reporting: please make -sure that what you are trying do works on the ttySx/cuax ports first; then -tell us what went wrong with the ip2 ports!) - -Higher speeds can be obtained using the setserial utility which remaps -38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. -Intelliport II installations using the PowerPort expansion module can -use the custom speed setting to select the highest speeds: 153,600 bps, -230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for -custom baud rate configuration is fixed at 921,600 for cards/expansion -modules with ST654's and 115200 for those with Cirrus CD1400's. This -corresponds to the maximum bit rates those chips are capable. -For example if the baud base is 921600 and the baud divisor is 18 then -the custom rate is 921600/18 = 51200 bps. See the setserial man page for -complete details. Of course if stty accepts the higher rates now you can -use that as well as the standard ioctls(). - - -5. ip2mkdev and assorted utilities... - -Several utilities, including the source for a binary ip2mkdev utility are -available under .../drivers/char/ip2. These can be build by changing to -that directory and typing "make" after the kernel has be built. If you do -not wish to compile the binary utilities, the shell script below can be -cut out and run as "ip2mkdev" to create the necessary device files. To -use the ip2mkdev script, you must have procfs enabled and the proc file -system mounted on /proc. - - -6. NOTES - -This is a release version of the driver, but it is impossible to test it -in all configurations of Linux. If there is any anomalous behaviour that -does not match the standard serial port's behaviour please let us know. - - -7. ip2mkdev shell script - -Previously, this script was simply attached here. It is now attached as a -shar archive to make it easier to extract the script from the documentation. -To create the ip2mkdev shell script change to a convenient directory (/tmp -works just fine) and run the following command: - - unshar Documentation/serial/computone.txt - (This file) - -You should now have a file ip2mkdev in your current working directory with -permissions set to execute. Running that script with then create the -necessary devices for the Computone boards, interfaces, and ports which -are present on you system at the time it is run. - - -#!/bin/sh -# This is a shell archive (produced by GNU sharutils 4.2.1). -# To extract the files from this archive, save it to some FILE, remove -# everything before the `!/bin/sh' line above, then type `sh FILE'. -# -# Made on 2001-10-29 10:32 EST by . -# Source directory was `/home2/src/tmp'. -# -# Existing files will *not* be overwritten unless `-c' is specified. -# -# This shar contains: -# length mode name -# ------ ---------- ------------------------------------------ -# 4251 -rwxr-xr-x ip2mkdev -# -save_IFS="${IFS}" -IFS="${IFS}:" -gettext_dir=FAILED -locale_dir=FAILED -first_param="$1" -for dir in $PATH -do - if test "$gettext_dir" = FAILED && test -f $dir/gettext \ - && ($dir/gettext --version >/dev/null 2>&1) - then - set `$dir/gettext --version 2>&1` - if test "$3" = GNU - then - gettext_dir=$dir - fi - fi - if test "$locale_dir" = FAILED && test -f $dir/shar \ - && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) - then - locale_dir=`$dir/shar --print-text-domain-dir` - fi -done -IFS="$save_IFS" -if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED -then - echo=echo -else - TEXTDOMAINDIR=$locale_dir - export TEXTDOMAINDIR - TEXTDOMAIN=sharutils - export TEXTDOMAIN - echo="$gettext_dir/gettext -s" -fi -if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then - shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"' -elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then - shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"' -elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then - shar_touch='touch -am $3$4$5$6$2 "$8"' -else - shar_touch=: - echo - $echo 'WARNING: not restoring timestamps. Consider getting and' - $echo "installing GNU \`touch', distributed in GNU File Utilities..." - echo -fi -rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch -# -if mkdir _sh17581; then - $echo 'x -' 'creating lock directory' -else - $echo 'failed to create lock directory' - exit 1 -fi -# ============= ip2mkdev ============== -if test -f 'ip2mkdev' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)' -else - $echo 'x -' extracting 'ip2mkdev' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' && -#!/bin/sh - -# -# ip2mkdev -# -# Make or remove devices as needed for Computone Intelliport drivers -# -# First rule! If the dev file exists and you need it, don't mess -# with it. That prevents us from screwing up open ttys, ownership -# and permissions on a running system! -# -# This script will NOT remove devices that no longer exist if their -# board or interface box has been removed. If you want to get rid -# of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*" -# before running this script. Running this script will then recreate -# all the valid devices. -# -# Michael H. Warfield -# /\/\|=mhw=|\/\/ -# mhw@wittsend.com -# -# Updated 10/29/2000 for version 1.2.13 naming convention -# under devfs. /\/\|=mhw=|\/\/ -# -# Updated 03/09/2000 for devfs support in ip2 drivers. /\/\|=mhw=|\/\/ -# -X -if test -d /dev/ip2 ; then -# This is devfs mode... We don't do anything except create symlinks -# from the real devices to the old names! -X cd /dev -X echo "Creating symbolic links to devfs devices" -X for i in `ls ip2` ; do -X if test ! -L ip2$i ; then -X # Remove it incase it wasn't a symlink (old device) -X rm -f ip2$i -X ln -s ip2/$i ip2$i -X fi -X done -X for i in `( cd tts ; ls F* )` ; do -X if test ! -L tty$i ; then -X # Remove it incase it wasn't a symlink (old device) -X rm -f tty$i -X ln -s tts/$i tty$i -X fi -X done -X for i in `( cd cua ; ls F* )` ; do -X DEVNUMBER=`expr $i : 'F\(.*\)'` -X if test ! -L cuf$DEVNUMBER ; then -X # Remove it incase it wasn't a symlink (old device) -X rm -f cuf$DEVNUMBER -X ln -s cua/$i cuf$DEVNUMBER -X fi -X done -X exit 0 -fi -X -if test ! -f /proc/tty/drivers -then -X echo "\ -Unable to check driver status. -Make sure proc file system is mounted." -X -X exit 255 -fi -X -if test ! -f /proc/tty/driver/ip2 -then -X echo "\ -Unable to locate ip2 proc file. -Attempting to load driver" -X -X if /sbin/insmod ip2 -X then -X if test ! -f /proc/tty/driver/ip2 -X then -X echo "\ -Unable to locate ip2 proc file after loading driver. -Driver initialization failure or driver version error. -" -X exit 255 -X fi -X else -X echo "Unable to load ip2 driver." -X exit 255 -X fi -fi -X -# Ok... So we got the driver loaded and we can locate the procfs files. -# Next we need our major numbers. -X -TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` -CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` -BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2` -X -echo "\ -TTYMAJOR = $TTYMAJOR -CUAMAJOR = $CUAMAJOR -BRDMAJOR = $BRDMAJOR -" -X -# Ok... Now we should know our major numbers, if appropriate... -# Now we need our boards and start the device loops. -X -grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest -do -X # The test for blank "type" will catch the stats lead-in lines -X # if they exist in the file -X if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = "" -X then -X continue -X fi -X -X BOARDNO=`expr "$number" : '\([0-9]\):'` -X PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '` -X MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '` -X -X if test "$BOARDNO" = "" -o "$PORTS" = "" -X then -# This may be a bug. We should at least get this much information -X echo "Unable to process board line" -X continue -X fi -X -X if test "$MINORS" = "" -X then -# Silently skip this one. This board seems to have no boxes -X continue -X fi -X -X echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS" -X -X if test "$BRDMAJOR" != "" -X then -X BRDMINOR=`expr $BOARDNO \* 4` -X STSMINOR=`expr $BRDMINOR + 1` -X if test ! -c /dev/ip2ipl$BOARDNO ; then -X mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR -X fi -X if test ! -c /dev/ip2stat$BOARDNO ; then -X mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR -X fi -X fi -X -X if test "$TTYMAJOR" != "" -X then -X PORTNO=$BOARDBASE -X -X for PORTNO in $MINORS -X do -X if test ! -c /dev/ttyF$PORTNO ; then -X # We got the hardware but no device - make it -X mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO -X fi -X done -X fi -X -X if test "$CUAMAJOR" != "" -X then -X PORTNO=$BOARDBASE -X -X for PORTNO in $MINORS -X do -X if test ! -c /dev/cuf$PORTNO ; then -X # We got the hardware but no device - make it -X mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO -X fi -X done -X fi -done -X -Xexit 0 -SHAR_EOF - (set 20 01 10 29 10 32 01 'ip2mkdev'; eval "$shar_touch") && - chmod 0755 'ip2mkdev' || - $echo 'restore of' 'ip2mkdev' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'ip2mkdev:' 'MD5 check failed' -cb5717134509f38bad9fde6b1f79b4a4 ip2mkdev -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`" - test 4251 -eq "$shar_count" || - $echo 'ip2mkdev:' 'original size' '4251,' 'current size' "$shar_count!" - fi -fi -rm -fr _sh17581 -exit 0 diff --git a/firmware/Makefile b/firmware/Makefile index 344713b1166..fdc9ff045ef 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -40,7 +40,6 @@ fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \ bnx2/bnx2-mips-06-6.2.1.fw \ bnx2/bnx2-rv2p-06-6.0.15.fw fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin -fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ cxgb3/t3c_psram-1.1.0.bin \ cxgb3/t3fw-7.10.0.bin \ diff --git a/firmware/intelliport2.bin.ihex b/firmware/intelliport2.bin.ihex deleted file mode 100644 index e9cfe8cb2b2..00000000000 --- a/firmware/intelliport2.bin.ihex +++ /dev/null @@ -1,2147 +0,0 @@ -:100000003C4237180201030000000000000000001D -:10001000576564204465632030312031323A3234F0 -:100020003A33302031393939000000000000000037 -:10003000E96C0F426547694E6E496E47206F462056 -:10004000634F6445CC135A15E8167618041A921BB0 -:10005000201DAE1E3C20CA215823E6247426022807 -:1000600090291E2BAC2C3A2EC82F5631E432723414 -:1000700000368E371C39AA3A383CC63D543FE24020 -:100080007042FE438C451A47A848364AC44B524D2D -:10009000E04E6E50FC518A531855A6563458C2593A -:1000A000505BDE5C6C5EFA5F88611663A464326646 -:1000B000C0674E69DC6A6A6CF86D866F1471A27253 -:1000C0003074BE754C776C778C77AC7733DB8ADC19 -:1000D0005333DB250700750A8A1E080183E30CEB06 -:1000E00020903C01750A8A1E080180E3C0EB129043 -:1000F0008A1E0D013C02750680E30CEB049080E340 -:10010000C053508B1EBA138EDBE86A65558BEC53D7 -:100110001E2BC08ED88B5E04C1E304035E06D1E3C0 -:100120002E8B9F44008D472A1E5A1F5B5DC3558B43 -:10013000EC531E2BC08ED88B5E04C1E304035E0615 -:10014000D1E32E8B9F44008D47341E5A1F5B5DC345 -:10015000FB558BEC53515256571E061E0733C08E6B -:10016000D88B5E04268A47592503008BF0D1E62EF2 -:100170008BB4C400C1E0042602471AD1E08BE82EFC -:100180008BAE4400892C268A471C88440F268A4758 -:100190001D884410268A471E884411268A471F88D6 -:1001A0004412268A4720884413268A472388441409 -:1001B000268A4724884415268A475A88440E33C025 -:1001C00089440689440888440B88440AB021B464F1 -:1001D000894404894402B05588440D88440CE86A77 -:1001E00000725BE8C900E8C110894408807C0F01F7 -:1001F0007429E82B02E87F02807C0F03741DE8A9B4 -:10020000108BF82B44083DA00F7210897C0833C076 -:1002100087440685C07504C6440AFF8A440A84C020 -:10022000750BB80800E86A4AE8A90173BFE84F01F6 -:100230008166487FFF83667ABFB002E8040E8A4475 -:100240000A98071F5F5E5A595B5DC3814E48800064 -:10025000B040E83D4AE88940732AE84D108BD8B099 -:1002600005E82E4AF6462702751AE83D102BC33DD5 -:10027000581B72EB8166487FFFB002E8C40DC6448C -:100280000A01F9C3834E7A40F8C3FBB001E8024A81 -:10029000FAE8991EE40A84C075F0B04EE60AFBB095 -:1002A00001E8EE49FAE8851EE40A84C075F0C3FA55 -:1002B000E87A1EE4EC884416E4E4884417E4F888FD -:1002C0004418E4F0884419E41088441AE41288447D -:1002D0001BE41488441CE43488441DE43688441E1E -:1002E000E4D824018AE0E4DA24020AC488441F8A9C -:1002F0004410E8CD1F8A4411E835218A4412E88968 -:10030000218A4413E84321C686A10000E414241086 -:10031000E614E412243DE6128A44153C01721E776D -:1003200016B011E634B013E636E4140C10E614E40B -:10033000120C40E612EB06E4120C02E6128A440F9D -:100340003C0174063C02740AEB0EE4120C08E6123F -:10035000EB06E4120C10E612E82FFF8A44143C026C -:100360007508B05588440C88440DB021B4648944A4 -:1003700004894402E40C0C10E60CE8ED39FBC3E8F8 -:100380005F3F7308FBB00AE80849EBF3FAE89D1DEC -:100390008A64168A441789869400E6E48AC4E6ECE7 -:1003A0008A64188A441989869600E6F08AC4E6F8B9 -:1003B0008A441AE6108A441BE6128A441CE6148A10 -:1003C000441DE6348A441EE6368A441FE6D8E6DA3F -:1003D000E9B7FE90FA8A440EE6FEE402A80175052C -:1003E00033C0FBF8C333C0E400FBF9C38A64148054 -:1003F000FC02742BFEC0FEC780FF4E721C74098085 -:10040000FF507308B00AEB17B00DEB1302DC32FF9C -:1004100080FB7F7C02B3218AC33C7F7C02B021C376 -:10042000FA807C0B047602FBC38B46243D080072E5 -:10043000F68E46028B7E228A440C8B5C02AAE8ABC5 -:10044000FFAAE8A7FFAAE8A3FFAAE89FFF88440C39 -:10045000895C0280440B04897E22836E24048346D7 -:100460001A04807E26027406806626FDFBC360B0F7 -:10047000FDE8023F61FBC3FA807C0F037509C644A7 -:100480000B00E8E538FBC3C47E148B4E3A85C97572 -:1004900035268B0D4747E3EA3B7E047622B80200FF -:1004A00039462E7707C7462E0000EB138B5E2C894A -:1004B0005E0426C70700004343895E2C29462E852B -:1004C000C978CE894E3A8A440D8B5C04268A25472A -:1004D0003AC47516FE4C0BFF4406E80FFFE2ED88A8 -:1004E000440D895C04894E3AEBA7C6440AFEE879BC -:1004F00038FBC390E8B30D8AE88A0ECB13B3078AA2 -:10050000C1EEEB00EC3AC1750902CDFECB75F0EB04 -:100510000C90880ECB138AE8BBFFFFF9C3880ECB83 -:1005200013F8C390BB3F3F8A8E9E00BAFE00EC8A50 -:10053000E832C122C37502F8C3F9C390E8E5FF733E -:1005400001C3BAD000BB03038A8E9F00EC8AE83255 -:10055000C122C37502F8C3F9C39033C08ED88EC0D0 -:10056000803EC813007507B00AE82647EBF2FB335C -:10057000DB8A1EC913434383FB7E760733DBB0025D -:10058000E80F472E8BAF4400837E080074E7881E77 -:10059000C913B002E8FB46FAF7463840007414E885 -:1005A000961BE87FFF721C33D28A969F0083C20E8F -:1005B000EB0C90E8771BE883FF7208BA4800E83339 -:1005C000FF73AB23CB898E9A0089969C00FE86B57B -:1005D00000C606C81300B00AE8670AFBEB891018CA -:1005E000082833C0A005018AC824407524C7067CAA -:1005F000128E45C70642120100C606541202B00808 -:10060000F6C1017402B004A34612A24C12A29412C5 -:10061000C3C7067C12B645A00F0184C0750E6A00E0 -:100620001FC60693121E9C0EE8B10C90C70644121A -:100630000100A342128BD8C1E304881E9412BEE2CB -:10064000052BF08BC833DB8BFB2EAC888548128AD8 -:10065000D80C05E6FE8AE0EB00E4FE32C4A83F7445 -:1006600003E99E00E400888550128AE02430BA1025 -:10067000FF3C30741280FC04740ABA0403F60608C6 -:1006800001FE7403BA080F88954C1202FA32C0F6C4 -:10069000C4087402B001888558128AC43C35745B62 -:1006A0003C3674573C3474533C04744F3C14744BC4 -:1006B0003C157447A8407425C685541204D1E7B48C -:1006C000038AC389855C128AC38AE380CC01898549 -:1006D0006412D1EF47E203EB1A90E96CFFC6855430 -:1006E0001202D1E78AE68AC30C0489855C12D1EF35 -:1006F00047E2E733C08AC7A34612C3C68554120631 -:10070000EBBBC68554120033C08885501288854CD7 -:100710001288855812EBA6C7462602128B461E8900 -:1007200046008946228B4620894624C7461A000087 -:10073000C3C7463C8000C7463801001E568B763042 -:100740008976048976148E5E0633C089044646890C -:10075000762C89463A8B4632484889462E5E1FC31E -:1007600033C089464889464AC74646AE0189464E47 -:100770008B46448946508B4642894640894608C389 -:1007800033C0894676894678C7467A1000561E8B54 -:10079000767089761089760C8E5E12C70400008B05 -:1007A00046728946741F5EC3895618895602895657 -:1007B0000689560A89560E8956128956168BD84BC9 -:1007C0004BC1E302BF0200897E1E03FB897E30031A -:1007D000FB897E4203FB897E7083EB08895E20895A -:1007E0005E32895E44895E7250E82BFFE871FFE853 -:1007F0003FFFE88BFF58C3B83075C1E8040E5B03B8 -:10080000C3A3BA13833E4212007407803E941200C1 -:10081000750E6A001FC60693121E9C0EE8BD0A9054 -:10082000B8307AC1E80440A3C0132B061201F7D8F0 -:1008300033D28BCA8A0E9412F7F13D8000770E6A8C -:10084000001FC6069312259C0EE8900A90483DFFB3 -:10085000077203B8FF07A3C21333C98A0E94123379 -:10086000F6B800092E8BAC440089464C404646E25F -:10087000F38A0E941233F68B16C013A1C2132E8B7B -:10088000AC4400E822FF03D04646E2F2C333C02E58 -:100890008BAD44008946084747E2F4C35133C00A90 -:1008A000C22E8BAD440089869E00814E38002047C1 -:1008B00047FEC480FC04720432E4FEC0E2E35983C4 -:1008C000E9107405F7D9E8C4FFC35133C00AC22E3A -:1008D0008BAD440089869E00834E3840474780C4D4 -:1008E00010790432E4FEC0E2E65983E9107405F79A -:1008F000D9E899FFC3E8D2FFC38D089C08CA08F560 -:10090000088B0E421233F6515633DB8BCB8A944858 -:10091000128A8C4C128A9C54128BFEC1E70585DB2F -:100920007502B1102EFF97F9085E5946E2D9C3014E -:10093000CC03D000E802D000E801D000E800D000ED -:10094000E804D0A8DA00DC00DE01D803CC03CC0335 -:10095000CC04D0A8DA20DC00DE03CC03CC03CC002E -:10096000D803CC03CC03CC03CC03CC03CC03CC0303 -:10097000CC03CC03CC03CC03CC03CC03CC03CC03FF -:10098000CC04D000DA20DC03DE01D803CC03CC0396 -:10099000CC03CC00D800CC00D0000056521E0E1F55 -:1009A000BE2F0933D2FCAD85C0740D8AD4EEAD855F -:1009B000C074058AD4EEEBEE1F5A5EC3E48084C097 -:1009C00074167814B027E6FCB011E634E4FC3C273A -:1009D0007506E4117502F8C3F9C383C206B0BFEE11 -:1009E00083EA02B010EE8886AF00B01183C204EE35 -:1009F00083C202EEB01383C202EE83C202EE2EA1C6 -:100A00004C2D8986940083EA0EEE83C2028AC4EEDE -:100A100083C204B003EE8886A80083EA0432C0EEE5 -:100A200083C202B089EE8886A6000C06EEB040B400 -:100A30003889461CC74636380083C20432C0EE8867 -:100A400086A700C383C206B0BFEE83EA02EC3A86F3 -:100A5000AF00752483C204EC3C11751C83C206EC04 -:100A60003C13751483EA088A86A800EE83EA02EC38 -:100A700024C03CC07502F8C3F9C333C98BD18BF1D4 -:100A80008A0E9412C1E9022E8BAC4400F74638005E -:100A900020740E8A869E00E6FE32C0E68042E8FAA6 -:100AA000FE83C608E2E185D27403E80508C333C9B2 -:100AB0008BF18A0E94122E8BAC4400F7463840001E -:100AC0007406E87316E812FF4646E2EAC333C98BA0 -:100AD000F18A0E9412C1E9022E8BAC4400F746381D -:100AE00000207416E84616E8D2FE730E6A001FC690 -:100AF0000693121C9C0EE8E3079083C608E2D9C354 -:100B000033C98BF18A0E94122E8BAC4400F7463811 -:100B100040007416E82116E82AFF730E6A001FC60B -:100B20000693121C9C0EE8B307904646E2DAC30C0B -:100B300000001000131200001400283C001B3E00AF -:100B4000002A00002C0000420014D80000DA000047 -:100B50003400113600133800113A001300005650CB -:100B600052BE2F0B2EAD85C07406922EACEEEBF468 -:100B70005A585EC3532EA16022E6E4E6F08AC4E62A -:100B8000ECE6F8E8D8FFB04BE610B050E612B0380B -:100B9000E614E8AE15B046E60AE8A715B01AE60A6C -:100BA000E8A015B022E60AE89915E8FD068BD8E41E -:100BB00016A8047518E8F2062BC33D320072F06ADD -:100BC000001FC6069312239C0EE8100790E8DA0671 -:100BD0002BC33D2400771BB031E6FC565155B910AC -:100BE000002E8BAC4400814E3880004646E2F25D18 -:100BF000595EE869FFE84B15B046E60AE844155B24 -:100C0000C333F68B0E42122E8BAC4400F7463800ED -:100C1000207406E81715E85BFF83C620E2E9C38B62 -:100C2000C20504008946282EA14C2D89868E008994 -:100C300086900089869200C686A3000AC686C300F5 -:100C4000035283C2048A86A6000C06EE5A83C202AF -:100C5000B005EE8886A500C3E803FFE8E514B042BE -:100C6000E60AF74638800074062EA19C22EB042E7B -:100C7000A16C22C7461C0C008986940089869600C8 -:100C800089868E008986900089869200E6F0E6E4E7 -:100C90008AC4E6F8E6ECC686C30003E8A514B01AD9 -:100CA000E60AB0108886A500E60CC333C98BF18A2A -:100CB0000E94122E8BAC4400F7463840007406E8C0 -:100CC0007614E85AFF4646E2EAC333C98BF18A0E2E -:100CD00094122E8BAC4400F7463800207406E84C82 -:100CE00014E874FF4646E2EAC390833E441200755E -:100CF00014B001BA0601EE2AC0EEB002EEB004EE66 -:100D0000B80002EB0FBA0601B040EEB801008A0E3F -:100D10000E01D3E0A38812C3A18812A384122D2050 -:100D200000A38A122D2000A38212C706861220007B -:100D3000C70680123200C3833E44120074768B0EC5 -:100D4000421233F68AA4541284E4745F8A844812EF -:100D50000C04E6FEF6C4047425B01BBA0000EEEBEA -:100D6000002AC0BA0200EEEB00B003EEEB0032C086 -:100D7000BA0200EEEB00BA0000B000EEEB2DB01F9F -:100D8000BA0000EEEB002AC0BA0200EEEB00B0039E -:100D9000EEEB00D1E68A845D12D1EEF6D0BA020005 -:100DA000EEEB00BA0000B00AEEEB00E404EB00E466 -:100DB0000446E290C390B81400BA3EFFEFB80600B4 -:100DC000BA32FFEFB80F00BA34FFEFBA36FFEF8345 -:100DD0003E4412007516B81100BA38FFEFB8120081 -:100DE000BA3AFFEFB81B00BA3CFFEFC3B81100BA24 -:100DF00038FFEFB81200BA3AFFEFB81B00BA3CFF59 -:100E0000EFC3B8FC00BA28FFEFFB833E4412007426 -:100E100007B8CC00BA28FFEFC300FFFF202428FF4B -:100E20002CFFFF303438FFFF3C903C0F770EBB198E -:100E30000E2ED73CFF74058AD8F8C3902ADBF9C37D -:100E4000833E4412007427A00601802606013080EC -:100E50003E0601307518B90200BFC413BA0601EC92 -:100E6000A82075F8BA0401EDABE2F1EB1690B904D5 -:100E700000BFC413BA0601ECA82075F8BA0401EC4F -:100E8000AAE2F1FA90BEC413AD80E43F80FC027484 -:100E90000E6A001FC60693120A9C0EE83E0490AD2F -:100EA0003C0F75ED8AC4E881FF72E6881E1A01C600 -:100EB000068E1200B0000A061A01BA0001EEC6063C -:100EC0008F1240833E4412007506B80C00EB04906C -:100ED000B84C00BA28FFEFC3833E4412007501C32B -:100EE000A150120B0652120AC4A80874F2A00F01F6 -:100EF0002AE450FF36BA131FE8505683C4026A0032 -:100F00001F33C0A3BC13A00F01A3BE138B1EBC13C1 -:100F10008A875012F687501208740D24078AE0BEA3 -:100F2000CC00A0BC13E8943DFF06BC13FF0EBE131B -:100F300075DAC3901E33C08ED8B001E8543D1FC38C -:100F400033C98BF18A0E94122E8BAC4400C74662D3 -:100F50003844C7467CFC3BC7467EE23BC7868000E0 -:100F6000EC3CE8AB16C686C00011837E080074070F -:100F70005156E833335E594646E2CDC333C98BF14F -:100F80008BF98A0E9412C1E902E3132E8BAC440054 -:100F90008A869E0088856C1283C60847E2EDC3FAF4 -:100FA000FCB0C0BA0001EE33C08ED88EC08ED0BF68 -:100FB0001601B9CC772BCFD1E9F3ABBC4012E8D9FD -:100FC00002E8703CBECC0FE8F23CF49033C08ED8FF -:100FD0008EC08ED0F6060A0180740BBE3555E8DB54 -:100FE0003CB001E8AC3CE8B300E8F6F5E808F8E806 -:100FF0000FF9E885FAE8B6FAE8EFFCE8C210E80372 -:101000003CE8B2FDE830FDE85402C6068F12C0E8A5 -:10101000BBFAE8EBFAE8E9FBE8AFFCE88DFCE81F77 -:10102000FFE858FFE8DBFDE816FE33C0BE5A05E8CE -:101030008A3CE8A3FEE8E0FCFBBEA444E87D3CE972 -:10104000CA2D56988BF08B425285C07527C74252E5 -:10105000010053368B9C2C01F6C301750C36896850 -:10106000523689AC2C015B5EC33689AC2C013689C3 -:10107000AC1C015B5EC356988BF033ED368B841C41 -:1010800001A80175158BE833C08742523689841C4C -:1010900001A80174053689842C015EC3565133F6CC -:1010A000B80100B9080089841C0189842C014646D6 -:1010B000E2F4595EC390BB01008BE8FF4E6E740AE8 -:1010C0008BDD8B4658A80174F0C38B4648A90800F5 -:1010D0007445F7463840007427E85C1080C2068AE1 -:1010E00086A80024BF8886A800EE60B0FEE886329D -:1010F00061B002E84CFF8B464824F7894648EB175D -:10110000E82A10814E2600408A86A5000C028886B7 -:10111000A500E60C8B4648A904007414B002E8212F -:10112000FF8B464824FB89464860B0DFE8473261C0 -:1011300033C0874658F6C301750B36894758A80156 -:10114000750DE974FFA32201A8017503E96AFF89FF -:101150001E3201C3BB01008BE8F74638400074150E -:10116000E8D50F80C20AECA840750A8BDD8B465685 -:10117000A80174E3C38B462680E4FE80CC02894636 -:1011800026B002E8BCFE33C0874656F6C301750A96 -:1011900036894756A801750BEBBDA32001A8017540 -:1011A00002EBB4891E3001C3601E062BC08ED8A08E -:1011B000901284C07549A12201A8017503E8F6FECA -:1011C000A12001A8017503E88AFFA1AC13487805A6 -:1011D0007445A3AC13A1AE134878057451A3AE13A4 -:1011E000A1B0134878057463A3B013A17E124078B0 -:1011F00003A37E12B80080BA22FFEF071F61CFA0C1 -:101200009112403C02720B33C0A29112FF167C1265 -:10121000EBA4A29112EB9FA08E1232068F12A28E27 -:10122000120A061A01BA0001EEB82C01EBA4833EA3 -:101230008412107211BA28FFED0C81EFE85337BA0F -:1012400028FFED247EEFB80400EB92C6068D120154 -:10125000E83F37C6068D1200A1B213EB8B908A1EB1 -:101260000B012AFF6BC319BA62FFEFB80A00BA601C -:10127000FFEFB801E0BA66FFEFB8FFFFBA52FFEF29 -:10128000B809C0BA56FFEFC706AC132C01C706AEAB -:10129000130400C606911200C3908A1E0B012AFF98 -:1012A0006BC305D1E8A31801C39052BA50FFED5AA1 -:1012B000C39053518B1E1801B9320590E2FE4B7555 -:1012C000F7595BC3B080BA00010A061A01EEC39059 -:1012D000B040EBF2B0C0EBEEB000EBEAFA60061EF5 -:1012E000162BDB8EDB2EA1BA4C2EA3924CA09312B0 -:1012F000988BE889262D7A803ECA13007403E96B27 -:1013000042E8C0FFE8ABFFE8A8FFB020C606901295 -:1013100000FF167C128BFD83FF0A7211E8B9FFE80B -:1013200090FFE8ABFFE88AFF83EF0AEBEA0BFF745C -:101330000FE8A4FFE87BFFE89AFFE875FF4F75F11F -:10134000E895FFE86CFFEBB98A86A50024FDEE88DE -:1013500086A500C38A86A6000C02EEC38B7638F7FA -:10136000C6010074EF8B4E368B462E3BC173028B49 -:10137000C82BC189462E014E34C47E0426010D8B34 -:101380007E2C83EA04F36C8EC1897E2C3B463C7232 -:1013900012F7C62000750B83CE20897638B000E89E -:1013A000A0FCC3F7C60400741B8BD883CE108976CB -:1013B000388A86A70024FE8886A70083C208EE83A9 -:1013C000EA088BC33D40007201C3814E380004839C -:1013D000C2028A86A50024FA8886A500EEC38A8602 -:1013E000A6000C02EEC3F74638010074F18B4E2EB6 -:1013F00032DB8ABEA30083C206C476048B7E2C83B4 -:10140000F908722CECA80174168AE083EA0AEC83CE -:10141000C20A84E77551AAFEC34983F90873E5320D -:10142000FF26011C015E34897604894E2E897E2CAC -:101430003B4E3C7211F64638207401C3834E38206F -:10144000B000E8FDFBC3F64638047415834E38102F -:101450008A86A70024FE8886A70083EA02EE83C25C -:10146000023D4000725DC332FF26031C85DB740918 -:1014700026891C8BF74747494980E41E80CCC0264B -:101480008904F6C41074278B7638F7C60010740BE5 -:1014900050FE86B200B00AE8A8FB58F7C6000174F7 -:1014A0000DE882268B76388B4E2E8B7E04AB8BF725 -:1014B00033C0AB32DB8ABEA300494983F9087217F7 -:1014C000E941FF814E38000483C2F88A86A50024D2 -:1014D000FA8886A500EEC3E945FF83C208EC88863A -:1014E000AA00C0E8048AE08AC88686A90032E08B98 -:1014F0005E3E84E3744F8AC18B4E26F6C504740C9D -:10150000A808740580E1BFEB0380C940F6C50874E4 -:101510000CA802740580E17FEB0380C980884E2609 -:101520008BF08A86A50084C97408A802741524FD6E -:10153000EB06A802750D0C028886A50083EA0AEE68 -:1015400083C20A8BC684E77501C3C686BA0001B0A0 -:101550000EE8EEFAF74638000274EE837E2E06722D -:10156000E88AA6AA00C45E048B7E2CB0FFAAB00253 -:10157000AB26830703836E2E03897E2CF646382024 -:101580007401C3834E3820B000E8B6FAC39083EAF2 -:1015900008E9B4FD83C2068B5E26F6C3C075EF8BE7 -:1015A0004E1CEC8886A40083EA0AA82075028ACD26 -:1015B00032ED8B461A3BC87318014E2A2BC189465F -:1015C0001AC57600F36E8ED98976003D2000723000 -:1015D000C385C074318BC801462AC57600F36E8E70 -:1015E000D980CB02895E26E832F1F6C701751683F1 -:1015F000C202E853FDF6C710750BB002E843FAC308 -:10160000F6C70174F0C380CB02895E26F6C7017469 -:10161000DE83C202E831FDF686A40040740B80E749 -:10162000FE80CF02895E26EBCCB004E814FAC3C07A -:10163000C2C8CAC4C6CCCED0D2D8DAD4D6DCDE90EA -:10164000E90E01E4C48AE0E4C48BD083F90872F0A7 -:1016500026833F0074048BDF49498BFB8ADE83E3DA -:101660000F2E8AA72F16ABF6C4107424F7C60010ED -:10167000740B50FE86B200B00AE8C6F958F7C600EF -:1016800001740DE8A0248B76388B4E2E8B7E04AB34 -:10169000897E0433C0AB4949894E2E897E2C8BC18B -:1016A000EB4E90EB9E90E4D684C07963E6D08AC876 -:1016B00025030003D8D1E32E8BAF4400888EAE0003 -:1016C0008B4E2EC45E048B7E2C8B7638E4862407EA -:1016D0003C0375CFE41C913BC173028BC82BC189BD -:1016E000462E014E3426010FBAC400F36C897E2CBD -:1016F0003B463C721CF7C62000750B83CE208976D2 -:1017000038B000E83CF98A86AE00243FE6D6C3F93B -:10171000C3F7C60A007435F7C61000752F83CE10C4 -:10172000897638F7C60200740E50E4D824FEE6D855 -:1017300058F7C6080074155051B9E803E40A84C08C -:10174000E0FA84C07504B024E60A59583D4000739D -:10175000B58A86A50024EF8886A500E60C81CE1008 -:1017600004897638EBA00008040C0109050D020A73 -:10177000060E030B070F004080C02060A0E0105051 -:1017800090D03070B0F0E4D2E6D08AC825030003D0 -:10179000D8D1E32E8BAF4400888EAE00E4D8C0E8E9 -:1017A000048BD82E8A8766178AE08AC88686A900A5 -:1017B00032E0E4988B5E3E84E374548AC18B4E26FB -:1017C000F6C504740CA808740580E1BFEB0380C95A -:1017D00040F6C508740CA802740580E17FEB038015 -:1017E000C980884E268BF08A86A500F6C1FD740854 -:1017F000A806741924F9EB0FA8067511F6C5017532 -:10180000040C04EB020C028886A500E60C8BC6844F -:10181000E775098A86AE00243FE6D2C3C686BA00C1 -:1018200001B00EE81CF8F74638000274E6837E2EFD -:101830000672E08A86A9008AE08686AA008AC832F3 -:10184000C480C90B22C1C0E4040AE0C45E048B7EDC -:101850002CB0FFAAB002AB26830703836E2E038948 -:101860007E2CF646382075AB834E3820B000E8D188 -:10187000F7EBA090E41224DFE61281E3FE9F895E7D -:1018800026836648F7EB7390F6C72075E7E4120CE1 -:1018900020E61232C0E6C6B083E6C680CF20895E5D -:1018A000268A86A5000C028886A500E60CEB7490BB -:1018B000F6C74075D3E4120C20E61232C0E6C6B07B -:1018C00081E6C680E7DF80CB01895E26B006E8713D -:1018D000F7908A86A50024F9E60C8886A500EB43DC -:1018E000E4D4E6D08BF825030003D8D1E32E8BAFE8 -:1018F00044008B5E26F6C76075B6F6C3C075D3BAD2 -:10190000C6008B4E1C8B461A3BC8731E014E2A2BF9 -:10191000C189461AC57600F36E8ED98976003D20BE -:1019200000723D8BC7243FE6D4C385C074398BC891 -:1019300001462AC57600F36E8ED983CB02895E26D6 -:10194000E8D9EDF6C70175398A86A50024F9E60CB9 -:101950008886A500F6C71075CAB002E8E4F6EBC3A6 -:10196000F6C70174EFEBBCF6C70174DC8A86A500EC -:10197000A802741181E3FFFE81CB0002895E26EB91 -:10198000C78A86A50024FB0C02E60C8886A500EB1E -:101990009290FDF7DF7FFEFBEFBF0004000405041B -:1019A00005040104000405040504060406040504F6 -:1019B00005040604060405040504020400040504E5 -:1019C00005040104000405040504060406040504D6 -:1019D00005040604060405040504070407040504B9 -:1019E00005040704070405040504060406040504A9 -:1019F0000504060406040504050407040704050499 -:101A00000504070407040504050406040604050488 -:101A10000504060406040504050403040004050483 -:101A20000504010400040504050406040604050475 -:101A30000504060406040504050402040004050464 -:101A40000504010400040504050406040604050455 -:101A50000504060406040504050407040704050438 -:101A60000504070407040504050406040604050428 -:101A70000504060406040504050407040704050418 -:101A80000504070407040504050406040604050408 -:101A90000504060406040504050433DB8AD88A8796 -:101AA0006C12E6FEC1E302E4CEA8047509A8027434 -:101AB00003E92CFEF9C35053E8CBFC5B58A8027431 -:101AC00003E91CFEF8C333DB8AD88A876C12E6FE72 -:101AD000C1E302E9D0FB9A1AC61A00000200040012 -:101AE00002000600020004000200080002000400D8 -:101AF000020006000200040002000A0002000400C6 -:101B000002000600020004000200080002000400B7 -:101B1000020006000200040002000C0002000400A3 -:101B20000200060002000400020008000200040097 -:101B3000020006000200040002000A000200040085 -:101B40000200060002000400020008000200040077 -:101B5000020006000200040002000E000200040061 -:101B60000200060002000400020008000200040057 -:101B7000020006000200040002000A000200040045 -:101B80000200060002000400020008000200040037 -:101B9000020006000200040002000C000200040023 -:101BA0000200060002000400020008000200040017 -:101BB000020006000200040002000A000200040005 -:101BC00002000600020004000200080002000400F7 -:101BD00002000600020004000200C390DA1494150B -:101BE0005C13E613DA1BDA1BE613DA1B8B94641220 -:101BF000C1E604A80174355033C08AC2E6FEE4A0F1 -:101C000085C074278BD82E8A9FDA1A52562E8BA83D -:101C100044008B5628ECA801750D8886AD00240E73 -:101C20008AD82EFF97DC1B5E5AEBCD58A80274367B -:101C300083C61033C08AC6E6FEE4A085C074278B35 -:101C4000D82E8A9FDA1A52562E8BA844008B56281B -:101C5000ECA801750D8886AD00240E8AD82EFF975A -:101C6000DC1B5E5AEBCDC39032E48BD88BD02E8A2E -:101C70009F9A192E2297921956528AC3240303C69B -:101C800080E304D0EB2EFF97D61A585EA955007555 -:101C9000D9C3601E062BC08ED8A15C12E6FEE400FC -:101CA00022C4740833F6E8BFFFEBEE90E40407E4C7 -:101CB000041FB80080BA22FFEF61CF90601E062B90 -:101CC000C08ED8A15E12E6FEE40022C47408BE04F1 -:101CD00000E894FFEBEDE40407E4041FB80080BAC9 -:101CE00022FFEF61CF90601E062BC08ED8A15C1240 -:101CF000E6FEE40022C4741833F6E86BFFA160121C -:101D0000E6FEE40022C474E5BE0800E85AFFEBDDFD -:101D1000A16012E6FEE40022C475EDE40407E404C9 -:101D2000A15C12E6FEE4041FE404B80080BA22FFBE -:101D3000EF61CF90601E062BC08ED8A15E12E6FE2A -:101D4000E40022C47419BE0400E81CFFA16212E67C -:101D5000FEE40022C474E4BE0C00E80BFFEBDCA13F -:101D60006212E6FEE40022C475EDE40407E404A177 -:101D70005E12E6FEE4041FE404B80080BA22FFEF1E -:101D800061CF601E062BC08ED8A15C12E6FEE480F7 -:101D900084C4740833F6E853FEEBEE90B80080BAC2 -:101DA00022FFEF071F61CF90601E062BC08ED8A1C7 -:101DB0005E12E6FEE48084C47408BE0200E82CFED5 -:101DC000EBEDB80080BA22FFEF071F61CF90601ED5 -:101DD000062BC08ED8A16012E6FEE48084C474088D -:101DE000BE0400E806FEEBEDB80080BA22FFEF0764 -:101DF0001F61CF90601E062BC08ED8A16212E6FE36 -:101E0000E48084C47408BE0600E8E0FDEBEDB80091 -:101E100080BA22FFEF071F61CF90601E062BC08E95 -:101E2000D8A15C12E6FEE40022C4741833F6E83749 -:101E3000FEA16012E6FEE48084C474E5BE0400E8FE -:101E4000AAFDEBDDA16012E6FEE48084C475EDA17D -:101E50005C12E6FEE40407E4041FB80080BA22FF27 -:101E6000EF61CF90601E062BC08ED8A15E12E6FEF9 -:101E7000E40022C47419BE0400E8ECFDA16212E67D -:101E8000FEE48084C474E4BE0600E85FFDEBDCA1E0 -:101E90006212E6FEE48084C475EDA15E12E6FEE403 -:101EA0000407E4041FB80080BA22FFEF61CF601E70 -:101EB000062BC08ED8A15C12E6FEE48084C47418A0 -:101EC00033F6E827FDA16012E6FEE40022C474E5C3 -:101ED000BE0800E892FDEBDDA16012E6FEE4002200 -:101EE000C475EDE40407E4041FB80080BA22FFEFD4 -:101EF00061CF601E062BC08ED8A15E12E6FEE48084 -:101F000084C47419BE0200E8E2FCA16212E6FEE499 -:101F10000022C474E4BE0C00E84DFDEBDCA16212AB -:101F2000E6FEE40022C475EDE40407E4041FB800F3 -:101F300080BA22FFEF61CF90601E062BC08ED8A121 -:101F40005C12E6FEE48084C4741833F6E89DFCA1BC -:101F50006012E6FEE48084C474E5BE0400E88CFCF4 -:101F6000EBDDA16012E6FEE48084C475ED071FB8C6 -:101F70000080BA22FFEF61CF601E062BC08ED8A171 -:101F80005E12E6FEE48084C47419BE0200E85CFCC4 -:101F9000A16212E6FEE48084C474E4BE0600E84B4D -:101FA000FCEBDCA16212E6FEE48084C475ED071F41 -:101FB000B80080BA22FFEF61CF90601E062BC08E62 -:101FC000D8902AC0E6FEE4CEA801741433DBE8D52D -:101FD000F6EBEF90B80080BA22FFEF071F61CF90B9 -:101FE000F60605010175EDB001E6FEE4CEA8017428 -:101FF000E3BB0400E8AFF6EBC990601E062BC08E71 -:10200000D890FB90FA2AC0E6FEE4CEA802741333FF -:10201000DBE8CCF8EBECB80080BA22FFEF071F61D9 -:10202000CF90A80474F033DBE85BF7EBD590601E2B -:10203000062BC08ED890FB90FAB001E6FEE4CEA845 -:10204000027415BB0400E897F8EBEB90B80080BA77 -:1020500022FFEF071F61CF90A80474F0BB0400E8D3 -:1020600024F7EBD26A001FC6069312099C0EE86B98 -:10207000F2906A001FC6069312299C0EE85DF2904A -:10208000722072207220CE1D921CE61C1A1E722035 -:10209000821DAE1E381F7220821D72207220381FD2 -:1020A000722072207220F41DBC1C341D641E72202C -:1020B000A81DF21E781F7220A81D72207220781FA2 -:1020C000FCB940008CCBB864202BFFAB93AB93E200 -:1020D000FAC7064C00A811833E4412007520C706BB -:1020E0003C00084BC7063000BA1FC7063400FA1F71 -:1020F000F6060501017506C70638002E20C3C7067F -:102100003C00564B33DB8A1E5412C1E302021E56BA -:10211000122E8B878020A330008A1E5512C1E30245 -:10212000021E57122E8B87A020A33400C38B869EDD -:1021300000E6FE86C4E6D0C38B869E00E6FE33D260 -:102140008AD4C351B91027E40A909084C07405E280 -:10215000F659F9C359F8C384C0781E518AE88AC871 -:10216000B80100D3E0098698003AAEA00059751076 -:10217000E8A9E5834E2602F9C39889869800EBF01A -:10218000F8C384C07812518AE08AC8B80100D3E04D -:1021900059F7D021869800C3C78698000000C383F2 -:1021A000C2048A86A6000C04EE83EA04C3E893FF07 -:1021B0007204B082E60AC38B4626A8FD74118A8693 -:1021C000A500A806740824F98886A500E60CC3F6C5 -:1021D000C401740A8A86A50024FB0C02EB0CA80239 -:1021E000750F8A86A50024FD0C043A86A50075D8D3 -:1021F000C38A86A500EBCFE4D833DB8AD8C0EB04D2 -:102200002E8A9F6617889EA9008B5E2680E33FF684 -:10221000C7047407A810750380CB40F6C70874077D -:10222000A880750380CB40885E268A86A500F6C309 -:10223000FD740DA806740824F98886A500E60CC371 -:10224000F6C70174040C02EBF0F6C30275E90C0446 -:10225000EBE7C404C4048504590448044104C303DF -:10226000820341038202570241028201410182003E -:1022700041004E02AD0157012D002B002700210027 -:102280001600F404F404A3046F045B045104F40383 -:10229000A3035103A3026D025102A3015101A30044 -:1022A00051006202D9016D01380036003100290069 -:1022B0001B005157BF0200EB0F905156BF0100EBBE -:1022C00007905156BF0300903C197602B017988BC7 -:1022D000F08A82C4002AE48BF083FE187346D1E6AC -:1022E0002E8B8C5222F74638800074052E8B8C8200 -:1022F00022F7C7020074123B8E9400740C898E94EE -:10230000008AC5E6EC8AC1E6E4F7C7010074123B17 -:102310008E9600740C898E96008AC5E6F88AC1E60E -:10232000F05E59C377068B8E8E00EBC58B8E9000C6 -:10233000EBBFD503F6003E0010000400CA043301D1 -:102340004D00140005000103050709000102030404 -:1023500080841E00A02526000000608BF033FF2E35 -:10236000A150232E8B165223BB3223F74638800010 -:10237000740C2EA154232E8B165623BB3C23B90577 -:10238000002E3B31730A4747E2F7B8FFFFEB1D9081 -:10239000D1EF2E8A8D46232AEDD1EAD1D8E2FAF781 -:1023A000F6050200C1E8022E8AA54B232EA358236E -:1023B000612EA15823C3080020008000000260099C -:1023C0000800200080000002000800000100020058 -:1023D0000300040052565785C074053D0109760379 -:1023E000B80109BF5B01F7463880007403BFB20132 -:1023F00033F62E3B84B62376044646EBF5F7E72EFC -:102400008BBCC02303C783D200D1E7F7F72E8AA481 -:10241000CA235F5E5AC3E43E80BEC30003750CF757 -:10242000467A200074050C80E63EC3247FE63EC356 -:1024300024038886C3008AE0E41024FC0AC4E61062 -:10244000808EA10042E8CEFFC390568BF083E60752 -:10245000D1E62EFFA458249068246C2470247424A0 -:102460007824872487248724B400EB0EB4C0EB0AB9 -:10247000B440EB06B420EB02B4A0E410241F0AC45D -:10248000E610808EA100425EC3903C0277128AE083 -:10249000E41024F3C0E4020AC4E610808EA10042D6 -:1024A000C3908B5E3884C0741F3C02742083CB08B9 -:1024B0008B462E3B463C770CE888FC7207B024E63E -:1024C0000A83CB10895E38C383E3F7EBF7F7C310B9 -:1024D0000074F5E86DFC72EC8A86C000E638B02323 -:1024E000E60AEBE08B5E388B462E3B463CE4D87721 -:1024F0000B24FE80CB12E6D8895E38C30C0180CB5A -:1025000002EBF35033DBC1E804250F0F8AD82E8A83 -:102510008766178ADC2E8AA7661709463E58C3507D -:1025200033DBC1E804250F0F8AD82E8A8766178A05 -:10253000DC2E8AA76617F7D021463E58C38B463E4D -:1025400033DB8AD80ADC2E8A877617E62C8AE0E409 -:102550002A240F0AC4E62A8A86A50084E4750DA8F9 -:10256000807411247F8886A500E60CC3A8807504BA -:102570000C80EBF1C31E6033C933D233F68ED98D94 -:10258000BEFD00578B0584C074168BD1428BFE4F65 -:10259000780938A3E40074084F79F788A2E400466C -:1025A0005F83C7094183F91072D989B6860089967D -:1025B0008400611FC353C7466600008B4664A94070 -:1025C00000740DB300A980007402B37F889EC1001F -:1025D00032DBA90200740380CB40A9004074038061 -:1025E000CB02A90080740380CB01A9301E74038044 -:1025F000CBBCA90020740380CB08A904017403801C -:10260000CB10A90800740380CB20889EC2005BC356 -:102610000651575016078DBEC400B91F0033C0AA1B -:1026200040E2FC8B86920089868E00898690005855 -:102630005F5907C3E4D8C0E80453250F008BD82E98 -:102640008A8766178886A9005AC30886AC00C686A2 -:10265000BA0001B00EE8EAE9C3AD36A3B413AD3653 -:10266000A3B613AD36A3B81383E90636F706B6133F -:102670000F00C38A4626F74648800074020C108873 -:1026800086BD0032C0837E1A00750E8B5E4043808B -:10269000E3FE3B5E0875020C01837E3A00750D1E59 -:1026A000C55E148B1F1F85DB75020C02F7463810C0 -:1026B0000074020C048B5E7AF7C3020074020C08EB -:1026C000F7C3040074020C10F7C3080074020C2056 -:1026D000F7C3400074020C408886BF00C3906A00B4 -:1026E0001FC60693120D9C0EE8F1EB90B002E6DADD -:1026F000F8C333C0E6DAF8C3B001E6D8F8C333C094 -:10270000E6D8F8C3B0FFE84EFAE8A1FAF8C3AC493E -:10271000E8AFFBF8C390AC49E815FDF8C390AC49AD -:10272000E867FDF8C390AC49E81FFDF8C390AC49D9 -:10273000E634F8C3AC49E636F8C3AC493C02771F2F -:1027400084C0751DE41424EFE614E412243FE6125D -:10275000E416A8047409E8EAF97204B018E60AF865 -:10276000C38AE0E4140C10E614E4120CC0F6C401B1 -:102770007402247FE612F8C3AC49E825FDF8C39043 -:10278000B80040E87DFDE8B4FDE8A8FEB001E8B976 -:10279000FEF8C390B80040E885FDE8A0FDF8C390BE -:1027A000B80010E85DFDE894FDE888FEB008E899FF -:1027B000FEF8C390B80010E865FDE880FDF8C3900E -:1027C000B80080E83DFDE874FDE868FEB002E879F5 -:1027D000FEF8C390B80080E845FDE860FDF8C390BE -:1027E000B80020E81DFDE854FDE848FEB004E859B3 -:1027F000FEF8C390B80020E825FDE840FDF8C3903E -:10280000AC49E84814E43C24E70AC4E63CF8C39029 -:10281000B8FC3B89467CE43C0C18E63CF8C3E41267 -:102820000C02E612F8C3E41224FDEBF6E8B5FCF85E -:10283000C390836638FDF8C3AC49A8017406834E83 -:102840007A20EB0483667ADFE8CBFBF8C3908A86B4 -:10285000A5000C0224FB8886A500E60C814E26010B -:1028600020AC4932E489466E834E48084946F9C394 -:102870008A86A5000C0224FB8886A500E60C814E02 -:10288000260120ACB40AF6E4EBD8E8FA13E43C24C1 -:10289000F80AC4E63CF8C390AD4949894664A901E9 -:1028A00000741B8BD883E3FA751AA90400740FE433 -:1028B0003E0C02E63EB83844894662F8C390E43ED6 -:1028C00024FCEBEFE43E24FCE63EE8E8FCB8AA403A -:1028D000EBE6E86EF87205B018E60AF8C390AC496A -:1028E000E8CFF9F8C390AC49E8CFF9F8C390E868AD -:1028F000FD750632C0E6DAF8C3B002E6DA36A0B4F7 -:102900001324103410E8160136A1B413A901007481 -:1029100005E8FCFEEB0EA90200740432C0EB02B025 -:1029200001E8DEFE36A1B413E8B513E43C24F80A4E -:10293000C4E63C36A1B413C1E805250100E8FAFE5F -:1029400036A0B5132410E859FB32C0368A26B513D9 -:10295000F6C4047409FEC0F6C4087402FEC0E8DBC5 -:10296000FD36A1B613250F00E857F936A1B613C1FD -:10297000E804250300E8B8FA36A1B613C1E8052536 -:102980000200E805FB36A1B613F6C401750432C097 -:10299000EB0980E402D0ECB0022AC4E8ACFA36F6C7 -:1029A00006B713407405E883FEEB03E884FE36F6B1 -:1029B00006B713207405E865FEEB03E868FEF8C36C -:1029C000E4120C01E612F8C3E41224FEEBF6E41460 -:1029D00024F00C05E614E42A24F00C06E62AF8C3D9 -:1029E000E42A24F0E62AE41424F00C07E614F8C3E1 -:1029F000AD4949E864F989868E00F8C3AD4949E8D4 -:102A000058F989869000F8C3834E2604E8A8F7F8A1 -:102A1000C390836626FBE89EF7F8C390AC4984C058 -:102A2000750DE41024EFE610808EA10042F8C3E497 -:102A3000100C10EBF190AC493C02760232C0C0E0C1 -:102A400004A82074020C0824188AE0E41224E70A7F -:102A5000C4E612808EA10044F8C3AC498886C00049 -:102A6000F8C3AC49E63AF8C3AC4984C07408E41230 -:102A70000C04E612F8C3E41224FBEBF6AC49E8D6EA -:102A8000F67303E827F7F8C3E412A802740424FDE0 -:102A9000E612B8F000E887FA816626FFF3E857F7F8 -:102AA000E89AFAF8C390B88000E857FA804E2708F1 -:102AB000E844F7E887FAF8C3B88000E861FA81666D -:102AC00026FFF7E831F7E874FAF8C390B81000E889 -:102AD00031FA804E2704E81EF7E861FAF8C3B8100F -:102AE00000E83BFA816626FFFBE80BF7E84EFAF8B0 -:102AF000C39033C0AC493C017304B001EB063C0CFD -:102B00007602B00C89461CF8C390814E2600208ABC -:102B100086A5000C0224FB8886A500E60C834E26C1 -:102B200001F8C390814E2600408A86A5000C0288D9 -:102B300086A500E60CF8C390AC4950E805F658723B -:102B400008E638B023E60AF8C3F9C390AC50ADE804 -:102B500082F85AF6C201741239869600740C89867E -:102B60009600E6F086E0E6F886E0F6C202741039D8 -:102B7000869400740A89869400E6E486E0E6EC8395 -:102B8000E903C390E4168886BC00E8E6FA33DBE488 -:102B90000CA806740380CB01A810740380CB02A894 -:102BA00080740380CB04E4128AE024180AD8E4DAA3 -:102BB000F6C4027407A840750380CB20A8027509EB -:102BC000E42AA80F740380CB40F74638020074094A -:102BD000E4D8A801750380CB80889EBE00FE86B431 -:102BE00000B00AE85CE4F8C3AC493C027441771FCA -:102BF00050E84FF558720C84C0740AB012E60A808F -:102C00004E3801F8C3B011E60A806638FEF8C38B6F -:102C1000463825FFF7894638A9000475E68A86A557 -:102C200000A81075DE0C108886A500E60CF8C3819C -:102C30004E3800088A86A500A81074C724EFEBE779 -:102C4000AD49493C0172113C0C770D508AE0E41407 -:102C500025F00F0AC4E614588AC484C07402E64200 -:102C6000F8C3E8CFF9FE86B900B00EE8D4E3F8C3A4 -:102C70003A86AF00741F8886AF008AE080C206B033 -:102C8000BFEE80EA028AC4EE8A86A80080C202EE05 -:102C900080EA068AC4C38B463E85C08A86A5007436 -:102CA00012A808750D0C088886A50080C202EE8067 -:102CB000EA02C3A80874FB24F7EBEC8B462684C019 -:102CC00074168A86A500A802740D24FD8886A500C6 -:102CD00083C202EE83EA02C38A86A500A80275F7C2 -:102CE0000C02EBE85283C20CECC0E8048886A90011 -:102CF0008B5E2680E33FF6C7047407A8087503803F -:102D0000CB40F6C7087407A802750380CB80885EA5 -:102D1000268A86A50084DB7410A802740A24FD8824 -:102D200086A50083EA0AEE5AC3A80275FA0C02EBE4 -:102D3000EE90FFFF00480030BA20C41A00180012BD -:102D4000000C0006000300028001C000600030009B -:102D50001800CD0100018000100010000E000C00D2 -:102D6000080000000000060004000300020001004B -:102D70005251563C1E7747988BF08A82C40032E449 -:102D800083FE18743D83FE19743E83FE1E772FD197 -:102D9000E62E8B8C322D3B8E94007422898E94000B -:102DA00083C2068A86A8008AE00C80EE83EA068A3F -:102DB000C1EE83C2028AC5EE83C2048AC4EE5E59A4 -:102DC0005AC38B8E8E00EBCE8B8E9000EBC8525187 -:102DD0003D05007703B805008BC8BA0200B800D0E3 -:102DE000F7F1050100D1E8595AC38B467AA820743F -:102DF0000B80BEC3000375040C01EB0224FE894660 -:102E00007AC324038886C3008AA6A8008ADC80E4EB -:102E1000FC0AC43AC3740B8886A80083C206EE83FA -:102E2000EA06E8C5FFC30008183828903C04772359 -:102E300032E48BD82E8A87262E8AA6A8008ADC80C8 -:102E4000E4C70AC43AC3740B8886A80083C206EE9E -:102E500083EA06C384C07402B0048AA6A8008ADC90 -:102E600080E4FB0AC43AC3740B8886A80083C206B8 -:102E7000EE83EA06C3908B5E3884C074343C0274DF -:102E80003B8A86AF000C04E8E6FD8B462E3B463CB1 -:102E9000771BF7C30004751581CB000483C2028A37 -:102EA00086A50024FA8886A500EE83EA02895E38AA -:102EB000C38A86AF0024FBE8B6FDEBF1F7C3100030 -:102EC00074EFEBED83C20CEC83EA0CC0E804888657 -:102ED000A900C3908A86A7000C018886A7008BDA18 -:102EE00080C208EE8BD3F8C38A86A70024FEEBEAE3 -:102EF0008A86A7000C02EBE28A86A70024FDEBDAA3 -:102F0000B0FFE852F2E897F2F8C3AC49E861FEF886 -:102F1000C390AC49E8EBFEF8C390AC49E835FFF844 -:102F2000C390AC49E805FFF8C3905283C206B0BF16 -:102F3000EE5283C202AC49EE5A8A86A800EE5AF8D5 -:102F4000C3905283C206B0BFEE5283C206EBE69036 -:102F5000AC493C02770D84C0750B8A86AF0024FD16 -:102F6000E80DFDF8C3508A86AF000C02E801FD5B56 -:102F700083C2088A86A700F6C301740C24DF888602 -:102F8000A700EE83EA08F8C30C20EBF2AC49E8E5B1 -:102F9000FEF8C390B80040E869F5E8F9FCE824FFC2 -:102FA000B001E8A5F6F8C390B80040E871F5E8E58F -:102FB000FCF8C390B80010E849F5E8D9FCE804FF34 -:102FC000B008E885F6F8C390B80010E851F5E8C5F8 -:102FD000FCF8C390B80080E829F5E8B9FCE8E4FE05 -:102FE000B002E865F6F8C390B80080E831F5E8A5CE -:102FF000FCF8C390B80020E809F5E899FCE8C4FEA5 -:10300000B004E845F6F8C390B80020E811F5E8856B -:10301000FCF8C390AC49E8340CF8C390B8FC3B8989 -:10302000467CF8C38A86AF000C80E843FCF8C39066 -:103030008A86AF00247FEBF28A86AF000C40E82F2F -:10304000FCF8C3908A86AF0024BFEBF2AC49A8011C -:103050007407834E7A20EB059083667ADFE88AFD59 -:10306000F8C383C2068A86A8000C408886A800EEB2 -:1030700083EA06AC4932E489466E834E2601834ECC -:103080004808B006E8BBDF4946F9C39083C2068A08 -:1030900086A8000C408886A800EE83EA06ACB40A35 -:1030A000F6E4EBD0E8E00BF8C390AD4949894664FB -:1030B000A9010074198BD883E3FA750AA904007476 -:1030C0000DB8E23FEB0BE8ECF4B8AA40EB03B838DC -:1030D00044894662F8C38A86AF00A802740A24FDB8 -:1030E000E88DFB0C02E888FBF8C3AC49E881FCF8EA -:1030F000C390AC49E879FCF8C390E85CF57505E845 -:10310000E6FDF8C3E8CDFD36A0B41324103410E872 -:10311000260136A1B413A901007405E8FEFEEB0EEA -:10312000A90200740432C0EB02B001E8E8FE36A147 -:10313000B413E8AB0B36A1B413C1E805250100E8D0 -:103140000CFF36A0B5132410E82BFD32C0368A26BA -:10315000B513F6C4047409FEC0F6C4087402FEC0B8 -:10316000E8EFFD36A1B613250F00E803FC36A1B643 -:1031700013C1E804250300E888FC36A1B613C1E8B2 -:1031800005250200E8CDFC36A1B613F6C40175048E -:1031900032C0EB0980E402D0ECB0022AC4E88CFC17 -:1031A00036F606B713407405E88DFEEB03E894FE8F -:1031B00036F606B713207405E869FEEB03E870FEE7 -:1031C000F8C3F8C38B4638A9040075230D040089A1 -:1031D000463883C2088B462E3B463C7314834E38D8 -:1031E000108A86A70024FE8886A700EE83EA08F8E6 -:1031F000C38A86A7000C01EBEE908B4638A9040029 -:10320000740625FBFF894638F8C3AD4949E8BEFB83 -:1032100089868E00F8C3AD4949E8B2FB89869000E3 -:10322000F8C3834E2604E892FAF8C390836626FB1F -:10323000E888FAF8C390AC4984C07507808EA30073 -:1032400004F8C380A6A300FBF8C3AC4983C2083CC2 -:1032500002760232C03C017412770B8A86A70024E2 -:10326000EF8886A700EE83EA08F8C38A86A7000CD9 -:1032700010EBEE905283C206B0BFEE5283C204AC94 -:1032800049EE5A8A86A800EE5AF8C3905283C206C5 -:10329000B0BFEE5283C208EBE690AC49F8C3AC492C -:1032A000E8B4EE7303E8F7EEF8C38A86AF00247F34 -:1032B000E8BDF9B8F000E866F2816626FFF3E8237E -:1032C000FAE8D2F9F8C3B88000E837F2804E270850 -:1032D000E811FAE8C0F9F8C3B88000E841F2816665 -:1032E00026FFF7E8FEF9E8ADF9F8C390B81000E85A -:1032F00011F2804E2704E8EBF9E89AF9F8C3B81008 -:1033000000E8FFF1816626FFFBE8D8F9F8C3AC4975 -:10331000F8C383C2068A86A8000C408886A800EEFF -:1033200083EA06F8C39083C2068A86A80024BFEB0E -:10333000EA90AC498AE080C20AEC80EA0AA82074CC -:10334000058AC4EEF8C30651578B4E24E3344989ED -:103350004E24FF461A8E46028B7E228AC4AA897E9C -:10336000228B462624FD89462675298A86A500A833 -:1033700002752180C2020C028886A500EE80EA0256 -:10338000EB12C47E003B7E1E760A4F268825897E7E -:1033900000FF461A5F5907F8C390ACAD83E9038577 -:1033A000C074053D00207205B8FFFFEB03C1E003C8 -:1033B0003B8694007426898694008BD85283C2067B -:1033C0008A86A8008AE00C80EE83EA068AC3EE8330 -:1033D000C2028AC7EE83C2048AC4EE5AF8C3B08818 -:1033E0008886BC00E88CF233DB8A86A500A80274CC -:1033F0000380CB01A805740380CB02A80874038066 -:10340000CB04F686A70010740380CB108A86A9002F -:10341000F6C304750A83C20CEC83EA0CC0E8048A84 -:10342000E08A86AF00A8807408F6C401750380CBDB -:1034300020F686A70002750AF74638040074038058 -:10344000CB40889EBE00FE86B400B00AE8F3DBF8ED -:10345000C3FE86B400B00AE8E8DBF8C3AC493C021E -:103460007437771084C07406804E3801F8C38066C4 -:1034700038FEF8C38B463825FFF7894638A9000483 -:1034800075EA8A86A500A80175E20C0583C2028848 -:1034900086A500EE83EA02F8C3814E3800088A86CA -:1034A000A500A80174C624FAEBE2AD4949F8C3901F -:1034B000E811FAFE86B900B00EE886DBF8C3B0FF6B -:1034C000E8BFECF8C39083667AFBB000E873DBF8E2 -:1034D000C390AC49E853D9721136881E1A0136A040 -:1034E0008E120AC352BA0001EE5AF8C3AC4932E454 -:1034F00036A38612050600368B1E88122BD8368915 -:103500001E8A12F8C390AD8BD8AD83E90403C32B98 -:103510004676894678F7467A0200740A83667AFD11 -:10352000B80000E81CDBF8C3061607AC49250F00FD -:103530006BC0098DBEFD0003F8AC49250F00AA85BC -:10354000C074082BC8518BC8F3A459E827F0E8448D -:103550000307F8C333C0AC4936A3B21336A3B01384 -:10356000F8C383667AEFE82C03F8C390834E7A1091 -:10357000EBF4E89BF0F8C390AD3C19770E3C19775B -:103580000A8BF881E7FF0088A6C400F8C390834E39 -:103590002620AC4932E4D1E08BD8C1E30203C389D1 -:1035A000466E834E4804B006E897DA4946F9C39060 -:1035B000FE86B300B00AE889DAF8C39033C0AC499C -:1035C0006BC00A89868A00F8C390AC4932E43D0A90 -:1035D000007705B80A00EB083D5A007203B85A009C -:1035E00051F7D80564008BC88B4644F7E1B96400F5 -:1035F000F7F189464659F8C3AC49E885EBF8C39022 -:10360000AC4984C07507816638FFFDF8C3814E3828 -:103610000002F74638400075088A86A9008886AA05 -:1036200000F8C3905156E87F0C5E59F8C390FE86AF -:10363000B600B00AE80BDAF8C390FE86B700B00A0D -:10364000E8FFD9F8C390FE86B800B00AE8F3D9F8CD -:10365000C39000905155AC2EA2523633C9AD8BF9B0 -:10366000C1E705A9010074232E8BAD4400837E08B9 -:103670000074182E803E523601740960B004E8BB15 -:103680000C61EB0760B0FBE8EC0C614747D1E875D3 -:10369000D24183F90472C65D5983E905F746384083 -:1036A000007405E887EAF8C3E88DEAF8C39036C6E7 -:1036B00006C81301F8C333C0AC4936A38012AC4925 -:1036C000362B068812F7D836A38212F8C390DE266E -:1036D000DE26EC26F226F826FE2604270E271627DD -:1036E0001E2726272E273427BE34C634D2343A2745 -:1036F000782780279427A027B427C027D427E0273E -:10370000F42700281028EC34DE261E2826282C2832 -:10371000322838284E288A28063528359828BE2889 -:10372000D228DE28E628543562356C35EE28C029CB -:10373000C829CE29E02972357835F029FC298E3543 -:10374000082A122A1C2AB035362ABC355A2A622A7F -:10375000682ACA357C2AF835882AA62AB82ACC2AAB -:10376000DE2AF22A00360A2B242B2436382B4C2B47 -:10377000842B2E363A3646365436E82BAE36402C5D -:10378000622CB6367028DE26DE26D42EE82EF02EE9 -:10379000F82E002F0A2F122F1A2F222F2A2F422FF6 -:1037A000BE34C634D234502F8C2F942FA82FB42F70 -:1037B000C82FD42FE82FF42F083014301C30EC34ED -:1037C000DE2624303030383044304C306230A43083 -:1037D00006352835AA30CE30D630EA30F2305435AE -:1037E00062356C35FA30C231C231C431FA317235CA -:1037F00078350A3216328E3522322C323632B035D6 -:103800004A32BC3574328C329A32CA359E32F8351F -:10381000AA32C632D832EC32FE320E3300361233C0 -:103820002633243632339A33DE332E363A36463652 -:1038300054365C34AE36AA34B034B6368C30E32815 -:10384000F7463840007532E8E3E833C0AC493D5BE9 -:103850000077198BD8D1E32EFF97CE36720B85C92E -:1038600075E88B4648E81A0CC34E41C36A001FC670 -:103870000693120C9C0EE863DAE8BCE833C0AC494E -:103880003D5B0077E78BD8D1E32EFF97863772D95F -:1038900085C975E8C3F7467A1000750F83BE8400AA -:1038A000007408B8483A89868000C381BE8000EC65 -:1038B0003C74F783BE8800007505B8EC3CEBE7F775 -:1038C000467A080075401E608B8E88003B4E7477E8 -:1038D000333B4E78772EC47E108BDF26033D47475F -:1038E00033C08ED88DB6F4008BC1F7467A010075CF -:1038F0001DF3A4260107294678014676294674B0AF -:103900000CE83ED7611FC78688000000EBACE3E3FC -:103910005090AC247FAAE2FA58EBD8908B8E8800A6 -:10392000E3468B9E8A0085DB743EBA50FFED2B8602 -:1039300082003BC372378DB6F400C47E108BDF2645 -:10394000033D47478BC1161FF7467A01007524F3E4 -:10395000A4260107294678014676294674C7868839 -:10396000000000B00CE8DAD683667AF7C3B000E84E -:10397000D0D6C3E3DC50AC247FAAE2FA58EBD29055 -:103980001E6033C08ED88DB6FD008B8688008B9666 -:1039900084003A0475108BDE468BC88DBEF400F3AC -:1039A000A674668BF39083C6094A75E68DB6FD0052 -:1039B0008B9684003A0473108BDE468BC88DBEF460 -:1039C00000F3A674768BF39083C6094A75E68DB62C -:1039D000F400ACF7467A01007402247F1EC55E1025 -:1039E0008B37884002468937FF4E78FF4676FF4E78 -:1039F000741F8B8E880049898E8800E3438DB6F44E -:103A0000008BFE46F3A4E97DFFC576108B1C85DB99 -:103A1000740803F383C60383E6FE8B8684002BC2FF -:103A2000B48089044646C7040000897610834E7A24 -:103A300004C78688000000611FF9C333C0611FC33B -:103A4000B08084C0611FC3908B4E782B8E88007627 -:103A50002789B68C008B5E743BCB72028BCB3BC844 -:103A600072028BC88BC1E34433D28EC28BD183BE2A -:103A70008800007406E98E0033C0C38B5E10031FFC -:103A8000434352F7467A0100752AAC8DBEE4008BA1 -:103A90008E8600F2AE74348807434A75ED588B5E0B -:103AA0001001072946780146762946748BC62B8675 -:103AB0008C00C390AC8DBEE4008B8E8600F2AE7499 -:103AC0000A247F8807434A75EBEBD28886F400C747 -:103AD0008688000100582BC2740E8B5E10010729E6 -:103AE000467801467629467440E894FE72BE4A75CF -:103AF0001583BE8A000074B4BA50FFED8986820037 -:103B0000834E7A08EBA68DBEF40003BE8800A4FFA6 -:103B1000868800E86AFE729479064A748FE95BFF32 -:103B20004A74CEEBE19050E811CC8B467439467262 -:103B300074271E565133C9C5760CAD74107809032D -:103B4000C805010024FE03F03B761076ED294E7681 -:103B5000014E78E837CC595E1F58C390C47E1026BA -:103B60008B1D83C30326891D4B03FBAB91AAB803AE -:103B700000294678014676294674C390C47E1026F3 -:103B80008B1D4326891D4303FBAAFF4E78FF467613 -:103B9000FF4E74C3E8E5FFC38081848582838687F6 -:103BA00050538ADC83E30ED1EB2E8A87983B08863C -:103BB000B000FE86B100B00AE887D45B58C3508AD3 -:103BC000C8B8FF00E895FF58C3908A86BB00E8ABF1 -:103BD000FFC3E8CBFFE8F2FFC390E8C3FFE8B4FF00 -:103BE000C39033C0E895FFC3B8FF0033C9E86CFF4A -:103BF000C390B8FF01B110E862FFC390C3FC3BE281 -:103C00003BF23BF23BFC3BE23BE83BE83BFC3BE26C -:103C10003BE83BE83BFC3BE23BE23BE23B00100085 -:103C20000000100000001000000010000000100054 -:103C3000000010000000100000001000000008004C -:103C40000000080000000800000008000051538B2D -:103C50004E3881E1FFEEA804740481C900018AE0B6 -:103C600080E4032418D0E40AC433DB8AD82E8B877F -:103C7000FD3B89467C2E0B8F1D3C894E38D1EB2EA7 -:103C80008AA73D3C5B59C3AC493C01721D74203C82 -:103C900003722374283C08722B74303C20723774F2 -:103CA0003ABBDA3B32E4895E7EC3BBA03BEBF5BB9B -:103CB000943BB401EBF0BBFC3BB402EBE9BBE23B51 -:103CC000B403EBE2BBBE3BB404EBDBBBCA3BAC4989 -:103CD0008886BB00EBCEBBD23BEBF3BBFC3BEBC41B -:103CE000A9040075D1A9080075DAEBD18B5E748B3D -:103CF0004E783BCB72028BCB3BC872028BC88BC118 -:103D0000E32CC47E108BDF26033D4747F7467A013C -:103D100000751CF7C70100740249A4D1E9F3A5732B -:103D200001A4260107294678014676294674C35026 -:103D300053BB7F7FF7C70100740549AC22C3AAD1EA -:103D4000E9E31D9CAD23C3AB497414AD23C3AB4958 -:103D5000740DAD23C3AB497406AD23C3ABE2E59D3F -:103D60007304AC22C3AB5B58EBB8E8CEC98B5E38AA -:103D7000F7C310047501C3F7C340007405E8B8E346 -:103D8000EB03E8A8E3816638EFFBF6C310743CF65A -:103D9000C3027406E4D80C01E6D8F6C30474118398 -:103DA000C2088A86A7000C01EE8886A70083EA086D -:103DB000F6C308740FE88BE3720A8A86C000E638FF -:103DC000B023E60AF7C300047501C3F7C300087502 -:103DD000F98A86A500F6C340750DA81075EC0C1085 -:103DE0008886A500E60CC3A80175DF83C2020C0516 -:103DF000EE8886A500C3B000E847D2EB0FB002E81A -:103E0000900EEB08836638DF834E7A0233C08ED87B -:103E1000FAA0921240A292123C05721EC60692129D -:103E200000FBB001E86B0EFAA1260123062A01A8C7 -:103E3000017507E8E207E8610990B000E837D2FBB6 -:103E400085ED74B9FAF7467A460075C08B46783D21 -:103E50000A0072B08B4E7483F950729A836638DF11 -:103E6000C576148B463A85C07558AD85C0750FE888 -:103E7000F8FEF7467A08007493E8A0FAEB8E3B76DA -:103E8000047621B90200394E2E7705C7462E000070 -:103E9000568B762C897604C7040000464689762C1A -:103EA000294E2E5E85C07917F6C4107405FF567C26 -:103EB000EB03FF567E897614B00CE885D1EB86893A -:103EC000463AFF96800029463A897614B00CE8718C -:103ED000D1E971FF0000000000000000080410029A -:103EE00001200000000000000000000000000000B1 -:103EF00000000000808080808080808080808080C2 -:103F000080808080808080808080808080808080B1 -:103F100080808080808080808080808080808080A1 -:103F20008080808080808080808080808080808091 -:103F30008080808080C0C0C0C0C0C0C0C0C0C0C0C1 -:103F4000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C080B1 -:103F500080808000808080808080808080808080E1 -:103F60008080808080808080808080808080808051 -:103F70008080808080808080808080808080808041 -:103F80008080808080808080808080808080808031 -:103F90008080808080808080808080808080808021 -:103FA0008080808080808080808080808080808011 -:103FB0008080808080808080808080808080808001 -:103FC00080808080808080808080808080808080F1 -:103FD000808080804E417841D041F44106421842B1 -:103FE000C3908E46028B7E22897E6C806627FD8B75 -:103FF000562483FA0472E983EA028BD93BCA76021B -:104000008BCAB00A57518BFEF2AE8BC1595F751E39 -:1040100050402BC874062BD12BD9F3A4594B4A4AD4 -:10402000B00DAAA43BCA76028BCAE313EBD42BD9FA -:10403000F7C601007402A449D1E9F3A57301A4896C -:104040007E222B7E6C297E24017E1A8BCB807E26DD -:10405000027405806626FDC360B0FDE8180361C3E5 -:10406000C390E87C0272F990834E26208B466A89C1 -:10407000466E8B46480D040025BFFF894648B006B2 -:10408000E8BFCFC3897E222B7E6C017E1A297E2455 -:10409000807E26027405836626FDC360B0FDE8D5E8 -:1040A0000261C3908ABEC200EB24F7464840007507 -:1040B000B18E46028B7E22897E6C8B562483EA0A5F -:1040C000789E03D7806627FD33C08ABEC200E3B462 -:1040D0003BFA77B0AC49932E8A87D43E9322DF75A2 -:1040E00017AAE3A03BFA779CAC49932E8A87D43E6B -:1040F0009322DF7503AAEBD6F6C37F7505FF4666EC -:10410000EBDFF6C340750C8BD883EB08D1E32EFFB1 -:10411000A7D43FFF46662C20EBC785C0742C894688 -:104120006A834E4840897E222B7E6C017E1A297E4E -:1041300024807E26027408836626FDE8A301C360FE -:10414000B0FDE8310261E89801C3E957FF908B5E4A -:10415000664B7803895E66AA8B5E64F7C3002075A0 -:1041600003E940FFF7C3400074088A86C100AAE94A -:1041700032FFB83200EBA3908B5E66895E6883C322 -:104180000880E3F8895E668B5E6481E3001881FB3A -:104190000018742DAA85DB7425F746644000751855 -:1041A00081FB0010740C8B46662B4668C1E004E965 -:1041B00068FFB86400E962FF8A86C100AAAAE9E341 -:1041C000FE518B4E662B4E68B020F3AA59E9D4FEFF -:1041D0008B5E66895E688B5E64F7C324007410C7CB -:1041E00046660000F7C304007405B00DAAB00AAA21 -:1041F000EB489090AAF7466400407406B8D007E9EF -:1042000018FFE99FFE90AAF7466400807406B8D0B4 -:1042100007E906FFE98DFE908B5E66895E6885DBA7 -:10422000750C8B5E64F7C310007406E976FE8B5E36 -:1042300064F7C308007427B00AAAF7C32000751FEB -:10424000F7C300017503E95BFEF7C340007506B8CC -:104250006400E9C5FE8A86C100AAAAE946FEAAC78B -:1042600046660000F7C3000674F1F7C340007419F6 -:104270008A86C10081E3000681FB00047206760293 -:10428000AAAAAAAAAAAAE91BFE81E3000681FB004A -:1042900004720E7606B89600E97FFEB86400E979EC -:1042A000FE8B4668E973FE90368B0EDA1283F93284 -:1042B000731D1E0633C08ED88EC08D764CBFDC12A7 -:1042C00003F9A5A5A583C106890EDA12071FC3B09D -:1042D00008E86ECDC390836648FEE893C4E8C8FF43 -:1042E000C3F6462702750F9CFA837E1A0074098074 -:1042F0004E27019DF9C3F8C35052F7463840007469 -:104300001DE834DE83C20AECA840752783EA088AD8 -:1043100086A5000C028886A500EE5A58EBD1E80C61 -:10432000DE8A86A50024FB0C028886A500E60C5ACE -:1043300058EBBC804E27025A589DF8C30846269C6D -:10434000FA8A8EA500F7463840007514F6C1067447 -:1043500023E8D9DD8AC124F98886A500E60C9DC32F -:10436000F6C102740FE8D0DD83C2028AC124FD8841 -:1043700086A500EE9DC38B5E2622C3884626740167 -:10438000C3806627FD9CFA8A8EA500F74638400058 -:104390007516F6C104750FE893DD8AC124FD0C047F -:1043A0008886A500E60C9DC3F6C10275F9E888DD94 -:1043B00083C20AECA820750E83EA088AC10C028821 -:1043C00086A500EE9DC383EA0A33C98A4E1C8B463C -:1043D0001A3BC8731B014E2A2BC189461A1EC5768B -:1043E00000F36E1F89760083C2028A86A500EBCD9A -:1043F00085C0741201462A8BC81EC57600F36E1F55 -:10440000897600894E1AF6C701752380CB02895E32 -:1044100026E808C383C2028A86A50024FDEE8886AA -:10442000A500F6C7107505B002E816CC9DC383C27F -:10443000028A86A500EB86908BD18B46243BC876FA -:10444000028BC82BD12BC18BD9E322806627FD8E2E -:1044500046028B7E22F7C601007402A449D1E9F31B -:10446000A57301A4897E22894624015E1A8BCA8025 -:104470007E26027405806626FDC360B0FDE8F6FE68 -:1044800061C350E40A84C0750A8686A10084C074A2 -:104490000AE60A580C20894648F9C35824DF8946A1 -:1044A00048F8C390FBB002E8E807FAE82E01FBB039 -:1044B00001E8DE07FAB002E8BCCBFB85ED74E5FA53 -:1044C0008E5E0AFB90FA8B46488B7640A88C75DE90 -:1044D000A820741A50E855DC58E8A6FF7310B00203 -:1044E000E85FCBEBC99025FF008BC8EB3690A801A5 -:1044F00075224683E6FE3B76087479AD8AFCB3F0FC -:1045000022FB3AFB74E03ABEA000742EE8D2FD73A1 -:1045100077EB9B908AE024FC8846488B4E4AF6C491 -:1045200002741DE8BBFD7286E813F3897640E393BD -:10453000834E4803894E4AE974FF25FF0F8BC890CC -:104540008B86980085C0741A518A8EA000C0E90439 -:10455000BA0100D3E25923C2740803F1897640E915 -:1045600061FFFF5662E3F5834E4801894E4A897622 -:1045700040E93AFF814E2600108B46503B46467775 -:1045800003E852FDE927FF9088BEA000EBAC0A06C5 -:1045900090128AE0BA0601B004EEEC84C07512B045 -:1045A00004EE8AC4EE32E4A8807406C706841200C2 -:1045B0000088269012C30A0690128AE0BA0601EC1F -:1045C000A80175EDBA08018AC4EE32E4A88074E14E -:1045D000C7068412000088269012C39036F706247E -:1045E0000101007530368B0EDA1280F936732633EE -:1045F000C08EC08ED8BFDC1203F9B008E877CA8538 -:10460000ED740E8D764CA5A5A580C10680F9367295 -:10461000E9890EDA12C3C390F7062601010075F688 -:104620008B0E201385C975EE33C08EC08ED8BF2483 -:1046300013B93600B00AE83DCA85ED7506E91201E6 -:10464000E90A0133DB8A464C8AA6B300FECC780E19 -:1046500088A6B3000ADCB40AAB83E90276E28AA634 -:10466000B200FECC780E88A6B2000ADCB408AB8398 -:10467000E90276CC8AA6B100FECC78188ABEB000DA -:10468000750488A6B00088A6B1000ADC8AE7AB836F -:10469000E90276AC8AA6B400FECC781F88A6B400E6 -:1046A0000ADCB40BAB8A86BC008AA6BD00AB8B8645 -:1046B000BE00AB83E90676888A464C8AA6B600FE21 -:1046C000CC781988A6B6000ADCB40CABE8DBCBAB1F -:1046D0008B462AAB83E90676748A464C8AA6B700D5 -:1046E000FECC781988A6B7000ADCB40DABE8BACBCB -:1046F000AB8B4634AB83E90676538A464C8AA6B820 -:1047000000FECC781988A6B8000ADCB40EABA15024 -:1047100012ABA15212AB83E90676328A464C8AA6C6 -:10472000B500FECC781888A6B5000ADCB40FAB8BB8 -:10473000869A00AB8B869C00AB83E906760F84DB00 -:104740007503E9EFFEB00AE8F8C8E9E7FEB00AE849 -:10475000F0C8F7D983C1368BC10D800086C4A3226F -:10476000134141890E2013C3A184122BC17211A3DE -:104770008412BE2213D1E9F36F90890E2013F8C37F -:10478000F9C3C381EF6A1374F98BC70D800086C427 -:10479000A368134747893E6613C3F7062A01010041 -:1047A00075E08B0E6613E30780F92077D54949330E -:1047B000C08EC08ED8BF6A138BF703F983C6343B13 -:1047C000FE77C0B00EE8AEC885ED74B78A464C8A55 -:1047D000B6B900FECE781588B6B9008AA6A90080C1 -:1047E000CCC0AB84F67405B00EE856C88AB6BA00E1 -:1047F000FECE78CB8A9EA9008ABEAB008A563F8A3D -:10480000F332F70AB6AC00C686AC000022F2744B55 -:10481000F6C608740FB402F6C3087502B403AB8081 -:10482000E6F77437F6C601740FB400F6C3017502DB -:10483000B401AB80E6FE7423F6C602740FB404F62E -:10484000C3027502B405AB80E6FD740FF6C60474AE -:104850000AB406F6C3047502B407ABC686BA0000F4 -:10486000889EAB00E958FF90A184122BC17211A35E -:104870008412BE6813D1E9F36F90890E6613F8C3F2 -:10488000F9C3A1841241412BC17223A384128BC1AD -:10489000484832E40C8086C4EF9090909090BEDC43 -:1048A000124949D1E9F36F90890EDA12F8C3F9C3BE -:1048B0008AC88A464CB40183EB06EF9090909090A2 -:1048C000B80100EF90909090908AC1EF90909090F6 -:1048D00090E99700E9AC0033C08ED8891E8412C3DA -:1048E000368B1E8412FB90FAB00CE889C785ED74F4 -:1048F000E6C5760C83FB1472DBFB90FAAD85C078BD -:10490000AF74E28BFE03F8368B0E86123BC1770242 -:104910008BC883EB043BD977028BCB33C08A464CE0 -:10492000EF90909090908BC1EF90909090904180FC -:10493000E1FE2BD951D1E9F36F90598BC74024FE8A -:104940003BC674272BFE4E4E538B5E103BF3721307 -:10495000031F83C30380E3FEC7070000836E740256 -:10496000895E105B893C89760CEB8989760C3976F7 -:104970001077817208833C007403E977FFE80DBE6D -:10498000E962FF36891E8412B00CE8B5C633C08ECA -:10499000D8C3A184123D10007277BA04013B068887 -:1049A000127506C7067E1200008B0EDA12E30BE8C2 -:1049B000D0FE7257C7067E12FF7F8B0E2013E30BCB -:1049C000E8A5FD7246C7067E12FF7F8B0E6613E3D5 -:1049D0000BE894FE7235C7067E12FF7FA12801A95D -:1049E00001007503E8F9FE803E8D1200751DA1845B -:1049F000123D200076153B0682127609A17E123BFD -:104A0000068012720C800E901280C3B080FF167C5C -:104A100012C3800E901240C36A001FC6069312177D -:104A20009C0EE8B7C86A001FC6069312209C0EE8C9 -:104A3000AAC86A001FC6069312169C0EE89DC8906D -:104A4000BA0601ECA82075CAFB90FABA0401ED90F1 -:104A5000909090903A06941277BE33DB8AD8D1E3D7 -:104A60002E8BAF4400C47E0885FF74B9F6C4C075B0 -:104A70005532C0C1E00280E4F08BF0ED9090909050 -:104A80009085C074BB8BC84180E1FE0BC68B5E5025 -:104A90004B4B2BD9789CAB8BC1404001464ED1E9A2 -:104AA000F36D90895E50897E088B462680E4EF89FD -:104AB0004626F6C401750CF746480C007505B00291 -:104AC000E87FC5E97AFF86C48BC883E13F4180E176 -:104AD000FEE30A3C807209243FB4F0EBB0E960FFCA -:104AE000253F0033FF8EC7BF96128BF7D1E9F36DD8 -:104AF000908BC8E848EDE947FF906A001FC606930F -:104B0000121B9C0EE8D5C790601E0633C08ED88E4F -:104B1000C0BA0601ECA80474E1B006EEECA28C1257 -:104B2000A8407411A18812A38412C6068D1200E851 -:104B300060FEA08C12A8807403E804FFB80080BA5D -:104B400022FFEF071F61CF906A001FC60693121B5A -:104B50009C0EE887C790601E0633C08ED88EC0BA00 -:104B60000601ECA80474E1BA0801ECA28C12A8407A -:104B70007411A18812A38412C6068D1200E812FED9 -:104B8000A08C12A8807403E8B6FEB80080BA22FF99 -:104B9000EF071F61CF90EE86E0EE86E0EC86E0EC5A -:104BA00086E080E1FEF36C9080E1FEF36E900500FC -:104BB0007547A84B05007548A84B0500A348A84BAE -:104BC00005003549A84B06009848964B0600BA48A0 -:104BD000964B0600C348964B0600CB48964B060002 -:104BE0002049964B06002849964B06004E4A9C4B9E -:104BF00006007B4A9C4B05009E4AA24B0500EC4AEE -:104C0000A24B00001E06833E4412007409A0060158 -:104C100024303C30741A8CC88ED88EC0BBAE4B8BFF -:104C20000FE30D8B7F028B7704F3A483C306EBEFB6 -:104C3000071FC39033C0A33E01B90C01BE40018BD6 -:104C4000FE81C6B40F89048BC62BF13BC777F6A350 -:104C50003C01C3901E0660368B2E3E018B5E003BEE -:104C6000EB742B8B7602891C89770236A13C018973 -:104C7000460036892E3C018BEBFF4E0674088B6E86 -:104C800000FF4E0675F836892E3E018B66046107DB -:104C90001FC31E0660368B2E3E0198894606896624 -:104CA000043B6E0074108B6E00FF4E0675F836895B -:104CB0002E3E018B660461071FC3C3901E06609CD5 -:104CC000FA33ED8EDD8B2E3C0185ED743D8B4E006D -:104CD000890E3C018BCC8DA60A01561E06608966A2 -:104CE00004C746080F1AC7460601008B1E3E018501 -:104CF000DB741D8BC58707894600895E028BD889C6 -:104D00006F028BE19D61071FF8C39D61071FF9C307 -:104D1000892E3E01896E00896E0287E19D8BE1EB51 -:104D2000E4000D0A5465726D696E616C73207375D1 -:104D300070706F727465643A0D0A312920414E53C8 -:104D40004920636F6D70617469626C650D0A322968 -:104D500020577973652033300D0A506C6561736597 -:104D60002073656C6563743A20000D0A636F646597 -:104D7000207365676D656E743D000D0A4D6F6E6939 -:104D8000746F722076322E350A0D0A3E000D0A50DD -:104D90006172646F6E3F000D0A4E6F206164647231 -:104DA00065737320737065636966696564000D0AD5 -:104DB0003A000D0A004C6F633D000D0A4641544114 -:104DC0004C204552524F523D000D0A4D6F6E697492 -:104DD0006F7220636F6D6D616E64733A2D0D0A20E2 -:104DE0002020442C645B5B787878783A5D7878781A -:104DF000785D202D2064756D70206D656D6F727902 -:104E00000D0A2020204C2C6C5B5B787878783A5D1A -:104E1000787878785D202D2064756D702073696EC8 -:104E2000676C65206C696E650D0A202020452C6535 -:104E30005B5B787878783A5D787878785D202D209B -:104E400065646974206D656D6F72790D0A2020208C -:104E5000462C665B5B78787878205D787878785D2A -:104E6000202D2066696C6C206D656D6F72792070E5 -:104E70006172616772617068730D0A202020495B5E -:104E8000787878785D202020202020202020202D78 -:104E900020776F726420696E7075742066726F6D12 -:104EA00020706F72740D0A202020695B7878787802 -:104EB0005D202020202020202020202D20627974B9 -:104EC0006520696E7075742066726F6D20706F72E8 -:104ED000740D0A2020204F78787878207878202068 -:104EE000202020202020202D206F757470757420C4 -:104EF000776F726420746F20706F72740D0A2020B7 -:104F0000206F787878782078782020202020202042 -:104F100020202D206F75747075742062797465205F -:104F2000746F20706F72740D0A202020475B5B78CD -:104F30007878783A5D787878785D2020202D206721 -:104F40006F746F20616464726573730D0A20202092 -:104F5000575B5B787878783A5D787878785D202050 -:104F6000202D207761746368206120776F72640D53 -:104F70000A20202043202020202020202020202024 -:104F800020202020202D20696E7465727275707447 -:104F900073206F66660D0A202020532020202020D9 -:104FA00020202020202020202020202D20696E7409 -:104FB00065727275707473206F6E0D0A20202073F5 -:104FC00020202020202020202020202020202020E1 -:104FD0002D2073696E676C6520737465700D0A20EF -:104FE000202042787878782020202020202020203F -:104FF0002020202D20627265616B706F696E7420B5 -:105000007365740D0A20202062202020202020209B -:105010002020202020202020202D20627265616B1E -:10502000706F696E7420636C6561720D0A202020B8 -:10503000522020202020202020202020202020203E -:10504000202D207265737461727420627265616BC9 -:10505000706F696E740D0A2020207220202020209D -:1050600020202020202020202020202D2072656755 -:105070006973746572732061742062726B70740D51 -:105080000A202020582C78206E202020202020204C -:1050900020202020202D206578616D696E652063B9 -:1050A00068616E6E656C206E0D0A202020482C3FD2 -:1050B00020202020202020202020202020202D20E3 -:1050C00074686973206D657373616765001B5B327B -:1050D0004A1B5B313B3148414E5349205465726D48 -:1050E000696E616C0D0A0A001B5B4B001B5B4A007A -:1050F0001B5B324A1B5B313B3148001B5B44201B6E -:105100005B44001B5B313B373248001B5B003B00BC -:1051100048001B5B73001B5B75001B7A2B0B7F1B0E -:105120007A2E0C7F1B7A2D087F1B7A2C0A7F1B7A24 -:1051300022087F1A57797365203330205465726DC9 -:10514000696E616C0D0A001B54001B59001A001E89 -:105150000008200800001B3D0000001B46000D0059 -:105160003F4464456546664767486849694F6F43F1 -:1051700063537342625272577758784C6C3C60D4D8 -:1051800057D45750585058D659D659B459B4593C99 -:10519000603C606C57485726570657905790579871 -:1051A00057485F0C5F585F335F405FA057A057FEC2 -:1051B00059FE59DC57DC5788619861C061CC61D8D1 -:1051C00061F66102622262F8564A625862605920B2 -:1051D00020666C6167733D00202061783D002020CF -:1051E00062783D00202063783D00202064783D00F7 -:1051F000202063733D00202064733D0020206573F0 -:105200003D00202073733D00202064693D00202074 -:1052100073693D00202062703D00202073703D00C6 -:10522000202069703D00206368616E656C3D002040 -:105230002020207365673D002074695F7374723DA0 -:10524000002074695F746F733D002074695F6D6145 -:10525000783D002074695F6261733D002074695F6E -:1052600073697A3D002074695F7374663D00207431 -:10527000695F726F6F3D002074695F666C673D0007 -:105280002074695F746F743D002072695F70636E93 -:105290003D002072695F7374723D002072695F7314 -:1052A00074663D002072695F726F6F3D0020726905 -:1052B0005F6261733D002072695F73697A3D00200F -:1052C00072695F746F743D002072695F6D696E3D35 -:1052D000002072695F666C673D002072695F746FC1 -:1052E000733D002072695F7468723D002074685FCE -:1052F0007374663D002074685F7374723D0020749F -:10530000685F6261733D002074685F73697A3D0075 -:105310002074685F7472673D002074685F666C6714 -:105320003D002074685F636E743D002072685F7397 -:1053300074723D002072685F7374663D002072686D -:105340005F6261733D002072685F73697A3D00207F -:1053500072685F7370613D002072685F61736F3DBA -:10536000002072685F726F6F3D002072685F666C2C -:10537000673D00206D5F636172653D002070745F62 -:10538000666C6F3D002061735F666C6F3D0020723C -:105390006D5F666C6F3D00202020715F696E3D007F -:1053A0002020715F6F75743D0020715F6472616EC3 -:1053B0003D002020715F74696D3D00202020715FE9 -:1053C00066633D0020715F737461743D0020715FFE -:1053D000646174613D0020715F6D6F646D3D0020FC -:1053E00068616E645F6F3D002068616E645F623D5E -:1053F000002068616E645F653D002068616E645FD7 -:10540000693D0020206F706F73743D002020746927 -:105410006D656F3D0020637573746D313D002063D1 -:105420007573746D323D0020637573746D643D0057 -:10543000207478726174653D0020727872617465C1 -:105440003D002020635F6D61703D0020635F6164FB -:1054500064723D0020635F616973723D0020635F89 -:10546000787461673D0020635F646566723D00206B -:10547000635F666C73683D002074786D6178733D7E -:10548000002072695F656D733D002020635F6C735F -:10549000723D002020635F6965723D002020635FDC -:1054A0006663723D002020635F6D63723D002020C3 -:1054B000635F6C63723D002020635F6473733D0023 -:1054C00020635F647373693D0020635F647373726C -:1054D0003D002020635F6973723D002020635F639D -:1054E00061723D002020635F6566723D0020635F4E -:1054F000657273743D0020635F65636E743D0020C8 -:10550000635F62726B633D0020635F626F6B633D3C -:105510000020635F7265706C3D0020635F6363739E -:10552000723D0020635F737474313D0020635F73CC -:105530007474323D002BC08ED88EC0E8C200E8E5FE -:1055400000FABF8400C705DC568C4D02BF0C00C7B3 -:10555000056E5E8C4D02BF0400C705BA5E8C4D021D -:10556000E8F10090E84901E81600F490E8E500BE93 -:10557000BA4DE8090CA09312E85D0CE8C209EBE40F -:10558000E8D50CE8C40C0AC074F68B1EF8793C0D03 -:10559000742E3C0874173C7F741383FB207FE188D2 -:1055A00087D67943891EF879E8770CEBD30BDB7447 -:1055B000CF4B891EF8798B36167AE8C10BEBC19078 -:1055C000E80200EBBBC687D679000BDB741EA0D6C1 -:1055D00079BF6051B91D008BD9060E07F2AE077571 -:1055E00017412BD9D1E32EFF977D519033C0A3F8FB -:1055F00079BE894DE8870BC3BE8D4DE8800BEBEC7F -:10560000BA0002B093EEB055EEBA1002B093EEB00D -:10561000AAEEBA0002EC3C557508BA1002EC3CAA9E -:105620007403E82FF6C3BA0402B01AEEB020EEB04D -:1056300030EEB040EEB080EEBA0002B013EEB0072C -:10564000EEBA0802B080EEBA0202B0BBEEBA0402B3 -:10565000B005EEC3C606CA1301C706F8790000C636 -:1056600006F67901C706D0790000C706D279000096 -:10567000C706D4790000C706FA790000C706FC798E -:105680000000C706FE790000C706007A0000C706C2 -:10569000027ACE598C0E047AC706067A0000C70635 -:1056A000277A0000C606297A00C6062A7A00C39027 -:1056B000BE224DE8C80AE83F002C313C0177F7E8EC -:1056C00081098B360C7AE8B50ABE6A4DE8AF0A0E3E -:1056D00058E8F80ABE7A4DE8A40AC39060D1E38383 -:1056E000FB1873111EBA00008EDA2EFF97B7518B8C -:1056F000EC8946101F61CF90E84F0B0AC07505E892 -:10570000560BEBF4C390833EF879017416BED7793B -:10571000E8310A8BD0AC3C2C74043C207505E8239E -:105720000AEEC3E9D2FE833EF8790174F6BED7795A -:10573000E8110A8BD0AC3C2C74083C207404E9B707 -:10574000FE90E8FF09EFC3908B16067A833EF87946 -:1057500001740BBED779E8EB098BD0A3067AB02091 -:10576000E8570B8B16067AECE86F0BC38B16067A9C -:10577000833EF87901740BBED779E8C7098BD0A3B3 -:10578000067AB020E8330B8B16067AEDE8670BC378 -:10579000FAC606F67900C390C606F67901FBC390F7 -:1057A00006E85809B020E8110B268B05E8470BB036 -:1057B00008E8060BE8030BE8000BE8FD0AB8010057 -:1057C000E8CFF4BA0202EC24017502EBDCBA06025F -:1057D000EC07C390C706087A1000EB06C706087AE4 -:1057E0000100068E06FC798B3EFA79E80E09E80B7B -:1057F00000893EFA798C06FC7907C390BEB24DE869 -:105800007C098B16087A52E82A09E80F0AE80C0A84 -:1058100033DBB9100090268A01E8BC09E8FD094392 -:10582000E2F4E8F709E8F40933DBB9100090268ABE -:10583000013C2072053C7E760390B02EE8E30943DC -:10584000E2ECBEB24DE8360983C7105A4A75B7C3B9 -:10585000068E06007A8B3EFE79E8A008893EFE7926 -:105860008C06007A578B360E7AE81209C706087A3A -:105870001000BA0002E8E800E881FF5FBA0000E823 -:10588000DE00BEB54DE8F6088CC0E83F09B03AE846 -:1058900090098BC7E83509E87E08E8C30090E8B7AF -:1058A00009E8A6090AC074F63C0B750683EF10EBF5 -:1058B00019903C0A750683C710EB0F903C0C7504D9 -:1058C00047EB07903C0875244F908B36FE798BC7C9 -:1058D0002BC63D000172A53D1001720483EE20909D -:1058E00083C6108936FE79578BFEEB803C2E7508F7 -:1058F000BA0113E86A0007C3C6060A7A0232C990E1 -:105900003C30724C3C39760C245F3C4172423C4640 -:10591000773E2C072C3050E8CC085802C8FE0E0AFF -:105920007A740FC0E104E82F09E81E090AC074F672 -:10593000EBCE26880DE8E0078AD0E823008AC13C38 -:105940002072053C7E760390B02EE8D508E970FF02 -:10595000E8C507E80A00268A05E87C08E91DFF90EB -:10596000F606267A02750286F2528B361A7AE80D0E -:10597000085A528AC60206247AF606267A01750665 -:10598000E89F08EB0D9032E4E80D088B361C7AE8AE -:10599000EC075A8AC20206257AF606267A017506AF -:1059A000E87F08EB069032E4E8ED078B361E7AE8D4 -:1059B000CC07C390068E06047A8B3E027AE83C0739 -:1059C000893E027A8C06047A07FF1E027AC3BE97CC -:1059D0004DE8AA07CB900657BED779E866078BD863 -:1059E000E861078BC82BCB78118EC3BF0000B8FFCE -:1059F000FF51B90800F3AB59E2F75F07C39006BE49 -:105A0000D779E83F078BD8D1E32E8B9F4400BE2681 -:105A100052E8F1088BC3E8DD08B80100E873F2E84A -:105A2000E008BE2F52E8DD088B4718E8C808BE77AB -:105A300052E8D1088B4726E8BC08BE5352E8C50897 -:105A40008B471EE8B008BE5C52E8B9088B4720E8D7 -:105A5000A408BE6E52E8AD088B4724E89808BE80C3 -:105A600052E8A1088B472AE88C08E89508BE38520E -:105A7000E892088B07E87E08BE4152E887088B470A -:105A80001AE87208BE4A52E87B088B471CE8660891 -:105A9000BE6552E86F088B4722E85A08E86308BEE3 -:105AA000D152E860088B4738E84B08BEAD52E85445 -:105AB000088B4730E83F08BEB652E848088B4732AB -:105AC000E83308BEA452E83C088B472EE82708BEFE -:105AD000BF52E830088B4734E81B08E82408BE8929 -:105AE00052E821088B4704E80C08BE9252E81508DA -:105AF0008B4714E80008BE9B52E809088B472CE846 -:105B0000F407BEC852E8FD078B4736E8E807BEDA5F -:105B100052E8F1078B473AE8DC07BEE352E8E507B5 -:105B20008B473CE8D007E8D907BE1953E8D6078B66 -:105B30004748E8C107BEFE52E8CA078B4742E8B5AE -:105B400007BE0753E8BE078B4744E8A907BE7C534E -:105B5000E8B2078B474CE89D07BE8553E8A6078B44 -:105B6000474EE89107BE8E53E89A078B4750E88569 -:105B700007E88E07BE2253E88B078B474AE8760773 -:105B8000BEEC52E87F078B4708E86A07BEF552E88B -:105B900073078B4740E85E07BE1053E867078B47E3 -:105BA00046E85207E85B07BE6A53E858078B477A16 -:105BB000E84307BE3D53E84C078B4770E83707BE04 -:105BC0004653E840078B4772E82B07BE4F53E83433 -:105BD000078B4774E81F07E82807BE2B53E8250703 -:105BE0008B470CE81007BE3453E819078B4710E8C1 -:105BF0000407BE5853E80D078B4776E8F806BE61E8 -:105C000053E801078B4778E8EC06BE7353E8F506C6 -:105C10008B473EE8E006E8E906BE9753E8E6068BC8 -:105C20004752E8D106BEA053E8DA068B4754E8C5D0 -:105C300006BEA953E8CE068B4756E8B906BEB25356 -:105C4000E8C2068B4758E8AD06BEBB53E8B6068BE4 -:105C5000475AE8A106BEC453E8AA068B475CE895FC -:105C600006E89E06BECD53E89B068B475EE8860697 -:105C7000BED653E88F068B4760E87A06BEDF53E84E -:105C800083068B4762E86E06BEE853E877068B47CB -:105C90007CE86206BEF153E86B068B477EE8560649 -:105CA000BEFA53E85F068B878000E84906E8520693 -:105CB000BE4254E84F068B879E00E83906BE035467 -:105CC000E842068B4764E82D06BE0C54E836068B86 -:105CD000476EE82106BE1554E82A068B878E00E839 -:105CE0001406BE1E54E81D068B879000E80706BE0A -:105CF0002754E810068B879200E8FA05E80306BEF1 -:105D00003054E800068B879400E8EA05BE3954E871 -:105D1000F3058B879600E8DD05BE6F54E8E6058B3A -:105D2000879800E8D005BE5D54E8D9058A87A000B1 -:105D3000E8A705BE5454E8CC058A4728E89B05BE71 -:105D40006654E8C0058A87A100E88E05E8B305BE61 -:105D50007854E8B0058A87A200E87E05BE8154E841 -:105D6000A3058A87A300E87105BE8A54E896058AD0 -:105D700087A400E86405BE9354E889058A87A500D6 -:105D8000E85705BE9C54E87C058A87A600E84A05CA -:105D9000BEA554E86F058A87A700E83D05BEAE544E -:105DA000E862058A87A800E83005E85505BEB754C3 -:105DB000E852058A87A900E82005BEC054E84505D9 -:105DC0008A87AA00E81305BEC954E838058A87AB5C -:105DD00000E80605BED254E82B058A87AD00E8F935 -:105DE00004BEDB54E81E058A87AE00E8EC04BEE47E -:105DF00054E811058A87AF00E8DF04BEED54E804DB -:105E0000058A87B000E8D204E8F704BEF654E8F447 -:105E1000048A87B100E8C204BEFF54E8E7048A8719 -:105E2000B200E8B504BE0855E8DA048A87B300E892 -:105E3000A804BE1155E8CD048A87BB00E89B04E89E -:105E4000C004BE1A55E8BD048A87BC00E88B04BEB6 -:105E50002355E8B0048A87BE00E87E04BE2C55E8CE -:105E6000A3048A87BF00E87104E8960407C36006AC -:105E70001E168BECFF4E16F7461A00027401FBB893 -:105E800000008ED88EC0892E2D7AE8CB0081661A4C -:105E9000FFFEC6062A7A00E8D800B8005FA32B7A76 -:105EA000E85D00803E2A7A00740A814E1A0001C61D -:105EB000062A7A00171F0761CF9060061E168BEC2A -:105EC000F7461A00027401FBB800008ED88EC08914 -:105ED0002E2D7A81661AFFFEC6062A7A00E8920005 -:105EE000B8005FA32B7AE81700803E2A7A00740A74 -:105EF000814E1A0001C6062A7A00171F0761CF904B -:105F0000B8F000E88CEDFF262B7AC390065356803C -:105F10003E297A007403E83F00BED779E825028B5A -:105F2000D8A3277A2E8A07A2297AB0CC2E88075EBA -:105F30005B07C3C6062A7A00B80A5FA32B7AC39010 -:105F40008B2E2D7AE82B00C3C6062A7A01E80800BA -:105F5000B80A5FA32B7AC39057803E297A00740F4A -:105F60008B3E277AA0297A2E8805C606297A005FFB -:105F7000C390BEB24DE80602BED851E80002FF76DB -:105F80001458E84702BEDE51E8F301FF760E58E8E8 -:105F90003A02BEE451E8E601FF761258E82D02BE4F -:105FA000EA51E8D901FF761058E82002BE1452E801 -:105FB000CC01FF760A58E81302BE1A52E8BF01FF6F -:105FC000760C58E80602BECF51E8B201FF761A58A7 -:105FD000E8F901BEB24DE8A501BEF051E89F01FF0E -:105FE000761858E8E601BEF651E89201FF760258AD -:105FF000E8D901BEFC51E88501FF760458E8CC01E0 -:10600000BE0252E87801FF760058E8BF01BE085290 -:10601000E86B01FF760658E8B201BE0E52E85E0159 -:10602000FF760858E8A501BE2052E85101FF761618 -:1060300058E89801BE894DE84401C390BEC94DE8B7 -:106040003C01C33C0074053C017459C3C7060C7A7B -:10605000CD50C7060E7AF050C706107AE850C70632 -:10606000127AEC50C706147AF450C706167AFB5021 -:10607000C706187A0351C7061A7A0B51C7061C7A4D -:106080000E51C7061E7A1051C706207A1251C70654 -:10609000227A1651C606247A01C606257A01C6065A -:1060A000267A03C3C7060C7A1A51C7060E7A4D51D9 -:1060B000C706107A4751C706127A4A51C706147AA2 -:1060C0004F51C706167A5151C706187A5551C7065F -:1060D0001A7A5651C7061C7A5951C7061E7A5A5168 -:1060E000C706207A5B51C706227A5E51C606247A1B -:1060F00020C606257A20C606267A02C3A1F879486A -:106100007414BED779E83C008BF8AC3C3A75078E26 -:10611000C7E830008BF8C3908BC72B06FE798AF056 -:10612000240F8AD002D002D080C20BC0EE0480C6F9 -:1061300003043DC38CC0E89300B03AE8E4008BC789 -:10614000E88900C35133C990AC3C2074FB900AC06D -:1061500074262C3072223C0976143C11721A2C07DA -:106160003C0F760A3C2A72102C203C0F770A98C10B -:10617000E10403C8ACEBD7904E8BC159C390068C99 -:10618000C88EC0E8020007C3268A04460AC0740607 -:10619000E88F00EBF390C3900BC0747A5133D2B9FF -:1061A000E803F7F18BCAE803008BC159BA6400F623 -:1061B000F2E80C008AC498B20AF6F2E802008AC437 -:1061C000500AF074050430E8580058C386C4E80744 -:1061D0000086C4E80200C390C1C804E80800C1C03A -:1061E00004E80200C3905350240FBBCA622ED7E8C4 -:1061F0003000585BC39086C4E8070086C4E80200FC -:10620000C39050B908008AE032C0D1C00430E81110 -:1062100000E2F558C390B030E80700C3B020E801B1 -:1062200000C3568B36D0798884D0774681E6FF014B -:10623000FF06D4798936D079813ED479FE0175087C -:1062400056E814005EEBF1905EC3BA0202EC240142 -:106250007404BA0602ECC390803EF67900740960BB -:10626000B80100E82CEA6190BA0202ECA804742894 -:106270008B36D279833ED47900741D8A84D07746D8 -:1062800081E6FF018936D279FF0ED479BA0602EE93 -:10629000BA0202ECA80475DCA1D479C352BA060292 -:1062A000EE5AC3905250BA0202ECA8047408585A2D -:1062B000E8E9FFF9C390585AF8C35250BA0202EC09 -:1062C000A80474FB585AE8D3FFC330313233343555 -:1062D0003637383941424344454653508AE080E4DA -:1062E0000FBBCA62C0E8042ED7E8CEFF8AC42ED7FF -:1062F000E8C7FF585BC386E0E8DFFF86E0E8DAFF27 -:10630000C390BEB24D502EAC3C007405E8ABFFEB21 -:10631000F558C390C808000056578B7604BF040098 -:10632000C746FC0000C746FA0000C746F8000083D5 -:106330007E0600750E56E8B60E590BC075058BC764 -:10634000E95B018B46FC8946FE0BFF7505B8010031 -:10635000EB0233C05056E8A40D5959B4008946FCED -:106360008B5EFC83FB087603E92B01D1E32EFFA7AC -:10637000B264B80300E92601837EFA007414C746AC -:10638000FA00008A445898508A44599850E8C20F3D -:106390005959837EF800740AC746F8000056E89BF6 -:1063A0000859837E060075058BC7E9F10083FF0459 -:1063B0007503E9E6008BC7E9E400837EFE00750300 -:1063C000BF0200E9D500837EFE007503BF0100E92E -:1063D000C9008B5EFE83FB077603E98600D1E32EBE -:1063E000FFA7A26433FFE97F00BF0400807C580F41 -:1063F0007422837EF800751CFE44586A0856E87EB5 -:106400000C59598A445804805056E8720C5959C79F -:1064100046FA0100837EF800740AC746F800005669 -:10642000E8190859EB42BF0400807C5800742283AD -:106430007EF800751CFE4C586A0856E8410C595904 -:106440008A445804805056E8350C5959C746FA0119 -:1064500000837EF800740AC746F8000056E8DC079F -:1064600059EB05BF0400EB00EB31BF0400EB2CC778 -:1064700046F801006A0856E8050C5959807C58090D -:106480007D04B00FEB02B00004805056E8F00B59C9 -:1064900059BF0400EB05BF0400EB00E9A5FE5F5EF9 -:1064A000C9C3E4636364636463646364E963266427 -:1064B00051647863BA63C6639664D2636A646A643B -:1064C0006F647263C808000056578B76048B7E0891 -:1064D0006A0156E8A90B59598A4606C0E0060480AD -:1064E0005056E89A0B5959C746FE0000897EF8EBD2 -:1064F00003FF46FE8B5EF8FF46F8803F0075F2838F -:106500007EFE107D25B810002B46FED1F88946FC92 -:10651000C746FA0000EB0B6A2056E8620B5959FF98 -:1065200046FA8B46FA3B46FC7CEDEB0C8BDF478A48 -:10653000075056E8490B5959803D0075EF6A0256DD -:10654000E83C0B5959EB005F5EC9C3C80400005614 -:10655000578B7E04C746FE0000BE1400E909018B7C -:106560005EFE83C3042BDF8A87AC0B88445AC64483 -:1065700058088A46FE884459C744060000C6441994 -:1065800000C6441A00C6441B00C6441D0DC6441E66 -:1065900003C6441F00C6442000C6442100C6445B15 -:1065A00000C6445D00C6445E00C6445F00C6446049 -:1065B00000C746FC0000EB0D8B5EFCD1E3C740300A -:1065C0000000FF46FC837EFC107CEDC746FC00000B -:1065D000EB0A8B5EFCC6405000FF46FC837EFC0449 -:1065E0007CF0C744540000C7445600008A445A98BF -:1065F000BAF80023D0B805000BC28946FC9CFA8A81 -:1066000046FCBAFE00EEBA0000EC9D24088846FC69 -:10661000837EFC007502EB4AFF76FEE87A0C59682F -:10662000350256E8320A59590BC07534683802569B -:10663000E8250A59590BC0752768420256E8180A1E -:1066400059590BC0751A684C0256E80B0A59590B78 -:10665000C0750D68560256E8FE0959590BC0740200 -:10666000EB00FF46FE83C662397EFE7D03E9EFFE46 -:10667000EB005F5EC9C3C808000056578B4604BADA -:106680006200F7EA0514008BF0837E06007405B8FB -:106690001000EB03B808008944048A460888445C6B -:1066A00056E85904598BF88BC78944568944548A53 -:1066B000445D88442F0BFF751D68C20F6A0156E8C0 -:1066C00002FE83C406EB006A0156E847FC59590BE9 -:1066D000C075F4BF0100897EFAB90500BBE96A2ED6 -:1066E0008B073B46FA74074343E2F4E9A4032EFF09 -:1066F000670AC744060200C74408F4088B5E04D149 -:10670000E38B87FC0889440A33C08BF8894454E939 -:10671000800356E8BB0559BF01008A445D88446088 -:10672000E96F03837C04087530807C5C0175158AF1 -:10673000445DB400D1E08BD8FFB7E40856E8F70811 -:106740005959EB138A445DB400D1E08BD8FFB7C42C -:106750000856E8E2085959EB2E807C5C0175158AD1 -:10676000445DB400D1E08BD8FFB7D40856E8C70821 -:106770005959EB138A445DB400D1E08BD8FFB7B40C -:106780000856E8B20859596A0156E887FB59598BEF -:10679000D883FB03772AD1E32EFFA7E16ABF01006C -:1067A0008A445D88445EEB188A445D04FF240788B0 -:1067B000445DEB0C8A445DFEC0240788445DEB0019 -:1067C000E9CF028A445DB400D1E08BD8FFB7FD0267 -:1067D00056E863085959681D0356E85A0859596A1A -:1067E0000156E82FFB59598BD883FB037736D1E349 -:1067F0002EFFA7D96ABF01008A445D88445FEB245D -:106800008A445D04FF8A540480C2FF22C288445D2A -:10681000EB128A445DFEC08A540480C2FF22C28803 -:10682000445DEB00E96B028B5C0683C3FED1E38B16 -:10683000400889048B1CFF77066A0056E885FC83B4 -:10684000C4068B5C064BD1E38B40088944028B5C09 -:1068500002FF77066A0156E86AFC83C4066A01569D -:10686000E8B1FA59598BD883FB037603E91F02D1AB -:10687000E32EFFA7D16A8B5C028B47048944028B0D -:106880005C02803F44750D8B5C028A4701B4003B7B -:1068900044047DE28B4604D1E08B1C03D88B440278 -:1068A0008947088B5C064BD1E38B4402894008E999 -:1068B000DE018B5C028B47028944028B5C02803FC5 -:1068C00044750D8B5C028A4701B4003B44047DE2B1 -:1068D0008B4604D1E08B1C03D88B44028947088B7C -:1068E0005C064BD1E38B4402894008E9A201BF0159 -:1068F00000E99C018B5C028A07B4008946F8B90C58 -:1069000000BBA16A2E8B073B46F874074343E2F4B1 -:10691000E977012EFF67188B4604D1E08B5C0203F8 -:10692000D88B47088B5C06FF4406D1E38940088B6F -:106930001C807F010074128B5C028A47018B1C8AC9 -:106940005701B6008BDA884018E94001FF4C06E990 -:106950003A018B5C028A47018B1C8A5701B6008B77 -:10696000DA884018E925018B5C028A47018B1C8A72 -:106970005701B6008BDA884018FF4C06E90D018BF1 -:106980005C028A47018B1C8A5701B6008BDA3040C3 -:1069900018E9F800B8F0108BF88944548A445F88ED -:1069A000445DE9E7008A441C983D020074073D03FA -:1069B000007402EB07C746FE0000EB2B8A441C98CC -:1069C000D1E08BD8FFB7690256E86B0659596A01C6 -:1069D00056E840F959598946FE837EFE00740683C5 -:1069E0007EFE0375E9EB00837EFE0374628A441C1D -:1069F00098D1E08BD8FFB76D0256E83A0659595640 -:106A0000E84D97598946FC8B5EFC83EBFE83FB03C4 -:106A10007733D1E32EFFA7996A68AC0256E81706D0 -:106A20005959EB23688F0256E80C065959EB186840 -:106A3000750256E801065959EB0D68C60256E8F68C -:106A4000055959EB02EB006A0156E8C7F85959BFDE -:106A50000100EB3868DD0256E8DC0559596A015639 -:106A6000E8B1F85959BF0100EB22B8D0308BF88952 -:106A700044548A446088445DEB12B8E0208BF88966 -:106A800044548A445E88445DEB02EB00EB02EB0069 -:106A9000EB00E941FC5F5EC9C3196A246A2F6A3AB8 -:106AA0006A0000010002000400410042004300446B -:106AB00000800081008200FF001769546A7A6AA58D -:106AC00069526994696A6A676952697F6967694C42 -:106AD00069F4687668B268EE68F56700681268F570 -:106AE000679D67A867B4679D6700000100F010E02C -:106AF00020D0302768F266C36723671267C8040096 -:106B00000056578B76048A4459988946FC6A098B4B -:106B100046FC05840150E8930859598BF88BC7252A -:106B200000F03D001075558BC725F0003DF0007555 -:106B30004B8BC725000FC1F8088946FE8B44043BE8 -:106B400046FE7D0533C0E9EF008BC7250F00BA0F65 -:106B5000002BD03B56FE740533C0E9DB00C744026E -:106B600004098A46FE88445F88445D8B5EFCD1E35D -:106B7000C787FC080409B8F010E9BC008BC72500E2 -:106B8000F03D002075528BC725F0003DE0007548B0 -:106B90008BC725000FC1F8088946FE837EFE087E5C -:106BA0000533C0E992008BC7250F00BA0F002BD028 -:106BB0003B56FE740533C0EB7F90C744020C098A34 -:106BC00046FE88445E88445D8B5EFCD1E3C787FC4B -:106BD000080C09B8E020EB608BC72500F03D0030C1 -:106BE00075528BC725F0003DD00075488BC7250036 -:106BF0000FC1F8088946FE8B44043B46FE7D0433F2 -:106C0000C0EB358BC7250F00BA0F002BD03B56FECB -:106C1000740433C0EB22C7440214098A46FE884438 -:106C20006088445D8B5EFCD1E3C787FC081409B81B -:106C3000D030EB0433C0EB005F5EC9C3C806000070 -:106C4000568B76046A0856E8350459598A44580424 -:106C5000805056E8290459598B44543B4456750AD0 -:106C60008A445D3A442F7502EB648B445489445640 -:106C70008B5C028A470188442F8A445DB400C1E0DE -:106C8000088B54540BD08A445DB400BB0F002BD842 -:106C90000BD38956FE6A108A445998050400990559 -:106CA000400183D2005250E8540883C4068956FC40 -:106CB0008946FA8B46FE0946FA834EFC006A19FFA4 -:106CC00076FCFF76FAE8730783C406E8FE075EC920 -:106CD000C3C81C000056578B5E048A4759988BF036 -:106CE0008B5E048A475DB4008946E6837EE6007DBC -:106CF0000A8B5E048B4704488946E68B5E048B470B -:106D0000043B46E67F05C746E600008B5E048A46E4 -:106D1000E688475D8BDED1E38B9F5902C647022090 -:106D20008BDED1E38B9F5902C64703308BDED1E364 -:106D30008B9F6102C64702208BDED1E38B9F6102ED -:106D4000C64703308B46E68946FA837EFA007418FC -:106D50008B46FABB0A0033D2F7F380C2308BDED108 -:106D6000E38B9F5902885703BB0A008B46FA33D244 -:106D7000F7F38946FA837EFA0074188B46FABB0A49 -:106D80000033D2F7F380C2308BDED1E38B9F590200 -:106D90008857028B46E68946FA837EFA0074188B80 -:106DA00046FABB0A0033D2F7F380C2308BDED1E360 -:106DB0008B9F6102885703BB0A008B46FA33D2F7D8 -:106DC000F38946FA837EFA0074188B46FABB0A00F0 -:106DD00033D2F7F380C2308BDED1E38B9F61028820 -:106DE00057028B5EE6D1E3FFB712026A00FF76041A -:106DF000E8D1F683C40668D30F6A01FF7604E8C3BE -:106E0000F683C406FF76E656E8019359598956F28F -:106E10008946F0FF76E656E8149359598956EE896B -:106E200046EC9CFAC45EF0268B078946EAC45EEC09 -:106E3000268B078946E8BA50FFED8946FE9DC74676 -:106E4000E40100E8EEA0BA50FFED8946FC8B46FC59 -:106E50002B46FE3DE8037303E980019CFABA50FF1C -:106E6000ED8946FC8B46FC2B46FE8946F8C45EF055 -:106E7000268B072B46EA8946F6C45EF0268B0789E7 -:106E800046EAC45EEC268B072B46E88946F4C45ECE -:106E9000EC268B078946E8BA50FFED8946FE9D81B6 -:106EA0007EF8E803761CFF76F8FF76F6E87601595F -:106EB000598946F6FF76F8FF76F4E8680159598952 -:106EC00046F4BF0E00EB178BDED1E38B9F5902C651 -:106ED00001208BDED1E38B9F6102C601204783FF37 -:106EE0001176E48BDED1E38B9F5902C6470D308BC0 -:106EF000DED1E38B9F6102C6470D30837EF60977B2 -:106F000005B80D00EB26837EF6637705B80E00EB1F -:106F10001B817EF6E7037705B80F00EB0F817EF645 -:106F20000F277705B81000EB03B811008BF8EB259D -:106F30008B46F6BB0A0033D2F7F380C2308BDED12A -:106F4000E38B9F590288114FBB0A008B46F633D260 -:106F5000F7F38946F6837EF60075D5837EF40977CC -:106F600005B80D00EB26837EF4637705B80E00EBC1 -:106F70001B817EF4E7037705B80F00EB0F817EF4E9 -:106F80000F277705B81000EB03B811008BF8EB253D -:106F90008B46F4BB0A0033D2F7F380C2308BDED1CC -:106FA000E38B9F610288114FBB0A008B46F433D2FA -:106FB000F7F38946F4837EF40075D58BDED1E3FFC9 -:106FC000B75902FF7604E86E0059598BDED1E3FF12 -:106FD000B76102FF7604E85E0059596A00FF760443 -:106FE000E831F359598BD883FB04771FD1E32EFF87 -:106FF000A71B70EB22C746E40000FF4EE6EB0CC770 -:1070000046E40000FF46E6EB02EB00837EE40074FA -:1070100003E92AFEE9D4FC5F5EC9C3F36FF56FFF95 -:107020006FF36F0970558BEC8B4604B9E803F7E1F9 -:107030008B4E06F7F15DC3558BEC568B7606EB0E47 -:107040008BDE468A0750FF7604E833005959803CAE -:107050000075EDEB005E5DC3558BEC568B7606EB51 -:10706000148BDE468A0750FF7604E8450059590B19 -:10707000C07402EB07803C0075E7EB005E5DC3C89F -:10708000020000568B76048A445A988946FE9CFA80 -:107090008A46FEBAFE00EEBA0200ECA80274069D13 -:1070A000E8919EEBE9BA00008A4606EE9DEB005E91 -:1070B000C9C3C8040000568B76048A445A9889468E -:1070C000FEE8E6A18946FCE8E0A12B46FC3DB80BB2 -:1070D0007605B80100EB239CFA8A46FEBAFE00EE64 -:1070E000BA0200ECA80274069DE8489EEBD9BA00EB -:1070F000008A4606EE9D33C0EB005EC9C3C804009B -:107100000056578B7604837E0600740756E8030109 -:1071100059EB0556E8A200598846FF807EFF0877A4 -:10712000068A46FFE98400807EFF0F7603EB7990A4 -:107130008A46FFB4002D0A008BD883FB047767D101 -:10714000E32EFFA7AF71B000EB6156E86B0059B4B6 -:1071500000250F008946FC56E85E0059B4008BF804 -:1071600056E8550059B400C1E0088BD703D08BFA1C -:107170008B5EFCD1E3897830EB2E56E83B005988D2 -:10718000445BEB2456E831005988445056E8290006 -:107190005988445156E821005988445256E819004C -:1071A00059884453EB02EB00E95BFF5F5EC9C346BD -:1071B00071A6714A717A718471C8040000568B7689 -:1071C000048A445A988946FE9CFA8A46FEBAFE0012 -:1071D000EEBA0200ECA80175069DE8579DEBE9BAEE -:1071E0000000EC8846FD9D8A46FDEB005EC9C3C8E1 -:1071F000020000568B76048A445A988946FE9CFA0F -:107200008A46FEBAFE00EEBA0200EC32E424019D8A -:107210005EC9C3C8060000568B76048A445A988912 -:1072200046FEE885A08946FAE87FA02B46FA3DB8DD -:107230000B7604B008EB249CFA8A46FEBAFE00EEF8 -:10724000BA0200ECA80175069DE8E89CEBDABA00EA -:1072500000EC8846FD9D8A46FDEB005EC9C3558B58 -:10726000EC568B56048A4606EE33F6EB035058462E -:1072700083FE147CF85E5DC3C8020000568B560482 -:10728000EC8846FF33F6EB0350584683FE147CF837 -:107290008A46FFEB005EC9C3C802000056578B76D2 -:1072A00004833EB00B00751FBA8801B000EEBA86A9 -:1072B00001B000EE6A096A00683001E87D0183C40C -:1072C00006C706B00B01006A098BC605800150E8AD -:1072D000DA0059598BF88BC7C1E80C250F00894695 -:1072E000FE8BC7C1E808250F008B56FE83F20C3BCE -:1072F000C275218BC7C1E804250F008B56FE83F2AF -:10730000063BC2750F8BC7250F008B56FE83F20913 -:107310003BC2740D6A0756E838005959C746FE0744 -:10732000008A46FE0480A233028BC6BA6200F7EAE6 -:107330008A56FE8BD888976C006832028BC6BA6278 -:1073400000F7EA05140050E80EFD5959EB005F5EA6 -:10735000C9C3C8020000568B760683E60F8BC6C1F0 -:10736000E00C8BD683F20CC1E2080BC28BD683F201 -:1073700006C1E2040BC28BD683F2090BC28946FE1A -:107380006A196A108B46049905400183D200525055 -:10739000E86B0183C4060B46FE83CA005250E89A8C -:1073A0000083C406E82501EB005EC9C3558BEC568B -:1073B0005733FF6A01688601E8A3FE5959B1102AC4 -:1073C0004E06D3660433F6EB2E817E0400807204F1 -:1073D000B001EB02B00050688801E881FE59596A9B -:1073E00003688601E877FE59596A01688601E86DED -:1073F000FE5959D16604463B76067CCD33F6EB2424 -:10740000D1E76A03688601E854FE59596A01688623 -:1074100001E84AFE5959688801E85CFE599825013F -:10742000000BF84683FE107CD76A00688601E82DC1 -:10743000FE59598BC7EB005F5E5DC3558BEC565709 -:107440008B7E086A01688601E813FE5959B820004E -:107450002BC750FF7606FF7604E8A20083C4068996 -:10746000560689460433F6EB47817E060080720C8F -:107470007506837E04007204B001EB02B000506810 -:107480008801E8D9FD59596A03688601E8CFFD599A -:10749000596A01688601E8C5FD59596A01FF7606F7 -:1074A000FF7604E8580083C40689560689460446D8 -:1074B0003BF77CB56A00688601E8A2FD59596A006D -:1074C000688601E898FD59595F5E5DC3558BEC569F -:1074D0006A01688601E886FD595933F6EB00688831 -:1074E00001E894FD59A80175088BC6463D64007CEF -:1074F000ED6A00688601E865FD59595E5DC3C80400 -:1075000000008B46048B56068B4E08E306D1E0D173 -:10751000D2E2FA8946FC8956FE8B56FE8B46FCEB7E -:1075200000C9C300000000000000000000000000CF -:1075300050726576696F7573204D656E7500426592 -:1075400067696E00000000000000000000000000FD -:10755000000000000000000000000000000000002B -:10756000000000000000000000000000000000001B -:10757000000000000000000000000000000000000B -:1075800000000000000000000000000000000000FB -:1075900000000000000000000000000000000000EB -:1075A00000000000000000000000000000000000DB -:1075B00000000000000000000000000000000000CB -:1075C00000000000000000000000000000000000BB -:1075D00000000000000000000000000000000000AB -:1075E000000000000000000000000000000000009B -:1075F000000000000000000000000000000000008B -:10760000000000000000000000000000000000007A -:10761000000000000000000000000000000000006A -:10762000000000000000000000000000000000005A -:10763000000000000000000000000000000000004A -:10764000000000000000000000000000000000003A -:10765000000000000000000000000000000000002A -:10766000000000000000000000000000000000001A -:10767000000000000000000000000000000000000A -:1076800000000000000000000000000000000000FA -:1076900000000000000000000000000000000000EA -:1076A00000000000000000000000000000000000DA -:1076B00000000000000000000000000000000000CA -:1076C000000000000000000000000000506F727415 -:1076D000203000506F7274203100506F727420326D -:1076E00000506F7274203300506F72742034005059 -:1076F0006F7274203500506F7274203600506F72B4 -:1077000074203700506F7274203800506F727420EC -:107710003900506F727420313000506F7274203114 -:107720003100506F727420313200506F727420310A -:107730003300506F727420313400506F72742031F6 -:1077400035009C01A301AA01B101B801BF01C60126 -:10775000CD01D401DB01E201EA01F201FA010202EA -:107760000A02080000078100038080809F919591A4 -:107770009F000381848E95848484840003828484A2 -:107780008484958E8400048800B20BC60BDA0BEE5D -:107790000B020C160C2A0C3E0C520C770C9C0CBEE7 -:1077A0000CE00C020D01802054657374205061734D -:1077B000736564201F20507265737320800200017E -:1077C00080204D697373696E67205278204461741C -:1077D000611F205072657373208002000180204277 -:1077E00061642052782044617461201F20507265CA -:1077F000737320800200018020586D7472204275DE -:1078000073791F20507265737320800200018020FD -:107810006E6F742063757272656E746C791F2020B0 -:10782000696D706C656D656E7465640200240D2F62 -:107830000D3A0D450D500D5B0D660D710D7C0D87DC -:107840000D920D9D0DA80DB30DBE0DC90D53802CCD -:107850003254442053862C334454522053822C33C8 -:10786000525453201F53812C3252442053852C32C2 -:1078700043442053832C334354532053842C3344A8 -:1078800053522053872C3252492702000180202076 -:10789000444344202D2070696E2032301F275385C9 -:1078A0002E31818263908081828384858687888956 -:1078B0008A8B8C8D8E8F27020001802020445352AA -:1078C000202D2070696E2031311F2753842E318185 -:1078D000826390808182838485868788898A8B8C65 -:1078E0008D8E8F27020001802020435453202D20AD -:1078F00070696E20341F2753832E318182639080FC -:107900008182838485868788898A8B8C8D8E8F2758 -:107910000200018020205249202D2070696E203203 -:10792000321F2753872E3181826390808182838426 -:1079300085868788898A8B8C8D8E8F2702000180AF -:107940002020445452202D2070696E20362F381F7D -:107950002753862E3181826390808182838485863D -:107960008788898A8B8C8D8E8F270200018020204A -:10797000525453202D2070696E20351F2753822EBC -:107980003181826390808182838485868788898A19 -:107990008B8C8D8E8F27020001802020527844200E -:1079A0002D2070696E20321F2753812E30534D8158 -:1079B000826390808182838485868788898A8B8C84 -:1079C0008D8E8F27020001802020547844202D20A6 -:1079D00070696E20331F2753802E30534D81826390 -:1079E00090808182838485868788898A8B8C8D8E1E -:1079F0008F27020001802020444344202D207069FD -:107A00006E20351F2753852E3181826390808182BD -:107A1000838485868788898A8B8C8D8E8F27020048 -:107A200001802020445352202D2070696E20351F84 -:107A30002753842E3181826390808182838485865E -:107A40008788898A8B8C8D8E8F2702000180202069 -:107A5000435453202D2070696E20311F2753832EED -:107A60003181826390808182838485868788898A38 -:107A70008B8C8D8E8F270200018020205249202D73 -:107A800020286E2E632E291F2753872E3181826373 -:107A900090808182838485868788898A8B8C8D8E6D -:107AA0008F27020001802020445452202D2070692D -:107AB0006E20321F2753862E31818263908081820F -:107AC000838485868788898A8B8C8D8E8F27020098 -:107AD00001802020525453202D2070696E20371FC2 -:107AE0002753822E318182639080818283848586B0 -:107AF0008788898A8B8C8D8E8F27020001802020B9 -:107B0000527844202D2070696E20361F2753812E15 -:107B100030534D81826390808182838485868788FB -:107B2000898A8B8C8D8E8F270200018020205478CB -:107B300044202D2070696E20331F2753802E305330 -:107B40004D81826390808182838485868788898A3B -:107B50008B8C8D8E8F27020001802020444344208F -:107B60002D2070696E20351F202020202753852E60 -:107B700031818263888081828384858687270200A1 -:107B800001802020445352202D2070696E20351F23 -:107B9000202020202753842E318182638880818297 -:107BA0008384858687270200018020204354532048 -:107BB0002D2070696E20311F202020202753832E16 -:107BC0003181826388808182838485868727020051 -:107BD000018020205249202D20286E2E632E291F3F -:107BE000202020202753872E318182638880818244 -:107BF00083848586872702000180202044545220F8 -:107C00002D2070696E20321F202020202753862EC1 -:107C10003181826388808182838485868727020000 -:107C200001802020525453202D2070696E20371F70 -:107C3000202020202753822E3181826388808182F8 -:107C40008384858687270200018020205278442083 -:107C50002D2070696E20361F202020202753812E72 -:107C600030534D8182638880818283848586872713 -:107C7000020001802020547844202D2070696E205D -:107C8000331F202020202753802E30534D818263C4 -:107C90008880818283848586872702000180202056 -:107CA000444344202D2070696E2032301F20202054 -:107CB000202753852E318182638880818283848549 -:107CC000868727020001802020445352202D2070F7 -:107CD000696E2031311F202020202753842E3181CE -:107CE0008263888081828384858687270200018061 -:107CF0002020435453202D2070696E20341F2020F3 -:107D000020202753832E318182638880818283845F -:107D1000858687270200018020205249202D20706F -:107D2000696E2032321F202020202753872E318178 -:107D30008263888081828384858687270200018010 -:107D40002020445452202D2070696E20362F381F79 -:107D5000202020202753862E3181826388808182D3 -:107D60008384858687270200018020205254532077 -:107D70002D2070696E20351F202020202753822E51 -:107D8000318182638880818283848586872702008F -:107D900001802020527844202D2070696E20321FEF -:107DA000202020202753812E30534D8182638880EC -:107DB0008182838485868727020001802020547871 -:107DC00044202D2070696E20331F2020202027534F -:107DD000802E30534D8182638880818283848586A2 -:107DE0008727020068049604B6033C040E04890346 -:107DF0005C03E20360088A08BE0738080E0895078E -:107E00006C07E6071C057405FA05C404F004CC05EC -:107E1000A00548057806C806420728065006180738 -:107E2000F006A0060000F408F408D40D04090409C3 -:107E30000409040942000C091C09E50D020014099B -:107E40000409F40D43001C090C09050E0004040983 -:107E50001409120E2C092C092C092C0900003C09CC -:107E60006C091E0E740974097409740900014C0927 -:107E70002C092D0E740974097409740900025C0937 -:107E80003C093D0E740974097409740900036C09F6 -:107E90004C094D0E7409740974097409FF002C090A -:107EA0005C09000000058409EC095E0EF409F40980 -:107EB000F409F409000694097409680EAC0AAC0AC6 -:107EC000AC0AAC0A0007A4098409720EBC0ABC0AF9 -:107ED000BC0ABC0A0008B40994097C0ED40AD40A6E -:107EE000D40AD40A000BC409A409830EFC0AFC0AB4 -:107EF000FC0AFC0A000CD409B409900E140B140BF4 -:107F0000140B140B0002E409C409A00E2C0B2C0B5B -:107F10002C0B2C0B0400EC09D4090E00FF00740993 -:107F2000E40900008201FC09A40AAC0E8202040AE2 -:107F3000F409AF0E82030C0AFC09B20E8204140A83 -:107F4000040AB60E82051C0A0C0ABC0E8206240A1C -:107F5000140AC00E82072C0A1C0AC40E8208340AB6 -:107F6000240AC80E82093C0A2C0ACC0E820A440A52 -:107F7000340AD10E82104C0A3C0AD60E820B540AE7 -:107F8000440ADB0E82115C0A4C0AE00E820C640A81 -:107F9000540AE50E82126C0A5C0AEA0E820D740A1B -:107FA000640AEF0E820E7C0A6C0AF40E820F840AB9 -:107FB000740AFB0E82138C0A7C0A020F8214940A44 -:107FC000840A090F82159C0A8C0A100F8216A40AD3 -:107FD000940A170F8217F4099C0A1E0F8202B40A32 -:107FE000B40A260F8203AC0AAC0A2D0F8200C40A21 -:107FF000CC0A340F8201CC0ABC0A3F0F8202BC0AB1 -:10800000C40A4D0F8200DC0AF40A590F8201E40A07 -:10801000D40A630F8202EC0ADC0A6E0F8203F40AB0 -:10802000E40A7A0F8204D40AEC0A870F8200040B58 -:108030000C0B930F82010C0BFC0A9B0F8202FC0AB3 -:10804000040BA70F82001C0B240BB00F8201240B22 -:10805000140BB50F8202140B1C0BBE0F4400340B23 -:10806000A40B9C0144013C0B2C0BA3014402440BC8 -:10807000340BAA0144034C0B3C0BB1014404540BD8 -:10808000440BB80144055C0B4C0BBF014406640B68 -:10809000540BC60144076C0B5C0BCD014408740BF8 -:1080A000640BD40144097C0B6C0BDB01440A840B88 -:1080B000740BE201440B8C0B7C0BEA01440C940B17 -:1080C000840BF201440D9C0B8C0BFA01440EA40BA3 -:1080D000940B0202440F2C0B9C0B0A02171F0F2F4C -:1080E0000000018078783A20747820637073202A29 -:1080F0002A2A2A2A0200018078783A20747820639C -:108100007073202A2A2A2A2A0200018078783A20CD -:10811000747820637073202A2A2A2A2A0200018098 -:1081200078783A20747820637073202A2A2A2A2AC1 -:10813000020001C078783A20726320637073202AAD -:108140002A2A2A2A020001C078783A207263206322 -:108150007073202A2A2A2A2A020001C078783A203D -:10816000726320637073202A2A2A2A2A020001C01F -:1081700078783A20726320637073202A2A2A2A2A88 -:1081800002000180496E7374616C6C204C6F6F70DB -:108190006261636B1F5072657373208020746F205F -:1081A000737461727402000180204361626C652007 -:1081B000746F2052656D6F74651F50726573732004 -:1081C0008020746F20737461727402000180204CEF -:1081D0006F63616C204C6F6F706261636B201F2056 -:1081E0002052756E6E696E67202E2E2E0200018061 -:1081F00052656D6F7465204C6F6F706261636B20A8 -:108200001F202052756E6E696E67202E2E2E020082 -:10821000018020496E74726E6C204C6F6F706261C9 -:10822000636B1F202052756E6E696E67202E2E2E96 -:10823000020001805472616E736D69742050617424 -:108240007465726E1F202052756E6E696E67202EE7 -:108250002E2E020001802020303A2027438000018A -:10826000802020313A202743810001802020323AAB -:10827000202743820001802020333A2027438300B7 -:1082800001802020343A20274384000180202035BB -:108290003A202743850001802020363A2027438654 -:1082A0000001802020373A202743870001802020CA -:1082B000383A202743880001802020393A2027437C -:1082C000890001802031303A2027438A0001802034 -:1082D00031313A2027438B0001802031323A202768 -:1082E000438C0001802031333A2027438D000180E8 -:1082F0002031343A2027438E0001802031353A2046 -:1083000027438F002A2A204D61696E20204D656E1B -:1083100075202A2A004D6F6E69746F72206120509B -:108320006F7274004D6F6E69746F722061205369B3 -:10833000676E616C00457374696D617465204350AC -:108340005300446961676E6F7374696373004C6FA7 -:1083500063616C204C6F6F706261636B0052656D7E -:108360006F7465204C6F6F706261636B00496E744F -:10837000726E6C204C6F6F706261636B005472613F -:108380006E736D6974205061747465726E00426121 -:10839000756420526174650044617461204269749F -:1083A000730053746F702042697473005061726976 -:1083B00074790044617461205061747465726E0058 -:1083C000547820466C6F7720436F6E74726F6C0028 -:1083D000506F7274204E756D6265720035300037D3 -:1083E0003500313130003133342E35003135300035 -:1083F00032303000333030003630300031323030FF -:10840000003138303000323030300032343030001B -:1084100033363030003438303000373230300039C5 -:108420003630300031392C3230300033382C343093 -:10843000300035362C3030300035372C36303000B7 -:1084400036342C3030300037362C38303000313173 -:10845000352C323030003720626974730038206266 -:1084600069747300312073746F7020626974003115 -:108470002E352073746F702062697473003220731C -:10848000746F702062697473006E6F20706172691E -:108490007479006F64642070617269747900657624 -:1084A000656E207061726974790073706163652014 -:1084B000706172697479006D61726B2070617269AC -:1084C000747900436F6C756D6E7300426172626502 -:1084D0007220506F6C650055555555552E2E2E0047 -:1084E0004E6F6E6500586F6E2F586F66660043546E -:1084F00053005072657373208020666F72206D6523 -:108500006E750028636F756E74696E672E2E2E2946 -:108510000000654E64204F6620436F4465000000F4 -:10852000000000000000000000000000000000004B -:10853000000000000000000000000000000000003B -:10854000000000000000000000000000000000002B -:10855000000000000000000000000000000000001B -:10856000000000000000000000000000000000000B -:1085700000000000000000000000000000000000FB -:1085800000000000000000000000000000000000EB -:1085900000000000000000000000000000000000DB -:1085A00000000000000000000000000000000000CB -:1085B00000000000000000000000000000000000BB -:1085C00000000000000000000000000000000000AB -:1085D000000000000000000000000000000000009B -:1085E000000000000000000000000000000000008B -:1085F000000000000000000000000000000000007B -:00000001FF -/* Intelliport II loadware */ -/* -31232 bytes read from ff.lod */ -- cgit v1.2.3-70-g09d2 From 8ad551d150e3bb0902696496a9d2aa094335705a Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Sat, 21 Jul 2012 22:58:52 +1200 Subject: ARM: vt8500: Update vt8500-ehci driver to support device tree. Signed-off-by: Tony Prisk Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/vt8500-ehci.txt | 12 ++++++++++++ drivers/usb/host/ehci-vt8500.c | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/vt8500-ehci.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt new file mode 100644 index 00000000000..5fb8fd6e250 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt @@ -0,0 +1,12 @@ +VIA VT8500 and Wondermedia WM8xxx SoC USB controllers. + +Required properties: + - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci". + - reg: Address range of the ehci registers. size should be 0x200 + - interrupts: Should contain the ehci interrupt. + +usb: ehci@D8007100 { + compatible = "wm,prizm-ehci", "usb-ehci"; + reg = <0xD8007100 0x200>; + interrupts = <1>; +}; diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c index a8916177bed..96722bfebc8 100644 --- a/drivers/usb/host/ehci-vt8500.c +++ b/drivers/usb/host/ehci-vt8500.c @@ -16,6 +16,7 @@ * */ +#include #include static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) @@ -139,6 +140,12 @@ static int vt8500_ehci_drv_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id vt8500_ehci_ids[] = { + { .compatible = "via,vt8500-ehci", }, + { .compatible = "wm,prizm-ehci", }, + {} +}; + static struct platform_driver vt8500_ehci_driver = { .probe = vt8500_ehci_drv_probe, .remove = vt8500_ehci_drv_remove, @@ -146,7 +153,9 @@ static struct platform_driver vt8500_ehci_driver = { .driver = { .name = "vt8500-ehci", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(vt8500_ehci_ids), } }; MODULE_ALIAS("platform:vt8500-ehci"); +MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); -- cgit v1.2.3-70-g09d2 From 100d45970327f78584ff4846deeca14bba511e28 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Sat, 21 Jul 2012 22:58:53 +1200 Subject: ARM: vt8500: Add support for UHCI companion controller Add support for a generic non-pci UHCI companion controller. Existing board files for arch-vt8500 updated to include UHCI support. Signed-off-by: Tony Prisk Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/platform-uhci.txt | 12 ++ arch/arm/mach-vt8500/bv07.c | 1 + arch/arm/mach-vt8500/devices-vt8500.c | 5 + arch/arm/mach-vt8500/devices-wm8505.c | 4 + arch/arm/mach-vt8500/devices.c | 11 ++ arch/arm/mach-vt8500/devices.h | 1 + arch/arm/mach-vt8500/wm8505_7in.c | 1 + drivers/usb/host/Kconfig | 12 +- drivers/usb/host/uhci-hcd.c | 5 + drivers/usb/host/uhci-platform.c | 157 +++++++++++++++++++++ 10 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/platform-uhci.txt create mode 100644 drivers/usb/host/uhci-platform.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt new file mode 100644 index 00000000000..91477d6830e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/platform-uhci.txt @@ -0,0 +1,12 @@ +Generic Platform UHCI controllers. + +Required properties: + - compatible: Should be "platform-uhci". + - reg: Address range of the uhci registers + - interrupts: Should contain the uhci interrupt. + +usb: uhci@D8007301 { + compatible = "platform-uhci", "usb-uhci"; + reg = <0xD8007301 0x200>; + interrupts = <0>; +}; diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c index f9fbeb2d10e..6fd9d609eba 100644 --- a/arch/arm/mach-vt8500/bv07.c +++ b/arch/arm/mach-vt8500/bv07.c @@ -33,6 +33,7 @@ static struct platform_device *devices[] __initdata = { &vt8500_device_uart0, &vt8500_device_lcdc, &vt8500_device_ehci, + &vt8500_device_uhci, &vt8500_device_ge_rops, &vt8500_device_pwm, &vt8500_device_pwmbl, diff --git a/arch/arm/mach-vt8500/devices-vt8500.c b/arch/arm/mach-vt8500/devices-vt8500.c index 19519aeecf3..def7fe393a2 100644 --- a/arch/arm/mach-vt8500/devices-vt8500.c +++ b/arch/arm/mach-vt8500/devices-vt8500.c @@ -48,6 +48,11 @@ void __init vt8500_set_resources(void) tmp[1] = wmt_irq_res(IRQ_EHCI); wmt_res_add(&vt8500_device_ehci, tmp, 2); + /* vt8500 uses a single IRQ for both EHCI and UHCI controllers */ + tmp[0] = wmt_mmio_res(VT8500_UHCI_BASE, SZ_512); + tmp[1] = wmt_irq_res(IRQ_EHCI); + wmt_res_add(&vt8500_device_uhci, tmp, 2); + tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256); wmt_res_add(&vt8500_device_ge_rops, tmp, 1); diff --git a/arch/arm/mach-vt8500/devices-wm8505.c b/arch/arm/mach-vt8500/devices-wm8505.c index db4594e029f..c810454178d 100644 --- a/arch/arm/mach-vt8500/devices-wm8505.c +++ b/arch/arm/mach-vt8500/devices-wm8505.c @@ -55,6 +55,10 @@ void __init wm8505_set_resources(void) tmp[1] = wmt_irq_res(IRQ_EHCI); wmt_res_add(&vt8500_device_ehci, tmp, 2); + tmp[0] = wmt_mmio_res(WM8505_UHCI_BASE, SZ_512); + tmp[1] = wmt_irq_res(IRQ_UHCI); + wmt_res_add(&vt8500_device_uhci, tmp, 2); + tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256); wmt_res_add(&vt8500_device_ge_rops, tmp, 1); diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c index 1fcdc36b358..46ff82dad54 100644 --- a/arch/arm/mach-vt8500/devices.c +++ b/arch/arm/mach-vt8500/devices.c @@ -204,6 +204,17 @@ struct platform_device vt8500_device_ehci = { }, }; +static u64 uhci_dma_mask = DMA_BIT_MASK(32); + +struct platform_device vt8500_device_uhci = { + .name = "platform-uhci", + .id = 0, + .dev = { + .dma_mask = &uhci_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + struct platform_device vt8500_device_ge_rops = { .name = "wmt_ge_rops", .id = -1, diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h index 188d4e17f35..0e6d9f904c7 100644 --- a/arch/arm/mach-vt8500/devices.h +++ b/arch/arm/mach-vt8500/devices.h @@ -81,6 +81,7 @@ extern struct platform_device vt8500_device_uart5; extern struct platform_device vt8500_device_lcdc; extern struct platform_device vt8500_device_wm8505_fb; extern struct platform_device vt8500_device_ehci; +extern struct platform_device vt8500_device_uhci; extern struct platform_device vt8500_device_ge_rops; extern struct platform_device vt8500_device_pwm; extern struct platform_device vt8500_device_pwmbl; diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c index db19886caf7..4804e2a4557 100644 --- a/arch/arm/mach-vt8500/wm8505_7in.c +++ b/arch/arm/mach-vt8500/wm8505_7in.c @@ -32,6 +32,7 @@ static void __iomem *pmc_hiber; static struct platform_device *devices[] __initdata = { &vt8500_device_uart0, &vt8500_device_ehci, + &vt8500_device_uhci, &vt8500_device_wm8505_fb, &vt8500_device_ge_rops, &vt8500_device_pwm, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 075d2eca810..c3f619b1f59 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -450,7 +450,7 @@ config USB_OHCI_LITTLE_ENDIAN config USB_UHCI_HCD tristate "UHCI HCD (most Intel and VIA) support" - depends on USB && (PCI || SPARC_LEON) + depends on USB && (PCI || SPARC_LEON || ARCH_VT8500) ---help--- The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB @@ -468,7 +468,15 @@ config USB_UHCI_HCD config USB_UHCI_SUPPORT_NON_PCI_HC bool depends on USB_UHCI_HCD - default y if SPARC_LEON + default y if (SPARC_LEON || ARCH_VT8500) + +config USB_UHCI_PLATFORM + bool "Generic UHCI Platform Driver support" + depends on USB_UHCI_SUPPORT_NON_PCI_HC + default y if ARCH_VT8500 + ---help--- + Enable support for generic UHCI platform devices that require no + additional configuration. config USB_UHCI_BIG_ENDIAN_MMIO bool diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e4db350602b..4b9e9aba266 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -846,6 +846,11 @@ static const char hcd_name[] = "uhci_hcd"; #define PLATFORM_DRIVER uhci_grlib_driver #endif +#ifdef CONFIG_USB_UHCI_PLATFORM +#include "uhci-platform.c" +#define PLATFORM_DRIVER uhci_platform_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) #error "missing bus glue for uhci-hcd" #endif diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c new file mode 100644 index 00000000000..e4780491df4 --- /dev/null +++ b/drivers/usb/host/uhci-platform.c @@ -0,0 +1,157 @@ +/* + * Generic UHCI HCD (Host Controller Driver) for Platform Devices + * + * Copyright (c) 2011 Tony Prisk + * + * This file is based on uhci-grlib.c + * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu + */ + +#include +#include + +static int uhci_platform_init(struct usb_hcd *hcd) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + uhci->rh_numports = uhci_count_ports(hcd); + + /* Set up pointers to to generic functions */ + uhci->reset_hc = uhci_generic_reset_hc; + uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc; + + /* No special actions need to be taken for the functions below */ + uhci->configure_hc = NULL; + uhci->resume_detect_interrupts_are_broken = NULL; + uhci->global_suspend_mode_is_broken = NULL; + + /* Reset if the controller isn't already safely quiescent. */ + check_and_reset_hc(uhci); + return 0; +} + +static const struct hc_driver uhci_platform_hc_driver = { + .description = hcd_name, + .product_desc = "Generic UHCI Host Controller", + .hcd_priv_size = sizeof(struct uhci_hcd), + + /* Generic hardware linkage */ + .irq = uhci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + /* Basic lifecycle operations */ + .reset = uhci_platform_init, + .start = uhci_start, +#ifdef CONFIG_PM + .pci_suspend = NULL, + .pci_resume = NULL, + .bus_suspend = uhci_rh_suspend, + .bus_resume = uhci_rh_resume, +#endif + .stop = uhci_stop, + + .urb_enqueue = uhci_urb_enqueue, + .urb_dequeue = uhci_urb_dequeue, + + .endpoint_disable = uhci_hcd_endpoint_disable, + .get_frame_number = uhci_hcd_get_frame_number, + + .hub_status_data = uhci_hub_status_data, + .hub_control = uhci_hub_control, +}; + + +static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct uhci_hcd *uhci; + struct resource *res; + int ret; + + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, + pdev->name); + if (!hcd) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_err("%s: request_mem_region failed\n", __func__); + ret = -EBUSY; + goto err_rmr; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_err("%s: ioremap failed\n", __func__); + ret = -ENOMEM; + goto err_irq; + } + uhci = hcd_to_uhci(hcd); + + uhci->regs = hcd->regs; + + ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED | + IRQF_SHARED); + if (ret) + goto err_uhci; + + return 0; + +err_uhci: + iounmap(hcd->regs); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return ret; +} + +static int uhci_hcd_platform_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +/* Make sure the controller is quiescent and that we're not using it + * any more. This is mainly for the benefit of programs which, like kexec, + * expect the hardware to be idle: not doing DMA or generating IRQs. + * + * This routine may be called in a damaged or failing kernel. Hence we + * do not acquire the spinlock before shutting down the controller. + */ +static void uhci_hcd_platform_shutdown(struct platform_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + uhci_hc_died(hcd_to_uhci(hcd)); +} + +static const struct of_device_id platform_uhci_ids[] = { + { .compatible = "platform-uhci", }, + {} +}; + +static struct platform_driver uhci_platform_driver = { + .probe = uhci_hcd_platform_probe, + .remove = uhci_hcd_platform_remove, + .shutdown = uhci_hcd_platform_shutdown, + .driver = { + .name = "platform-uhci", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(platform_uhci_ids), + }, +}; -- cgit v1.2.3-70-g09d2 From df981d03eeff7971ac7e6ff37000bfa702327ef1 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 17 Aug 2012 09:48:17 -0400 Subject: ext4: add max_dir_size_kb mount option Very large directories can cause significant performance problems, or perhaps even invoke the OOM killer, if the process is running in a highly constrained memory environment (whether it is VM's with a small amount of memory or in a small memory cgroup). So it is useful, in cloud server/data center environments, to be able to set a filesystem-wide cap on the maximum size of a directory, to ensure that directories never get larger than a sane size. We do this via a new mount option, max_dir_size_kb. If there is an attempt to grow the directory larger than max_dir_size_kb, the system call will return ENOSPC instead. Google-Bug-Id: 6863013 Signed-off-by: "Theodore Ts'o" --- Documentation/filesystems/ext4.txt | 10 ++++++++++ fs/ext4/ext4.h | 1 + fs/ext4/namei.c | 7 +++++++ fs/ext4/super.c | 7 +++++++ 4 files changed, 25 insertions(+) (limited to 'Documentation') diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 1b7f9acbcbb..104322bf378 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -375,6 +375,16 @@ dioread_nolock locking. If the dioread_nolock option is specified Because of the restrictions this options comprises it is off by default (e.g. dioread_lock). +max_dir_size_kb=n This limits the size of directories so that any + attempt to expand them beyond the specified + limit in kilobytes will cause an ENOSPC error. + This is useful in memory constrained + environments, where a very large directory can + cause severe performance problems or even + provoke the Out Of Memory killer. (For example, + if there is only 512mb memory available, a 176mb + directory may seriously cramp the system's style.) + i_version Enable 64-bit inode version support. This option is off by default. diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index c3411d4ce2d..7c0841ecde6 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1243,6 +1243,7 @@ struct ext4_sb_info { unsigned int s_mb_order2_reqs; unsigned int s_mb_group_prealloc; unsigned int s_max_writeback_mb_bump; + unsigned int s_max_dir_size_kb; /* where last allocation was done - for stream allocation */ unsigned long s_mb_last_group; unsigned long s_mb_last_start; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 2a42cc04466..7450ff01c3c 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -55,6 +55,13 @@ static struct buffer_head *ext4_append(handle_t *handle, { struct buffer_head *bh; + if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb && + ((inode->i_size >> 10) >= + EXT4_SB(inode->i_sb)->s_max_dir_size_kb))) { + *err = -ENOSPC; + return NULL; + } + *block = inode->i_size >> inode->i_sb->s_blocksize_bits; bh = ext4_bread(handle, inode, *block, 1, err); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 59849890403..5a97e590692 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1230,6 +1230,7 @@ enum { Opt_inode_readahead_blks, Opt_journal_ioprio, Opt_dioread_nolock, Opt_dioread_lock, Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, + Opt_max_dir_size_kb, }; static const match_table_t tokens = { @@ -1303,6 +1304,7 @@ static const match_table_t tokens = { {Opt_init_itable, "init_itable=%u"}, {Opt_init_itable, "init_itable"}, {Opt_noinit_itable, "noinit_itable"}, + {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_removed, "check=none"}, /* mount option from ext2/3 */ {Opt_removed, "nocheck"}, /* mount option from ext2/3 */ {Opt_removed, "reservation"}, /* mount option from ext2/3 */ @@ -1483,6 +1485,7 @@ static const struct mount_opts { {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT}, {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, + {Opt_max_dir_size_kb, 0, MOPT_GTE0}, {Opt_err, 0, 0} }; @@ -1598,6 +1601,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, if (!args->from) arg = EXT4_DEF_LI_WAIT_MULT; sbi->s_li_wait_mult = arg; + } else if (token == Opt_max_dir_size_kb) { + sbi->s_max_dir_size_kb = arg; } else if (token == Opt_stripe) { sbi->s_stripe = arg; } else if (m->flags & MOPT_DATAJ) { @@ -1829,6 +1834,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, if (nodefs || (test_opt(sb, INIT_INODE_TABLE) && (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT))) SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult); + if (nodefs || sbi->s_max_dir_size_kb) + SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb); ext4_show_quota_options(seq, sb); return 0; -- cgit v1.2.3-70-g09d2 From 67a5da564f97f31c4054d358e00b34d7ee570da5 Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Fri, 17 Aug 2012 09:54:17 -0400 Subject: ext4: make the zero-out chunk size tunable Currently in ext4 the length of zero-out chunk is set to 7 file system blocks. But if an inode has uninitailized extents from using fallocate to preallocate space, and the workload issues many random writes, this can cause a fragmented extent tree that will unnecessarily grow the extent tree. So create a new sysfs tunable, extent_max_zeroout_kb, which controls the maximum size where blocks will be zeroed out instead of creating a new uninitialized extent. The default of this has been sent to 32kb. CC: Zach Brown CC: Andreas Dilger Signed-off-by: Zheng Liu Signed-off-by: "Theodore Ts'o" --- Documentation/ABI/testing/sysfs-fs-ext4 | 13 +++++++++++++ fs/ext4/ext4.h | 3 +++ fs/ext4/extents.c | 25 +++++++++++++------------ fs/ext4/super.c | 3 +++ 4 files changed, 32 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4 index f22ac0872ae..c631253cf85 100644 --- a/Documentation/ABI/testing/sysfs-fs-ext4 +++ b/Documentation/ABI/testing/sysfs-fs-ext4 @@ -96,3 +96,16 @@ Contact: "Theodore Ts'o" Description: The maximum number of megabytes the writeback code will try to write out before move on to another inode. + +What: /sys/fs/ext4//extent_max_zeroout_kb +Date: August 2012 +Contact: "Theodore Ts'o" +Description: + The maximum number of kilobytes which will be zeroed + out in preference to creating a new uninitialized + extent when manipulating an inode's extent tree. Note + that using a larger value will increase the + variability of time necessary to complete a random + write operation (since a 4k random write might turn + into a much larger write due to the zeroout + operation). diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 7c0841ecde6..0df5ee102b6 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1271,6 +1271,9 @@ struct ext4_sb_info { unsigned long s_sectors_written_start; u64 s_kbytes_written; + /* the size of zero-out chunk */ + unsigned int s_extent_max_zeroout_kb; + unsigned int s_log_groups_per_flex; struct flex_groups *s_flex_groups; diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e8755c21f4b..2f082abf499 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3085,7 +3085,6 @@ out: return err ? err : map->m_len; } -#define EXT4_EXT_ZERO_LEN 7 /* * This function is called by ext4_ext_map_blocks() if someone tries to write * to an uninitialized extent. It may result in splitting the uninitialized @@ -3111,13 +3110,14 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, struct ext4_map_blocks *map, struct ext4_ext_path *path) { + struct ext4_sb_info *sbi; struct ext4_extent_header *eh; struct ext4_map_blocks split_map; struct ext4_extent zero_ex; struct ext4_extent *ex; ext4_lblk_t ee_block, eof_block; unsigned int ee_len, depth; - int allocated; + int allocated, max_zeroout = 0; int err = 0; int split_flag = 0; @@ -3125,6 +3125,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, "block %llu, max_blocks %u\n", inode->i_ino, (unsigned long long)map->m_lblk, map->m_len); + sbi = EXT4_SB(inode->i_sb); eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; if (eof_block < map->m_lblk + map->m_len) @@ -3224,9 +3225,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, */ split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; - /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */ - if (ee_len <= 2*EXT4_EXT_ZERO_LEN && - (EXT4_EXT_MAY_ZEROOUT & split_flag)) { + if (EXT4_EXT_MAY_ZEROOUT & split_flag) + max_zeroout = sbi->s_extent_max_zeroout_kb >> + inode->i_sb->s_blocksize_bits; + + /* If extent is less than s_max_zeroout_kb, zeroout directly */ + if (max_zeroout && (ee_len <= max_zeroout)) { err = ext4_ext_zeroout(inode, ex); if (err) goto out; @@ -3250,9 +3254,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, split_map.m_lblk = map->m_lblk; split_map.m_len = map->m_len; - if (allocated > map->m_len) { - if (allocated <= EXT4_EXT_ZERO_LEN && - (EXT4_EXT_MAY_ZEROOUT & split_flag)) { + if (max_zeroout && (allocated > map->m_len)) { + if (allocated <= max_zeroout) { /* case 3 */ zero_ex.ee_block = cpu_to_le32(map->m_lblk); @@ -3264,9 +3267,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, goto out; split_map.m_lblk = map->m_lblk; split_map.m_len = allocated; - } else if ((map->m_lblk - ee_block + map->m_len < - EXT4_EXT_ZERO_LEN) && - (EXT4_EXT_MAY_ZEROOUT & split_flag)) { + } else if (map->m_lblk - ee_block + map->m_len < max_zeroout) { /* case 2 */ if (map->m_lblk != ee_block) { zero_ex.ee_block = ex->ee_block; @@ -3286,7 +3287,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, } allocated = ext4_split_extent(handle, inode, path, - &split_map, split_flag, 0); + &split_map, split_flag, 0); if (allocated < 0) err = allocated; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 5a97e590692..0423e2e7f61 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2541,6 +2541,7 @@ EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump); +EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error); static struct attribute *ext4_attrs[] = { @@ -2556,6 +2557,7 @@ static struct attribute *ext4_attrs[] = { ATTR_LIST(mb_stream_req), ATTR_LIST(mb_group_prealloc), ATTR_LIST(max_writeback_mb_bump), + ATTR_LIST(extent_max_zeroout_kb), ATTR_LIST(trigger_fs_error), NULL, }; @@ -3756,6 +3758,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sbi->s_stripe = ext4_get_stripe_size(sbi); sbi->s_max_writeback_mb_bump = 128; + sbi->s_extent_max_zeroout_kb = 32; /* * set up enough so that it can read an inode -- cgit v1.2.3-70-g09d2 From 4ad1e5b5d1dde19f09e728ba8b5164968f9dabeb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 3 Aug 2012 17:26:14 +0200 Subject: spi/mxs: Add SSP/SPI device tree documentation Signed-off-by: Marek Vasut Acked-by: Chris Ball Acked-by: Shawn Guo Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mxs-spi.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/mxs-spi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/mxs-spi.txt b/Documentation/devicetree/bindings/spi/mxs-spi.txt new file mode 100644 index 00000000000..c36296f5ad2 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/mxs-spi.txt @@ -0,0 +1,18 @@ +* Freescale MX233/MX28 SSP/SPI + +Required properties: +- compatible: Should be "fsl,-spi", where soc is "imx23" or "imx28" +- reg: Offset and length of the register set for the device +- interrupts: Should contain SSP interrupts (error irq first, dma irq second) +- fsl,ssp-dma-channel: APBX DMA channel for the SSP + +Example: + +ssp0: ssp@80010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-spi"; + reg = <0x80010000 0x2000>; + interrupts = <96 82>; + fsl,ssp-dma-channel = <0>; +}; -- cgit v1.2.3-70-g09d2 From 8a4c6e19cfed5e650045312affed7e6056383278 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 15 Aug 2012 17:43:30 -0400 Subject: nfsd: document kernel interfaces for nfsd configuration These are only needed by nfs-utils. But I needed to remind myself how they worked recently and thought this might be helpful. It's short and incomplete for now as I was only interested in startup, shutdown, and configuration of listening sockets. Signed-off-by: J. Bruce Fields --- .../filesystems/nfs/nfsd-admin-interfaces.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/filesystems/nfs/nfsd-admin-interfaces.txt (limited to 'Documentation') diff --git a/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt b/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt new file mode 100644 index 00000000000..56a96fb08a7 --- /dev/null +++ b/Documentation/filesystems/nfs/nfsd-admin-interfaces.txt @@ -0,0 +1,41 @@ +Administrative interfaces for nfsd +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note that normally these interfaces are used only by the utilities in +nfs-utils. + +nfsd is controlled mainly by pseudofiles under the "nfsd" filesystem, +which is normally mounted at /proc/fs/nfsd/. + +The server is always started by the first write of a nonzero value to +nfsd/threads. + +Before doing that, NFSD can be told which sockets to listen on by +writing to nfsd/portlist; that write may be: + + - an ascii-encoded file descriptor, which should refer to a + bound (and listening, for tcp) socket, or + - "transportname port", where transportname is currently either + "udp", "tcp", or "rdma". + +If nfsd is started without doing any of these, then it will create one +udp and one tcp listener at port 2049 (see nfsd_init_socks). + +On startup, nfsd and lockd grace periods start. + +nfsd is shut down by a write of 0 to nfsd/threads. All locks and state +are thrown away at that point. + +Between startup and shutdown, the number of threads may be adjusted up +or down by additional writes to nfsd/threads or by writes to +nfsd/pool_threads. + +For more detail about files under nfsd/ and what they control, see +fs/nfsd/nfsctl.c; most of them have detailed comments. + +Implementation notes +^^^^^^^^^^^^^^^^^^^^ + +Note that the rpc server requires the caller to serialize addition and +removal of listening sockets, and startup and shutdown of the server. +For nfsd this is done using nfsd_mutex. -- cgit v1.2.3-70-g09d2 From 4d8b81abc47b83a1939e59df2fdb0e98dfe0eedd Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 21 Aug 2012 11:02:51 +0800 Subject: KVM: introduce readonly memslot In current code, if we map a readonly memory space from host to guest and the page is not currently mapped in the host, we will get a fault pfn and async is not allowed, then the vm will crash We introduce readonly memory region to map ROM/ROMD to the guest, read access is happy for readonly memslot, write access on readonly memslot will cause KVM_EXIT_MMIO exit Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- Documentation/virtual/kvm/api.txt | 10 ++-- arch/x86/include/asm/kvm.h | 1 + arch/x86/kvm/mmu.c | 9 ++++ arch/x86/kvm/x86.c | 1 + include/linux/kvm.h | 6 ++- include/linux/kvm_host.h | 7 +-- virt/kvm/kvm_main.c | 96 +++++++++++++++++++++++++++++++-------- 7 files changed, 102 insertions(+), 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index bf33aaa4c59..b91bfd43f00 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -857,7 +857,8 @@ struct kvm_userspace_memory_region { }; /* for kvm_memory_region::flags */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL +#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) +#define KVM_MEM_READONLY (1UL << 1) This ioctl allows the user to create or modify a guest physical memory slot. When changing an existing slot, it may be moved in the guest @@ -873,9 +874,12 @@ It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr be identical. This allows large pages in the guest to be backed by large pages in the host. -The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which +The flags field supports two flag, KVM_MEM_LOG_DIRTY_PAGES, which instructs kvm to keep track of writes to memory within the slot. See -the KVM_GET_DIRTY_LOG ioctl. +the KVM_GET_DIRTY_LOG ioctl. Another flag is KVM_MEM_READONLY when the +KVM_CAP_READONLY_MEM capability, it indicates the guest memory is read-only, +that means, guest is only allowed to read it. Writes will be posted to +userspace as KVM_EXIT_MMIO exits. When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory region are automatically reflected into the guest. For example, an mmap() diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index 246617efd67..521bf252e34 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -25,6 +25,7 @@ #define __KVM_HAVE_DEBUGREGS #define __KVM_HAVE_XSAVE #define __KVM_HAVE_XCRS +#define __KVM_HAVE_READONLY_MEM /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 5548971ae80..8e312a2e141 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2647,6 +2647,15 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct * static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn) { + /* + * Do not cache the mmio info caused by writing the readonly gfn + * into the spte otherwise read access on readonly gfn also can + * caused mmio page fault and treat it as mmio access. + * Return 1 to tell kvm to emulate it. + */ + if (pfn == KVM_PFN_ERR_RO_FAULT) + return 1; + if (pfn == KVM_PFN_ERR_HWPOISON) { kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current); return 0; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 704680d0fa3..42bbf4187d2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2175,6 +2175,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_GET_TSC_KHZ: case KVM_CAP_PCI_2_3: case KVM_CAP_KVMCLOCK_CTRL: + case KVM_CAP_READONLY_MEM: r = 1; break; case KVM_CAP_COALESCED_MMIO: diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 2de335d7f63..d808694673f 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -106,7 +106,8 @@ struct kvm_userspace_memory_region { * other bits are reserved for kvm internal use which are defined in * include/linux/kvm_host.h. */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL +#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) +#define KVM_MEM_READONLY (1UL << 1) /* for KVM_IRQ_LINE */ struct kvm_irq_level { @@ -621,6 +622,9 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_GET_SMMU_INFO 78 #define KVM_CAP_S390_COW 79 #define KVM_CAP_PPC_ALLOC_HTAB 80 +#ifdef __KVM_HAVE_READONLY_MEM +#define KVM_CAP_READONLY_MEM 81 +#endif #ifdef KVM_CAP_IRQ_ROUTING diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index a913ac709a9..5972c9845dd 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -465,6 +465,7 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); +unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn); void kvm_release_page_clean(struct page *page); void kvm_release_page_dirty(struct page *page); void kvm_set_page_dirty(struct page *page); @@ -792,12 +793,6 @@ hva_to_gfn_memslot(unsigned long hva, struct kvm_memory_slot *slot) return slot->base_gfn + gfn_offset; } -static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, - gfn_t gfn) -{ - return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE; -} - static inline gpa_t gfn_to_gpa(gfn_t gfn) { return (gpa_t)gfn << PAGE_SHIFT; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e3e1658c491..3416f8a31f6 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -680,7 +680,13 @@ void update_memslots(struct kvm_memslots *slots, struct kvm_memory_slot *new) static int check_memory_region_flags(struct kvm_userspace_memory_region *mem) { - if (mem->flags & ~KVM_MEM_LOG_DIRTY_PAGES) + u32 valid_flags = KVM_MEM_LOG_DIRTY_PAGES; + +#ifdef KVM_CAP_READONLY_MEM + valid_flags |= KVM_MEM_READONLY; +#endif + + if (mem->flags & ~valid_flags) return -EINVAL; return 0; @@ -973,18 +979,45 @@ out: return size; } -static unsigned long gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, - gfn_t *nr_pages) +static bool memslot_is_readonly(struct kvm_memory_slot *slot) +{ + return slot->flags & KVM_MEM_READONLY; +} + +static unsigned long __gfn_to_hva_memslot(struct kvm_memory_slot *slot, + gfn_t gfn) +{ + return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE; +} + +static unsigned long __gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, + gfn_t *nr_pages, bool write) { if (!slot || slot->flags & KVM_MEMSLOT_INVALID) return KVM_HVA_ERR_BAD; + if (memslot_is_readonly(slot) && write) + return KVM_HVA_ERR_RO_BAD; + if (nr_pages) *nr_pages = slot->npages - (gfn - slot->base_gfn); - return gfn_to_hva_memslot(slot, gfn); + return __gfn_to_hva_memslot(slot, gfn); } +static unsigned long gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, + gfn_t *nr_pages) +{ + return __gfn_to_hva_many(slot, gfn, nr_pages, true); +} + +unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, + gfn_t gfn) +{ + return gfn_to_hva_many(slot, gfn, NULL); +} +EXPORT_SYMBOL_GPL(gfn_to_hva_memslot); + unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) { return gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL); @@ -997,7 +1030,7 @@ EXPORT_SYMBOL_GPL(gfn_to_hva); */ static unsigned long gfn_to_hva_read(struct kvm *kvm, gfn_t gfn) { - return gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL); + return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false); } static int kvm_read_hva(void *data, void __user *hva, int len) @@ -1106,6 +1139,17 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault, return npages; } +static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) +{ + if (unlikely(!(vma->vm_flags & VM_READ))) + return false; + + if (write_fault && (unlikely(!(vma->vm_flags & VM_WRITE)))) + return false; + + return true; +} + /* * Pin guest page in memory and return its pfn. * @addr: host virtual address which maps memory to the guest @@ -1130,8 +1174,6 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, /* we can do it either atomically or asynchronously, not both */ BUG_ON(atomic && async); - BUG_ON(!write_fault && !writable); - if (hva_to_pfn_fast(addr, atomic, async, write_fault, writable, &pfn)) return pfn; @@ -1158,7 +1200,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, vma->vm_pgoff; BUG_ON(!kvm_is_mmio_pfn(pfn)); } else { - if (async && (vma->vm_flags & VM_WRITE)) + if (async && vma_is_valid(vma, write_fault)) *async = true; pfn = KVM_PFN_ERR_FAULT; } @@ -1167,19 +1209,40 @@ exit: return pfn; } +static pfn_t +__gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn, bool atomic, + bool *async, bool write_fault, bool *writable) +{ + unsigned long addr = __gfn_to_hva_many(slot, gfn, NULL, write_fault); + + if (addr == KVM_HVA_ERR_RO_BAD) + return KVM_PFN_ERR_RO_FAULT; + + if (kvm_is_error_hva(addr)) + return KVM_PFN_ERR_BAD; + + /* Do not map writable pfn in the readonly memslot. */ + if (writable && memslot_is_readonly(slot)) { + *writable = false; + writable = NULL; + } + + return hva_to_pfn(addr, atomic, async, write_fault, + writable); +} + static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic, bool *async, bool write_fault, bool *writable) { - unsigned long addr; + struct kvm_memory_slot *slot; if (async) *async = false; - addr = gfn_to_hva(kvm, gfn); - if (kvm_is_error_hva(addr)) - return KVM_PFN_ERR_BAD; + slot = gfn_to_memslot(kvm, gfn); - return hva_to_pfn(addr, atomic, async, write_fault, writable); + return __gfn_to_pfn_memslot(slot, gfn, atomic, async, write_fault, + writable); } pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn) @@ -1210,15 +1273,12 @@ EXPORT_SYMBOL_GPL(gfn_to_pfn_prot); pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn) { - unsigned long addr = gfn_to_hva_memslot(slot, gfn); - return hva_to_pfn(addr, false, NULL, true, NULL); + return __gfn_to_pfn_memslot(slot, gfn, false, NULL, true, NULL); } pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn) { - unsigned long addr = gfn_to_hva_memslot(slot, gfn); - - return hva_to_pfn(addr, true, NULL, true, NULL); + return __gfn_to_pfn_memslot(slot, gfn, true, NULL, true, NULL); } EXPORT_SYMBOL_GPL(gfn_to_pfn_memslot_atomic); -- cgit v1.2.3-70-g09d2 From 26a84b3eaef0f6091fd9771ff15613a35862525a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 22 Aug 2012 14:10:02 +0530 Subject: drivers: bus: add a new driver for omap-ocp2scp Adds a new driver *omap-ocp2scp*. This driver takes the responsibility of creating all the devices that is connected to OCP2SCP. In the case of OMAP4, USB2PHY is connected to ocp2scp. This also includes device tree support for ocp2scp driver and the documentation with device tree binding information is updated. Acked-by: Felipe Balbi Acked-by: Arnd Bergmann Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Arnd Bergmann --- .../devicetree/bindings/bus/omap-ocp2scp.txt | 10 +++ drivers/Kconfig | 2 + drivers/Makefile | 2 + drivers/bus/Kconfig | 15 ++++ drivers/bus/Makefile | 5 ++ drivers/bus/omap-ocp2scp.c | 88 ++++++++++++++++++++++ 6 files changed, 122 insertions(+) create mode 100644 Documentation/devicetree/bindings/bus/omap-ocp2scp.txt create mode 100644 drivers/bus/Kconfig create mode 100644 drivers/bus/Makefile create mode 100644 drivers/bus/omap-ocp2scp.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt b/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt new file mode 100644 index 00000000000..d2fe064a828 --- /dev/null +++ b/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt @@ -0,0 +1,10 @@ +* OMAP OCP2SCP - ocp interface to scp interface + +properties: +- compatible : Should be "ti,omap-ocp2scp" +- #address-cells, #size-cells : Must be present if the device has sub-nodes +- ranges : the child address space are mapped 1:1 onto the parent address space +- ti,hwmods : must be "ocp2scp_usb_phy" + +Sub-nodes: +All the devices connected to ocp2scp are described using sub-node to ocp2scp diff --git a/drivers/Kconfig b/drivers/Kconfig index ece958d3762..324e958d5ac 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -2,6 +2,8 @@ menu "Device Drivers" source "drivers/base/Kconfig" +source "drivers/bus/Kconfig" + source "drivers/connector/Kconfig" source "drivers/mtd/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5b421840c48..f8cdeeb5c48 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -5,6 +5,8 @@ # Rewritten to use lists instead of if-statements. # +obj-y += bus/ + # GPIO must come after pinctrl as gpios may need to mux pins etc obj-y += pinctrl/ obj-y += gpio/ diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig new file mode 100644 index 00000000000..6270415107d --- /dev/null +++ b/drivers/bus/Kconfig @@ -0,0 +1,15 @@ +# +# Bus Devices +# + +menu "Bus devices" + +config OMAP_OCP2SCP + tristate "OMAP OCP2SCP DRIVER" + help + Driver to enable ocp2scp module which transforms ocp interface + protocol to scp protocol. In OMAP4, USB PHY is connected via + OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via + OCP2SCP. + +endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile new file mode 100644 index 00000000000..0ec50bc43d7 --- /dev/null +++ b/drivers/bus/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the bus drivers. +# + +obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c new file mode 100644 index 00000000000..9075ef8baf5 --- /dev/null +++ b/drivers/bus/omap-ocp2scp.c @@ -0,0 +1,88 @@ +/* + * omap-ocp2scp.c - transform ocp interface protocol to scp protocol + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +static int ocp2scp_remove_devices(struct device *dev, void *c) +{ + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + + return 0; +} + +static int __devinit omap_ocp2scp_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *np = pdev->dev.of_node; + + if (np) { + ret = of_platform_populate(np, NULL, NULL, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to add resources for ocp2scp child\n"); + goto err0; + } + } + pm_runtime_enable(&pdev->dev); + + return 0; + +err0: + device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); + + return ret; +} + +static int __devexit omap_ocp2scp_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id omap_ocp2scp_id_table[] = { + { .compatible = "ti,omap-ocp2scp" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_usb2_id_table); +#endif + +static struct platform_driver omap_ocp2scp_driver = { + .probe = omap_ocp2scp_probe, + .remove = __devexit_p(omap_ocp2scp_remove), + .driver = { + .name = "omap-ocp2scp", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_ocp2scp_id_table), + }, +}; + +module_platform_driver(omap_ocp2scp_driver); + +MODULE_ALIAS("platform: omap-ocp2scp"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP OCP2SCP driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 3ce8859e2e72713d3619285cab609d05c3591fc4 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 18 Aug 2012 09:06:27 -0700 Subject: spi: Master driver for NXP SC18IS602/603 This driver adds support for NXP SC18IS602/603 I2C to SPI bus bridge. Signed-off-by: Guenter Roeck Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-sc18is602.txt | 23 ++ Documentation/spi/spi-sc18is602 | 36 ++ drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-sc18is602.c | 364 +++++++++++++++++++++ include/linux/platform_data/sc18is602.h | 19 ++ 6 files changed, 449 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-sc18is602.txt create mode 100644 Documentation/spi/spi-sc18is602 create mode 100644 drivers/spi/spi-sc18is602.c create mode 100644 include/linux/platform_data/sc18is602.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-sc18is602.txt b/Documentation/devicetree/bindings/spi/spi-sc18is602.txt new file mode 100644 index 00000000000..02f9033270a --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sc18is602.txt @@ -0,0 +1,23 @@ +NXP SC18IS602/SCIS603 + +Required properties: + - compatible : Should be one of + "nxp,sc18is602" + "nxp,sc18is602b" + "nxp,sc18is603" + - reg: I2C bus address + +Optional properties: + - clock-frequency : external oscillator clock frequency. If not + specified, the SC18IS602 default frequency (7372000) will be used. + +The clock-frequency property is relevant and needed only if the chip has an +external oscillator (SC18IS603). + +Example: + + sc18is603@28 { + compatible = "nxp,sc18is603"; + reg = <0x28>; + clock-frequency = <14744000>; + } diff --git a/Documentation/spi/spi-sc18is602 b/Documentation/spi/spi-sc18is602 new file mode 100644 index 00000000000..a45702865a3 --- /dev/null +++ b/Documentation/spi/spi-sc18is602 @@ -0,0 +1,36 @@ +Kernel driver spi-sc18is602 +=========================== + +Supported chips: + * NXP SI18IS602/602B/603 + Datasheet: http://www.nxp.com/documents/data_sheet/SC18IS602_602B_603.pdf + +Author: + Guenter Roeck + + +Description +----------- + +This driver provides connects a NXP SC18IS602/603 I2C-bus to SPI bridge to the +kernel's SPI core subsystem. + +The driver does not probe for supported chips, since the SI18IS602/603 does not +support Chip ID registers. You will have to instantiate the devices explicitly. +Please see Documentation/i2c/instantiating-devices for details. + + +Usage Notes +----------- + +This driver requires the I2C adapter driver to support raw I2C messages. I2C +adapter drivers which can only handle the SMBus protocol are not supported. + +The maximum SPI message size supported by SC18IS602/603 is 200 bytes. Attempts +to initiate longer transfers will fail with -EINVAL. EEPROM read operations and +similar large accesses have to be split into multiple chunks of no more than +200 bytes per SPI message (128 bytes of data per message is recommended). This +means that programs such as "cp" or "od", which automatically use large block +sizes to access a device, can not be used directly to read data from EEPROM. +Programs such as dd, where the block size can be specified, should be used +instead. diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 5f84b5563c2..920bb4d22d4 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -325,6 +325,12 @@ config SPI_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. +config SPI_SC18IS602 + tristate "NXP SC18IS602/602B/603 I2C to SPI bridge" + depends on I2C + help + SPI driver for NXP SC18IS602/602B/603 I2C to SPI bridge. + config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on SUPERH && HAVE_CLK diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3920dcf4c74..7559c984db7 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o +obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o obj-$(CONFIG_SPI_SH) += spi-sh.o obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c new file mode 100644 index 00000000000..dd9896423f0 --- /dev/null +++ b/drivers/spi/spi-sc18is602.c @@ -0,0 +1,364 @@ +/* + * NXP SC18IS602/603 SPI driver + * + * Copyright (C) Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum chips { sc18is602, sc18is602b, sc18is603 }; + +#define SC18IS602_BUFSIZ 200 +#define SC18IS602_CLOCK 7372000 + +#define SC18IS602_MODE_CPHA BIT(2) +#define SC18IS602_MODE_CPOL BIT(3) +#define SC18IS602_MODE_LSB_FIRST BIT(5) +#define SC18IS602_MODE_CLOCK_DIV_4 0x0 +#define SC18IS602_MODE_CLOCK_DIV_16 0x1 +#define SC18IS602_MODE_CLOCK_DIV_64 0x2 +#define SC18IS602_MODE_CLOCK_DIV_128 0x3 + +struct sc18is602 { + struct spi_master *master; + struct device *dev; + u8 ctrl; + u32 freq; + u32 speed; + + /* I2C data */ + struct i2c_client *client; + enum chips id; + u8 buffer[SC18IS602_BUFSIZ + 1]; + int tlen; /* Data queued for tx in buffer */ + int rindex; /* Receive data index in buffer */ +}; + +static int sc18is602_wait_ready(struct sc18is602 *hw, int len) +{ + int i, err; + int usecs = 1000000 * len / hw->speed + 1; + u8 dummy[1]; + + for (i = 0; i < 10; i++) { + err = i2c_master_recv(hw->client, dummy, 1); + if (err >= 0) + return 0; + usleep_range(usecs, usecs * 2); + } + return -ETIMEDOUT; +} + +static int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg, + struct spi_transfer *t, bool do_transfer) +{ + unsigned int len = t->len; + int ret; + + if (hw->tlen == 0) { + /* First byte (I2C command) is chip select */ + hw->buffer[0] = 1 << msg->spi->chip_select; + hw->tlen = 1; + hw->rindex = 0; + } + /* + * We can not immediately send data to the chip, since each I2C message + * resembles a full SPI message (from CS active to CS inactive). + * Enqueue messages up to the first read or until do_transfer is true. + */ + if (t->tx_buf) { + memcpy(&hw->buffer[hw->tlen], t->tx_buf, len); + hw->tlen += len; + if (t->rx_buf) + do_transfer = true; + else + hw->rindex = hw->tlen - 1; + } else if (t->rx_buf) { + /* + * For receive-only transfers we still need to perform a dummy + * write to receive data from the SPI chip. + * Read data starts at the end of transmit data (minus 1 to + * account for CS). + */ + hw->rindex = hw->tlen - 1; + memset(&hw->buffer[hw->tlen], 0, len); + hw->tlen += len; + do_transfer = true; + } + + if (do_transfer && hw->tlen > 1) { + ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ); + if (ret < 0) + return ret; + ret = i2c_master_send(hw->client, hw->buffer, hw->tlen); + if (ret < 0) + return ret; + if (ret != hw->tlen) + return -EIO; + + if (t->rx_buf) { + int rlen = hw->rindex + len; + + ret = sc18is602_wait_ready(hw, hw->tlen); + if (ret < 0) + return ret; + ret = i2c_master_recv(hw->client, hw->buffer, rlen); + if (ret < 0) + return ret; + if (ret != rlen) + return -EIO; + memcpy(t->rx_buf, &hw->buffer[hw->rindex], len); + } + hw->tlen = 0; + } + return len; +} + +static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) +{ + u8 ctrl = 0; + int ret; + + if (mode & SPI_CPHA) + ctrl |= SC18IS602_MODE_CPHA; + if (mode & SPI_CPOL) + ctrl |= SC18IS602_MODE_CPOL; + if (mode & SPI_LSB_FIRST) + ctrl |= SC18IS602_MODE_LSB_FIRST; + + /* Find the closest clock speed */ + if (hz >= hw->freq / 4) { + ctrl |= SC18IS602_MODE_CLOCK_DIV_4; + hw->speed = hw->freq / 4; + } else if (hz >= hw->freq / 16) { + ctrl |= SC18IS602_MODE_CLOCK_DIV_16; + hw->speed = hw->freq / 16; + } else if (hz >= hw->freq / 64) { + ctrl |= SC18IS602_MODE_CLOCK_DIV_64; + hw->speed = hw->freq / 64; + } else { + ctrl |= SC18IS602_MODE_CLOCK_DIV_128; + hw->speed = hw->freq / 128; + } + + /* + * Don't do anything if the control value did not change. The initial + * value of 0xff for hw->ctrl ensures that the correct mode will be set + * with the first call to this function. + */ + if (ctrl == hw->ctrl) + return 0; + + ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl); + if (ret < 0) + return ret; + + hw->ctrl = ctrl; + + return 0; +} + +static int sc18is602_check_transfer(struct spi_device *spi, + struct spi_transfer *t, int tlen) +{ + int bpw; + uint32_t hz; + + if (t && t->len + tlen > SC18IS602_BUFSIZ) + return -EINVAL; + + bpw = spi->bits_per_word; + if (t && t->bits_per_word) + bpw = t->bits_per_word; + if (bpw != 8) + return -EINVAL; + + hz = spi->max_speed_hz; + if (t && t->speed_hz) + hz = t->speed_hz; + if (hz == 0) + return -EINVAL; + + return 0; +} + +static int sc18is602_transfer_one(struct spi_master *master, + struct spi_message *m) +{ + struct sc18is602 *hw = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + int status = 0; + + /* SC18IS602 does not support CS2 */ + if (hw->id == sc18is602 && spi->chip_select == 2) { + status = -ENXIO; + goto error; + } + + hw->tlen = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + u32 hz = t->speed_hz ? : spi->max_speed_hz; + bool do_transfer; + + status = sc18is602_check_transfer(spi, t, hw->tlen); + if (status < 0) + break; + + status = sc18is602_setup_transfer(hw, hz, spi->mode); + if (status < 0) + break; + + do_transfer = t->cs_change || list_is_last(&t->transfer_list, + &m->transfers); + + if (t->len) { + status = sc18is602_txrx(hw, m, t, do_transfer); + if (status < 0) + break; + m->actual_length += status; + } + status = 0; + + if (t->delay_usecs) + udelay(t->delay_usecs); + } +error: + m->status = status; + spi_finalize_current_message(master); + + return status; +} + +static int sc18is602_setup(struct spi_device *spi) +{ + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST)) + return -EINVAL; + + return sc18is602_check_transfer(spi, NULL, 0); +} + +static int sc18is602_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *np = dev->of_node; + struct sc18is602_platform_data *pdata = dev_get_platdata(dev); + struct sc18is602 *hw; + struct spi_master *master; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -ENODEV; + + master = spi_alloc_master(dev, sizeof(struct sc18is602)); + if (!master) + return -ENOMEM; + + hw = spi_master_get_devdata(master); + i2c_set_clientdata(client, hw); + + hw->master = master; + hw->client = client; + hw->dev = dev; + hw->ctrl = 0xff; + + hw->id = id->driver_data; + + switch (hw->id) { + case sc18is602: + case sc18is602b: + master->num_chipselect = 4; + hw->freq = SC18IS602_CLOCK; + break; + case sc18is603: + master->num_chipselect = 2; + if (pdata) { + hw->freq = pdata->clock_frequency; + } else { + const __be32 *val; + int len; + + val = of_get_property(np, "clock-frequency", &len); + if (val && len >= sizeof(__be32)) + hw->freq = be32_to_cpup(val); + } + if (!hw->freq) + hw->freq = SC18IS602_CLOCK; + break; + } + master->bus_num = client->adapter->nr; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; + master->setup = sc18is602_setup; + master->transfer_one_message = sc18is602_transfer_one; + master->dev.of_node = np; + + error = spi_register_master(master); + if (error) + goto error_reg; + + return 0; + +error_reg: + spi_master_put(master); + return error; +} + +static int sc18is602_remove(struct i2c_client *client) +{ + struct sc18is602 *hw = i2c_get_clientdata(client); + struct spi_master *master = hw->master; + + spi_unregister_master(master); + + return 0; +} + +static const struct i2c_device_id sc18is602_id[] = { + { "sc18is602", sc18is602 }, + { "sc18is602b", sc18is602b }, + { "sc18is603", sc18is603 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sc18is602_id); + +static struct i2c_driver sc18is602_driver = { + .driver = { + .name = "sc18is602", + }, + .probe = sc18is602_probe, + .remove = sc18is602_remove, + .id_table = sc18is602_id, +}; + +module_i2c_driver(sc18is602_driver); + +MODULE_DESCRIPTION("SC18IC602/603 SPI Master Driver"); +MODULE_AUTHOR("Guenter Roeck"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/sc18is602.h b/include/linux/platform_data/sc18is602.h new file mode 100644 index 00000000000..997b0663415 --- /dev/null +++ b/include/linux/platform_data/sc18is602.h @@ -0,0 +1,19 @@ +/* + * Platform data for NXP SC18IS602/603 + * + * Copyright (C) 2012 Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * For further information, see the Documentation/spi/sc18is602 file. + */ + +/** + * struct sc18is602_platform_data - sc18is602 info + * @clock_frequency SC18IS603 oscillator frequency + */ +struct sc18is602_platform_data { + u32 clock_frequency; +}; -- cgit v1.2.3-70-g09d2 From 6d3952a7dfa80919842bbe01ac7f693d40a1eb84 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 22 Aug 2012 15:49:18 +0200 Subject: spi/pl022: Add devicetree support This patch adds device tree support to the spi-pl022 driver. Based on the initial patch by Alexandre Pereira da Silva Signed-off-by: Roland Stigge Acked-by: Alexandre Pereira da Silva Reviewed-by: Linus Walleij Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi_pl022.txt | 15 ++++ drivers/spi/spi-pl022.c | 79 +++++++++++++++++++--- 2 files changed, 85 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt index 306ec3ff3c0..877f832c30a 100644 --- a/Documentation/devicetree/bindings/spi/spi_pl022.txt +++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt @@ -6,7 +6,22 @@ Required properties: - interrupts : Should contain SPI controller interrupt Optional properties: +- num-cs : total number of chipselects - cs-gpios : should specify GPIOs used for chipselects. The gpios will be referred to as reg = in the SPI child nodes. If unspecified, a single SPI device without a chip select can be used. +SPI slave nodes must be children of the SPI master node and can +contain the following properties. + +- pl022,interface : interface type: + 0: SPI + 1: Texas Instruments Synchronous Serial Frame Format + 2: Microwire (Half Duplex) +- pl022,com-mode : polling, interrupt or dma +- pl022,rx-level-trig : Rx FIFO watermark level +- pl022,tx-level-trig : Tx FIFO watermark level +- pl022,ctrl-len : Microwire interface: Control length +- pl022,wait-state : Microwire interface: Wait state +- pl022,duplex : Microwire interface: Full/Half duplex + diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index cf47802f00c..959f2acff2d 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * This macro is used to define some register default values. @@ -1778,12 +1779,14 @@ static const struct pl022_config_chip pl022_default_chip_info = { static int pl022_setup(struct spi_device *spi) { struct pl022_config_chip const *chip_info; + struct pl022_config_chip chip_info_dt; struct chip_data *chip; struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0}; int status = 0; struct pl022 *pl022 = spi_master_get_devdata(spi->master); unsigned int bits = spi->bits_per_word; u32 tmp; + struct device_node *np = spi->dev.of_node; if (!spi->max_speed_hz) return -EINVAL; @@ -1806,10 +1809,32 @@ static int pl022_setup(struct spi_device *spi) chip_info = spi->controller_data; if (chip_info == NULL) { - chip_info = &pl022_default_chip_info; - /* spi_board_info.controller_data not is supplied */ - dev_dbg(&spi->dev, - "using default controller_data settings\n"); + if (np) { + chip_info_dt = pl022_default_chip_info; + + chip_info_dt.hierarchy = SSP_MASTER; + of_property_read_u32(np, "pl022,interface", + &chip_info_dt.iface); + of_property_read_u32(np, "pl022,com-mode", + &chip_info_dt.com_mode); + of_property_read_u32(np, "pl022,rx-level-trig", + &chip_info_dt.rx_lev_trig); + of_property_read_u32(np, "pl022,tx-level-trig", + &chip_info_dt.tx_lev_trig); + of_property_read_u32(np, "pl022,ctrl-len", + &chip_info_dt.ctrl_len); + of_property_read_u32(np, "pl022,wait-state", + &chip_info_dt.wait_state); + of_property_read_u32(np, "pl022,duplex", + &chip_info_dt.duplex); + + chip_info = &chip_info_dt; + } else { + chip_info = &pl022_default_chip_info; + /* spi_board_info.controller_data not is supplied */ + dev_dbg(&spi->dev, + "using default controller_data settings\n"); + } } else dev_dbg(&spi->dev, "using user supplied controller_data settings\n"); @@ -2006,7 +2031,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) struct pl022_ssp_controller *platform_info = adev->dev.platform_data; struct spi_master *master; struct pl022 *pl022 = NULL; /*Data for this driver */ - int status = 0, i; + struct device_node *np = adev->dev.of_node; + int status = 0, i, num_cs; dev_info(&adev->dev, "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); @@ -2016,9 +2042,19 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_pdata; } + if (platform_info->num_chipselect) { + num_cs = platform_info->num_chipselect; + } else if (IS_ENABLED(CONFIG_OF)) { + of_property_read_u32(np, "num-cs", &num_cs); + } else { + dev_err(&adev->dev, "probe: no chip select defined\n"); + status = -ENODEV; + goto err_no_pdata; + } + /* Allocate master with space for data */ master = spi_alloc_master(dev, sizeof(struct pl022) + sizeof(int) * - platform_info->num_chipselect); + num_cs); if (master == NULL) { dev_err(&adev->dev, "probe - cannot alloc SPI master\n"); status = -ENOMEM; @@ -2038,17 +2074,41 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) * on this board */ master->bus_num = platform_info->bus_id; - master->num_chipselect = platform_info->num_chipselect; + master->num_chipselect = num_cs; master->cleanup = pl022_cleanup; master->setup = pl022_setup; master->prepare_transfer_hardware = pl022_prepare_transfer_hardware; master->transfer_one_message = pl022_transfer_one_message; master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; master->rt = platform_info->rt; + master->dev.of_node = dev->of_node; - if (platform_info->num_chipselect && platform_info->chipselects) - for (i = 0; i < platform_info->num_chipselect; i++) + if (platform_info->num_chipselect && platform_info->chipselects) { + for (i = 0; i < num_cs; i++) pl022->chipselects[i] = platform_info->chipselects[i]; + } else if (IS_ENABLED(CONFIG_OF)) { + for (i = 0; i < num_cs; i++) { + int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); + + if (cs_gpio == -EPROBE_DEFER) { + status = -EPROBE_DEFER; + goto err_no_gpio; + } + + pl022->chipselects[i] = cs_gpio; + + if (gpio_is_valid(cs_gpio)) { + if (gpio_request(cs_gpio, "ssp-pl022")) + dev_err(&adev->dev, + "could not request %d gpio\n", + cs_gpio); + else if (gpio_direction_output(cs_gpio, 1)) + dev_err(&adev->dev, + "could set gpio %d as output\n", + cs_gpio); + } + } + } /* * Supports mode 0-3, loopback, and active low CS. Transfers are @@ -2158,6 +2218,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) err_no_ioremap: amba_release_regions(adev); err_no_ioregion: + err_no_gpio: spi_master_put(master); err_no_master: err_no_pdata: -- cgit v1.2.3-70-g09d2 From 41962f90c605983fb04c23bab9c060c9f49ee4c3 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 22 Aug 2012 15:49:19 +0200 Subject: spi/dt: DT bindings documentation: "num-cs" property for SPI controllers Several SPI controller drivers have defined differently named properties for the number of chip selects. Now adding "num-cs" as a reference name for new bindings. Signed-off-by: Roland Stigge Reviewed-by: Linus Walleij Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-bus.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt index e782add2e45..d2c33d0f533 100644 --- a/Documentation/devicetree/bindings/spi/spi-bus.txt +++ b/Documentation/devicetree/bindings/spi/spi-bus.txt @@ -21,6 +21,9 @@ assumption that board specific platform code will be used to manage chip selects. Individual drivers can define additional properties to support describing the chip select layout. +Optional property: +- num-cs : total number of chipselects + SPI slave nodes must be children of the SPI master node and can contain the following properties. - reg - (required) chip select address of device. -- cgit v1.2.3-70-g09d2 From 11dd586421b3091007e6f084a9211f3baa66f9fc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 Aug 2012 16:41:08 +0300 Subject: ASoC: omap-mcbsp: Add device tree bindings Device tree support for McBSP modules on OMAP2+ SoC. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/omap-mcbsp.txt | 45 +++++++++++++++ sound/soc/omap/omap-mcbsp.c | 66 +++++++++++++++++++++- 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/omap-mcbsp.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/omap-mcbsp.txt b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt new file mode 100644 index 00000000000..447cb131e90 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt @@ -0,0 +1,45 @@ +* Texas Instruments OMAP2+ McBSP module + +Required properties: +- compatible: "ti,omap2420-mcbsp" for McBSP on OMAP2420 + "ti,omap2430-mcbsp" for McBSP on OMAP2430 + "ti,omap3-mcbsp" for McBSP on OMAP3 + "ti,omap4-mcbsp" for McBSP on OMAP4 and newer SoC +- reg: Register location and size, for OMAP4+ as an array: + , + ; +- interrupts: Interrupt numbers for the McBSP port, as an array in case the + McBSP IP have more interrupt lines: + , + , + ; +- interrupt-parent: The parent interrupt controller +- ti,buffer-size: Size of the FIFO on the port (OMAP2430 and newer SoC) +- ti,hwmods: Name of the hwmod associated to the McBSP port + +Sidetone support for OMAP3 McBSP2 and 3 ports: +- sidetone { }: Within this section the following parameters are required: +- reg: Register location and size for the ST block +- interrupts: The interrupt number for the ST block +- interrupt-parent: The parent interrupt controller for the ST block + +Example: + +mcbsp2: mcbsp@49022000 { + compatible = "ti,omap3-mcbsp"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x49022000 0xff>; + interrupts = <0 17 0x4>, /* OCP compliant interrup */ + <0 62 0x4>, /* TX interrup */ + <0 63 0x4>; /* RX interrup */ + interrupt-parent = <&intc>; + ti,buffer-size = <1280>; + ti,hwmods = "mcbsp2"; + + sidetone { + reg = <0x49028000 0xff>; + interrupts = <0 4 0x4>; + interrupt-parent = <&intc>; + }; +}; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index b9770eea28a..2e1750e2ab3 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -737,13 +739,74 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); +static struct omap_mcbsp_platform_data omap2420_pdata = { + .reg_step = 4, + .reg_size = 2, +}; + +static struct omap_mcbsp_platform_data omap2430_pdata = { + .reg_step = 4, + .reg_size = 4, + .has_ccr = true, +}; + +static struct omap_mcbsp_platform_data omap3_pdata = { + .reg_step = 4, + .reg_size = 4, + .has_ccr = true, + .has_wakeup = true, +}; + +static struct omap_mcbsp_platform_data omap4_pdata = { + .reg_step = 4, + .reg_size = 4, + .has_ccr = true, + .has_wakeup = true, +}; + +static const struct of_device_id omap_mcbsp_of_match[] = { + { + .compatible = "ti,omap2420-mcbsp", + .data = &omap2420_pdata, + }, + { + .compatible = "ti,omap2430-mcbsp", + .data = &omap2430_pdata, + }, + { + .compatible = "ti,omap3-mcbsp", + .data = &omap3_pdata, + }, + { + .compatible = "ti,omap4-mcbsp", + .data = &omap4_pdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match); + static __devinit int asoc_mcbsp_probe(struct platform_device *pdev) { struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev); struct omap_mcbsp *mcbsp; + const struct of_device_id *match; int ret; - if (!pdata) { + match = of_match_device(omap_mcbsp_of_match, &pdev->dev); + if (match) { + struct device_node *node = pdev->dev.of_node; + int buffer_size; + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct omap_mcbsp_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + memcpy(pdata, match->data, sizeof(*pdata)); + if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size)) + pdata->buffer_size = buffer_size; + } else if (!pdata) { dev_err(&pdev->dev, "missing platform data.\n"); return -EINVAL; } @@ -785,6 +848,7 @@ static struct platform_driver asoc_mcbsp_driver = { .driver = { .name = "omap-mcbsp", .owner = THIS_MODULE, + .of_match_table = omap_mcbsp_of_match, }, .probe = asoc_mcbsp_probe, -- cgit v1.2.3-70-g09d2 From b8101048f0f3cd281ed4c4901e38ae2bcfb32030 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 21 Aug 2012 17:33:56 +0300 Subject: ASoC: omap-mcbsp: Device tree binding documentation update To reflect the final devicetree node structure of McBSPs. The initial OMAP McBSP DT structure was not able to describe the IP (and it's versions) correctly. The main issue was the sidetone block of McBSP2/3 on OMAP3. With this change in the DT description the OS can get the needed information about the IP. The sidetone is still not supported when the Linux kernel is booted with DT since we still depend on hwmod to fill the resources. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/omap-mcbsp.txt | 28 ++++++++-------------- 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/omap-mcbsp.txt b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt index 447cb131e90..17cce449045 100644 --- a/Documentation/devicetree/bindings/sound/omap-mcbsp.txt +++ b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt @@ -8,38 +8,30 @@ Required properties: - reg: Register location and size, for OMAP4+ as an array: , ; +- reg-names: Array of strings associated with the address space - interrupts: Interrupt numbers for the McBSP port, as an array in case the McBSP IP have more interrupt lines: , , ; +- interrupt-names: Array of strings associated with the interrupt numbers - interrupt-parent: The parent interrupt controller - ti,buffer-size: Size of the FIFO on the port (OMAP2430 and newer SoC) - ti,hwmods: Name of the hwmod associated to the McBSP port -Sidetone support for OMAP3 McBSP2 and 3 ports: -- sidetone { }: Within this section the following parameters are required: -- reg: Register location and size for the ST block -- interrupts: The interrupt number for the ST block -- interrupt-parent: The parent interrupt controller for the ST block - Example: mcbsp2: mcbsp@49022000 { compatible = "ti,omap3-mcbsp"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x49022000 0xff>; - interrupts = <0 17 0x4>, /* OCP compliant interrup */ - <0 62 0x4>, /* TX interrup */ - <0 63 0x4>; /* RX interrup */ + reg = <0x49022000 0xff>, + <0x49028000 0xff>; + reg-names = "mpu", "sidetone"; + interrupts = <0 17 0x4>, /* OCP compliant interrupt */ + <0 62 0x4>, /* TX interrupt */ + <0 63 0x4>, /* RX interrupt */ + <0 4 0x4>; /* Sidetone */ + interrupt-names = "common", "tx", "rx", "sidetone"; interrupt-parent = <&intc>; ti,buffer-size = <1280>; ti,hwmods = "mcbsp2"; - - sidetone { - reg = <0x49028000 0xff>; - interrupts = <0 4 0x4>; - interrupt-parent = <&intc>; - }; }; -- cgit v1.2.3-70-g09d2 From 1f862f0f96abdf8b030bda84d6b66d676f31785f Mon Sep 17 00:00:00 2001 From: Xiaoyan Zhang Date: Wed, 22 Aug 2012 18:47:21 +0800 Subject: Documentation: sysfs for Physical Presence Interface Signed-off-by: Xiaoyan Zhang Signed-off-by: Kent Yoder --- Documentation/ABI/testing/sysfs-driver-ppi | 70 ++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-ppi (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-ppi b/Documentation/ABI/testing/sysfs-driver-ppi new file mode 100644 index 00000000000..97a003ee058 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-ppi @@ -0,0 +1,70 @@ +What: /sys/devices/pnp0//ppi/ +Date: August 2012 +Kernel Version: 3.6 +Contact: xiaoyan.zhang@intel.com +Description: + This folder includes the attributes related with PPI (Physical + Presence Interface). Only if TPM is supported by BIOS, this + folder makes sence. The folder path can be got by command + 'find /sys/ -name 'pcrs''. For the detail information of PPI, + please refer to the PPI specification from + http://www.trustedcomputinggroup.org/ + +What: /sys/devices/pnp0//ppi/version +Date: August 2012 +Contact: xiaoyan.zhang@intel.com +Description: + This attribute shows the version of the PPI supported by the + platform. + This file is readonly. + +What: /sys/devices/pnp0//ppi/request +Date: August 2012 +Contact: xiaoyan.zhang@intel.com +Description: + This attribute shows the request for an operation to be + executed in the pre-OS environment. It is the only input from + the OS to the pre-OS environment. The request should be an + integer value range from 1 to 160, and 0 means no request. + This file can be read and written. + +What: /sys/devices/pnp0/00:/ppi/response +Date: August 2012 +Contact: xiaoyan.zhang@intel.com +Description: + This attribute shows the response to the most recent operation + request it acted upon. The format is " + : ". + This file is readonly. + +What: /sys/devices/pnp0//ppi/transition_action +Date: August 2012 +Contact: xiaoyan.zhang@intel.com +Description: + This attribute shows the platform-specific action that should + take place in order to transition to the BIOS for execution of + a requested operation. The format is ": ". + This file is readonly. + +What: /sys/devices/pnp0//ppi/tcg_operations +Date: August 2012 +Contact: xiaoyan.zhang@intel.com +Description: + This attribute shows whether it is allowed to request an + operation to be executed in the pre-OS environment by the BIOS + for the requests defined by TCG, i.e. requests from 1 to 22. + The format is " : ". + This attribute is only supported by PPI version 1.2+. + This file is readonly. + +What: /sys/devices/pnp0//ppi/vs_operations +Date: August 2012 +Contact: xiaoyan.zhang@intel.com +Description: + This attribute shows whether it is allowed to request an + operation to be executed in the pre-OS environment by the BIOS + for the verdor specific requests, i.e. requests from 128 to + 255. The format is same with tcg_operations. This attribute + is also only supported by PPI version 1.2+. + This file is readonly. -- cgit v1.2.3-70-g09d2 From 6b52c00f2b4931c12117dc32a7cf6d5ee59f14ea Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 22 Aug 2012 12:25:07 -0700 Subject: spi: Add SPI master controller for OCTEON SOCs. Add the driver, link it into the kbuild system and provide device tree binding documentation. Signed-off-by: David Daney Acked-by: Grant Likely Patchwork: http://patchwork.linux-mips.org/patch/4292/ Signed-off-by: John Crispin --- .../devicetree/bindings/spi/spi-octeon.txt | 33 ++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/spi-octeon.c | 362 +++++++++++++++++++++ 4 files changed, 403 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-octeon.txt create mode 100644 drivers/spi/spi-octeon.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-octeon.txt b/Documentation/devicetree/bindings/spi/spi-octeon.txt new file mode 100644 index 00000000000..431add19234 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-octeon.txt @@ -0,0 +1,33 @@ +Cavium, Inc. OCTEON SOC SPI master controller. + +Required properties: +- compatible : "cavium,octeon-3010-spi" +- reg : The register base for the controller. +- interrupts : One interrupt, used by the controller. +- #address-cells : <1>, as required by generic SPI binding. +- #size-cells : <0>, also as required by generic SPI binding. + +Child nodes as per the generic SPI binding. + +Example: + + spi@1070000001000 { + compatible = "cavium,octeon-3010-spi"; + reg = <0x10700 0x00001000 0x0 0x100>; + interrupts = <0 58>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + compatible = "st,m95256", "atmel,at25"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; + }; + diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 5f84b5563c2..d654f88f4cf 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -237,6 +237,13 @@ config SPI_OC_TINY help This is the driver for OpenCores tiny SPI master controller. +config SPI_OCTEON + tristate "Cavium OCTEON SPI controller" + depends on CPU_CAVIUM_OCTEON + help + SPI host driver for the hardware found on some Cavium OCTEON + SOCs. + config SPI_OMAP_UWIRE tristate "OMAP1 MicroWire" depends on ARCH_OMAP1 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3920dcf4c74..93d87bcdf3f 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o +obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c new file mode 100644 index 00000000000..ea8fb2efb0f --- /dev/null +++ b/drivers/spi/spi-octeon.c @@ -0,0 +1,362 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011, 2012 Cavium, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define OCTEON_SPI_CFG 0 +#define OCTEON_SPI_STS 0x08 +#define OCTEON_SPI_TX 0x10 +#define OCTEON_SPI_DAT0 0x80 + +#define OCTEON_SPI_MAX_BYTES 9 + +#define OCTEON_SPI_MAX_CLOCK_HZ 16000000 + +struct octeon_spi { + struct spi_master *my_master; + u64 register_base; + u64 last_cfg; + u64 cs_enax; +}; + +struct octeon_spi_setup { + u32 max_speed_hz; + u8 chip_select; + u8 mode; + u8 bits_per_word; +}; + +static void octeon_spi_wait_ready(struct octeon_spi *p) +{ + union cvmx_mpi_sts mpi_sts; + unsigned int loops = 0; + + do { + if (loops++) + __delay(500); + mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS); + } while (mpi_sts.s.busy); +} + +static int octeon_spi_do_transfer(struct octeon_spi *p, + struct spi_message *msg, + struct spi_transfer *xfer, + bool last_xfer) +{ + union cvmx_mpi_cfg mpi_cfg; + union cvmx_mpi_tx mpi_tx; + unsigned int clkdiv; + unsigned int speed_hz; + int mode; + bool cpha, cpol; + int bits_per_word; + const u8 *tx_buf; + u8 *rx_buf; + int len; + int i; + + struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi); + + speed_hz = msg_setup->max_speed_hz; + mode = msg_setup->mode; + cpha = mode & SPI_CPHA; + cpol = mode & SPI_CPOL; + bits_per_word = msg_setup->bits_per_word; + + if (xfer->speed_hz) + speed_hz = xfer->speed_hz; + if (xfer->bits_per_word) + bits_per_word = xfer->bits_per_word; + + if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) + speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; + + clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); + + mpi_cfg.u64 = 0; + + mpi_cfg.s.clkdiv = clkdiv; + mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0; + mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0; + mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0; + mpi_cfg.s.idlelo = cpha != cpol; + mpi_cfg.s.cslate = cpha ? 1 : 0; + mpi_cfg.s.enable = 1; + + if (msg_setup->chip_select < 4) + p->cs_enax |= 1ull << (12 + msg_setup->chip_select); + mpi_cfg.u64 |= p->cs_enax; + + if (mpi_cfg.u64 != p->last_cfg) { + p->last_cfg = mpi_cfg.u64; + cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64); + } + tx_buf = xfer->tx_buf; + rx_buf = xfer->rx_buf; + len = xfer->len; + while (len > OCTEON_SPI_MAX_BYTES) { + for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { + u8 d; + if (tx_buf) + d = *tx_buf++; + else + d = 0; + cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); + } + mpi_tx.u64 = 0; + mpi_tx.s.csid = msg_setup->chip_select; + mpi_tx.s.leavecs = 1; + mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; + mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; + cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); + + octeon_spi_wait_ready(p); + if (rx_buf) + for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { + u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); + *rx_buf++ = (u8)v; + } + len -= OCTEON_SPI_MAX_BYTES; + } + + for (i = 0; i < len; i++) { + u8 d; + if (tx_buf) + d = *tx_buf++; + else + d = 0; + cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); + } + + mpi_tx.u64 = 0; + mpi_tx.s.csid = msg_setup->chip_select; + if (last_xfer) + mpi_tx.s.leavecs = xfer->cs_change; + else + mpi_tx.s.leavecs = !xfer->cs_change; + mpi_tx.s.txnum = tx_buf ? len : 0; + mpi_tx.s.totnum = len; + cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); + + octeon_spi_wait_ready(p); + if (rx_buf) + for (i = 0; i < len; i++) { + u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); + *rx_buf++ = (u8)v; + } + + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + + return xfer->len; +} + +static int octeon_spi_validate_bpw(struct spi_device *spi, u32 speed) +{ + switch (speed) { + case 8: + break; + default: + dev_err(&spi->dev, "Error: %d bits per word not supported\n", + speed); + return -EINVAL; + } + return 0; +} + +static int octeon_spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) +{ + struct octeon_spi *p = spi_master_get_devdata(master); + unsigned int total_len = 0; + int status = 0; + struct spi_transfer *xfer; + + /* + * We better have set the configuration via a call to .setup + * before we get here. + */ + if (spi_get_ctldata(msg->spi) == NULL) { + status = -EINVAL; + goto err; + } + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->bits_per_word) { + status = octeon_spi_validate_bpw(msg->spi, + xfer->bits_per_word); + if (status) + goto err; + } + } + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + bool last_xfer = &xfer->transfer_list == msg->transfers.prev; + int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); + if (r < 0) { + status = r; + goto err; + } + total_len += r; + } +err: + msg->status = status; + msg->actual_length = total_len; + spi_finalize_current_message(master); + return status; +} + +static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) +{ + struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL); + if (!setup) + return NULL; + + setup->max_speed_hz = spi->max_speed_hz; + setup->chip_select = spi->chip_select; + setup->mode = spi->mode; + setup->bits_per_word = spi->bits_per_word; + return setup; +} + +static int octeon_spi_setup(struct spi_device *spi) +{ + int r; + struct octeon_spi_setup *new_setup; + struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); + + r = octeon_spi_validate_bpw(spi, spi->bits_per_word); + if (r) + return r; + + new_setup = octeon_spi_new_setup(spi); + if (!new_setup) + return -ENOMEM; + + spi_set_ctldata(spi, new_setup); + kfree(old_setup); + + return 0; +} + +static void octeon_spi_cleanup(struct spi_device *spi) +{ + struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); + spi_set_ctldata(spi, NULL); + kfree(old_setup); +} + +static int octeon_spi_nop_transfer_hardware(struct spi_master *master) +{ + return 0; +} + +static int __devinit octeon_spi_probe(struct platform_device *pdev) +{ + + struct resource *res_mem; + struct spi_master *master; + struct octeon_spi *p; + int err = -ENOENT; + + master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi)); + if (!master) + return -ENOMEM; + p = spi_master_get_devdata(master); + platform_set_drvdata(pdev, p); + p->my_master = master; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (res_mem == NULL) { + dev_err(&pdev->dev, "found no memory resource\n"); + err = -ENXIO; + goto fail; + } + if (!devm_request_mem_region(&pdev->dev, res_mem->start, + resource_size(res_mem), res_mem->name)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + goto fail; + } + p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, + resource_size(res_mem)); + + /* Dynamic bus numbering */ + master->bus_num = -1; + master->num_chipselect = 4; + master->mode_bits = SPI_CPHA | + SPI_CPOL | + SPI_CS_HIGH | + SPI_LSB_FIRST | + SPI_3WIRE; + + master->setup = octeon_spi_setup; + master->cleanup = octeon_spi_cleanup; + master->prepare_transfer_hardware = octeon_spi_nop_transfer_hardware; + master->transfer_one_message = octeon_spi_transfer_one_message; + master->unprepare_transfer_hardware = octeon_spi_nop_transfer_hardware; + + master->dev.of_node = pdev->dev.of_node; + err = spi_register_master(master); + if (err) { + dev_err(&pdev->dev, "register master failed: %d\n", err); + goto fail; + } + + dev_info(&pdev->dev, "OCTEON SPI bus driver\n"); + + return 0; +fail: + spi_master_put(master); + return err; +} + +static int __devexit octeon_spi_remove(struct platform_device *pdev) +{ + struct octeon_spi *p = platform_get_drvdata(pdev); + u64 register_base = p->register_base; + + spi_unregister_master(p->my_master); + + /* Clear the CSENA* and put everything in a known state. */ + cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0); + + return 0; +} + +static struct of_device_id octeon_spi_match[] = { + { .compatible = "cavium,octeon-3010-spi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_spi_match); + +static struct platform_driver octeon_spi_driver = { + .driver = { + .name = "spi-octeon", + .owner = THIS_MODULE, + .of_match_table = octeon_spi_match, + }, + .probe = octeon_spi_probe, + .remove = __devexit_p(octeon_spi_remove), +}; + +module_platform_driver(octeon_spi_driver); + +MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver"); +MODULE_AUTHOR("David Daney"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From b1b56872be3b36af19313bf0953b1361c36b4a98 Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Thu, 23 Aug 2012 06:50:21 +0530 Subject: power_supply: Add new power supply AUTHENTIC property It is possible that users can use non-standard chargers or use invalid batteries especially with mobile devices. This patch adds a new power supply property called 'AUTHENTIC' to indicate this to the user(user space). Signed-off-by: Ramakrishna Pallala Signed-off-by: Anton Vorontsov --- Documentation/power/power_supply_class.txt | 3 +++ drivers/power/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 3 files changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt index 2f0ddc15b5a..48badec1cec 100644 --- a/Documentation/power/power_supply_class.txt +++ b/Documentation/power/power_supply_class.txt @@ -81,6 +81,9 @@ This defines trickle and fast charges. For batteries that are already charged or discharging, 'n/a' can be displayed (or 'unknown', if the status is not known). +AUTHENTIC - indicates the power supply (battery or charger) connected +to the platform is authentic(1) or non authentic(0). + HEALTH - represents health of the battery, values corresponds to POWER_SUPPLY_HEALTH_*, defined in battery.h. diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 1d96614a17a..be34a6d4664 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -138,6 +138,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(health), POWER_SUPPLY_ATTR(present), POWER_SUPPLY_ATTR(online), + POWER_SUPPLY_ATTR(authentic), POWER_SUPPLY_ATTR(technology), POWER_SUPPLY_ATTR(cycle_count), POWER_SUPPLY_ATTR(voltage_max), diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 0bafbb15f29..204d43dc6dd 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -88,6 +88,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_AUTHENTIC, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_VOLTAGE_MAX, -- cgit v1.2.3-70-g09d2 From 2815b786c3bb86fff97f1f6e2f0874903ff2339b Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Mon, 30 Jul 2012 12:49:21 +0530 Subject: power_supply: Add new power supply properties CHARGE_CURRENT/VOLTAGE_MAX There are different types of chargers avalibale like AC, Solar, USB, etc.. Even in USB we have different types SDP/DCP/CDP/ACA and all these chargers have different o/p ratings. For example SDP supports only 500mA of charge current whereas AC charger can support upto 8A or more. Similarly batteries also come with charge current and voltage ratings and these ratings vary depending on its capacity and the technology used. This patch adds two new power supply properties CONSTANT_CHARGE_CURRENT_MAX and CONSTANT_CHARGE_CURRENT_MAX. Signed-off-by: Ramakrishna Pallala Signed-off-by: Anton Vorontsov --- Documentation/power/power_supply_class.txt | 4 ++++ drivers/power/power_supply_sysfs.c | 2 ++ include/linux/power_supply.h | 4 ++++ 3 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt index 48badec1cec..9c647bd7c5a 100644 --- a/Documentation/power/power_supply_class.txt +++ b/Documentation/power/power_supply_class.txt @@ -116,8 +116,12 @@ be negative; there is no empty or full value. It is only useful for relative, time-based measurements. CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger. +CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the +power supply object. CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger. +CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the +power supply object. ENERGY_FULL, ENERGY_EMPTY - same as above but for energy. diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index be34a6d4664..395c2cfa16c 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -161,7 +161,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(charge_avg), POWER_SUPPLY_ATTR(charge_counter), POWER_SUPPLY_ATTR(constant_charge_current), + POWER_SUPPLY_ATTR(constant_charge_current_max), POWER_SUPPLY_ATTR(constant_charge_voltage), + POWER_SUPPLY_ATTR(constant_charge_voltage_max), POWER_SUPPLY_ATTR(energy_full_design), POWER_SUPPLY_ATTR(energy_empty_design), POWER_SUPPLY_ATTR(energy_full), diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 204d43dc6dd..e5ef45834c3 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -111,7 +111,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_CHARGE_AVG, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, POWER_SUPPLY_PROP_ENERGY_FULL, @@ -249,6 +251,7 @@ static inline bool power_supply_is_amp_property(enum power_supply_property psp) case POWER_SUPPLY_PROP_CHARGE_AVG: case POWER_SUPPLY_PROP_CHARGE_COUNTER: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: case POWER_SUPPLY_PROP_CURRENT_MAX: case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_AVG: @@ -277,6 +280,7 @@ static inline bool power_supply_is_watt_property(enum power_supply_property psp) case POWER_SUPPLY_PROP_VOLTAGE_AVG: case POWER_SUPPLY_PROP_VOLTAGE_OCV: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: case POWER_SUPPLY_PROP_POWER_NOW: return 1; default: -- cgit v1.2.3-70-g09d2 From 6b923cb7188d46905f43fa84210c4c3e5f9cd8fb Mon Sep 17 00:00:00 2001 From: John Eaglesham Date: Tue, 21 Aug 2012 20:43:35 +0000 Subject: bonding: support for IPv6 transmit hashing Currently the "bonding" driver does not support load balancing outgoing traffic in LACP mode for IPv6 traffic. IPv4 (and TCP or UDP over IPv4) are currently supported; this patch adds transmit hashing for IPv6 (and TCP or UDP over IPv6), bringing IPv6 up to par with IPv4 support in the bonding driver. In addition, bounds checking has been added to all transmit hashing functions. The algorithm chosen (xor'ing the bottom three quads of the source and destination addresses together, then xor'ing each byte of that result into the bottom byte, finally xor'ing with the last bytes of the MAC addresses) was selected after testing almost 400,000 unique IPv6 addresses harvested from server logs. This algorithm had the most even distribution for both big- and little-endian architectures while still using few instructions. Its behavior also attempts to closely match that of the IPv4 algorithm. The IPv6 flow label was intentionally not included in the hash as it appears to be unset in the vast majority of IPv6 traffic sampled, and the current algorithm not using the flow label already offers a very even distribution. Fragmented IPv6 packets are handled the same way as fragmented IPv4 packets, ie, they are not balanced based on layer 4 information. Additionally, IPv6 packets with intermediate headers are not balanced based on layer 4 information. In practice these intermediate headers are not common and this should not cause any problems, and the alternative (a packet-parsing loop and look-up table) seemed slow and complicated for little gain. Tested-by: John Eaglesham Signed-off-by: John Eaglesham Signed-off-by: David S. Miller --- Documentation/networking/bonding.txt | 30 ++++++++++-- drivers/net/bonding/bond_main.c | 89 +++++++++++++++++++++++++----------- 2 files changed, 88 insertions(+), 31 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 6b1c7110534..10a015c384b 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -752,12 +752,22 @@ xmit_hash_policy protocol information to generate the hash. Uses XOR of hardware MAC addresses and IP addresses to - generate the hash. The formula is + generate the hash. The IPv4 formula is (((source IP XOR dest IP) AND 0xffff) XOR ( source MAC XOR destination MAC )) modulo slave count + The IPv6 formula is + + hash = (source ip quad 2 XOR dest IP quad 2) XOR + (source ip quad 3 XOR dest IP quad 3) XOR + (source ip quad 4 XOR dest IP quad 4) + + (((hash >> 24) XOR (hash >> 16) XOR (hash >> 8) XOR hash) + XOR (source MAC XOR destination MAC)) + modulo slave count + This algorithm will place all traffic to a particular network peer on the same slave. For non-IP traffic, the formula is the same as for the layer2 transmit @@ -778,19 +788,29 @@ xmit_hash_policy slaves, although a single connection will not span multiple slaves. - The formula for unfragmented TCP and UDP packets is + The formula for unfragmented IPv4 TCP and UDP packets is ((source port XOR dest port) XOR ((source IP XOR dest IP) AND 0xffff) modulo slave count - For fragmented TCP or UDP packets and all other IP - protocol traffic, the source and destination port + The formula for unfragmented IPv6 TCP and UDP packets is + + hash = (source port XOR dest port) XOR + ((source ip quad 2 XOR dest IP quad 2) XOR + (source ip quad 3 XOR dest IP quad 3) XOR + (source ip quad 4 XOR dest IP quad 4)) + + ((hash >> 24) XOR (hash >> 16) XOR (hash >> 8) XOR hash) + modulo slave count + + For fragmented TCP or UDP packets and all other IPv4 and + IPv6 protocol traffic, the source and destination port information is omitted. For non-IP traffic, the formula is the same as for the layer2 transmit hash policy. - This policy is intended to mimic the behavior of + The IPv4 policy is intended to mimic the behavior of certain switches, notably Cisco switches with PFC2 as well as some Foundry and IBM products. diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a86174c9fed..b24ce257ac7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3351,57 +3351,94 @@ static struct notifier_block bond_netdev_notifier = { /*---------------------------- Hashing Policies -----------------------------*/ +/* + * Hash for the output device based upon layer 2 data + */ +static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count) +{ + struct ethhdr *data = (struct ethhdr *)skb->data; + + if (skb_headlen(skb) >= offsetof(struct ethhdr, h_proto)) + return (data->h_dest[5] ^ data->h_source[5]) % count; + + return 0; +} + /* * Hash for the output device based upon layer 2 and layer 3 data. If - * the packet is not IP mimic bond_xmit_hash_policy_l2() + * the packet is not IP, fall back on bond_xmit_hash_policy_l2() */ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count) { struct ethhdr *data = (struct ethhdr *)skb->data; - struct iphdr *iph = ip_hdr(skb); - - if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph; + struct ipv6hdr *ipv6h; + u32 v6hash; + __be32 *s, *d; + + if (skb->protocol == htons(ETH_P_IP) && + skb_network_header_len(skb) >= sizeof(*iph)) { + iph = ip_hdr(skb); return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ (data->h_dest[5] ^ data->h_source[5])) % count; + } else if (skb->protocol == htons(ETH_P_IPV6) && + skb_network_header_len(skb) >= sizeof(*ipv6h)) { + ipv6h = ipv6_hdr(skb); + s = &ipv6h->saddr.s6_addr32[0]; + d = &ipv6h->daddr.s6_addr32[0]; + v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]); + v6hash ^= (v6hash >> 24) ^ (v6hash >> 16) ^ (v6hash >> 8); + return (v6hash ^ data->h_dest[5] ^ data->h_source[5]) % count; } - return (data->h_dest[5] ^ data->h_source[5]) % count; + return bond_xmit_hash_policy_l2(skb, count); } /* * Hash for the output device based upon layer 3 and layer 4 data. If * the packet is a frag or not TCP or UDP, just use layer 3 data. If it is - * altogether not IP, mimic bond_xmit_hash_policy_l2() + * altogether not IP, fall back on bond_xmit_hash_policy_l2() */ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count) { - struct ethhdr *data = (struct ethhdr *)skb->data; - struct iphdr *iph = ip_hdr(skb); - __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); - int layer4_xor = 0; - - if (skb->protocol == htons(ETH_P_IP)) { + u32 layer4_xor = 0; + struct iphdr *iph; + struct ipv6hdr *ipv6h; + __be32 *s, *d; + __be16 *layer4hdr; + + if (skb->protocol == htons(ETH_P_IP) && + skb_network_header_len(skb) >= sizeof(*iph)) { + iph = ip_hdr(skb); if (!ip_is_fragment(iph) && (iph->protocol == IPPROTO_TCP || - iph->protocol == IPPROTO_UDP)) { - layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1))); + iph->protocol == IPPROTO_UDP) && + (skb_headlen(skb) - skb_network_offset(skb) >= + iph->ihl * sizeof(u32) + sizeof(*layer4hdr) * 2)) { + layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); + layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); } return (layer4_xor ^ ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; - + } else if (skb->protocol == htons(ETH_P_IPV6) && + skb_network_header_len(skb) >= sizeof(*ipv6h)) { + ipv6h = ipv6_hdr(skb); + if ((ipv6h->nexthdr == IPPROTO_TCP || + ipv6h->nexthdr == IPPROTO_UDP) && + (skb_headlen(skb) - skb_network_offset(skb) >= + sizeof(*ipv6h) + sizeof(*layer4hdr) * 2)) { + layer4hdr = (__be16 *)(ipv6h + 1); + layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); + } + s = &ipv6h->saddr.s6_addr32[0]; + d = &ipv6h->daddr.s6_addr32[0]; + layer4_xor ^= (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]); + layer4_xor ^= (layer4_xor >> 24) ^ (layer4_xor >> 16) ^ + (layer4_xor >> 8); + return layer4_xor % count; } - return (data->h_dest[5] ^ data->h_source[5]) % count; -} - -/* - * Hash for the output device based upon layer 2 data - */ -static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count) -{ - struct ethhdr *data = (struct ethhdr *)skb->data; - - return (data->h_dest[5] ^ data->h_source[5]) % count; + return bond_xmit_hash_policy_l2(skb, count); } /*-------------------------- Device entry points ----------------------------*/ -- cgit v1.2.3-70-g09d2 From 816afe4ff98ee10b1d30fd66361be132a0a5cee6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 6 Aug 2012 17:29:49 +0930 Subject: x86/smp: Don't ever patch back to UP if we unplug cpus We still patch SMP instructions to UP variants if we boot with a single CPU, but not at any other time. In particular, not if we unplug CPUs to return to a single cpu. Paul McKenney points out: mean offline overhead is 6251/48=130.2 milliseconds. If I remove the alternatives_smp_switch() from the offline path [...] the mean offline overhead is 550/42=13.1 milliseconds Basically, we're never going to get those 120ms back, and the code is pretty messy. We get rid of: 1) The "smp-alt-once" boot option. It's actually "smp-alt-boot", the documentation is wrong. It's now the default. 2) The skip_smp_alternatives flag used by suspend. 3) arch_disable_nonboot_cpus_begin() and arch_disable_nonboot_cpus_end() which were only used to set this one flag. Signed-off-by: Rusty Russell Cc: Paul McKenney Cc: Suresh Siddha Cc: Linus Torvalds Cc: Andrew Morton Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/87vcgwwive.fsf@rustcorp.com.au Signed-off-by: Ingo Molnar --- Documentation/kernel-parameters.txt | 3 - arch/x86/include/asm/alternative.h | 4 +- arch/x86/kernel/alternative.c | 107 +++++++++--------------------------- arch/x86/kernel/smpboot.c | 20 +------ arch/x86/xen/smp.c | 6 +- kernel/cpu.c | 11 ---- 6 files changed, 32 insertions(+), 119 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ad7e2e5088c..7aef3345f73 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2638,9 +2638,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. smart2= [HW] Format: [,[,...,]] - smp-alt-once [X86-32,SMP] On a hotplug CPU system, only - attempt to substitute SMP alternatives once at boot. - smsc-ircc2.nopnp [HW] Don't use PNP to discover SMC devices smsc-ircc2.ircc_cfg= [HW] Device configuration I/O port smsc-ircc2.ircc_sir= [HW] SIR base I/O port diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 70780689599..444704c8e18 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -60,7 +60,7 @@ extern void alternatives_smp_module_add(struct module *mod, char *name, void *locks, void *locks_end, void *text, void *text_end); extern void alternatives_smp_module_del(struct module *mod); -extern void alternatives_smp_switch(int smp); +extern void alternatives_enable_smp(void); extern int alternatives_text_reserved(void *start, void *end); extern bool skip_smp_alternatives; #else @@ -68,7 +68,7 @@ static inline void alternatives_smp_module_add(struct module *mod, char *name, void *locks, void *locks_end, void *text, void *text_end) {} static inline void alternatives_smp_module_del(struct module *mod) {} -static inline void alternatives_smp_switch(int smp) {} +static inline void alternatives_enable_smp(void) {} static inline int alternatives_text_reserved(void *start, void *end) { return 0; diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index afb7ff79a29..af1f326a31c 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -23,19 +23,6 @@ #define MAX_PATCH_LEN (255-1) -#ifdef CONFIG_HOTPLUG_CPU -static int smp_alt_once; - -static int __init bootonly(char *str) -{ - smp_alt_once = 1; - return 1; -} -__setup("smp-alt-boot", bootonly); -#else -#define smp_alt_once 1 -#endif - static int __initdata_or_module debug_alternative; static int __init debug_alt(char *str) @@ -326,9 +313,6 @@ static void alternatives_smp_unlock(const s32 *start, const s32 *end, { const s32 *poff; - if (noreplace_smp) - return; - mutex_lock(&text_mutex); for (poff = start; poff < end; poff++) { u8 *ptr = (u8 *)poff + *poff; @@ -359,7 +343,7 @@ struct smp_alt_module { }; static LIST_HEAD(smp_alt_modules); static DEFINE_MUTEX(smp_alt); -static int smp_mode = 1; /* protected by smp_alt */ +static bool uniproc_patched = false; /* protected by smp_alt */ void __init_or_module alternatives_smp_module_add(struct module *mod, char *name, @@ -368,19 +352,18 @@ void __init_or_module alternatives_smp_module_add(struct module *mod, { struct smp_alt_module *smp; - if (noreplace_smp) - return; + mutex_lock(&smp_alt); + if (!uniproc_patched) + goto unlock; - if (smp_alt_once) { - if (boot_cpu_has(X86_FEATURE_UP)) - alternatives_smp_unlock(locks, locks_end, - text, text_end); - return; - } + if (num_possible_cpus() == 1) + /* Don't bother remembering, we'll never have to undo it. */ + goto smp_unlock; smp = kzalloc(sizeof(*smp), GFP_KERNEL); if (NULL == smp) - return; /* we'll run the (safe but slow) SMP code then ... */ + /* we'll run the (safe but slow) SMP code then ... */ + goto unlock; smp->mod = mod; smp->name = name; @@ -392,11 +375,10 @@ void __init_or_module alternatives_smp_module_add(struct module *mod, __func__, smp->locks, smp->locks_end, smp->text, smp->text_end, smp->name); - mutex_lock(&smp_alt); list_add_tail(&smp->next, &smp_alt_modules); - if (boot_cpu_has(X86_FEATURE_UP)) - alternatives_smp_unlock(smp->locks, smp->locks_end, - smp->text, smp->text_end); +smp_unlock: + alternatives_smp_unlock(locks, locks_end, text, text_end); +unlock: mutex_unlock(&smp_alt); } @@ -404,24 +386,18 @@ void __init_or_module alternatives_smp_module_del(struct module *mod) { struct smp_alt_module *item; - if (smp_alt_once || noreplace_smp) - return; - mutex_lock(&smp_alt); list_for_each_entry(item, &smp_alt_modules, next) { if (mod != item->mod) continue; list_del(&item->next); - mutex_unlock(&smp_alt); - DPRINTK("%s: %s\n", __func__, item->name); kfree(item); - return; + break; } mutex_unlock(&smp_alt); } -bool skip_smp_alternatives; -void alternatives_smp_switch(int smp) +void alternatives_enable_smp(void) { struct smp_alt_module *mod; @@ -436,34 +412,21 @@ void alternatives_smp_switch(int smp) pr_info("lockdep: fixing up alternatives\n"); #endif - if (noreplace_smp || smp_alt_once || skip_smp_alternatives) - return; - BUG_ON(!smp && (num_online_cpus() > 1)); + /* Why bother if there are no other CPUs? */ + BUG_ON(num_possible_cpus() == 1); mutex_lock(&smp_alt); - /* - * Avoid unnecessary switches because it forces JIT based VMs to - * throw away all cached translations, which can be quite costly. - */ - if (smp == smp_mode) { - /* nothing */ - } else if (smp) { + if (uniproc_patched) { pr_info("switching to SMP code\n"); + BUG_ON(num_online_cpus() != 1); clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP); clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP); list_for_each_entry(mod, &smp_alt_modules, next) alternatives_smp_lock(mod->locks, mod->locks_end, mod->text, mod->text_end); - } else { - pr_info("switching to UP code\n"); - set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP); - set_cpu_cap(&cpu_data(0), X86_FEATURE_UP); - list_for_each_entry(mod, &smp_alt_modules, next) - alternatives_smp_unlock(mod->locks, mod->locks_end, - mod->text, mod->text_end); + uniproc_patched = false; } - smp_mode = smp; mutex_unlock(&smp_alt); } @@ -540,40 +503,22 @@ void __init alternative_instructions(void) apply_alternatives(__alt_instructions, __alt_instructions_end); - /* switch to patch-once-at-boottime-only mode and free the - * tables in case we know the number of CPUs will never ever - * change */ -#ifdef CONFIG_HOTPLUG_CPU - if (num_possible_cpus() < 2) - smp_alt_once = 1; -#endif - #ifdef CONFIG_SMP - if (smp_alt_once) { - if (1 == num_possible_cpus()) { - pr_info("switching to UP code\n"); - set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP); - set_cpu_cap(&cpu_data(0), X86_FEATURE_UP); - - alternatives_smp_unlock(__smp_locks, __smp_locks_end, - _text, _etext); - } - } else { + /* Patch to UP if other cpus not imminent. */ + if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) { + uniproc_patched = true; alternatives_smp_module_add(NULL, "core kernel", __smp_locks, __smp_locks_end, _text, _etext); - - /* Only switch to UP mode if we don't immediately boot others */ - if (num_present_cpus() == 1 || setup_max_cpus <= 1) - alternatives_smp_switch(0); } -#endif - apply_paravirt(__parainstructions, __parainstructions_end); - if (smp_alt_once) + if (!uniproc_patched || num_possible_cpus() == 1) free_init_pages("SMP alternatives", (unsigned long)__smp_locks, (unsigned long)__smp_locks_end); +#endif + + apply_paravirt(__parainstructions, __parainstructions_end); restart_nmi(); } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 7c5a8c314c0..c80a33bc528 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -665,7 +665,8 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) unsigned long boot_error = 0; int timeout; - alternatives_smp_switch(1); + /* Just in case we booted with a single CPU. */ + alternatives_enable_smp(); idle->thread.sp = (unsigned long) (((struct pt_regs *) (THREAD_SIZE + task_stack_page(idle))) - 1); @@ -1053,20 +1054,6 @@ out: preempt_enable(); } -void arch_disable_nonboot_cpus_begin(void) -{ - /* - * Avoid the smp alternatives switch during the disable_nonboot_cpus(). - * In the suspend path, we will be back in the SMP mode shortly anyways. - */ - skip_smp_alternatives = true; -} - -void arch_disable_nonboot_cpus_end(void) -{ - skip_smp_alternatives = false; -} - void arch_enable_nonboot_cpus_begin(void) { set_mtrr_aps_delayed_init(); @@ -1256,9 +1243,6 @@ void native_cpu_die(unsigned int cpu) if (per_cpu(cpu_state, cpu) == CPU_DEAD) { if (system_state == SYSTEM_RUNNING) pr_info("CPU %u is now offline\n", cpu); - - if (1 == num_online_cpus()) - alternatives_smp_switch(0); return; } msleep(100); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index f58dca7a6e5..353c50f1870 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -377,7 +377,8 @@ static int __cpuinit xen_cpu_up(unsigned int cpu, struct task_struct *idle) return rc; if (num_online_cpus() == 1) - alternatives_smp_switch(1); + /* Just in case we booted with a single CPU. */ + alternatives_enable_smp(); rc = xen_smp_intr_init(cpu); if (rc) @@ -424,9 +425,6 @@ static void xen_cpu_die(unsigned int cpu) unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL); xen_uninit_lock_cpu(cpu); xen_teardown_timer(cpu); - - if (num_online_cpus() == 1) - alternatives_smp_switch(0); } static void __cpuinit xen_play_dead(void) /* used only with HOTPLUG_CPU */ diff --git a/kernel/cpu.c b/kernel/cpu.c index 14d32588ccc..f6bfe3e03f6 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -439,14 +439,6 @@ EXPORT_SYMBOL_GPL(cpu_up); #ifdef CONFIG_PM_SLEEP_SMP static cpumask_var_t frozen_cpus; -void __weak arch_disable_nonboot_cpus_begin(void) -{ -} - -void __weak arch_disable_nonboot_cpus_end(void) -{ -} - int disable_nonboot_cpus(void) { int cpu, first_cpu, error = 0; @@ -458,7 +450,6 @@ int disable_nonboot_cpus(void) * with the userspace trying to use the CPU hotplug at the same time */ cpumask_clear(frozen_cpus); - arch_disable_nonboot_cpus_begin(); printk("Disabling non-boot CPUs ...\n"); for_each_online_cpu(cpu) { @@ -474,8 +465,6 @@ int disable_nonboot_cpus(void) } } - arch_disable_nonboot_cpus_end(); - if (!error) { BUG_ON(num_online_cpus() > 1); /* Make sure the CPUs won't be enabled by someone else */ -- cgit v1.2.3-70-g09d2 From 9cad9c95d7e8d6d61d8c9729e0b6bbd18f47d86d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jul 2012 00:57:26 +0200 Subject: Documentation: DocBook DRM framework documentation Signed-off-by: Laurent Pinchart Reviewed-by: Rob Clark --- Documentation/DocBook/drm.tmpl | 2835 +++++++++++++++++++++++++++++++--------- 1 file changed, 2226 insertions(+), 609 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 196b8b9dba1..b0300529ab1 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -6,11 +6,36 @@ Linux DRM Developer's Guide + + + Jesse + Barnes + Initial version + + Intel Corporation +
+ jesse.barnes@intel.com +
+
+
+ + Laurent + Pinchart + Driver internals + + Ideas on board SPRL +
+ laurent.pinchart@ideasonboard.com +
+
+
+
+ 2008-2009 - - Intel Corporation (Jesse Barnes <jesse.barnes@intel.com>) - + 2012 + Intel Corporation + Laurent Pinchart @@ -20,6 +45,17 @@ the kernel source COPYING file. + + + + + 1.0 + 2012-07-13 + LP + Added extensive documentation about driver internals. + + +
@@ -72,342 +108,361 @@ submission & fencing, suspend/resume support, and DMA services. - - The core of every DRM driver is struct drm_driver. Drivers - typically statically initialize a drm_driver structure, - then pass it to drm_init() at load time. - - Driver initialization - - Before calling the DRM initialization routines, the driver must - first create and fill out a struct drm_driver structure. - - - static struct drm_driver driver = { - /* Don't use MTRRs here; the Xserver or userspace app should - * deal with them for Intel hardware. - */ - .driver_features = - DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_MODESET, - .load = i915_driver_load, - .unload = i915_driver_unload, - .firstopen = i915_driver_firstopen, - .lastclose = i915_driver_lastclose, - .preclose = i915_driver_preclose, - .save = i915_save, - .restore = i915_restore, - .device_is_agp = i915_driver_device_is_agp, - .get_vblank_counter = i915_get_vblank_counter, - .enable_vblank = i915_enable_vblank, - .disable_vblank = i915_disable_vblank, - .irq_preinstall = i915_driver_irq_preinstall, - .irq_postinstall = i915_driver_irq_postinstall, - .irq_uninstall = i915_driver_irq_uninstall, - .irq_handler = i915_driver_irq_handler, - .reclaim_buffers = drm_core_reclaim_buffers, - .get_map_ofs = drm_core_get_map_ofs, - .get_reg_ofs = drm_core_get_reg_ofs, - .fb_probe = intelfb_probe, - .fb_remove = intelfb_remove, - .fb_resize = intelfb_resize, - .master_create = i915_master_create, - .master_destroy = i915_master_destroy, -#if defined(CONFIG_DEBUG_FS) - .debugfs_init = i915_debugfs_init, - .debugfs_cleanup = i915_debugfs_cleanup, -#endif - .gem_init_object = i915_gem_init_object, - .gem_free_object = i915_gem_free_object, - .gem_vm_ops = &i915_gem_vm_ops, - .ioctls = i915_ioctls, - .fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .ioctl = drm_ioctl, - .mmap = drm_mmap, - .poll = drm_poll, - .fasync = drm_fasync, -#ifdef CONFIG_COMPAT - .compat_ioctl = i915_compat_ioctl, -#endif - .llseek = noop_llseek, - }, - .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - .probe = probe, - .remove = __devexit_p(drm_cleanup_pci), - }, - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, - }; - - - In the example above, taken from the i915 DRM driver, the driver - sets several flags indicating what core features it supports; - we go over the individual callbacks in later sections. Since - flags indicate which features your driver supports to the DRM - core, you need to set most of them prior to calling drm_init(). Some, - like DRIVER_MODESET can be set later based on user supplied parameters, - but that's the exception rather than the rule. - - - Driver flags - - DRIVER_USE_AGP - - Driver uses AGP interface - - - - DRIVER_REQUIRE_AGP - - Driver needs AGP interface to function. - - - - DRIVER_USE_MTRR - - - Driver uses MTRR interface for mapping memory. Deprecated. - - - - - DRIVER_PCI_DMA - - Driver is capable of PCI DMA. Deprecated. - - - - DRIVER_SG - - Driver can perform scatter/gather DMA. Deprecated. - - - - DRIVER_HAVE_DMA - Driver supports DMA. Deprecated. - - - DRIVER_HAVE_IRQDRIVER_IRQ_SHARED - - - DRIVER_HAVE_IRQ indicates whether the driver has an IRQ - handler. DRIVER_IRQ_SHARED indicates whether the device & - handler support shared IRQs (note that this is required of - PCI drivers). - - - - - DRIVER_DMA_QUEUE - - - Should be set if the driver queues DMA requests and completes them - asynchronously. Deprecated. - - - - - DRIVER_FB_DMA - - - Driver supports DMA to/from the framebuffer. Deprecated. - - - - - DRIVER_MODESET - - - Driver supports mode setting interfaces. - - - - - - In this specific case, the driver requires AGP and supports - IRQs. DMA, as discussed later, is handled by device-specific ioctls - in this case. It also supports the kernel mode setting APIs, though - unlike in the actual i915 driver source, this example unconditionally - exports KMS capability. + Driver Initialization + + At the core of every DRM driver is a drm_driver + structure. Drivers typically statically initialize a drm_driver structure, + and then pass it to one of the drm_*_init() functions + to register it with the DRM subsystem. - - - - - - Driver load - - In the previous section, we saw what a typical drm_driver - structure might look like. One of the more important fields in - the structure is the hook for the load function. - - - static struct drm_driver driver = { - ... - .load = i915_driver_load, - ... - }; - - - The load function has many responsibilities: allocating a driver - private structure, specifying supported performance counters, - configuring the device (e.g. mapping registers & command - buffers), initializing the memory manager, and setting up the - initial output configuration. - - - If compatibility is a concern (e.g. with drivers converted over - to the new interfaces from the old ones), care must be taken to - prevent device initialization and control that is incompatible with - currently active userspace drivers. For instance, if user - level mode setting drivers are in use, it would be problematic - to perform output discovery & configuration at load time. - Likewise, if user-level drivers unaware of memory management are - in use, memory management and command buffer setup may need to - be omitted. These requirements are driver-specific, and care - needs to be taken to keep both old and new applications and - libraries working. The i915 driver supports the "modeset" - module parameter to control whether advanced features are - enabled at load time or in legacy fashion. + + The drm_driver structure contains static + information that describes the driver and features it supports, and + pointers to methods that the DRM core will call to implement the DRM API. + We will first go through the drm_driver static + information fields, and will then describe individual operations in + details as they get used in later sections. - - Driver private & performance counters - - The driver private hangs off the main drm_device structure and - can be used for tracking various device-specific bits of - information, like register offsets, command buffer status, - register state for suspend/resume, etc. At load time, a - driver may simply allocate one and set drm_device.dev_priv - appropriately; it should be freed and drm_device.dev_priv set - to NULL when the driver is unloaded. - + Driver Information + + Driver Features + + Drivers inform the DRM core about their requirements and supported + features by setting appropriate flags in the + driver_features field. Since those flags + influence the DRM core behaviour since registration time, most of them + must be set to registering the drm_driver + instance. + + u32 driver_features; + + Driver Feature Flags + + DRIVER_USE_AGP + + Driver uses AGP interface, the DRM core will manage AGP resources. + + + + DRIVER_REQUIRE_AGP + + Driver needs AGP interface to function. AGP initialization failure + will become a fatal error. + + + + DRIVER_USE_MTRR + + Driver uses MTRR interface for mapping memory, the DRM core will + manage MTRR resources. Deprecated. + + + + DRIVER_PCI_DMA + + Driver is capable of PCI DMA, mapping of PCI DMA buffers to + userspace will be enabled. Deprecated. + + + + DRIVER_SG + + Driver can perform scatter/gather DMA, allocation and mapping of + scatter/gather buffers will be enabled. Deprecated. + + + + DRIVER_HAVE_DMA + + Driver supports DMA, the userspace DMA API will be supported. + Deprecated. + + + + DRIVER_HAVE_IRQDRIVER_IRQ_SHARED + + DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler. The + DRM core will automatically register an interrupt handler when the + flag is set. DRIVER_IRQ_SHARED indicates whether the device & + handler support shared IRQs (note that this is required of PCI + drivers). + + + + DRIVER_IRQ_VBL + Unused. Deprecated. + + + DRIVER_DMA_QUEUE + + Should be set if the driver queues DMA requests and completes them + asynchronously. Deprecated. + + + + DRIVER_FB_DMA + + Driver supports DMA to/from the framebuffer, mapping of frambuffer + DMA buffers to userspace will be supported. Deprecated. + + + + DRIVER_IRQ_VBL2 + Unused. Deprecated. + + + DRIVER_GEM + + Driver use the GEM memory manager. + + + + DRIVER_MODESET + + Driver supports mode setting interfaces (KMS). + + + + DRIVER_PRIME + + Driver implements DRM PRIME buffer sharing. + + + + + + Major, Minor and Patchlevel + int major; +int minor; +int patchlevel; + + The DRM core identifies driver versions by a major, minor and patch + level triplet. The information is printed to the kernel log at + initialization time and passed to userspace through the + DRM_IOCTL_VERSION ioctl. + + + The major and minor numbers are also used to verify the requested driver + API version passed to DRM_IOCTL_SET_VERSION. When the driver API changes + between minor versions, applications can call DRM_IOCTL_SET_VERSION to + select a specific version of the API. If the requested major isn't equal + to the driver major, or the requested minor is larger than the driver + minor, the DRM_IOCTL_SET_VERSION call will return an error. Otherwise + the driver's set_version() method will be called with the requested + version. + + + + Name, Description and Date + char *name; +char *desc; +char *date; + + The driver name is printed to the kernel log at initialization time, + used for IRQ registration and passed to userspace through + DRM_IOCTL_VERSION. + + + The driver description is a purely informative string passed to + userspace through the DRM_IOCTL_VERSION ioctl and otherwise unused by + the kernel. + + + The driver date, formatted as YYYYMMDD, is meant to identify the date of + the latest modification to the driver. However, as most drivers fail to + update it, its value is mostly useless. The DRM core prints it to the + kernel log at initialization time and passes it to userspace through the + DRM_IOCTL_VERSION ioctl. + + + + + Driver Load - The DRM supports several counters which may be used for rough - performance characterization. Note that the DRM stat counter - system is not often used by applications, and supporting - additional counters is completely optional. + The load method is the driver and device + initialization entry point. The method is responsible for allocating and + initializing driver private data, specifying supported performance + counters, performing resource allocation and mapping (e.g. acquiring + clocks, mapping registers or allocating command buffers), initializing + the memory manager (), installing + the IRQ handler (), setting up + vertical blanking handling (), mode + setting () and initial output + configuration (). + + If compatibility is a concern (e.g. with drivers converted over from + User Mode Setting to Kernel Mode Setting), care must be taken to prevent + device initialization and control that is incompatible with currently + active userspace drivers. For instance, if user level mode setting + drivers are in use, it would be problematic to perform output discovery + & configuration at load time. Likewise, if user-level drivers + unaware of memory management are in use, memory management and command + buffer setup may need to be omitted. These requirements are + driver-specific, and care needs to be taken to keep both old and new + applications and libraries working. + + int (*load) (struct drm_device *, unsigned long flags); - These interfaces are deprecated and should not be used. If performance - monitoring is desired, the developer should investigate and - potentially enhance the kernel perf and tracing infrastructure to export - GPU related performance information for consumption by performance - monitoring tools and applications. + The method takes two arguments, a pointer to the newly created + drm_device and flags. The flags are used to + pass the driver_data field of the device id + corresponding to the device passed to drm_*_init(). + Only PCI devices currently use this, USB and platform DRM drivers have + their load method called with flags to 0. + + Driver Private & Performance Counters + + The driver private hangs off the main + drm_device structure and can be used for + tracking various device-specific bits of information, like register + offsets, command buffer status, register state for suspend/resume, etc. + At load time, a driver may simply allocate one and set + drm_device.dev_priv + appropriately; it should be freed and + drm_device.dev_priv + set to NULL when the driver is unloaded. + + + DRM supports several counters which were used for rough performance + characterization. This stat counter system is deprecated and should not + be used. If performance monitoring is desired, the developer should + investigate and potentially enhance the kernel perf and tracing + infrastructure to export GPU related performance information for + consumption by performance monitoring tools and applications. + + + + IRQ Registration + + The DRM core tries to facilitate IRQ handler registration and + unregistration by providing drm_irq_install and + drm_irq_uninstall functions. Those functions only + support a single interrupt per device. + + + + Both functions get the device IRQ by calling + drm_dev_to_irq. This inline function will call a + bus-specific operation to retrieve the IRQ number. For platform devices, + platform_get_irq(..., 0) is used to retrieve the + IRQ number. + + + drm_irq_install starts by calling the + irq_preinstall driver operation. The operation + is optional and must make sure that the interrupt will not get fired by + clearing all pending interrupt flags or disabling the interrupt. + + + The IRQ will then be requested by a call to + request_irq. If the DRIVER_IRQ_SHARED driver + feature flag is set, a shared (IRQF_SHARED) IRQ handler will be + requested. + + + The IRQ handler function must be provided as the mandatory irq_handler + driver operation. It will get passed directly to + request_irq and thus has the same prototype as all + IRQ handlers. It will get called with a pointer to the DRM device as the + second argument. + + + Finally the function calls the optional + irq_postinstall driver operation. The operation + usually enables interrupts (excluding the vblank interrupt, which is + enabled separately), but drivers may choose to enable/disable interrupts + at a different time. + + + drm_irq_uninstall is similarly used to uninstall an + IRQ handler. It starts by waking up all processes waiting on a vblank + interrupt to make sure they don't hang, and then calls the optional + irq_uninstall driver operation. The operation + must disable all hardware interrupts. Finally the function frees the IRQ + by calling free_irq. + + + + Memory Manager Initialization + + Every DRM driver requires a memory manager which must be initialized at + load time. DRM currently contains two memory managers, the Translation + Table Manager (TTM) and the Graphics Execution Manager (GEM). + This document describes the use of the GEM memory manager only. See + for details. + + + + Miscellaneous Device Configuration + + Another task that may be necessary for PCI devices during configuration + is mapping the video BIOS. On many devices, the VBIOS describes device + configuration, LCD panel timings (if any), and contains flags indicating + device state. Mapping the BIOS can be done using the pci_map_rom() call, + a convenience function that takes care of mapping the actual ROM, + whether it has been shadowed into memory (typically at address 0xc0000) + or exists on the PCI device in the ROM BAR. Note that after the ROM has + been mapped and any necessary information has been extracted, it should + be unmapped; on many devices, the ROM address decoder is shared with + other BARs, so leaving it mapped could cause undesired behaviour like + hangs or memory corruption. + + + + - - Configuring the device - - Obviously, device configuration is device-specific. - However, there are several common operations: finding a - device's PCI resources, mapping them, and potentially setting - up an IRQ handler. - - - Finding & mapping resources is fairly straightforward. The - DRM wrapper functions, drm_get_resource_start() and - drm_get_resource_len(), may be used to find BARs on the given - drm_device struct. Once those values have been retrieved, the - driver load function can call drm_addmap() to create a new - mapping for the BAR in question. Note that you probably want a - drm_local_map_t in your driver private structure to track any - mappings you create. - - - - - if compatibility with other operating systems isn't a concern - (DRM drivers can run under various BSD variants and OpenSolaris), - native Linux calls may be used for the above, e.g. pci_resource_* - and iomap*/iounmap. See the Linux device driver book for more - info. - - - Once you have a register map, you may use the DRM_READn() and - DRM_WRITEn() macros to access the registers on your device, or - use driver-specific versions to offset into your MMIO space - relative to a driver-specific base pointer (see I915_READ for - an example). - - - If your device supports interrupt generation, you may want to - set up an interrupt handler when the driver is loaded. This - is done using the drm_irq_install() function. If your device - supports vertical blank interrupts, it should call - drm_vblank_init() to initialize the core vblank handling code before - enabling interrupts on your device. This ensures the vblank related - structures are allocated and allows the core to handle vblank events. - - - - Once your interrupt handler is registered (it uses your - drm_driver.irq_handler as the actual interrupt handling - function), you can safely enable interrupts on your device, - assuming any other state your interrupt handler uses is also - initialized. - - - Another task that may be necessary during configuration is - mapping the video BIOS. On many devices, the VBIOS describes - device configuration, LCD panel timings (if any), and contains - flags indicating device state. Mapping the BIOS can be done - using the pci_map_rom() call, a convenience function that - takes care of mapping the actual ROM, whether it has been - shadowed into memory (typically at address 0xc0000) or exists - on the PCI device in the ROM BAR. Note that after the ROM - has been mapped and any necessary information has been extracted, - it should be unmapped; on many devices, the ROM address decoder is - shared with other BARs, so leaving it mapped could cause - undesired behavior like hangs or memory corruption. - - - + + + Memory management + + Modern Linux systems require large amount of graphics memory to store + frame buffers, textures, vertices and other graphics-related data. Given + the very dynamic nature of many of that data, managing graphics memory + efficiently is thus crucial for the graphics stack and plays a central + role in the DRM infrastructure. + + + The DRM core includes two memory managers, namely Translation Table Maps + (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory + manager to be developed and tried to be a one-size-fits-them all + solution. It provides a single userspace API to accomodate the need of + all hardware, supporting both Unified Memory Architecture (UMA) devices + and devices with dedicated video RAM (i.e. most discrete video cards). + This resulted in a large, complex piece of code that turned out to be + hard to use for driver development. + + + GEM started as an Intel-sponsored project in reaction to TTM's + complexity. Its design philosophy is completely different: instead of + providing a solution to every graphics memory-related problems, GEM + identified common code between drivers and created a support library to + share it. GEM has simpler initialization and execution requirements than + TTM, but has no video RAM management capabitilies and is thus limited to + UMA devices. + - Memory manager initialization - - In order to allocate command buffers, cursor memory, scanout - buffers, etc., as well as support the latest features provided - by packages like Mesa and the X.Org X server, your driver - should support a memory manager. - + The Translation Table Manager (TTM) - If your driver supports memory management (it should!), you - need to set that up at load time as well. How you initialize - it depends on which memory manager you're using: TTM or GEM. + TTM design background and information belongs here. TTM initialization - - TTM (for Translation Table Manager) manages video memory and - aperture space for graphics devices. TTM supports both UMA devices - and devices with dedicated video RAM (VRAM), i.e. most discrete - graphics devices. If your device has dedicated RAM, supporting - TTM is desirable. TTM also integrates tightly with your - driver-specific buffer execution function. See the radeon - driver for examples. - - - The core TTM structure is the ttm_bo_driver struct. It contains - several fields with function pointers for initializing the TTM, - allocating and freeing memory, waiting for command completion - and fence synchronization, and memory migration. See the - radeon_ttm.c file for an example of usage. + This section is outdated. + + Drivers wishing to support TTM must fill out a drm_bo_driver + structure. The structure contains several fields with function + pointers for initializing the TTM, allocating and freeing memory, + waiting for command completion and fence synchronization, and memory + migration. See the radeon_ttm.c file for an example of usage. The ttm_global_reference structure is made up of several fields: @@ -445,82 +500,1081 @@ count for the TTM, which will call your initialization function. + + + The Graphics Execution Manager (GEM) + + The GEM design approach has resulted in a memory manager that doesn't + provide full coverage of all (or even all common) use cases in its + userspace or kernel API. GEM exposes a set of standard memory-related + operations to userspace and a set of helper functions to drivers, and let + drivers implement hardware-specific operations with their own private API. + + + The GEM userspace API is described in the + GEM - the Graphics + Execution Manager article on LWN. While slightly + outdated, the document provides a good overview of the GEM API principles. + Buffer allocation and read and write operations, described as part of the + common GEM API, are currently implemented using driver-specific ioctls. + + + GEM is data-agnostic. It manages abstract buffer objects without knowing + what individual buffers contain. APIs that require knowledge of buffer + contents or purpose, such as buffer allocation or synchronization + primitives, are thus outside of the scope of GEM and must be implemented + using driver-specific ioctls. + + + On a fundamental level, GEM involves several operations: + + Memory allocation and freeing + Command execution + Aperture management at command execution time + + Buffer object allocation is relatively straightforward and largely + provided by Linux's shmem layer, which provides memory to back each + object. + + + Device-specific operations, such as command execution, pinning, buffer + read & write, mapping, and domain ownership transfers are left to + driver-specific ioctls. + + + GEM Initialization + + Drivers that use GEM must set the DRIVER_GEM bit in the struct + drm_driver + driver_features field. The DRM core will + then automatically initialize the GEM core before calling the + load operation. Behind the scene, this will + create a DRM Memory Manager object which provides an address space + pool for object allocation. + + + In a KMS configuration, drivers need to allocate and initialize a + command ring buffer following core GEM initialization if required by + the hardware. UMA devices usually have what is called a "stolen" + memory region, which provides space for the initial framebuffer and + large, contiguous memory regions required by the device. This space is + typically not managed by GEM, and must be initialized separately into + its own DRM MM object. + + - GEM initialization - - GEM is an alternative to TTM, designed specifically for UMA - devices. It has simpler initialization and execution requirements - than TTM, but has no VRAM management capability. Core GEM - is initialized by calling drm_mm_init() to create - a GTT DRM MM object, which provides an address space pool for - object allocation. In a KMS configuration, the driver - needs to allocate and initialize a command ring buffer following - core GEM initialization. A UMA device usually has what is called a - "stolen" memory region, which provides space for the initial - framebuffer and large, contiguous memory regions required by the - device. This space is not typically managed by GEM, and it must - be initialized separately into its own DRM MM object. - - - Initialization is driver-specific. In the case of Intel - integrated graphics chips like 965GM, GEM initialization can - be done by calling the internal GEM init function, - i915_gem_do_init(). Since the 965GM is a UMA device - (i.e. it doesn't have dedicated VRAM), GEM manages - making regular RAM available for GPU operations. Memory set - aside by the BIOS (called "stolen" memory by the i915 - driver) is managed by the DRM memrange allocator; the - rest of the aperture is managed by GEM. - - /* Basic memrange allocator for stolen space (aka vram) */ - drm_memrange_init(&dev_priv->vram, 0, prealloc_size); - /* Let GEM Manage from end of prealloc space to end of aperture */ - i915_gem_do_init(dev, prealloc_size, agp_size); - - - - - Once the memory manager has been set up, we may allocate the - command buffer. In the i915 case, this is also done with a - GEM function, i915_gem_init_ringbuffer(). - + GEM Objects Creation + + GEM splits creation of GEM objects and allocation of the memory that + backs them in two distinct operations. + + + GEM objects are represented by an instance of struct + drm_gem_object. Drivers usually need to extend + GEM objects with private information and thus create a driver-specific + GEM object structure type that embeds an instance of struct + drm_gem_object. + + + To create a GEM object, a driver allocates memory for an instance of its + specific GEM object type and initializes the embedded struct + drm_gem_object with a call to + drm_gem_object_init. The function takes a pointer to + the DRM device, a pointer to the GEM object and the buffer object size + in bytes. + + + GEM uses shmem to allocate anonymous pageable memory. + drm_gem_object_init will create an shmfs file of + the requested size and store it into the struct + drm_gem_object filp + field. The memory is used as either main storage for the object when the + graphics hardware uses system memory directly or as a backing store + otherwise. + + + Drivers are responsible for the actual physical pages allocation by + calling shmem_read_mapping_page_gfp for each page. + Note that they can decide to allocate pages when initializing the GEM + object, or to delay allocation until the memory is needed (for instance + when a page fault occurs as a result of a userspace memory access or + when the driver needs to start a DMA transfer involving the memory). + + + Anonymous pageable memory allocation is not always desired, for instance + when the hardware requires physically contiguous system memory as is + often the case in embedded devices. Drivers can create GEM objects with + no shmfs backing (called private GEM objects) by initializing them with + a call to drm_gem_private_object_init instead of + drm_gem_object_init. Storage for private GEM + objects must be managed by drivers. + + + Drivers that do not need to extend GEM objects with private information + can call the drm_gem_object_alloc function to + allocate and initialize a struct drm_gem_object + instance. The GEM core will call the optional driver + gem_init_object operation after initializing + the GEM object with drm_gem_object_init. + int (*gem_init_object) (struct drm_gem_object *obj); + + + No alloc-and-init function exists for private GEM objects. + + + + GEM Objects Lifetime + + All GEM objects are reference-counted by the GEM core. References can be + acquired and release by calling drm_gem_object_reference + and drm_gem_object_unreference respectively. The + caller must hold the drm_device + struct_mutex lock. As a convenience, GEM + provides the drm_gem_object_reference_unlocked and + drm_gem_object_unreference_unlocked functions that + can be called without holding the lock. + + + When the last reference to a GEM object is released the GEM core calls + the drm_driver + gem_free_object operation. That operation is + mandatory for GEM-enabled drivers and must free the GEM object and all + associated resources. + + + void (*gem_free_object) (struct drm_gem_object *obj); + Drivers are responsible for freeing all GEM object resources, including + the resources created by the GEM core. If an mmap offset has been + created for the object (in which case + drm_gem_object::map_list::map + is not NULL) it must be freed by a call to + drm_gem_free_mmap_offset. The shmfs backing store + must be released by calling drm_gem_object_release + (that function can safely be called if no shmfs backing store has been + created). + + + + GEM Objects Naming + + Communication between userspace and the kernel refers to GEM objects + using local handles, global names or, more recently, file descriptors. + All of those are 32-bit integer values; the usual Linux kernel limits + apply to the file descriptors. + + + GEM handles are local to a DRM file. Applications get a handle to a GEM + object through a driver-specific ioctl, and can use that handle to refer + to the GEM object in other standard or driver-specific ioctls. Closing a + DRM file handle frees all its GEM handles and dereferences the + associated GEM objects. + + + To create a handle for a GEM object drivers call + drm_gem_handle_create. The function takes a pointer + to the DRM file and the GEM object and returns a locally unique handle. + When the handle is no longer needed drivers delete it with a call to + drm_gem_handle_delete. Finally the GEM object + associated with a handle can be retrieved by a call to + drm_gem_object_lookup. + + + Handles don't take ownership of GEM objects, they only take a reference + to the object that will be dropped when the handle is destroyed. To + avoid leaking GEM objects, drivers must make sure they drop the + reference(s) they own (such as the initial reference taken at object + creation time) as appropriate, without any special consideration for the + handle. For example, in the particular case of combined GEM object and + handle creation in the implementation of the + dumb_create operation, drivers must drop the + initial reference to the GEM object before returning the handle. + + + GEM names are similar in purpose to handles but are not local to DRM + files. They can be passed between processes to reference a GEM object + globally. Names can't be used directly to refer to objects in the DRM + API, applications must convert handles to names and names to handles + using the DRM_IOCTL_GEM_FLINK and DRM_IOCTL_GEM_OPEN ioctls + respectively. The conversion is handled by the DRM core without any + driver-specific support. + + + Similar to global names, GEM file descriptors are also used to share GEM + objects across processes. They offer additional security: as file + descriptors must be explictly sent over UNIX domain sockets to be shared + between applications, they can't be guessed like the globally unique GEM + names. + + + Drivers that support GEM file descriptors, also known as the DRM PRIME + API, must set the DRIVER_PRIME bit in the struct + drm_driver + driver_features field, and implement the + prime_handle_to_fd and + prime_fd_to_handle operations. + + + int (*prime_handle_to_fd)(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, + uint32_t flags, int *prime_fd); + int (*prime_fd_to_handle)(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, + uint32_t *handle); + Those two operations convert a handle to a PRIME file descriptor and + vice versa. Drivers must use the kernel dma-buf buffer sharing framework + to manage the PRIME file descriptors. + + + While non-GEM drivers must implement the operations themselves, GEM + drivers must use the drm_gem_prime_handle_to_fd + and drm_gem_prime_fd_to_handle helper functions. + Those helpers rely on the driver + gem_prime_export and + gem_prime_import operations to create a dma-buf + instance from a GEM object (dma-buf exporter role) and to create a GEM + object from a dma-buf instance (dma-buf importer role). + + + struct dma_buf * (*gem_prime_export)(struct drm_device *dev, + struct drm_gem_object *obj, + int flags); + struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, + struct dma_buf *dma_buf); + These two operations are mandatory for GEM drivers that support DRM + PRIME. + + + + GEM Objects Mapping + + Because mapping operations are fairly heavyweight GEM favours + read/write-like access to buffers, implemented through driver-specific + ioctls, over mapping buffers to userspace. However, when random access + to the buffer is needed (to perform software rendering for instance), + direct access to the object can be more efficient. + + + The mmap system call can't be used directly to map GEM objects, as they + don't have their own file handle. Two alternative methods currently + co-exist to map GEM objects to userspace. The first method uses a + driver-specific ioctl to perform the mapping operation, calling + do_mmap under the hood. This is often considered + dubious, seems to be discouraged for new GEM-enabled drivers, and will + thus not be described here. + + + The second method uses the mmap system call on the DRM file handle. + void *mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset); + DRM identifies the GEM object to be mapped by a fake offset passed + through the mmap offset argument. Prior to being mapped, a GEM object + must thus be associated with a fake offset. To do so, drivers must call + drm_gem_create_mmap_offset on the object. The + function allocates a fake offset range from a pool and stores the + offset divided by PAGE_SIZE in + obj->map_list.hash.key. Care must be taken not to + call drm_gem_create_mmap_offset if a fake offset + has already been allocated for the object. This can be tested by + obj->map_list.map being non-NULL. + + + Once allocated, the fake offset value + (obj->map_list.hash.key << PAGE_SHIFT) + must be passed to the application in a driver-specific way and can then + be used as the mmap offset argument. + + + The GEM core provides a helper method drm_gem_mmap + to handle object mapping. The method can be set directly as the mmap + file operation handler. It will look up the GEM object based on the + offset value and set the VMA operations to the + drm_driver gem_vm_ops + field. Note that drm_gem_mmap doesn't map memory to + userspace, but relies on the driver-provided fault handler to map pages + individually. + + + To use drm_gem_mmap, drivers must fill the struct + drm_driver gem_vm_ops + field with a pointer to VM operations. + + + struct vm_operations_struct *gem_vm_ops + + struct vm_operations_struct { + void (*open)(struct vm_area_struct * area); + void (*close)(struct vm_area_struct * area); + int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); + }; + + + The open and close + operations must update the GEM object reference count. Drivers can use + the drm_gem_vm_open and + drm_gem_vm_close helper functions directly as open + and close handlers. + + + The fault operation handler is responsible for mapping individual pages + to userspace when a page fault occurs. Depending on the memory + allocation scheme, drivers can allocate pages at fault time, or can + decide to allocate memory for the GEM object at the time the object is + created. + + + Drivers that want to map the GEM object upfront instead of handling page + faults can implement their own mmap file operation handler. + + + + Dumb GEM Objects + + The GEM API doesn't standardize GEM objects creation and leaves it to + driver-specific ioctls. While not an issue for full-fledged graphics + stacks that include device-specific userspace components (in libdrm for + instance), this limit makes DRM-based early boot graphics unnecessarily + complex. + + + Dumb GEM objects partly alleviate the problem by providing a standard + API to create dumb buffers suitable for scanout, which can then be used + to create KMS frame buffers. + + + To support dumb GEM objects drivers must implement the + dumb_create, + dumb_destroy and + dumb_map_offset operations. + + + + int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, + struct drm_mode_create_dumb *args); + + The dumb_create operation creates a GEM + object suitable for scanout based on the width, height and depth + from the struct drm_mode_create_dumb + argument. It fills the argument's handle, + pitch and size + fields with a handle for the newly created GEM object and its line + pitch and size in bytes. + + + + int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle); + + The dumb_destroy operation destroys a dumb + GEM object created by dumb_create. + + + + int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle, uint64_t *offset); + + The dumb_map_offset operation associates an + mmap fake offset with the GEM object given by the handle and returns + it. Drivers must use the + drm_gem_create_mmap_offset function to + associate the fake offset as described in + . + + + + + + Memory Coherency + + When mapped to the device or used in a command buffer, backing pages + for an object are flushed to memory and marked write combined so as to + be coherent with the GPU. Likewise, if the CPU accesses an object + after the GPU has finished rendering to the object, then the object + must be made coherent with the CPU's view of memory, usually involving + GPU cache flushing of various kinds. This core CPU<->GPU + coherency management is provided by a device-specific ioctl, which + evaluates an object's current domain and performs any necessary + flushing or synchronization to put the object into the desired + coherency domain (note that the object may be busy, i.e. an active + render target; in that case, setting the domain blocks the client and + waits for rendering to complete before performing any necessary + flushing operations). + + + + Command Execution + + Perhaps the most important GEM function for GPU devices is providing a + command execution interface to clients. Client programs construct + command buffers containing references to previously allocated memory + objects, and then submit them to GEM. At that point, GEM takes care to + bind all the objects into the GTT, execute the buffer, and provide + necessary synchronization between clients accessing the same buffers. + This often involves evicting some objects from the GTT and re-binding + others (a fairly expensive operation), and providing relocation + support which hides fixed GTT offsets from clients. Clients must take + care not to submit command buffers that reference more objects than + can fit in the GTT; otherwise, GEM will reject them and no rendering + will occur. Similarly, if several objects in the buffer require fence + registers to be allocated for correct rendering (e.g. 2D blits on + pre-965 chips), care must be taken not to require more fence registers + than are available to the client. Such resource management should be + abstracted from the client in libdrm. + + + + + + Mode Setting + + Drivers must initialize the mode setting core by calling + drm_mode_config_init on the DRM device. The function + initializes the drm_device + mode_config field and never fails. Once done, + mode configuration must be setup by initializing the following fields. + + + + int min_width, min_height; +int max_width, max_height; + + Minimum and maximum width and height of the frame buffers in pixel + units. + + + + struct drm_mode_config_funcs *funcs; + Mode setting functions. + + - Output configuration + Frame Buffer Creation + struct drm_framebuffer *(*fb_create)(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd2 *mode_cmd); - The final initialization task is output configuration. This involves: - - - Finding and initializing the CRTCs, encoders, and connectors - for the device. - - - Creating an initial configuration. - - - Registering a framebuffer console driver. - - + Frame buffers are abstract memory objects that provide a source of + pixels to scanout to a CRTC. Applications explicitly request the + creation of frame buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and + receive an opaque handle that can be passed to the KMS CRTC control, + plane configuration and page flip functions. + + + Frame buffers rely on the underneath memory manager for low-level memory + operations. When creating a frame buffer applications pass a memory + handle (or a list of memory handles for multi-planar formats) through + the drm_mode_fb_cmd2 argument. This document + assumes that the driver uses GEM, those handles thus reference GEM + objects. + + + Drivers must first validate the requested frame buffer parameters passed + through the mode_cmd argument. In particular this is where invalid + sizes, pixel formats or pitches can be caught. + + + If the parameters are deemed valid, drivers then create, initialize and + return an instance of struct drm_framebuffer. + If desired the instance can be embedded in a larger driver-specific + structure. The new instance is initialized with a call to + drm_framebuffer_init which takes a pointer to DRM + frame buffer operations (struct + drm_framebuffer_funcs). Frame buffer operations are + + + int (*create_handle)(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned int *handle); + + Create a handle to the frame buffer underlying memory object. If + the frame buffer uses a multi-plane format, the handle will + reference the memory object associated with the first plane. + + + Drivers call drm_gem_handle_create to create + the handle. + + + + void (*destroy)(struct drm_framebuffer *framebuffer); + + Destroy the frame buffer object and frees all associated + resources. Drivers must call + drm_framebuffer_cleanup to free resources + allocated by the DRM core for the frame buffer object, and must + make sure to unreference all memory objects associated with the + frame buffer. Handles created by the + create_handle operation are released by + the DRM core. + + + + int (*dirty)(struct drm_framebuffer *framebuffer, + struct drm_file *file_priv, unsigned flags, unsigned color, + struct drm_clip_rect *clips, unsigned num_clips); + + This optional operation notifies the driver that a region of the + frame buffer has changed in response to a DRM_IOCTL_MODE_DIRTYFB + ioctl call. + + + + + + After initializing the drm_framebuffer + instance drivers must fill its width, + height, pitches, + offsets, depth, + bits_per_pixel and + pixel_format fields from the values passed + through the drm_mode_fb_cmd2 argument. They + should call the drm_helper_mode_fill_fb_struct + helper function to do so. + + + + Output Polling + void (*output_poll_changed)(struct drm_device *dev); + + This operation notifies the driver that the status of one or more + connectors has changed. Drivers that use the fb helper can just call the + drm_fb_helper_hotplug_event function to handle this + operation. + + + + + + + + KMS Initialization and Cleanup + + A KMS device is abstracted and exposed as a set of planes, CRTCs, encoders + and connectors. KMS drivers must thus create and initialize all those + objects at load time after initializing mode setting. + + + CRTCs (struct <structname>drm_crtc</structname>) + + A CRTC is an abstraction representing a part of the chip that contains a + pointer to a scanout buffer. Therefore, the number of CRTCs available + determines how many independent scanout buffers can be active at any + given time. The CRTC structure contains several fields to support this: + a pointer to some video memory (abstracted as a frame buffer object), a + display mode, and an (x, y) offset into the video memory to support + panning or configurations where one piece of video memory spans multiple + CRTCs. - Output discovery and initialization - - Several core functions exist to create CRTCs, encoders, and - connectors, namely: drm_crtc_init(), drm_connector_init(), and - drm_encoder_init(), along with several "helper" functions to - perform common tasks. - - - Connectors should be registered with sysfs once they've been - detected and initialized, using the - drm_sysfs_connector_add() function. Likewise, when they're - removed from the system, they should be destroyed with - drm_sysfs_connector_remove(). - - -CRTC Initialization + + A KMS device must create and register at least one struct + drm_crtc instance. The instance is allocated + and zeroed by the driver, possibly as part of a larger structure, and + registered with a call to drm_crtc_init with a + pointer to CRTC functions. + + + + CRTC Operations + + Set Configuration + int (*set_config)(struct drm_mode_set *set); + + Apply a new CRTC configuration to the device. The configuration + specifies a CRTC, a frame buffer to scan out from, a (x,y) position in + the frame buffer, a display mode and an array of connectors to drive + with the CRTC if possible. + + + If the frame buffer specified in the configuration is NULL, the driver + must detach all encoders connected to the CRTC and all connectors + attached to those encoders and disable them. + + + This operation is called with the mode config lock held. + + + FIXME: How should set_config interact with DPMS? If the CRTC is + suspended, should it be resumed? + + + + Page Flipping + int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event); + + Schedule a page flip to the given frame buffer for the CRTC. This + operation is called with the mode config mutex held. + + + Page flipping is a synchronization mechanism that replaces the frame + buffer being scanned out by the CRTC with a new frame buffer during + vertical blanking, avoiding tearing. When an application requests a page + flip the DRM core verifies that the new frame buffer is large enough to + be scanned out by the CRTC in the currently configured mode and then + calls the CRTC page_flip operation with a + pointer to the new frame buffer. + + + The page_flip operation schedules a page flip. + Once any pending rendering targetting the new frame buffer has + completed, the CRTC will be reprogrammed to display that frame buffer + after the next vertical refresh. The operation must return immediately + without waiting for rendering or page flip to complete and must block + any new rendering to the frame buffer until the page flip completes. + + + If a page flip is already pending, the + page_flip operation must return + -EBUSY. + + + To synchronize page flip to vertical blanking the driver will likely + need to enable vertical blanking interrupts. It should call + drm_vblank_get for that purpose, and call + drm_vblank_put after the page flip completes. + + + If the application has requested to be notified when page flip completes + the page_flip operation will be called with a + non-NULL event argument pointing to a + drm_pending_vblank_event instance. Upon page + flip completion the driver must fill the + event::event + sequence, tv_sec + and tv_usec fields with the associated + vertical blanking count and timestamp, add the event to the + drm_file list of events to be signaled, and wake + up any waiting process. This can be performed with + event.sequence = drm_vblank_count_and_time(..., &now); + event->event.tv_sec = now.tv_sec; + event->event.tv_usec = now.tv_usec; + + spin_lock_irqsave(&dev->event_lock, flags); + list_add_tail(&event->base.link, &event->base.file_priv->event_list); + wake_up_interruptible(&event->base.file_priv->event_wait); + spin_unlock_irqrestore(&dev->event_lock, flags); + ]]> + + + FIXME: Could drivers that don't need to wait for rendering to complete + just add the event to dev->vblank_event_list and + let the DRM core handle everything, as for "normal" vertical blanking + events? + + + While waiting for the page flip to complete, the + event->base.link list head can be used freely by + the driver to store the pending event in a driver-specific list. + + + If the file handle is closed before the event is signaled, drivers must + take care to destroy the event in their + preclose operation (and, if needed, call + drm_vblank_put). + + + + Miscellaneous + + + void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, + uint32_t start, uint32_t size); + + Apply a gamma table to the device. The operation is optional. + + + + void (*destroy)(struct drm_crtc *crtc); + + Destroy the CRTC when not needed anymore. See + . + + + + + + + + Planes (struct <structname>drm_plane</structname>) + + A plane represents an image source that can be blended with or overlayed + on top of a CRTC during the scanout process. Planes are associated with + a frame buffer to crop a portion of the image memory (source) and + optionally scale it to a destination size. The result is then blended + with or overlayed on top of a CRTC. + + + Plane Initialization + + Planes are optional. To create a plane, a KMS drivers allocates and + zeroes an instances of struct drm_plane + (possibly as part of a larger structure) and registers it with a call + to drm_plane_init. The function takes a bitmask + of the CRTCs that can be associated with the plane, a pointer to the + plane functions and a list of format supported formats. + + + + Plane Operations + + + int (*update_plane)(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); + + Enable and configure the plane to use the given CRTC and frame buffer. + + + The source rectangle in frame buffer memory coordinates is given by + the src_x, src_y, + src_w and src_h + parameters (as 16.16 fixed point values). Devices that don't support + subpixel plane coordinates can ignore the fractional part. + + + The destination rectangle in CRTC coordinates is given by the + crtc_x, crtc_y, + crtc_w and crtc_h + parameters (as integer values). Devices scale the source rectangle to + the destination rectangle. If scaling is not supported, and the source + rectangle size doesn't match the destination rectangle size, the + driver must return a -EINVAL error. + + + + int (*disable_plane)(struct drm_plane *plane); + + Disable the plane. The DRM core calls this method in response to a + DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set to 0. + Disabled planes must not be processed by the CRTC. + + + + void (*destroy)(struct drm_plane *plane); + + Destroy the plane when not needed anymore. See + . + + + + + + + Encoders (struct <structname>drm_encoder</structname>) + + An encoder takes pixel data from a CRTC and converts it to a format + suitable for any attached connectors. On some devices, it may be + possible to have a CRTC send data to more than one encoder. In that + case, both encoders would receive data from the same scanout buffer, + resulting in a "cloned" display configuration across the connectors + attached to each encoder. + + + Encoder Initialization + + As for CRTCs, a KMS driver must create, initialize and register at + least one struct drm_encoder instance. The + instance is allocated and zeroed by the driver, possibly as part of a + larger structure. + + + Drivers must initialize the struct drm_encoder + possible_crtcs and + possible_clones fields before registering the + encoder. Both fields are bitmasks of respectively the CRTCs that the + encoder can be connected to, and sibling encoders candidate for cloning. + + + After being initialized, the encoder must be registered with a call to + drm_encoder_init. The function takes a pointer to + the encoder functions and an encoder type. Supported types are + + + DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A + + + DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort + + + DRM_MODE_ENCODER_LVDS for display panels + + + DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, Component, + SCART) + + + DRM_MODE_ENCODER_VIRTUAL for virtual machine displays + + + + + Encoders must be attached to a CRTC to be used. DRM drivers leave + encoders unattached at initialization time. Applications (or the fbdev + compatibility layer when implemented) are responsible for attaching the + encoders they want to use to a CRTC. + + + + Encoder Operations + + + void (*destroy)(struct drm_encoder *encoder); + + Called to destroy the encoder when not needed anymore. See + . + + + + + + + Connectors (struct <structname>drm_connector</structname>) + + A connector is the final destination for pixel data on a device, and + usually connects directly to an external display device like a monitor + or laptop panel. A connector can only be attached to one encoder at a + time. The connector is also the structure where information about the + attached display is kept, so it contains fields for display data, EDID + data, DPMS & connection status, and information about modes + supported on the attached displays. + + + Connector Initialization + + Finally a KMS driver must create, initialize, register and attach at + least one struct drm_connector instance. The + instance is created as other KMS objects and initialized by setting the + following fields. + + + + interlace_allowed + + Whether the connector can handle interlaced modes. + + + + doublescan_allowed + + Whether the connector can handle doublescan. + + + + display_info + + + Display information is filled from EDID information when a display + is detected. For non hot-pluggable displays such as flat panels in + embedded systems, the driver should initialize the + display_info.width_mm + and + display_info.height_mm + fields with the physical size of the display. + + + + polled + + Connector polling mode, a combination of + + + DRM_CONNECTOR_POLL_HPD + + The connector generates hotplug events and doesn't need to be + periodically polled. The CONNECT and DISCONNECT flags must not + be set together with the HPD flag. + + + + DRM_CONNECTOR_POLL_CONNECT + + Periodically poll the connector for connection. + + + + DRM_CONNECTOR_POLL_DISCONNECT + + Periodically poll the connector for disconnection. + + + + Set to 0 for connectors that don't support connection status + discovery. + + + + + The connector is then registered with a call to + drm_connector_init with a pointer to the connector + functions and a connector type, and exposed through sysfs with a call to + drm_sysfs_connector_add. + + + Supported connector types are + + DRM_MODE_CONNECTOR_VGA + DRM_MODE_CONNECTOR_DVII + DRM_MODE_CONNECTOR_DVID + DRM_MODE_CONNECTOR_DVIA + DRM_MODE_CONNECTOR_Composite + DRM_MODE_CONNECTOR_SVIDEO + DRM_MODE_CONNECTOR_LVDS + DRM_MODE_CONNECTOR_Component + DRM_MODE_CONNECTOR_9PinDIN + DRM_MODE_CONNECTOR_DisplayPort + DRM_MODE_CONNECTOR_HDMIA + DRM_MODE_CONNECTOR_HDMIB + DRM_MODE_CONNECTOR_TV + DRM_MODE_CONNECTOR_eDP + DRM_MODE_CONNECTOR_VIRTUAL + + + + Connectors must be attached to an encoder to be used. For devices that + map connectors to encoders 1:1, the connector should be attached at + initialization time with a call to + drm_mode_connector_attach_encoder. The driver must + also set the drm_connector + encoder field to point to the attached + encoder. + + + Finally, drivers must initialize the connectors state change detection + with a call to drm_kms_helper_poll_init. If at + least one connector is pollable but can't generate hotplug interrupts + (indicated by the DRM_CONNECTOR_POLL_CONNECT and + DRM_CONNECTOR_POLL_DISCONNECT connector flags), a delayed work will + automatically be queued to periodically poll for changes. Connectors + that can generate hotplug interrupts must be marked with the + DRM_CONNECTOR_POLL_HPD flag instead, and their interrupt handler must + call drm_helper_hpd_irq_event. The function will + queue a delayed work to check the state of all connectors, but no + periodic polling will be done. + + + + Connector Operations + + Unless otherwise state, all operations are mandatory. + + + DPMS + void (*dpms)(struct drm_connector *connector, int mode); + + The DPMS operation sets the power state of a connector. The mode + argument is one of + + DRM_MODE_DPMS_ON + DRM_MODE_DPMS_STANDBY + DRM_MODE_DPMS_SUSPEND + DRM_MODE_DPMS_OFF + + + + In all but DPMS_ON mode the encoder to which the connector is attached + should put the display in low-power mode by driving its signals + appropriately. If more than one connector is attached to the encoder + care should be taken not to change the power state of other displays as + a side effect. Low-power mode should be propagated to the encoders and + CRTCs when all related connectors are put in low-power mode. + + + + Modes + int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, + uint32_t max_height); + + Fill the mode list with all supported modes for the connector. If the + max_width and max_height + arguments are non-zero, the implementation must ignore all modes wider + than max_width or higher than + max_height. + + + The connector must also fill in this operation its + display_info + width_mm and + height_mm fields with the connected display + physical size in millimeters. The fields should be set to 0 if the value + isn't known or is not applicable (for instance for projector devices). + + + + Connection Status + + The connection status is updated through polling or hotplug events when + supported (see ). The status + value is reported to userspace through ioctls and must not be used + inside the driver, as it only gets initialized by a call to + drm_mode_getconnector from userspace. + + enum drm_connector_status (*detect)(struct drm_connector *connector, + bool force); + + Check to see if anything is attached to the connector. The + force parameter is set to false whilst polling or + to true when checking the connector due to user request. + force can be used by the driver to avoid + expensive, destructive operations during automated probing. + + + Return connector_status_connected if something is connected to the + connector, connector_status_disconnected if nothing is connected and + connector_status_unknown if the connection state isn't known. + + + Drivers should only return connector_status_connected if the connection + status has really been probed as connected. Connectors that can't detect + the connection status, or failed connection status probes, should return + connector_status_unknown. + + + + Miscellaneous + + + void (*destroy)(struct drm_connector *connector); + + Destroy the connector when not needed anymore. See + . + + + + + + + + Cleanup + + The DRM core manages its objects' lifetime. When an object is not needed + anymore the core calls its destroy function, which must clean up and + free every resource allocated for the object. Every + drm_*_init call must be matched with a + corresponding drm_*_cleanup call to cleanup CRTCs + (drm_crtc_cleanup), planes + (drm_plane_cleanup), encoders + (drm_encoder_cleanup) and connectors + (drm_connector_cleanup). Furthermore, connectors + that have been added to sysfs must be removed by a call to + drm_sysfs_connector_remove before calling + drm_connector_cleanup. + + + Connectors state change detection must be cleanup up with a call to + drm_kms_helper_poll_fini. + + + + Output discovery and initialization example + - - - In the example above (again, taken from the i915 driver), a - CRT connector and encoder combination is created. A device-specific - i2c bus is also created for fetching EDID data and - performing monitor detection. Once the process is complete, - the new connector is registered with sysfs to make its - properties available to applications. - - - Helper functions and core functions - - Since many PC-class graphics devices have similar display output - designs, the DRM provides a set of helper functions to make - output management easier. The core helper routines handle - encoder re-routing and the disabling of unused functions following - mode setting. Using the helpers is optional, but recommended for - devices with PC-style architectures (i.e. a set of display planes - for feeding pixels to encoders which are in turn routed to - connectors). Devices with more complex requirements needing - finer grained management may opt to use the core callbacks - directly. - - - [Insert typical diagram here.] [Insert OMAP style config here.] - - - - Each encoder object needs to provide: - - - A DPMS (basically on/off) function. - - - A mode-fixup function (for converting requested modes into - native hardware timings). - - - Functions (prepare, set, and commit) for use by the core DRM - helper functions. - - - Connector helpers need to provide functions (mode-fetch, validity, - and encoder-matching) for returning an ideal encoder for a given - connector. The core connector functions include a DPMS callback, - save/restore routines (deprecated), detection, mode probing, - property handling, and cleanup functions. - - - - - +}]]> + + In the example above (taken from the i915 driver), a CRTC, connector and + encoder combination is created. A device-specific i2c bus is also + created for fetching EDID data and performing monitor detection. Once + the process is complete, the new connector is registered with sysfs to + make its properties available to applications. + - + - VBlank event handling + Mid-layer Helper Functions - The DRM core exposes two vertical blank related ioctls: - - - DRM_IOCTL_WAIT_VBLANK - - - This takes a struct drm_wait_vblank structure as its argument, - and it is used to block or request a signal when a specified - vblank event occurs. - - - - - DRM_IOCTL_MODESET_CTL - - - This should be called by application level drivers before and - after mode setting, since on many devices the vertical blank - counter is reset at that time. Internally, the DRM snapshots - the last vblank count when the ioctl is called with the - _DRM_PRE_MODESET command, so that the counter won't go backwards - (which is dealt with when _DRM_POST_MODESET is used). - - - - - + The CRTC, encoder and connector functions provided by the drivers + implement the DRM API. They're called by the DRM core and ioctl handlers + to handle device state changes and configuration request. As implementing + those functions often requires logic not specific to drivers, mid-layer + helper functions are available to avoid duplicating boilerplate code. + + + The DRM core contains one mid-layer implementation. The mid-layer provides + implementations of several CRTC, encoder and connector functions (called + from the top of the mid-layer) that pre-process requests and call + lower-level functions provided by the driver (at the bottom of the + mid-layer). For instance, the + drm_crtc_helper_set_config function can be used to + fill the struct drm_crtc_funcs + set_config field. When called, it will split + the set_config operation in smaller, simpler + operations and call the driver to handle them. - To support the functions above, the DRM core provides several - helper functions for tracking vertical blank counters, and - requires drivers to provide several callbacks: - get_vblank_counter(), enable_vblank() and disable_vblank(). The - core uses get_vblank_counter() to keep the counter accurate - across interrupt disable periods. It should return the current - vertical blank event count, which is often tracked in a device - register. The enable and disable vblank callbacks should enable - and disable vertical blank interrupts, respectively. In the - absence of DRM clients waiting on vblank events, the core DRM - code uses the disable_vblank() function to disable - interrupts, which saves power. They are re-enabled again when - a client calls the vblank wait ioctl above. + To use the mid-layer, drivers call drm_crtc_helper_add, + drm_encoder_helper_add and + drm_connector_helper_add functions to install their + mid-layer bottom operations handlers, and fill the + drm_crtc_funcs, + drm_encoder_funcs and + drm_connector_funcs structures with pointers to + the mid-layer top API functions. Installing the mid-layer bottom operation + handlers is best done right after registering the corresponding KMS object. - A device that doesn't provide a count register may simply use an - internal atomic counter incremented on every vertical blank - interrupt (and then treat the enable_vblank() and disable_vblank() - callbacks as no-ops). + The mid-layer is not split between CRTC, encoder and connector operations. + To use it, a driver must provide bottom functions for all of the three KMS + entities. + + Helper Functions + + + int drm_crtc_helper_set_config(struct drm_mode_set *set); + + The drm_crtc_helper_set_config helper function + is a CRTC set_config implementation. It + first tries to locate the best encoder for each connector by calling + the connector best_encoder helper + operation. + + + After locating the appropriate encoders, the helper function will + call the mode_fixup encoder and CRTC helper + operations to adjust the requested mode, or reject it completely in + which case an error will be returned to the application. If the new + configuration after mode adjustment is identical to the current + configuration the helper function will return without performing any + other operation. + + + If the adjusted mode is identical to the current mode but changes to + the frame buffer need to be applied, the + drm_crtc_helper_set_config function will call + the CRTC mode_set_base helper operation. If + the adjusted mode differs from the current mode, or if the + mode_set_base helper operation is not + provided, the helper function performs a full mode set sequence by + calling the prepare, + mode_set and + commit CRTC and encoder helper operations, + in that order. + + + + void drm_helper_connector_dpms(struct drm_connector *connector, int mode); + + The drm_helper_connector_dpms helper function + is a connector dpms implementation that + tracks power state of connectors. To use the function, drivers must + provide dpms helper operations for CRTCs + and encoders to apply the DPMS state to the device. + + + The mid-layer doesn't track the power state of CRTCs and encoders. + The dpms helper operations can thus be + called with a mode identical to the currently active mode. + + + + int drm_helper_probe_single_connector_modes(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY); + + The drm_helper_probe_single_connector_modes helper + function is a connector fill_modes + implementation that updates the connection status for the connector + and then retrieves a list of modes by calling the connector + get_modes helper operation. + + + The function filters out modes larger than + max_width and max_height + if specified. It then calls the connector + mode_valid helper operation for each mode in + the probed list to check whether the mode is valid for the connector. + + + + + + CRTC Helper Operations + + + bool (*mode_fixup)(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + Let CRTCs adjust the requested mode or reject it completely. This + operation returns true if the mode is accepted (possibly after being + adjusted) or false if it is rejected. + + + The mode_fixup operation should reject the + mode if it can't reasonably use it. The definition of "reasonable" + is currently fuzzy in this context. One possible behaviour would be + to set the adjusted mode to the panel timings when a fixed-mode + panel is used with hardware capable of scaling. Another behaviour + would be to accept any input mode and adjust it to the closest mode + supported by the hardware (FIXME: This needs to be clarified). + + + + int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) + + Move the CRTC on the current frame buffer (stored in + crtc->fb) to position (x,y). Any of the frame + buffer, x position or y position may have been modified. + + + This helper operation is optional. If not provided, the + drm_crtc_helper_set_config function will fall + back to the mode_set helper operation. + + + FIXME: Why are x and y passed as arguments, as they can be accessed + through crtc->x and + crtc->y? + + + + void (*prepare)(struct drm_crtc *crtc); + + Prepare the CRTC for mode setting. This operation is called after + validating the requested mode. Drivers use it to perform + device-specific operations required before setting the new mode. + + + + int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, int x, int y, + struct drm_framebuffer *old_fb); + + Set a new mode, position and frame buffer. Depending on the device + requirements, the mode can be stored internally by the driver and + applied in the commit operation, or + programmed to the hardware immediately. + + + The mode_set operation returns 0 on success + or a negative error code if an error occurs. + + + + void (*commit)(struct drm_crtc *crtc); + + Commit a mode. This operation is called after setting the new mode. + Upon return the device must use the new mode and be fully + operational. + + + + + + Encoder Helper Operations + + + bool (*mode_fixup)(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + FIXME: The mode argument be const, but the i915 driver modifies + mode->clock in intel_dp_mode_fixup. + + + Let encoders adjust the requested mode or reject it completely. This + operation returns true if the mode is accepted (possibly after being + adjusted) or false if it is rejected. See the + mode_fixup CRTC helper + operation for an explanation of the allowed adjustments. + + + + void (*prepare)(struct drm_encoder *encoder); + + Prepare the encoder for mode setting. This operation is called after + validating the requested mode. Drivers use it to perform + device-specific operations required before setting the new mode. + + + + void (*mode_set)(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + Set a new mode. Depending on the device requirements, the mode can + be stored internally by the driver and applied in the + commit operation, or programmed to the + hardware immediately. + + + + void (*commit)(struct drm_encoder *encoder); + + Commit a mode. This operation is called after setting the new mode. + Upon return the device must use the new mode and be fully + operational. + + + + + + Connector Helper Operations + + + struct drm_encoder *(*best_encoder)(struct drm_connector *connector); + + Return a pointer to the best encoder for the connecter. Device that + map connectors to encoders 1:1 simply return the pointer to the + associated encoder. This operation is mandatory. + + + + int (*get_modes)(struct drm_connector *connector); + + Fill the connector's probed_modes list + by parsing EDID data with drm_add_edid_modes or + calling drm_mode_probed_add directly for every + supported mode and return the number of modes it has detected. This + operation is mandatory. + + + When adding modes manually the driver creates each mode with a call to + drm_mode_create and must fill the following fields. + + + __u32 type; + + Mode type bitmask, a combination of + + + DRM_MODE_TYPE_BUILTIN + not used? + + + DRM_MODE_TYPE_CLOCK_C + not used? + + + DRM_MODE_TYPE_CRTC_C + not used? + + + + DRM_MODE_TYPE_PREFERRED - The preferred mode for the connector + + + not used? + + + + DRM_MODE_TYPE_DEFAULT + not used? + + + DRM_MODE_TYPE_USERDEF + not used? + + + DRM_MODE_TYPE_DRIVER + + + The mode has been created by the driver (as opposed to + to user-created modes). + + + + + Drivers must set the DRM_MODE_TYPE_DRIVER bit for all modes they + create, and set the DRM_MODE_TYPE_PREFERRED bit for the preferred + mode. + + + + __u32 clock; + Pixel clock frequency in kHz unit + + + __u16 hdisplay, hsync_start, hsync_end, htotal; + __u16 vdisplay, vsync_start, vsync_end, vtotal; + Horizontal and vertical timing information + <----------------><-------------><--------------> + + //////////////////////| + ////////////////////// | + ////////////////////// |.................. ................ + _______________ + + <----- [hv]display -----> + <------------- [hv]sync_start ------------> + <--------------------- [hv]sync_end ---------------------> + <-------------------------------- [hv]total -----------------------------> +]]> + + + __u16 hskew; + __u16 vscan; + Unknown + + + __u32 flags; + + Mode flags, a combination of + + + DRM_MODE_FLAG_PHSYNC + + Horizontal sync is active high + + + + DRM_MODE_FLAG_NHSYNC + + Horizontal sync is active low + + + + DRM_MODE_FLAG_PVSYNC + + Vertical sync is active high + + + + DRM_MODE_FLAG_NVSYNC + + Vertical sync is active low + + + + DRM_MODE_FLAG_INTERLACE + + Mode is interlaced + + + + DRM_MODE_FLAG_DBLSCAN + + Mode uses doublescan + + + + DRM_MODE_FLAG_CSYNC + + Mode uses composite sync + + + + DRM_MODE_FLAG_PCSYNC + + Composite sync is active high + + + + DRM_MODE_FLAG_NCSYNC + + Composite sync is active low + + + + DRM_MODE_FLAG_HSKEW + + hskew provided (not used?) + + + + DRM_MODE_FLAG_BCAST + + not used? + + + + DRM_MODE_FLAG_PIXMUX + + not used? + + + + DRM_MODE_FLAG_DBLCLK + + not used? + + + + DRM_MODE_FLAG_CLKDIV2 + + ? + + + + + + Note that modes marked with the INTERLACE or DBLSCAN flags will be + filtered out by + drm_helper_probe_single_connector_modes if + the connector's interlace_allowed or + doublescan_allowed field is set to 0. + + + + char name[DRM_DISPLAY_MODE_LEN]; + + Mode name. The driver must call + drm_mode_set_name to fill the mode name from + hdisplay, + vdisplay and interlace flag after + filling the corresponding fields. + + + + + + The vrefresh value is computed by + drm_helper_probe_single_connector_modes. + + + When parsing EDID data, drm_add_edid_modes fill the + connector display_info + width_mm and + height_mm fields. When creating modes + manually the get_modes helper operation must + set the display_info + width_mm and + height_mm fields if they haven't been set + already (for instance at initilization time when a fixed-size panel is + attached to the connector). The mode width_mm + and height_mm fields are only used internally + during EDID parsing and should not be set when creating modes manually. + + + + int (*mode_valid)(struct drm_connector *connector, + struct drm_display_mode *mode); + + Verify whether a mode is valid for the connector. Return MODE_OK for + supported modes and one of the enum drm_mode_status values (MODE_*) + for unsupported modes. This operation is mandatory. + + + As the mode rejection reason is currently not used beside for + immediately removing the unsupported mode, an implementation can + return MODE_BAD regardless of the exact reason why the mode is not + valid. + + + Note that the mode_valid helper operation is + only called for modes detected by the device, and + not for modes set by the user through the CRTC + set_config operation. + + + + - - Memory management + + + + Vertical Blanking + + Vertical blanking plays a major role in graphics rendering. To achieve + tear-free display, users must synchronize page flips and/or rendering to + vertical blanking. The DRM API offers ioctls to perform page flips + synchronized to vertical blanking and wait for vertical blanking. + + + The DRM core handles most of the vertical blanking management logic, which + involves filtering out spurious interrupts, keeping race-free blanking + counters, coping with counter wrap-around and resets and keeping use + counts. It relies on the driver to generate vertical blanking interrupts + and optionally provide a hardware vertical blanking counter. Drivers must + implement the following operations. + + + + int (*enable_vblank) (struct drm_device *dev, int crtc); +void (*disable_vblank) (struct drm_device *dev, int crtc); + + Enable or disable vertical blanking interrupts for the given CRTC. + + + + u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); + + Retrieve the value of the vertical blanking counter for the given + CRTC. If the hardware maintains a vertical blanking counter its value + should be returned. Otherwise drivers can use the + drm_vblank_count helper function to handle this + operation. + + + - The memory manager lies at the heart of many DRM operations; it - is required to support advanced client features like OpenGL - pbuffers. The DRM currently contains two memory managers: TTM - and GEM. + Drivers must initialize the vertical blanking handling core with a call to + drm_vblank_init in their + load operation. The function will set the struct + drm_device + vblank_disable_allowed field to 0. This will + keep vertical blanking interrupts enabled permanently until the first mode + set operation, where vblank_disable_allowed is + set to 1. The reason behind this is not clear. Drivers can set the field + to 1 after calling drm_vblank_init to make vertical + blanking interrupts dynamically managed from the beginning. + + Vertical blanking interrupts can be enabled by the DRM core or by drivers + themselves (for instance to handle page flipping operations). The DRM core + maintains a vertical blanking use count to ensure that the interrupts are + not disabled while a user still needs them. To increment the use count, + drivers call drm_vblank_get. Upon return vertical + blanking interrupts are guaranteed to be enabled. + + + To decrement the use count drivers call + drm_vblank_put. Only when the use count drops to zero + will the DRM core disable the vertical blanking interrupts after a delay + by scheduling a timer. The delay is accessible through the vblankoffdelay + module parameter or the drm_vblank_offdelay global + variable and expressed in milliseconds. Its default value is 5000 ms. + + + When a vertical blanking interrupt occurs drivers only need to call the + drm_handle_vblank function to account for the + interrupt. + + + Resources allocated by drm_vblank_init must be freed + with a call to drm_vblank_cleanup in the driver + unload operation handler. + + + + + + Open/Close, File Operations and IOCTLs - The Translation Table Manager (TTM) + Open and Close + int (*firstopen) (struct drm_device *); +void (*lastclose) (struct drm_device *); +int (*open) (struct drm_device *, struct drm_file *); +void (*preclose) (struct drm_device *, struct drm_file *); +void (*postclose) (struct drm_device *, struct drm_file *); + Open and close handlers. None of those methods are mandatory. + - TTM was developed by Tungsten Graphics, primarily by Thomas - Hellström, and is intended to be a flexible, high performance - graphics memory manager. + The firstopen method is called by the DRM core + when an application opens a device that has no other opened file handle. + Similarly the lastclose method is called when + the last application holding a file handle opened on the device closes + it. Both methods are mostly used for UMS (User Mode Setting) drivers to + acquire and release device resources which should be done in the + load and unload + methods for KMS drivers. - Drivers wishing to support TTM must fill out a drm_bo_driver - structure. + Note that the lastclose method is also called + at module unload time or, for hot-pluggable devices, when the device is + unplugged. The firstopen and + lastclose calls can thus be unbalanced. - TTM design background and information belongs here. + The open method is called every time the device + is opened by an application. Drivers can allocate per-file private data + in this method and store them in the struct + drm_file driver_priv + field. Note that the open method is called + before firstopen. + + + The close operation is split into preclose and + postclose methods. Drivers must stop and + cleanup all per-file operations in the preclose + method. For instance pending vertical blanking and page flip events must + be cancelled. No per-file operation is allowed on the file handle after + returning from the preclose method. + + + Finally the postclose method is called as the + last step of the close operation, right before calling the + lastclose method if no other open file handle + exists for the device. Drivers that have allocated per-file private data + in the open method should free it here. + + + The lastclose method should restore CRTC and + plane properties to default value, so that a subsequent open of the + device will not inherit state from the previous user. - - The Graphics Execution Manager (GEM) + File Operations + const struct file_operations *fops + File operations for the DRM device node. - GEM is an Intel project, authored by Eric Anholt and Keith - Packard. It provides simpler interfaces than TTM, and is well - suited for UMA devices. + Drivers must define the file operations structure that forms the DRM + userspace API entry point, even though most of those operations are + implemented in the DRM core. The open, + release and ioctl + operations are handled by + + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + #ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, + #endif + - GEM-enabled drivers must provide gem_init_object() and - gem_free_object() callbacks to support the core memory - allocation routines. They should also provide several driver-specific - ioctls to support command execution, pinning, buffer - read & write, mapping, and domain ownership transfers. + Drivers that implement private ioctls that requires 32/64bit + compatibility support must provide their own + compat_ioctl handler that processes private + ioctls and calls drm_compat_ioctl for core ioctls. - On a fundamental level, GEM involves several operations: - - Memory allocation and freeing - Command execution - Aperture management at command execution time - - Buffer object allocation is relatively - straightforward and largely provided by Linux's shmem layer, which - provides memory to back each object. When mapped into the GTT - or used in a command buffer, the backing pages for an object are - flushed to memory and marked write combined so as to be coherent - with the GPU. Likewise, if the CPU accesses an object after the GPU - has finished rendering to the object, then the object must be made - coherent with the CPU's view - of memory, usually involving GPU cache flushing of various kinds. - This core CPU<->GPU coherency management is provided by a - device-specific ioctl, which evaluates an object's current domain and - performs any necessary flushing or synchronization to put the object - into the desired coherency domain (note that the object may be busy, - i.e. an active render target; in that case, setting the domain - blocks the client and waits for rendering to complete before - performing any necessary flushing operations). - - - Perhaps the most important GEM function is providing a command - execution interface to clients. Client programs construct command - buffers containing references to previously allocated memory objects, - and then submit them to GEM. At that point, GEM takes care to bind - all the objects into the GTT, execute the buffer, and provide - necessary synchronization between clients accessing the same buffers. - This often involves evicting some objects from the GTT and re-binding - others (a fairly expensive operation), and providing relocation - support which hides fixed GTT offsets from clients. Clients must - take care not to submit command buffers that reference more objects - than can fit in the GTT; otherwise, GEM will reject them and no rendering - will occur. Similarly, if several objects in the buffer require - fence registers to be allocated for correct rendering (e.g. 2D blits - on pre-965 chips), care must be taken not to require more fence - registers than are available to the client. Such resource management - should be abstracted from the client in libdrm. + The read and poll + operations provide support for reading DRM events and polling them. They + are implemented by + + .poll = drm_poll, + .read = drm_read, + .fasync = drm_fasync, + .llseek = no_llseek, + + + + The memory mapping implementation varies depending on how the driver + manages memory. Pre-GEM drivers will use drm_mmap, + while GEM-aware drivers will use drm_gem_mmap. See + . + + .mmap = drm_gem_mmap, + + + + No other file operation is supported by the DRM API. + + + + IOCTLs + struct drm_ioctl_desc *ioctls; +int num_ioctls; + Driver-specific ioctls descriptors table. + + Driver-specific ioctls numbers start at DRM_COMMAND_BASE. The ioctls + descriptors table is indexed by the ioctl number offset from the base + value. Drivers can use the DRM_IOCTL_DEF_DRV() macro to initialize the + table entries. + + + DRM_IOCTL_DEF_DRV(ioctl, func, flags) + + ioctl is the ioctl name. Drivers must define + the DRM_##ioctl and DRM_IOCTL_##ioctl macros to the ioctl number + offset from DRM_COMMAND_BASE and the ioctl number respectively. The + first macro is private to the device while the second must be exposed + to userspace in a public header. + + + func is a pointer to the ioctl handler function + compatible with the drm_ioctl_t type. + typedef int drm_ioctl_t(struct drm_device *dev, void *data, + struct drm_file *file_priv); + + + flags is a bitmask combination of the following + values. It restricts how the ioctl is allowed to be called. + + + DRM_AUTH - Only authenticated callers allowed + + + DRM_MASTER - The ioctl can only be called on the master file + handle + + + DRM_ROOT_ONLY - Only callers with the SYSADMIN capability allowed + + + DRM_CONTROL_ALLOW - The ioctl can only be called on a control + device + + + DRM_UNLOCKED - The ioctl handler will be called without locking + the DRM global mutex + + + - - - - - - Output management - - At the core of the DRM output management code is a set of - structures representing CRTCs, encoders, and connectors. - - - A CRTC is an abstraction representing a part of the chip that - contains a pointer to a scanout buffer. Therefore, the number - of CRTCs available determines how many independent scanout - buffers can be active at any given time. The CRTC structure - contains several fields to support this: a pointer to some video - memory, a display mode, and an (x, y) offset into the video - memory to support panning or configurations where one piece of - video memory spans multiple CRTCs. - - - An encoder takes pixel data from a CRTC and converts it to a - format suitable for any attached connectors. On some devices, - it may be possible to have a CRTC send data to more than one - encoder. In that case, both encoders would receive data from - the same scanout buffer, resulting in a "cloned" display - configuration across the connectors attached to each encoder. - - - A connector is the final destination for pixel data on a device, - and usually connects directly to an external display device like - a monitor or laptop panel. A connector can only be attached to - one encoder at a time. The connector is also the structure - where information about the attached display is kept, so it - contains fields for display data, EDID data, DPMS & - connection status, and information about modes supported on the - attached displays. - - - - - - Framebuffer management - - Clients need to provide a framebuffer object which provides a source - of pixels for a CRTC to deliver to the encoder(s) and ultimately the - connector(s). A framebuffer is fundamentally a driver-specific memory - object, made into an opaque handle by the DRM's addfb() function. - Once a framebuffer has been created this way, it may be passed to the - KMS mode setting routines for use in a completed configuration. - @@ -812,15 +2355,24 @@ void intel_crt_init(struct drm_device *dev) + + - Suspend/resume + Suspend/Resume + + The DRM core provides some suspend/resume code, but drivers wanting full + suspend/resume support should provide save() and restore() functions. + These are called at suspend, hibernate, or resume time, and should perform + any state save or restore required by your device across suspend or + hibernate states. + + int (*suspend) (struct drm_device *, pm_message_t state); +int (*resume) (struct drm_device *); - The DRM core provides some suspend/resume code, but drivers - wanting full suspend/resume support should provide save() and - restore() functions. These are called at suspend, - hibernate, or resume time, and should perform any state save or - restore required by your device across suspend or hibernate - states. + Those are legacy suspend and resume methods. New driver should use the + power management interface provided by their bus type (usually through + the struct device_driver dev_pm_ops) and set + these methods to NULL. @@ -833,6 +2385,35 @@ void intel_crt_init(struct drm_device *dev) + + @@ -853,6 +2434,42 @@ void intel_crt_init(struct drm_device *dev) Cover generic ioctls and sysfs layout here. We only need high-level info, since man pages should cover the rest. + + + + + VBlank event handling + + The DRM core exposes two vertical blank related ioctls: + + + DRM_IOCTL_WAIT_VBLANK + + + This takes a struct drm_wait_vblank structure as its argument, + and it is used to block or request a signal when a specified + vblank event occurs. + + + + + DRM_IOCTL_MODESET_CTL + + + This should be called by application level drivers before and + after mode setting, since on many devices the vertical blank + counter is reset at that time. Internally, the DRM snapshots + the last vblank count when the ioctl is called with the + _DRM_PRE_MODESET command, so that the counter won't go backwards + (which is dealt with when _DRM_POST_MODESET is used). + + + + + + + + -- cgit v1.2.3-70-g09d2 From 50243efde0993f6fe98f27a35692d0e8efdf7a0f Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Sat, 28 Jul 2012 16:05:55 +0100 Subject: ARM: perf: add devicetree bindings for 11MPcore, A5, A7 and A15 PMUs This patch adds separate devicetree bindings for 11MPcore and Cortex-{A5,A7,A15} PMUs in preparation for improved devicetree parsing in the ARM perf-event CPU PMU driver. Cc: Grant Likely Acked-by: Rob Herring Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/arm/pmu.txt | 4 ++++ arch/arm/kernel/perf_event.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt index 1c044eb320c..343781b9f24 100644 --- a/Documentation/devicetree/bindings/arm/pmu.txt +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -7,8 +7,12 @@ representation in the device tree should be done as under:- Required properties: - compatible : should be one of + "arm,cortex-a15-pmu" "arm,cortex-a9-pmu" "arm,cortex-a8-pmu" + "arm,cortex-a7-pmu" + "arm,cortex-a5-pmu" + "arm,arm11mpcore-pmu" "arm,arm1176-pmu" "arm,arm1136-pmu" - interrupts : 1 combined interrupt or 1 per core. diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index c44647ef735..3aa33884913 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -646,10 +646,14 @@ arch_initcall(cpu_pmu_reset); * PMU platform driver and devicetree bindings. */ static struct of_device_id armpmu_of_device_ids[] = { + {.compatible = "arm,cortex-a15-pmu"}, {.compatible = "arm,cortex-a9-pmu"}, {.compatible = "arm,cortex-a8-pmu"}, - {.compatible = "arm,arm1136-pmu"}, + {.compatible = "arm,cortex-a7-pmu"}, + {.compatible = "arm,cortex-a5-pmu"}, + {.compatible = "arm,arm11mpcore-pmu"}, {.compatible = "arm,arm1176-pmu"}, + {.compatible = "arm,arm1136-pmu"}, {}, }; -- cgit v1.2.3-70-g09d2 From 536a23f119e35e58c762a219bafd398ba2ed7980 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 18 Jun 2012 18:39:26 +0200 Subject: batman-adv: Add the backbone gateway list to debugfs This is especially useful if there are no claims yet, but we still want to know which gateways are using bridge loop avoidance in the network. Signed-off-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- Documentation/networking/batman-adv.txt | 7 ++-- net/batman-adv/bridge_loop_avoidance.c | 65 +++++++++++++++++++++++++++++++++ net/batman-adv/bridge_loop_avoidance.h | 8 ++++ net/batman-adv/debugfs.c | 12 ++++++ 4 files changed, 89 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt index 8f3ae4a6147..a173d2a879f 100644 --- a/Documentation/networking/batman-adv.txt +++ b/Documentation/networking/batman-adv.txt @@ -75,9 +75,10 @@ folder: There is a special folder for debugging information: -# ls /sys/kernel/debug/batman_adv/bat0/ -# bla_claim_table log socket transtable_local -# gateways originators transtable_global vis_data +# ls /sys/kernel/debug/batman_adv/bat0/ +# bla_backbone_table log transtable_global +# bla_claim_table originators transtable_local +# gateways socket vis_data Some of the files contain all sort of status information regard- ing the mesh network. For example, you can view the table of diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 6705d35b17c..7e60466f571 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -1616,3 +1616,68 @@ out: batadv_hardif_free_ref(primary_if); return ret; } + +int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset) +{ + struct net_device *net_dev = (struct net_device *)seq->private; + struct batadv_priv *bat_priv = netdev_priv(net_dev); + struct batadv_hashtable *hash = bat_priv->backbone_hash; + struct batadv_backbone_gw *backbone_gw; + struct batadv_hard_iface *primary_if; + struct hlist_node *node; + struct hlist_head *head; + int secs, msecs; + uint32_t i; + bool is_own; + int ret = 0; + uint8_t *primary_addr; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, + "BATMAN mesh %s disabled - please specify interfaces to enable it\n", + net_dev->name); + goto out; + } + + if (primary_if->if_status != BATADV_IF_ACTIVE) { + ret = seq_printf(seq, + "BATMAN mesh %s disabled - primary interface not active\n", + net_dev->name); + goto out; + } + + primary_addr = primary_if->net_dev->dev_addr; + seq_printf(seq, + "Backbones announced for the mesh %s (orig %pM, group id %04x)\n", + net_dev->name, primary_addr, + ntohs(bat_priv->claim_dest.group)); + seq_printf(seq, " %-17s %-5s %-9s (%-4s)\n", + "Originator", "VID", "last seen", "CRC"); + for (i = 0; i < hash->size; i++) { + head = &hash->table[i]; + + rcu_read_lock(); + hlist_for_each_entry_rcu(backbone_gw, node, head, hash_entry) { + msecs = jiffies_to_msecs(jiffies - + backbone_gw->lasttime); + secs = msecs / 1000; + msecs = msecs % 1000; + + is_own = batadv_compare_eth(backbone_gw->orig, + primary_addr); + if (is_own) + continue; + + seq_printf(seq, + " * %pM on % 5d % 4i.%03is (%04x)\n", + backbone_gw->orig, backbone_gw->vid, + secs, msecs, backbone_gw->crc); + } + rcu_read_unlock(); + } +out: + if (primary_if) + batadv_hardif_free_ref(primary_if); + return ret; +} diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index 3f0dfa2f6d7..789cb73bde6 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h @@ -27,6 +27,8 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid); int batadv_bla_is_backbone_gw(struct sk_buff *skb, struct batadv_orig_node *orig_node, int hdr_size); int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); +int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, + void *offset); int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig); int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, struct batadv_bcast_packet *bcast_packet, @@ -65,6 +67,12 @@ static inline int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, return 0; } +static inline int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, + void *offset) +{ + return 0; +} + static inline int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) { diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index 34fbb1667bc..391d4fb2026 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c @@ -267,6 +267,15 @@ static int batadv_bla_claim_table_open(struct inode *inode, struct file *file) return single_open(file, batadv_bla_claim_table_seq_print_text, net_dev); } + +static int batadv_bla_backbone_table_open(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, batadv_bla_backbone_table_seq_print_text, + net_dev); +} + #endif static int batadv_transtable_local_open(struct inode *inode, struct file *file) @@ -305,6 +314,8 @@ static BATADV_DEBUGINFO(transtable_global, S_IRUGO, batadv_transtable_global_open); #ifdef CONFIG_BATMAN_ADV_BLA static BATADV_DEBUGINFO(bla_claim_table, S_IRUGO, batadv_bla_claim_table_open); +static BATADV_DEBUGINFO(bla_backbone_table, S_IRUGO, + batadv_bla_backbone_table_open); #endif static BATADV_DEBUGINFO(transtable_local, S_IRUGO, batadv_transtable_local_open); @@ -316,6 +327,7 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { &batadv_debuginfo_transtable_global, #ifdef CONFIG_BATMAN_ADV_BLA &batadv_debuginfo_bla_claim_table, + &batadv_debuginfo_bla_backbone_table, #endif &batadv_debuginfo_transtable_local, &batadv_debuginfo_vis_data, -- cgit v1.2.3-70-g09d2 From ca6d43b051b5a061b33c43303b6b4c93b46a34b5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:41:41 -0700 Subject: [SCSI] libata: reset once Hotplug testing with libsas currently encounters a 55 second wait for link recovery to give up. In the case where the user trusts the response time of their devices permit the recovery attempts to be limited to one. Signed-off-by: Dan Williams Acked-by: Jeff Garzik Acked-by: Tejun Heo Signed-off-by: James Bottomley --- Documentation/kernel-parameters.txt | 3 +++ drivers/ata/libata-core.c | 1 + drivers/ata/libata-eh.c | 2 ++ include/linux/libata.h | 1 + 4 files changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ad7e2e5088c..2cb2d81a51a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1350,6 +1350,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. * nohrst, nosrst, norst: suppress hard, soft and both resets. + * rstonce: only attempt one reset during + hot-unplug link recovery + * dump_id: dump IDENTIFY data. If there are multiple matching configurations changing diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fadd5866d40..70964aabcb8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6387,6 +6387,7 @@ static int __init ata_parse_force_one(char **cur, { "nohrst", .lflags = ATA_LFLAG_NO_HRST }, { "nosrst", .lflags = ATA_LFLAG_NO_SRST }, { "norst", .lflags = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST }, + { "rstonce", .lflags = ATA_LFLAG_RST_ONCE }, }; char *start = *cur, *p = *cur; char *id, *val, *endp; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7d4535e989b..100428dde42 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2623,6 +2623,8 @@ int ata_eh_reset(struct ata_link *link, int classify, */ while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX) max_tries++; + if (link->flags & ATA_LFLAG_RST_ONCE) + max_tries = 1; if (link->flags & ATA_LFLAG_NO_HRST) hardreset = NULL; if (link->flags & ATA_LFLAG_NO_SRST) diff --git a/include/linux/libata.h b/include/linux/libata.h index 64f90e17e51..31a2853e953 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -184,6 +184,7 @@ enum { ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ + ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ -- cgit v1.2.3-70-g09d2 From cdd75750a17519cb8e8383ef1b19e8524c8903fe Mon Sep 17 00:00:00 2001 From: adam radford Date: Tue, 17 Jul 2012 18:21:01 -0700 Subject: [SCSI] megaraid_sas: Version and Changelog update Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- Documentation/scsi/ChangeLog.megaraid_sas | 10 ++++++++++ drivers/scsi/megaraid/megaraid_sas.h | 6 +++--- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas index 80441ab608e..3a3079411a3 100644 --- a/Documentation/scsi/ChangeLog.megaraid_sas +++ b/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,3 +1,13 @@ +Release Date : Tue. Jun 17, 2012 17:00:00 PST 2012 - + (emaild-id:megaraidlinux@lsi.com) + Adam Radford/Kashyap Desai +Current Version : 00.00.06.18-rc1 +Old Version : 00.00.06.15-rc1 + 1. Fix Copyright dates. + 2. Add throttlequeuedepth module parameter. + 3. Add resetwaittime module parameter. + 4. Move poll_aen_lock initializer. +------------------------------------------------------------------------------- Release Date : Mon. Mar 19, 2012 17:00:00 PST 2012 - (emaild-id:megaraidlinux@lsi.com) Adam Radford diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index f65025d63bc..fcb005fa4bd 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -33,9 +33,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.06.15-rc1" -#define MEGASAS_RELDATE "Mar. 19, 2012" -#define MEGASAS_EXT_VERSION "Mon. Mar. 19 17:00:00 PDT 2012" +#define MEGASAS_VERSION "00.00.06.18-rc1" +#define MEGASAS_RELDATE "Jun. 17, 2012" +#define MEGASAS_EXT_VERSION "Tue. Jun. 17 17:00:00 PDT 2012" /* * Device IDs diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 2ee7052ac6b..7cd70e8c4bd 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * FILE: megaraid_sas_base.c - * Version : v00.00.06.15-rc1 + * Version : v00.00.06.18-rc1 * * Authors: LSI Corporation * Sreenivas Bagalkote -- cgit v1.2.3-70-g09d2 From c2b5acc3a3ba80bef61b9df712004e83cbab4a11 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 24 Aug 2012 14:32:07 -0600 Subject: PCI: Remove the fakephp driver The fakephp driver was scheduled for removal in 2011. Fakephp presented /sys/bus/pci/slots/.../power files for every PCI function. Writing "0" to one of these files logically removed the device from the system. The PCI core now provides the same functionality with /sys/bus/pci/devices/.../remove. Signed-off-by: Bjorn Helgaas --- Documentation/feature-removal-schedule.txt | 32 ------ drivers/pci/hotplug/Kconfig | 24 +---- drivers/pci/hotplug/Makefile | 3 - drivers/pci/hotplug/fakephp.c | 164 ----------------------------- 4 files changed, 1 insertion(+), 222 deletions(-) delete mode 100644 drivers/pci/hotplug/fakephp.c (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index afaff312bf4..529e8323ca8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -253,38 +253,6 @@ Who: Dave Jones , Matthew Garrett ----------------------------- -What: fakephp and associated sysfs files in /sys/bus/pci/slots/ -When: 2011 -Why: In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to - represent a machine's physical PCI slots. The change in semantics - had userspace implications, as the hotplug core no longer allowed - drivers to create multiple sysfs files per physical slot (required - for multi-function devices, e.g.). fakephp was seen as a developer's - tool only, and its interface changed. Too late, we learned that - there were some users of the fakephp interface. - - In 2.6.30, the original fakephp interface was restored. At the same - time, the PCI core gained the ability that fakephp provided, namely - function-level hot-remove and hot-add. - - Since the PCI core now provides the same functionality, exposed in: - - /sys/bus/pci/rescan - /sys/bus/pci/devices/.../remove - /sys/bus/pci/devices/.../rescan - - there is no functional reason to maintain fakephp as well. - - We will keep the existing module so that 'modprobe fakephp' will - present the old /sys/bus/pci/slots/... interface for compatibility, - but users are urged to migrate their applications to the API above. - - After a reasonable transition period, we will remove the legacy - fakephp interface. -Who: Alex Chiang - ---------------------------- - What: CONFIG_RFKILL_INPUT When: 2.6.33 Why: Should be implemented in userspace, policy daemon. diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 66f29bc00be..b0e46dede1a 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -17,28 +17,6 @@ menuconfig HOTPLUG_PCI if HOTPLUG_PCI -config HOTPLUG_PCI_FAKE - tristate "Fake PCI Hotplug driver" - help - Say Y here if you want to use the fake PCI hotplug driver. It can - be used to simulate PCI hotplug events if even if your system is - not PCI hotplug capable. - - This driver will "emulate" removing PCI devices from the system. - If the "power" file is written to with "0" then the specified PCI - device will be completely removed from the kernel. - - WARNING, this does NOT turn off the power to the PCI device. - This is a "logical" removal, not a physical or electrical - removal. - - Use this module at your own risk. You have been warned! - - To compile this driver as a module, choose M here: the - module will be called fakephp. - - When in doubt, say N. - config HOTPLUG_PCI_COMPAQ tristate "Compaq PCI Hotplug driver" depends on X86 && PCI_BIOS @@ -143,7 +121,7 @@ config HOTPLUG_PCI_SHPC config HOTPLUG_PCI_RPA tristate "RPA PCI Hotplug driver" - depends on PPC_PSERIES && EEH && !HOTPLUG_PCI_FAKE + depends on PPC_PSERIES && EEH help Say Y here if you have a RPA system that supports PCI Hotplug. diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 6cd9f3c9887..c459cd4e39c 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -23,9 +23,6 @@ obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o -# Link this last so it doesn't claim devices that have a real hotplug driver -obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o - pci_hotplug-objs := pci_hotplug_core.o pcihp_slot.o ifdef CONFIG_HOTPLUG_PCI_CPCI diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c deleted file mode 100644 index a019c9a712b..00000000000 --- a/drivers/pci/hotplug/fakephp.c +++ /dev/null @@ -1,164 +0,0 @@ -/* Works like the fakephp driver used to, except a little better. - * - * - It's possible to remove devices with subordinate busses. - * - New PCI devices that appear via any method, not just a fakephp triggered - * rescan, will be noticed. - * - Devices that are removed via any method, not just a fakephp triggered - * removal, will also be noticed. - * - * Uses nothing from the pci-hotplug subsystem. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../pci.h" - -struct legacy_slot { - struct kobject kobj; - struct pci_dev *dev; - struct list_head list; -}; - -static LIST_HEAD(legacy_list); - -static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj); - strcpy(buf, "1\n"); - return 2; -} - -static void remove_callback(void *data) -{ - pci_stop_and_remove_bus_device((struct pci_dev *)data); -} - -static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t len) -{ - struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj); - unsigned long val; - - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; - - if (val) - pci_rescan_bus(slot->dev->bus); - else - sysfs_schedule_callback(&slot->dev->dev.kobj, remove_callback, - slot->dev, THIS_MODULE); - return len; -} - -static struct attribute *legacy_attrs[] = { - &(struct attribute){ .name = "power", .mode = 0644 }, - NULL, -}; - -static void legacy_release(struct kobject *kobj) -{ - struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj); - - pci_dev_put(slot->dev); - kfree(slot); -} - -static struct kobj_type legacy_ktype = { - .sysfs_ops = &(const struct sysfs_ops){ - .store = legacy_store, .show = legacy_show - }, - .release = &legacy_release, - .default_attrs = legacy_attrs, -}; - -static int legacy_add_slot(struct pci_dev *pdev) -{ - struct legacy_slot *slot = kzalloc(sizeof(*slot), GFP_KERNEL); - - if (!slot) - return -ENOMEM; - - if (kobject_init_and_add(&slot->kobj, &legacy_ktype, - &pci_slots_kset->kobj, "%s", - dev_name(&pdev->dev))) { - dev_warn(&pdev->dev, "Failed to created legacy fake slot\n"); - return -EINVAL; - } - slot->dev = pci_dev_get(pdev); - - list_add(&slot->list, &legacy_list); - - return 0; -} - -static int legacy_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct pci_dev *pdev = to_pci_dev(data); - - if (action == BUS_NOTIFY_ADD_DEVICE) { - legacy_add_slot(pdev); - } else if (action == BUS_NOTIFY_DEL_DEVICE) { - struct legacy_slot *slot; - - list_for_each_entry(slot, &legacy_list, list) - if (slot->dev == pdev) - goto found; - - dev_warn(&pdev->dev, "Missing legacy fake slot?"); - return -ENODEV; -found: - kobject_del(&slot->kobj); - list_del(&slot->list); - kobject_put(&slot->kobj); - } - - return 0; -} - -static struct notifier_block legacy_notifier = { - .notifier_call = legacy_notify -}; - -static int __init init_legacy(void) -{ - struct pci_dev *pdev = NULL; - - /* Add existing devices */ - for_each_pci_dev(pdev) - legacy_add_slot(pdev); - - /* Be alerted of any new ones */ - bus_register_notifier(&pci_bus_type, &legacy_notifier); - return 0; -} -module_init(init_legacy); - -static void __exit remove_legacy(void) -{ - struct legacy_slot *slot, *tmp; - - bus_unregister_notifier(&pci_bus_type, &legacy_notifier); - - list_for_each_entry_safe(slot, tmp, &legacy_list, list) { - list_del(&slot->list); - kobject_del(&slot->kobj); - kobject_put(&slot->kobj); - } -} -module_exit(remove_legacy); - - -MODULE_AUTHOR("Trent Piepho "); -MODULE_DESCRIPTION("Legacy version of the fakephp interface"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From c24fdc886fde9ce7bda8115b9c2b338818796c65 Mon Sep 17 00:00:00 2001 From: "Hebbar, Gururaja" Date: Mon, 27 Aug 2012 18:56:44 +0530 Subject: ASoC: tlv320aic3x: Add device tree bindings Device tree support for tlv320aic3x CODEC driver. Signed-off-by: Hebbar, Gururaja Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tlv320aic3x.txt | 20 ++++++++++++++ sound/soc/codecs/tlv320aic3x.c | 31 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tlv320aic3x.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt new file mode 100644 index 00000000000..e7b98f41fa5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -0,0 +1,20 @@ +Texas Instruments - tlv320aic3x Codec module + +The tlv320aic3x serial control bus communicates through I2C protocols + +Required properties: +- compatible - "string" - "ti,tlv320aic3x" +- reg - - I2C slave address + + +Optional properties: + +- gpio-reset - gpio pin number used for codec reset +- ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality + +Example: + +tlv320aic3x: tlv320aic3x@1b { + compatible = "ti,tlv320aic3x"; + reg = <0x1b>; +}; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 01485bd5140..5708a973a77 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1457,6 +1458,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, { struct aic3x_pdata *pdata = i2c->dev.platform_data; struct aic3x_priv *aic3x; + struct aic3x_setup_data *ai3x_setup; + struct device_node *np = i2c->dev.of_node; int ret; aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); @@ -1471,6 +1474,25 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, if (pdata) { aic3x->gpio_reset = pdata->gpio_reset; aic3x->setup = pdata->setup; + } else if (np) { + ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), + GFP_KERNEL); + if (ai3x_setup == NULL) { + dev_err(&i2c->dev, "failed to create private data\n"); + return -ENOMEM; + } + + ret = of_get_named_gpio(np, "gpio-reset", 0); + if (ret >= 0) + aic3x->gpio_reset = ret; + else + aic3x->gpio_reset = -1; + + if (of_property_read_u32_array(np, "ai3x-gpio-func", + ai3x_setup->gpio_func, 2) >= 0) { + aic3x->setup = ai3x_setup; + } + } else { aic3x->gpio_reset = -1; } @@ -1488,11 +1510,20 @@ static int aic3x_i2c_remove(struct i2c_client *client) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id tlv320aic3x_of_match[] = { + { .compatible = "ti,tlv320aic3x", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); +#endif + /* machine i2c codec control layer */ static struct i2c_driver aic3x_i2c_driver = { .driver = { .name = "tlv320aic3x-codec", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tlv320aic3x_of_match), }, .probe = aic3x_i2c_probe, .remove = aic3x_i2c_remove, -- cgit v1.2.3-70-g09d2 From 3e3b8c3415b15adb5a7ffcbfbeb360e7c9f5f4f7 Mon Sep 17 00:00:00 2001 From: "Hebbar, Gururaja" Date: Mon, 27 Aug 2012 18:56:42 +0530 Subject: ASoC: Davinci: McASP: add device tree support for McASP Add device tree probe for McASP driver. Note: DMA parameters are not populated from DT and will be done later. Signed-off-by: Hebbar, Gururaja Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 44 ++++++++ sound/soc/davinci/davinci-mcasp.c | 124 ++++++++++++++++++++- 2 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt new file mode 100644 index 00000000000..e6148eca294 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -0,0 +1,44 @@ +Texas Instruments McASP controller + +Required properties: +- compatible : + "ti,dm646x-mcasp-audio" : for DM646x platforms + "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms + +- reg : Should contain McASP registers offset and length +- interrupts : Interrupt number for McASP +- op-mode : I2S/DIT ops mode. +- tdm-slots : Slots for TDM operation. +- num-serializer : Serializers used by McASP. +- serial-dir : A list of serializer pin mode. The list number should be equal + to "num-serializer" parameter. Each entry is a number indication + serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) + + +Optional properties: + +- ti,hwmods : Must be "mcasp", n is controller instance starting 0 +- tx-num-evt : FIFO levels. +- rx-num-evt : FIFO levels. +- sram-size-playback : size of sram to be allocated during playback +- sram-size-capture : size of sram to be allocated during capture + +Example: + +mcasp0: mcasp0@1d00000 { + compatible = "ti,da830-mcasp-audio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x100000 0x3000>; + interrupts = <82 83>; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + num-serializer = <16>; + serial-dir = < + 0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 0 0 + 0 0 0 1 + 2 0 0 0 >; + tx-num-evt = <1>; + rx-num-evt = <1>; +}; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 8f3c5a4cf53..7ecf19dfb07 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -856,6 +859,114 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }; +static const struct of_device_id mcasp_dt_ids[] = { + { + .compatible = "ti,dm646x-mcasp-audio", + .data = (void *)MCASP_VERSION_1, + }, + { + .compatible = "ti,da830-mcasp-audio", + .data = (void *)MCASP_VERSION_2, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mcasp_dt_ids); + +static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_platform_data *pdata = NULL; + const struct of_device_id *match = + of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev); + + const u32 *of_serial_dir32; + u8 *of_serial_dir; + u32 val; + int i, ret = 0; + + if (pdev->dev.platform_data) { + pdata = pdev->dev.platform_data; + return pdata; + } else if (match) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + ret = -ENOMEM; + goto nodata; + } + } else { + /* control shouldn't reach here. something is wrong */ + ret = -EINVAL; + goto nodata; + } + + if (match->data) + pdata->version = (u8)((int)match->data); + + ret = of_property_read_u32(np, "op-mode", &val); + if (ret >= 0) + pdata->op_mode = val; + + ret = of_property_read_u32(np, "tdm-slots", &val); + if (ret >= 0) + pdata->tdm_slots = val; + + ret = of_property_read_u32(np, "num-serializer", &val); + if (ret >= 0) + pdata->num_serializer = val; + + of_serial_dir32 = of_get_property(np, "serial-dir", &val); + val /= sizeof(u32); + if (val != pdata->num_serializer) { + dev_err(&pdev->dev, + "num-serializer(%d) != serial-dir size(%d)\n", + pdata->num_serializer, val); + ret = -EINVAL; + goto nodata; + } + + if (of_serial_dir32) { + of_serial_dir = devm_kzalloc(&pdev->dev, + (sizeof(*of_serial_dir) * val), + GFP_KERNEL); + if (!of_serial_dir) { + ret = -ENOMEM; + goto nodata; + } + + for (i = 0; i < pdata->num_serializer; i++) + of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); + + pdata->serial_dir = of_serial_dir; + } + + ret = of_property_read_u32(np, "tx-num-evt", &val); + if (ret >= 0) + pdata->txnumevt = val; + + ret = of_property_read_u32(np, "rx-num-evt", &val); + if (ret >= 0) + pdata->rxnumevt = val; + + ret = of_property_read_u32(np, "sram-size-playback", &val); + if (ret >= 0) + pdata->sram_size_playback = val; + + ret = of_property_read_u32(np, "sram-size-capture", &val); + if (ret >= 0) + pdata->sram_size_capture = val; + + return pdata; + +nodata: + if (ret < 0) { + dev_err(&pdev->dev, "Error populating platform data, err %d\n", + ret); + pdata = NULL; + } + return pdata; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct davinci_pcm_dma_params *dma_data; @@ -864,11 +975,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev) struct davinci_audio_dev *dev; int ret; + if (!pdev->dev.platform_data && !pdev->dev.of_node) { + dev_err(&pdev->dev, "No platform data supplied\n"); + return -EINVAL; + } + dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev), GFP_KERNEL); if (!dev) return -ENOMEM; + pdata = davinci_mcasp_set_pdata_from_of(pdev); + if (!pdata) { + dev_err(&pdev->dev, "no platform data\n"); + return -EINVAL; + } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no mem resource?\n"); @@ -882,7 +1004,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) return -EBUSY; } - pdata = pdev->dev.platform_data; pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); @@ -980,6 +1101,7 @@ static struct platform_driver davinci_mcasp_driver = { .driver = { .name = "davinci-mcasp", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mcasp_dt_ids), }, }; -- cgit v1.2.3-70-g09d2 From 82aceae4f0d42f03d9ad7d1e90389e731153898f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 27 Aug 2012 13:32:15 -0700 Subject: debugfs: more tightly restrict default mount mode Since the debugfs is mostly only used by root, make the default mount mode 0700. Most system owners do not need a more permissive value, but they can choose to weaken the restrictions via their fstab. Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/debugfs.txt | 4 ++-- fs/debugfs/inode.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt index 7a34f827989..3a863f69272 100644 --- a/Documentation/filesystems/debugfs.txt +++ b/Documentation/filesystems/debugfs.txt @@ -15,8 +15,8 @@ Debugfs is typically mounted with a command like: mount -t debugfs none /sys/kernel/debug (Or an equivalent /etc/fstab line). -The debugfs root directory is accessible by anyone by default. To -restrict access to the tree the "uid", "gid" and "mode" mount +The debugfs root directory is accessible only to the root user by +default. To change access to the tree the "uid", "gid" and "mode" mount options can be used. Note that the debugfs API is exported GPL-only to modules. diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 2c9fafbe842..6393fd61d5c 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -28,7 +28,7 @@ #include #include -#define DEBUGFS_DEFAULT_MODE 0755 +#define DEBUGFS_DEFAULT_MODE 0700 static struct vfsmount *debugfs_mount; static int debugfs_mount_count; -- cgit v1.2.3-70-g09d2 From 6cc2ff82492d89f763e69ea6b8681926aceda610 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 24 Aug 2012 09:10:53 +0000 Subject: netdev/phy: add MDIO bus multiplexer driven by a memory-mapped device Add support for an MDIO bus multiplexer controlled by a simple memory-mapped device, like an FPGA. The device must be memory-mapped and contain only 8-bit registers (which keeps things simple). Tested on a Freescale P5020DS board which uses the "PIXIS" FPGA attached to the localbus. Signed-off-by: Timur Tabi Signed-off-by: David S. Miller --- .../devicetree/bindings/net/mdio-mux-mmioreg.txt | 75 +++++++++ drivers/net/phy/Kconfig | 13 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/mdio-mux-mmioreg.c | 170 +++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/mdio-mux-mmioreg.txt create mode 100644 drivers/net/phy/mdio-mux-mmioreg.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/mdio-mux-mmioreg.txt b/Documentation/devicetree/bindings/net/mdio-mux-mmioreg.txt new file mode 100644 index 00000000000..8516929c725 --- /dev/null +++ b/Documentation/devicetree/bindings/net/mdio-mux-mmioreg.txt @@ -0,0 +1,75 @@ +Properties for an MDIO bus multiplexer controlled by a memory-mapped device + +This is a special case of a MDIO bus multiplexer. A memory-mapped device, +like an FPGA, is used to control which child bus is connected. The mdio-mux +node must be a child of the memory-mapped device. The driver currently only +supports devices with eight-bit registers. + +Required properties in addition to the generic multiplexer properties: + +- compatible : string, must contain "mdio-mux-mmioreg" + +- reg : integer, contains the offset of the register that controls the bus + multiplexer. The size field in the 'reg' property is the size of + register, and must therefore be 1. + +- mux-mask : integer, contains an eight-bit mask that specifies which + bits in the register control the actual bus multiplexer. The + 'reg' property of each child mdio-mux node must be constrained by + this mask. + +Example: + +The FPGA node defines a memory-mapped FPGA with a register space of 0x30 bytes. +For the "EMI2" MDIO bus, register 9 (BRDCFG1) controls the mux on that bus. +A bitmask of 0x6 means that bits 1 and 2 (bit 0 is lsb) are the bits on +BRDCFG1 that control the actual mux. + + /* The FPGA node */ + fpga: board-control@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p5020ds-fpga", "fsl,fpga-ngpixis"; + reg = <3 0 0x30>; + ranges = <0 3 0 0x30>; + + mdio-mux-emi2 { + compatible = "mdio-mux-mmioreg", "mdio-mux"; + mdio-parent-bus = <&xmdio0>; + #address-cells = <1>; + #size-cells = <0>; + reg = <9 1>; // BRDCFG1 + mux-mask = <0x6>; // EMI2 + + emi2_slot1: mdio@0 { // Slot 1 XAUI (FM2) + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + phy_xgmii_slot1: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <4>; + }; + }; + + emi2_slot2: mdio@2 { // Slot 2 XAUI (FM1) + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + phy_xgmii_slot2: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + }; + }; + }; + + /* The parent MDIO bus. */ + xmdio0: mdio@f1000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + interrupts = <100 1 0 0>; + }; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 3090dc65a6f..983bbf4d5ef 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -159,6 +159,19 @@ config MDIO_BUS_MUX_GPIO several child MDIO busses to a parent bus. Child bus selection is under the control of GPIO lines. +config MDIO_BUS_MUX_MMIOREG + tristate "Support for MMIO device-controlled MDIO bus multiplexers" + depends on OF_MDIO + select MDIO_BUS_MUX + help + This module provides a driver for MDIO bus multiplexers that + are controlled via a simple memory-mapped device, like an FPGA. + The multiplexer connects one of several child MDIO busses to a + parent bus. Child bus selection is under the control of one of + the FPGA's registers. + + Currently, only 8-bit registers are supported. + endif # PHYLIB config MICREL_KS8995MA diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 6d2dc6c94f2..426674debae 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o +obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o diff --git a/drivers/net/phy/mdio-mux-mmioreg.c b/drivers/net/phy/mdio-mux-mmioreg.c new file mode 100644 index 00000000000..098239a98b1 --- /dev/null +++ b/drivers/net/phy/mdio-mux-mmioreg.c @@ -0,0 +1,170 @@ +/* + * Simple memory-mapped device MDIO MUX driver + * + * Author: Timur Tabi + * + * Copyright 2012 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct mdio_mux_mmioreg_state { + void *mux_handle; + phys_addr_t phys; + uint8_t mask; +}; + +/* + * MDIO multiplexing switch function + * + * This function is called by the mdio-mux layer when it thinks the mdio bus + * multiplexer needs to switch. + * + * 'current_child' is the current value of the mux register (masked via + * s->mask). + * + * 'desired_child' is the value of the 'reg' property of the target child MDIO + * node. + * + * The first time this function is called, current_child == -1. + * + * If current_child == desired_child, then the mux is already set to the + * correct bus. + */ +static int mdio_mux_mmioreg_switch_fn(int current_child, int desired_child, + void *data) +{ + struct mdio_mux_mmioreg_state *s = data; + + if (current_child ^ desired_child) { + void *p = ioremap(s->phys, 1); + uint8_t x, y; + + if (!p) + return -ENOMEM; + + x = ioread8(p); + y = (x & ~s->mask) | desired_child; + if (x != y) { + iowrite8((x & ~s->mask) | desired_child, p); + pr_debug("%s: %02x -> %02x\n", __func__, x, y); + } + + iounmap(p); + } + + return 0; +} + +static int __devinit mdio_mux_mmioreg_probe(struct platform_device *pdev) +{ + struct device_node *np2, *np = pdev->dev.of_node; + struct mdio_mux_mmioreg_state *s; + struct resource res; + const __be32 *iprop; + int len, ret; + + dev_dbg(&pdev->dev, "probing node %s\n", np->full_name); + + s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(&pdev->dev, "could not obtain memory map for node %s\n", + np->full_name); + return ret; + } + s->phys = res.start; + + if (resource_size(&res) != sizeof(uint8_t)) { + dev_err(&pdev->dev, "only 8-bit registers are supported\n"); + return -EINVAL; + } + + iprop = of_get_property(np, "mux-mask", &len); + if (!iprop || len != sizeof(uint32_t)) { + dev_err(&pdev->dev, "missing or invalid mux-mask property\n"); + return -ENODEV; + } + if (be32_to_cpup(iprop) > 255) { + dev_err(&pdev->dev, "only 8-bit registers are supported\n"); + return -EINVAL; + } + s->mask = be32_to_cpup(iprop); + + /* + * Verify that the 'reg' property of each child MDIO bus does not + * set any bits outside of the 'mask'. + */ + for_each_available_child_of_node(np, np2) { + iprop = of_get_property(np2, "reg", &len); + if (!iprop || len != sizeof(uint32_t)) { + dev_err(&pdev->dev, "mdio-mux child node %s is " + "missing a 'reg' property\n", np2->full_name); + return -ENODEV; + } + if (be32_to_cpup(iprop) & ~s->mask) { + dev_err(&pdev->dev, "mdio-mux child node %s has " + "a 'reg' value with unmasked bits\n", + np2->full_name); + return -ENODEV; + } + } + + ret = mdio_mux_init(&pdev->dev, mdio_mux_mmioreg_switch_fn, + &s->mux_handle, s); + if (ret) { + dev_err(&pdev->dev, "failed to register mdio-mux bus %s\n", + np->full_name); + return ret; + } + + pdev->dev.platform_data = s; + + return 0; +} + +static int __devexit mdio_mux_mmioreg_remove(struct platform_device *pdev) +{ + struct mdio_mux_mmioreg_state *s = dev_get_platdata(&pdev->dev); + + mdio_mux_uninit(s->mux_handle); + + return 0; +} + +static struct of_device_id mdio_mux_mmioreg_match[] = { + { + .compatible = "mdio-mux-mmioreg", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mdio_mux_mmioreg_match); + +static struct platform_driver mdio_mux_mmioreg_driver = { + .driver = { + .name = "mdio-mux-mmioreg", + .owner = THIS_MODULE, + .of_match_table = mdio_mux_mmioreg_match, + }, + .probe = mdio_mux_mmioreg_probe, + .remove = __devexit_p(mdio_mux_mmioreg_remove), +}; + +module_platform_driver(mdio_mux_mmioreg_driver); + +MODULE_AUTHOR("Timur Tabi "); +MODULE_DESCRIPTION("Memory-mapped device MDIO MUX driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 6c9ff979d1921e9fd05d89e1383121c2503759b9 Mon Sep 17 00:00:00 2001 From: Alex Bergmann Date: Fri, 31 Aug 2012 02:48:31 +0000 Subject: tcp: Increase timeout for SYN segments Commit 9ad7c049 ("tcp: RFC2988bis + taking RTT sample from 3WHS for the passive open side") changed the initRTO from 3secs to 1sec in accordance to RFC6298 (former RFC2988bis). This reduced the time till the last SYN retransmission packet gets sent from 93secs to 31secs. RFC1122 is stating that the retransmission should be done for at least 3 minutes, but this seems to be quite high. "However, the values of R1 and R2 may be different for SYN and data segments. In particular, R2 for a SYN segment MUST be set large enough to provide retransmission of the segment for at least 3 minutes. The application can close the connection (i.e., give up on the open attempt) sooner, of course." This patch increases the value of TCP_SYN_RETRIES to the value of 6, providing a retransmission window of 63secs. The comments for SYN and SYNACK retries have also been updated to describe the current settings. The same goes for the documentation file "Documentation/networking/ip-sysctl.txt". Signed-off-by: Alexander Bergmann Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 8 ++++++-- include/net/tcp.h | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index ca447b35b83..d64e53124b8 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -439,7 +439,9 @@ tcp_stdurg - BOOLEAN tcp_synack_retries - INTEGER Number of times SYNACKs for a passive TCP connection attempt will be retransmitted. Should not be higher than 255. Default value - is 5, which corresponds to ~180seconds. + is 5, which corresponds to 31seconds till the last retransmission + with the current initial RTO of 1second. With this the final timeout + for a passive TCP connection will happen after 63seconds. tcp_syncookies - BOOLEAN Only valid when the kernel was compiled with CONFIG_SYNCOOKIES @@ -478,7 +480,9 @@ tcp_fastopen - INTEGER tcp_syn_retries - INTEGER Number of times initial SYNs for an active TCP connection attempt will be retransmitted. Should not be higher than 255. Default value - is 5, which corresponds to ~180seconds. + is 6, which corresponds to 63seconds till the last restransmission + with the current initial RTO of 1second. With this the final timeout + for an active TCP connection attempt will happen after 127seconds. tcp_timestamps - BOOLEAN Enable timestamps as defined in RFC1323. diff --git a/include/net/tcp.h b/include/net/tcp.h index 9a0021d16d9..0fca06f1646 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -98,11 +98,21 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); * 15 is ~13-30min depending on RTO. */ -#define TCP_SYN_RETRIES 5 /* number of times to retry active opening a - * connection: ~180sec is RFC minimum */ +#define TCP_SYN_RETRIES 6 /* This is how many retries are done + * when active opening a connection. + * RFC1122 says the minimum retry MUST + * be at least 180secs. Nevertheless + * this value is corresponding to + * 63secs of retransmission with the + * current initial RTO. + */ -#define TCP_SYNACK_RETRIES 5 /* number of times to retry passive opening a - * connection: ~180sec is RFC minimum */ +#define TCP_SYNACK_RETRIES 5 /* This is how may retries are done + * when passive opening a connection. + * This is corresponding to 31secs of + * retransmission with the current + * initial RTO. + */ #define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT * state, about 60 seconds */ -- cgit v1.2.3-70-g09d2 From d56631a66c0d0c9d662abfb38cd1f6326eeebd7c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 30 Aug 2012 05:50:43 +0000 Subject: net:stmmac: Remove bus_id from mdio platform data. This patch removes bus_id from mdio platform data, The reason to remove bus_id is, stmmac mdio bus_id is always same as stmmac bus-id, so there is no point in passing this in different variable. Also stmmac ethernet driver connects to phy with bus_id passed its platform data. So, having single bus-id is much simpler. Signed-off-by: Srinivas Kandagatla Signed-off-by: David S. Miller --- Documentation/networking/stmmac.txt | 5 ----- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 8 +++----- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 1 - include/linux/stmmac.h | 1 - 4 files changed, 3 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index c676b9cedbd..ef9ee71b4d7 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -173,7 +173,6 @@ Where: For MDIO bus The we have: struct stmmac_mdio_bus_data { - int bus_id; int (*phy_reset)(void *priv); unsigned int phy_mask; int *irqs; @@ -181,7 +180,6 @@ For MDIO bus The we have: }; Where: - o bus_id: bus identifier; o phy_reset: hook to reset the phy device attached to the bus. o phy_mask: phy mask passed when register the MDIO bus within the driver. o irqs: list of IRQs, one per PHY. @@ -230,9 +228,6 @@ there are two MAC cores: one MAC is for MDIO Bus/PHY emulation with fixed_link support. static struct stmmac_mdio_bus_data stmmac1_mdio_bus = { - .bus_id = 1, - | - |-> phy device on the bus_id 1 .phy_reset = phy_reset; | |-> function to provide the phy_reset on this board diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index e1f3d04a8c9..0376a5e6b2b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -177,7 +177,7 @@ int stmmac_mdio_register(struct net_device *ndev) new_bus->write = &stmmac_mdio_write; new_bus->reset = &stmmac_mdio_reset; snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", - new_bus->name, mdio_bus_data->bus_id); + new_bus->name, priv->plat->bus_id); new_bus->priv = ndev; new_bus->irq = irqlist; new_bus->phy_mask = mdio_bus_data->phy_mask; @@ -213,12 +213,10 @@ int stmmac_mdio_register(struct net_device *ndev) * and no PHY number was provided to the MAC, * use the one probed here. */ - if ((priv->plat->bus_id == mdio_bus_data->bus_id) && - (priv->plat->phy_addr == -1)) + if (priv->plat->phy_addr == -1) priv->plat->phy_addr = addr; - act = (priv->plat->bus_id == mdio_bus_data->bus_id) && - (priv->plat->phy_addr == addr); + act = (priv->plat->phy_addr == addr); switch (phydev->irq) { case PHY_POLL: irq_str = "POLL"; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 13afb8edfad..1f069b0f6af 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -40,7 +40,6 @@ static void stmmac_default_data(void) plat_dat.has_gmac = 1; plat_dat.force_sf_dma_mode = 1; - mdio_data.bus_id = 1; mdio_data.phy_reset = NULL; mdio_data.phy_mask = 0; plat_dat.mdio_bus_data = &mdio_data; diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index b69bdb1e08b..a1547ea3920 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -76,7 +76,6 @@ /* Platfrom data for platform device structure's platform_data field */ struct stmmac_mdio_bus_data { - int bus_id; int (*phy_reset)(void *priv); unsigned int phy_mask; int *irqs; -- cgit v1.2.3-70-g09d2 From 1046716368979dee857a2b8a91c4a8833f21b9cb Mon Sep 17 00:00:00 2001 From: Jerry Chu Date: Fri, 31 Aug 2012 12:29:11 +0000 Subject: tcp: TCP Fast Open Server - header & support functions This patch adds all the necessary data structure and support functions to implement TFO server side. It also documents a number of flags for the sysctl_tcp_fastopen knob, and adds a few Linux extension MIBs. In addition, it includes the following: 1. a new TCP_FASTOPEN socket option an application must call to supply a max backlog allowed in order to enable TFO on its listener. 2. A number of key data structures: "fastopen_rsk" in tcp_sock - for a big socket to access its request_sock for retransmission and ack processing purpose. It is non-NULL iff 3WHS not completed. "fastopenq" in request_sock_queue - points to a per Fast Open listener data structure "fastopen_queue" to keep track of qlen (# of outstanding Fast Open requests) and max_qlen, among other things. "listener" in tcp_request_sock - to point to the original listener for book-keeping purpose, i.e., to maintain qlen against max_qlen as part of defense against IP spoofing attack. 3. various data structure and functions, many in tcp_fastopen.c, to support server side Fast Open cookie operations, including /proc/sys/net/ipv4/tcp_fastopen_key to allow manual rekeying. Signed-off-by: H.K. Jerry Chu Cc: Yuchung Cheng Cc: Neal Cardwell Cc: Eric Dumazet Cc: Tom Herbert Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 29 +++++++++--- include/linux/snmp.h | 4 ++ include/linux/tcp.h | 45 ++++++++++++++++-- include/net/request_sock.h | 36 +++++++++++++++ include/net/tcp.h | 46 ++++++++++++++++--- net/ipv4/proc.c | 4 ++ net/ipv4/sysctl_net_ipv4.c | 45 ++++++++++++++++++ net/ipv4/tcp_fastopen.c | 83 +++++++++++++++++++++++++++++++++- net/ipv4/tcp_input.c | 4 +- 9 files changed, 276 insertions(+), 20 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index d64e53124b8..c7fc1072494 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -467,16 +467,31 @@ tcp_syncookies - BOOLEAN tcp_fastopen - INTEGER Enable TCP Fast Open feature (draft-ietf-tcpm-fastopen) to send data in the opening SYN packet. To use this feature, the client application - must not use connect(). Instead, it should use sendmsg() or sendto() - with MSG_FASTOPEN flag which performs a TCP handshake automatically. - - The values (bitmap) are: - 1: Enables sending data in the opening SYN on the client - 5: Enables sending data in the opening SYN on the client regardless - of cookie availability. + must use sendmsg() or sendto() with MSG_FASTOPEN flag rather than + connect() to perform a TCP handshake automatically. + + The values (bitmap) are + 1: Enables sending data in the opening SYN on the client. + 2: Enables TCP Fast Open on the server side, i.e., allowing data in + a SYN packet to be accepted and passed to the application before + 3-way hand shake finishes. + 4: Send data in the opening SYN regardless of cookie availability and + without a cookie option. + 0x100: Accept SYN data w/o validating the cookie. + 0x200: Accept data-in-SYN w/o any cookie option present. + 0x400/0x800: Enable Fast Open on all listeners regardless of the + TCP_FASTOPEN socket option. The two different flags designate two + different ways of setting max_qlen without the TCP_FASTOPEN socket + option. Default: 0 + Note that the client & server side Fast Open flags (1 and 2 + respectively) must be also enabled before the rest of flags can take + effect. + + See include/net/tcp.h and the code for more details. + tcp_syn_retries - INTEGER Number of times initial SYNs for an active TCP connection attempt will be retransmitted. Should not be higher than 255. Default value diff --git a/include/linux/snmp.h b/include/linux/snmp.h index ad6e3a6bf9f..fdfba235f9f 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -241,6 +241,10 @@ enum LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */ LINUX_MIB_TCPFASTOPENACTIVE, /* TCPFastOpenActive */ + LINUX_MIB_TCPFASTOPENPASSIVE, /* TCPFastOpenPassive*/ + LINUX_MIB_TCPFASTOPENPASSIVEFAIL, /* TCPFastOpenPassiveFail */ + LINUX_MIB_TCPFASTOPENLISTENOVERFLOW, /* TCPFastOpenListenOverflow */ + LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */ __LINUX_MIB_MAX }; diff --git a/include/linux/tcp.h b/include/linux/tcp.h index eb125a4c30b..ae46df59062 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -110,6 +110,7 @@ enum { #define TCP_REPAIR_QUEUE 20 #define TCP_QUEUE_SEQ 21 #define TCP_REPAIR_OPTIONS 22 +#define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ struct tcp_repair_opt { __u32 opt_code; @@ -246,6 +247,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) /* TCP Fast Open */ #define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ #define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ +#define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ /* TCP Fast Open Cookie as stored in memory */ struct tcp_fastopen_cookie { @@ -312,9 +314,14 @@ struct tcp_request_sock { /* Only used by TCP MD5 Signature so far. */ const struct tcp_request_sock_ops *af_specific; #endif + struct sock *listener; /* needed for TFO */ u32 rcv_isn; u32 snt_isn; u32 snt_synack; /* synack sent time */ + u32 rcv_nxt; /* the ack # by SYNACK. For + * FastOpen it's the seq# + * after data-in-SYN. + */ }; static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) @@ -505,14 +512,18 @@ struct tcp_sock { struct tcp_md5sig_info __rcu *md5sig_info; #endif -/* TCP fastopen related information */ - struct tcp_fastopen_request *fastopen_req; - /* When the cookie options are generated and exchanged, then this * object holds a reference to them (cookie_values->kref). Also * contains related tcp_cookie_transactions fields. */ struct tcp_cookie_values *cookie_values; + +/* TCP fastopen related information */ + struct tcp_fastopen_request *fastopen_req; + /* fastopen_rsk points to request_sock that resulted in this big + * socket. Used to retransmit SYNACKs etc. + */ + struct request_sock *fastopen_rsk; }; enum tsq_flags { @@ -552,6 +563,34 @@ static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) return (struct tcp_timewait_sock *)sk; } +static inline bool tcp_passive_fastopen(const struct sock *sk) +{ + return (sk->sk_state == TCP_SYN_RECV && + tcp_sk(sk)->fastopen_rsk != NULL); +} + +static inline bool fastopen_cookie_present(struct tcp_fastopen_cookie *foc) +{ + return foc->len != -1; +} + +static inline int fastopen_init_queue(struct sock *sk, int backlog) +{ + struct request_sock_queue *queue = + &inet_csk(sk)->icsk_accept_queue; + + if (queue->fastopenq == NULL) { + queue->fastopenq = kzalloc( + sizeof(struct fastopen_queue), + sk->sk_allocation); + if (queue->fastopenq == NULL) + return -ENOMEM; + spin_lock_init(&queue->fastopenq->lock); + } + queue->fastopenq->max_qlen = backlog; + return 0; +} + #endif /* __KERNEL__ */ #endif /* _LINUX_TCP_H */ diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 4c0766e201e..c3cdd6c9f44 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -106,6 +106,34 @@ struct listen_sock { struct request_sock *syn_table[0]; }; +/* + * For a TCP Fast Open listener - + * lock - protects the access to all the reqsk, which is co-owned by + * the listener and the child socket. + * qlen - pending TFO requests (still in TCP_SYN_RECV). + * max_qlen - max TFO reqs allowed before TFO is disabled. + * + * XXX (TFO) - ideally these fields can be made as part of "listen_sock" + * structure above. But there is some implementation difficulty due to + * listen_sock being part of request_sock_queue hence will be freed when + * a listener is stopped. But TFO related fields may continue to be + * accessed even after a listener is closed, until its sk_refcnt drops + * to 0 implying no more outstanding TFO reqs. One solution is to keep + * listen_opt around until sk_refcnt drops to 0. But there is some other + * complexity that needs to be resolved. E.g., a listener can be disabled + * temporarily through shutdown()->tcp_disconnect(), and re-enabled later. + */ +struct fastopen_queue { + struct request_sock *rskq_rst_head; /* Keep track of past TFO */ + struct request_sock *rskq_rst_tail; /* requests that caused RST. + * This is part of the defense + * against spoofing attack. + */ + spinlock_t lock; + int qlen; /* # of pending (TCP_SYN_RECV) reqs */ + int max_qlen; /* != 0 iff TFO is currently enabled */ +}; + /** struct request_sock_queue - queue of request_socks * * @rskq_accept_head - FIFO head of established children @@ -129,6 +157,12 @@ struct request_sock_queue { u8 rskq_defer_accept; /* 3 bytes hole, try to pack */ struct listen_sock *listen_opt; + struct fastopen_queue *fastopenq; /* This is non-NULL iff TFO has been + * enabled on this listener. Check + * max_qlen != 0 in fastopen_queue + * to determine if TFO is enabled + * right at this moment. + */ }; extern int reqsk_queue_alloc(struct request_sock_queue *queue, @@ -136,6 +170,8 @@ extern int reqsk_queue_alloc(struct request_sock_queue *queue, extern void __reqsk_queue_destroy(struct request_sock_queue *queue); extern void reqsk_queue_destroy(struct request_sock_queue *queue); +extern void reqsk_fastopen_remove(struct sock *sk, + struct request_sock *req, bool reset); static inline struct request_sock * reqsk_queue_yank_acceptq(struct request_sock_queue *queue) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0fca06f1646..9f8821e3293 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -224,8 +224,24 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); /* Bit Flags for sysctl_tcp_fastopen */ #define TFO_CLIENT_ENABLE 1 +#define TFO_SERVER_ENABLE 2 #define TFO_CLIENT_NO_COOKIE 4 /* Data in SYN w/o cookie option */ +/* Process SYN data but skip cookie validation */ +#define TFO_SERVER_COOKIE_NOT_CHKED 0x100 +/* Accept SYN data w/o any cookie option */ +#define TFO_SERVER_COOKIE_NOT_REQD 0x200 + +/* Force enable TFO on all listeners, i.e., not requiring the + * TCP_FASTOPEN socket option. SOCKOPT1/2 determine how to set max_qlen. + */ +#define TFO_SERVER_WO_SOCKOPT1 0x400 +#define TFO_SERVER_WO_SOCKOPT2 0x800 +/* Always create TFO child sockets on a TFO listener even when + * cookie/data not present. (For testing purpose!) + */ +#define TFO_SERVER_ALWAYS 0x1000 + extern struct inet_timewait_death_row tcp_death_row; /* sysctl variables for tcp */ @@ -421,12 +437,6 @@ extern void tcp_metrics_init(void); extern bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check); extern bool tcp_remember_stamp(struct sock *sk); extern bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw); -extern void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, - struct tcp_fastopen_cookie *cookie, - int *syn_loss, unsigned long *last_syn_loss); -extern void tcp_fastopen_cache_set(struct sock *sk, u16 mss, - struct tcp_fastopen_cookie *cookie, - bool syn_lost); extern void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst); extern void tcp_disable_fack(struct tcp_sock *tp); extern void tcp_close(struct sock *sk, long timeout); @@ -537,6 +547,7 @@ extern void tcp_send_delayed_ack(struct sock *sk); extern void tcp_cwnd_application_limited(struct sock *sk); extern void tcp_resume_early_retransmit(struct sock *sk); extern void tcp_rearm_rto(struct sock *sk); +extern void tcp_reset(struct sock *sk); /* tcp_timer.c */ extern void tcp_init_xmit_timers(struct sock *); @@ -586,6 +597,7 @@ extern int tcp_mtu_to_mss(struct sock *sk, int pmtu); extern int tcp_mss_to_mtu(struct sock *sk, int mss); extern void tcp_mtup_init(struct sock *sk); extern void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt); +extern void tcp_init_buffer_space(struct sock *sk); static inline void tcp_bound_rto(const struct sock *sk) { @@ -1104,6 +1116,7 @@ static inline void tcp_openreq_init(struct request_sock *req, req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ req->cookie_ts = 0; tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; + tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; req->mss = rx_opt->mss_clamp; req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; ireq->tstamp_ok = rx_opt->tstamp_ok; @@ -1308,15 +1321,34 @@ extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *key); +/* From tcp_fastopen.c */ +extern void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, + struct tcp_fastopen_cookie *cookie, + int *syn_loss, unsigned long *last_syn_loss); +extern void tcp_fastopen_cache_set(struct sock *sk, u16 mss, + struct tcp_fastopen_cookie *cookie, + bool syn_lost); struct tcp_fastopen_request { /* Fast Open cookie. Size 0 means a cookie request */ struct tcp_fastopen_cookie cookie; struct msghdr *data; /* data in MSG_FASTOPEN */ u16 copied; /* queued in tcp_connect() */ }; - void tcp_free_fastopen_req(struct tcp_sock *tp); +extern struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; +int tcp_fastopen_reset_cipher(void *key, unsigned int len); +void tcp_fastopen_cookie_gen(__be32 addr, struct tcp_fastopen_cookie *foc); + +#define TCP_FASTOPEN_KEY_LENGTH 16 + +/* Fastopen key context */ +struct tcp_fastopen_context { + struct crypto_cipher __rcu *tfm; + __u8 key[TCP_FASTOPEN_KEY_LENGTH]; + struct rcu_head rcu; +}; + /* write queue abstraction */ static inline void tcp_write_queue_purge(struct sock *sk) { diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 957acd12250..8de53e1ddd5 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -263,6 +263,10 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), SNMP_MIB_ITEM("TCPSYNChallenge", LINUX_MIB_TCPSYNCHALLENGE), SNMP_MIB_ITEM("TCPFastOpenActive", LINUX_MIB_TCPFASTOPENACTIVE), + SNMP_MIB_ITEM("TCPFastOpenPassive", LINUX_MIB_TCPFASTOPENPASSIVE), + SNMP_MIB_ITEM("TCPFastOpenPassiveFail", LINUX_MIB_TCPFASTOPENPASSIVEFAIL), + SNMP_MIB_ITEM("TCPFastOpenListenOverflow", LINUX_MIB_TCPFASTOPENLISTENOVERFLOW), + SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 3e78c79b558..9205e492dc9 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -232,6 +232,45 @@ static int ipv4_tcp_mem(ctl_table *ctl, int write, return 0; } +int proc_tcp_fastopen_key(ctl_table *ctl, int write, void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) }; + struct tcp_fastopen_context *ctxt; + int ret; + u32 user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */ + + tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL); + if (!tbl.data) + return -ENOMEM; + + rcu_read_lock(); + ctxt = rcu_dereference(tcp_fastopen_ctx); + if (ctxt) + memcpy(user_key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); + rcu_read_unlock(); + + snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x", + user_key[0], user_key[1], user_key[2], user_key[3]); + ret = proc_dostring(&tbl, write, buffer, lenp, ppos); + + if (write && ret == 0) { + if (sscanf(tbl.data, "%x-%x-%x-%x", user_key, user_key + 1, + user_key + 2, user_key + 3) != 4) { + ret = -EINVAL; + goto bad_key; + } + tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH); + } + +bad_key: + pr_debug("proc FO key set 0x%x-%x-%x-%x <- 0x%s: %u\n", + user_key[0], user_key[1], user_key[2], user_key[3], + (char *)tbl.data, ret); + kfree(tbl.data); + return ret; +} + static struct ctl_table ipv4_table[] = { { .procname = "tcp_timestamps", @@ -385,6 +424,12 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "tcp_fastopen_key", + .mode = 0600, + .maxlen = ((TCP_FASTOPEN_KEY_LENGTH * 2) + 10), + .proc_handler = proc_tcp_fastopen_key, + }, { .procname = "tcp_tw_recycle", .data = &tcp_death_row.sysctl_tw_recycle, diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index a7f729c409d..8f7ef0ad80e 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -1,10 +1,91 @@ +#include #include #include +#include +#include +#include +#include +#include +#include -int sysctl_tcp_fastopen; +int sysctl_tcp_fastopen __read_mostly; + +struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; + +static DEFINE_SPINLOCK(tcp_fastopen_ctx_lock); + +static void tcp_fastopen_ctx_free(struct rcu_head *head) +{ + struct tcp_fastopen_context *ctx = + container_of(head, struct tcp_fastopen_context, rcu); + crypto_free_cipher(ctx->tfm); + kfree(ctx); +} + +int tcp_fastopen_reset_cipher(void *key, unsigned int len) +{ + int err; + struct tcp_fastopen_context *ctx, *octx; + + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->tfm = crypto_alloc_cipher("aes", 0, 0); + + if (IS_ERR(ctx->tfm)) { + err = PTR_ERR(ctx->tfm); +error: kfree(ctx); + pr_err("TCP: TFO aes cipher alloc error: %d\n", err); + return err; + } + err = crypto_cipher_setkey(ctx->tfm, key, len); + if (err) { + pr_err("TCP: TFO cipher key error: %d\n", err); + crypto_free_cipher(ctx->tfm); + goto error; + } + memcpy(ctx->key, key, len); + + spin_lock(&tcp_fastopen_ctx_lock); + + octx = rcu_dereference_protected(tcp_fastopen_ctx, + lockdep_is_held(&tcp_fastopen_ctx_lock)); + rcu_assign_pointer(tcp_fastopen_ctx, ctx); + spin_unlock(&tcp_fastopen_ctx_lock); + + if (octx) + call_rcu(&octx->rcu, tcp_fastopen_ctx_free); + return err; +} + +/* Computes the fastopen cookie for the peer. + * The peer address is a 128 bits long (pad with zeros for IPv4). + * + * The caller must check foc->len to determine if a valid cookie + * has been generated successfully. +*/ +void tcp_fastopen_cookie_gen(__be32 addr, struct tcp_fastopen_cookie *foc) +{ + __be32 peer_addr[4] = { addr, 0, 0, 0 }; + struct tcp_fastopen_context *ctx; + + rcu_read_lock(); + ctx = rcu_dereference(tcp_fastopen_ctx); + if (ctx) { + crypto_cipher_encrypt_one(ctx->tfm, + foc->val, + (__u8 *)peer_addr); + foc->len = TCP_FASTOPEN_COOKIE_SIZE; + } + rcu_read_unlock(); +} static int __init tcp_fastopen_init(void) { + __u8 key[TCP_FASTOPEN_KEY_LENGTH]; + + get_random_bytes(key, sizeof(key)); + tcp_fastopen_reset_cipher(key, sizeof(key)); return 0; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ce4ffe9ed55..d47d5fe8f3f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -378,7 +378,7 @@ static void tcp_fixup_rcvbuf(struct sock *sk) /* 4. Try to fixup all. It is made immediately after connection enters * established state. */ -static void tcp_init_buffer_space(struct sock *sk) +void tcp_init_buffer_space(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); int maxwin; @@ -4038,7 +4038,7 @@ static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq) } /* When we get a reset we do this. */ -static void tcp_reset(struct sock *sk) +void tcp_reset(struct sock *sk) { /* We want the right error as BSD sees it (and indeed as we do). */ switch (sk->sk_state) { -- cgit v1.2.3-70-g09d2 From 19feb61e9956270e1be47250ace881ebbe130b8e Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 1 Jul 2012 15:46:56 +0200 Subject: oss: remove maui_boot.h from .gitignore and dontdiff Commit d56b9b9c464a10ab1ee51a4c6190a2b57b8ef7a6 ("The scheduled removal of some OSS drivers") removed all traces of maui_boot.h from the tree. Remove its entries in dontdiff and oss's .gitignore file. Signed-off-by: Paul Bolle Signed-off-by: Jiri Kosina --- Documentation/dontdiff | 1 - sound/oss/.gitignore | 1 - 2 files changed, 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dontdiff b/Documentation/dontdiff index b4a898f43c3..3af5ad47385 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -163,7 +163,6 @@ mach-types.h machtypes.h map map_hugetlb -maui_boot.h media mconf miboot* diff --git a/sound/oss/.gitignore b/sound/oss/.gitignore index 7efb12b4550..12a3920d6fb 100644 --- a/sound/oss/.gitignore +++ b/sound/oss/.gitignore @@ -1,4 +1,3 @@ #Ignore generated files -maui_boot.h pss_boot.h trix_boot.h -- cgit v1.2.3-70-g09d2 From 5ffd27fa8d7950a3c2136100860273e6ff2605e0 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 8 Aug 2012 00:07:03 +0200 Subject: doc: aliasing-test: close fd on write error If write fails, remember to close(fd) before returning. Signed-off-by: Jesper Juhl Signed-off-by: Jiri Kosina --- Documentation/ia64/aliasing-test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c index 5caa2af3320..62a190d45f3 100644 --- a/Documentation/ia64/aliasing-test.c +++ b/Documentation/ia64/aliasing-test.c @@ -132,6 +132,7 @@ static int read_rom(char *path) rc = write(fd, "1", 2); if (rc <= 0) { + close(fd); perror("write"); return -1; } -- cgit v1.2.3-70-g09d2 From 0de4b95409367f5012ff5be7fd3785dc11c6cda8 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 8 Aug 2012 20:56:14 +0200 Subject: doc: getdelays.c: remember to close() socket on error in create_nl_socket() If the call to setsockopt() fails in Documentation/accounting/getdelays.c::create_nl_socket() we return -1 without closing the socket, thus leaking it when the 'fd' variable goes out of scope. Easily fixed by just jumping to the 'error' label instead of returning since we do the proper cleanup there. While I was there I noticed that the error message that is printet if setsockopt() fails was broken over two lines - put that on a single line so it is easier to grep for. Signed-off-by: Jesper Juhl Signed-off-by: Jiri Kosina --- Documentation/accounting/getdelays.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c index f6318f6d7ba..6f706aca204 100644 --- a/Documentation/accounting/getdelays.c +++ b/Documentation/accounting/getdelays.c @@ -98,10 +98,9 @@ static int create_nl_socket(int protocol) if (rcvbufsz) if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, sizeof(rcvbufsz)) < 0) { - fprintf(stderr, "Unable to set socket rcv buf size " - "to %d\n", + fprintf(stderr, "Unable to set socket rcv buf size to %d\n", rcvbufsz); - return -1; + goto error; } memset(&local, 0, sizeof(local)); -- cgit v1.2.3-70-g09d2 From 1557cc4211951ba92a318d1ddf743448637d1d3f Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Tue, 21 Aug 2012 09:54:09 +0000 Subject: doc: fix broken utf8 encoding conversion to utf8 left some extra control character here, remove it. Signed-off-by: Oskar Schirmer Cc: John Anthony Kazos Jr Cc: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/power/swsusp.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 92341b84250..0b4b63e7e9b 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -53,7 +53,7 @@ before suspend (it is limited to 500 MB by default). Article about goals and implementation of Software Suspend for Linux ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Author: G‚ábor Kuti +Author: Gábor Kuti Last revised: 2003-10-20 by Pavel Machek Idea and goals to achieve -- cgit v1.2.3-70-g09d2 From b9aa8f13eaaf65f6939c67920d2cda4399be1e2a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 9 Aug 2012 18:23:32 +0200 Subject: pinctrl: pinctrl-imx: add imx35 pinctrl driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mostly cut'n'paste from the imx51 pinctrl driver. The data was generated using sed and awk on arch/arm/plat-mxc/include/mach/iomux-mx35.h. Changes since (implicit) v1 - remove references to file names in binding documentation - remove sed commands from comments in driver - add explicit numbers for pins and functions Acked-by: Shawn Guo Acked-by: Stephen Warren Acked-by: Dong Aisheng Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- .../bindings/pinctrl/fsl,imx35-pinctrl.txt | 984 ++++++++++++ drivers/pinctrl/Kconfig | 8 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-imx35.c | 1595 ++++++++++++++++++++ 4 files changed, 2588 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl-imx35.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt new file mode 100644 index 00000000000..1183f1a3be3 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt @@ -0,0 +1,984 @@ +* Freescale IMX35 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx35-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx35 datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_DRIVE_VOLAGAGE_18 (1 << 13) +PAD_CTL_DRIVE_VOLAGAGE_33 (0 << 13) +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE_CMOS (0 << 3) +PAD_CTL_ODE_OPENDRAIN (1 << 3) +PAD_CTL_DSE_NOMINAL (0 << 1) +PAD_CTL_DSE_HIGH (1 << 1) +PAD_CTL_DSE_MAX (2 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +See below for available PIN_FUNC_ID for imx35: +0 MX35_PAD_CAPTURE__GPT_CAPIN1 +1 MX35_PAD_CAPTURE__GPT_CMPOUT2 +2 MX35_PAD_CAPTURE__CSPI2_SS1 +3 MX35_PAD_CAPTURE__EPIT1_EPITO +4 MX35_PAD_CAPTURE__CCM_CLK32K +5 MX35_PAD_CAPTURE__GPIO1_4 +6 MX35_PAD_COMPARE__GPT_CMPOUT1 +7 MX35_PAD_COMPARE__GPT_CAPIN2 +8 MX35_PAD_COMPARE__GPT_CMPOUT3 +9 MX35_PAD_COMPARE__EPIT2_EPITO +10 MX35_PAD_COMPARE__GPIO1_5 +11 MX35_PAD_COMPARE__SDMA_EXTDMA_2 +12 MX35_PAD_WDOG_RST__WDOG_WDOG_B +13 MX35_PAD_WDOG_RST__IPU_FLASH_STROBE +14 MX35_PAD_WDOG_RST__GPIO1_6 +15 MX35_PAD_GPIO1_0__GPIO1_0 +16 MX35_PAD_GPIO1_0__CCM_PMIC_RDY +17 MX35_PAD_GPIO1_0__OWIRE_LINE +18 MX35_PAD_GPIO1_0__SDMA_EXTDMA_0 +19 MX35_PAD_GPIO1_1__GPIO1_1 +20 MX35_PAD_GPIO1_1__PWM_PWMO +21 MX35_PAD_GPIO1_1__CSPI1_SS2 +22 MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT +23 MX35_PAD_GPIO1_1__SDMA_EXTDMA_1 +24 MX35_PAD_GPIO2_0__GPIO2_0 +25 MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK +26 MX35_PAD_GPIO3_0__GPIO3_0 +27 MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK +28 MX35_PAD_RESET_IN_B__CCM_RESET_IN_B +29 MX35_PAD_POR_B__CCM_POR_B +30 MX35_PAD_CLKO__CCM_CLKO +31 MX35_PAD_CLKO__GPIO1_8 +32 MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0 +33 MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1 +34 MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0 +35 MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1 +36 MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26 +37 MX35_PAD_VSTBY__CCM_VSTBY +38 MX35_PAD_VSTBY__GPIO1_7 +39 MX35_PAD_A0__EMI_EIM_DA_L_0 +40 MX35_PAD_A1__EMI_EIM_DA_L_1 +41 MX35_PAD_A2__EMI_EIM_DA_L_2 +42 MX35_PAD_A3__EMI_EIM_DA_L_3 +43 MX35_PAD_A4__EMI_EIM_DA_L_4 +44 MX35_PAD_A5__EMI_EIM_DA_L_5 +45 MX35_PAD_A6__EMI_EIM_DA_L_6 +46 MX35_PAD_A7__EMI_EIM_DA_L_7 +47 MX35_PAD_A8__EMI_EIM_DA_H_8 +48 MX35_PAD_A9__EMI_EIM_DA_H_9 +49 MX35_PAD_A10__EMI_EIM_DA_H_10 +50 MX35_PAD_MA10__EMI_MA10 +51 MX35_PAD_A11__EMI_EIM_DA_H_11 +52 MX35_PAD_A12__EMI_EIM_DA_H_12 +53 MX35_PAD_A13__EMI_EIM_DA_H_13 +54 MX35_PAD_A14__EMI_EIM_DA_H2_14 +55 MX35_PAD_A15__EMI_EIM_DA_H2_15 +56 MX35_PAD_A16__EMI_EIM_A_16 +57 MX35_PAD_A17__EMI_EIM_A_17 +58 MX35_PAD_A18__EMI_EIM_A_18 +59 MX35_PAD_A19__EMI_EIM_A_19 +60 MX35_PAD_A20__EMI_EIM_A_20 +61 MX35_PAD_A21__EMI_EIM_A_21 +62 MX35_PAD_A22__EMI_EIM_A_22 +63 MX35_PAD_A23__EMI_EIM_A_23 +64 MX35_PAD_A24__EMI_EIM_A_24 +65 MX35_PAD_A25__EMI_EIM_A_25 +66 MX35_PAD_SDBA1__EMI_EIM_SDBA1 +67 MX35_PAD_SDBA0__EMI_EIM_SDBA0 +68 MX35_PAD_SD0__EMI_DRAM_D_0 +69 MX35_PAD_SD1__EMI_DRAM_D_1 +70 MX35_PAD_SD2__EMI_DRAM_D_2 +71 MX35_PAD_SD3__EMI_DRAM_D_3 +72 MX35_PAD_SD4__EMI_DRAM_D_4 +73 MX35_PAD_SD5__EMI_DRAM_D_5 +74 MX35_PAD_SD6__EMI_DRAM_D_6 +75 MX35_PAD_SD7__EMI_DRAM_D_7 +76 MX35_PAD_SD8__EMI_DRAM_D_8 +77 MX35_PAD_SD9__EMI_DRAM_D_9 +78 MX35_PAD_SD10__EMI_DRAM_D_10 +79 MX35_PAD_SD11__EMI_DRAM_D_11 +80 MX35_PAD_SD12__EMI_DRAM_D_12 +81 MX35_PAD_SD13__EMI_DRAM_D_13 +82 MX35_PAD_SD14__EMI_DRAM_D_14 +83 MX35_PAD_SD15__EMI_DRAM_D_15 +84 MX35_PAD_SD16__EMI_DRAM_D_16 +85 MX35_PAD_SD17__EMI_DRAM_D_17 +86 MX35_PAD_SD18__EMI_DRAM_D_18 +87 MX35_PAD_SD19__EMI_DRAM_D_19 +88 MX35_PAD_SD20__EMI_DRAM_D_20 +89 MX35_PAD_SD21__EMI_DRAM_D_21 +90 MX35_PAD_SD22__EMI_DRAM_D_22 +91 MX35_PAD_SD23__EMI_DRAM_D_23 +92 MX35_PAD_SD24__EMI_DRAM_D_24 +93 MX35_PAD_SD25__EMI_DRAM_D_25 +94 MX35_PAD_SD26__EMI_DRAM_D_26 +95 MX35_PAD_SD27__EMI_DRAM_D_27 +96 MX35_PAD_SD28__EMI_DRAM_D_28 +97 MX35_PAD_SD29__EMI_DRAM_D_29 +98 MX35_PAD_SD30__EMI_DRAM_D_30 +99 MX35_PAD_SD31__EMI_DRAM_D_31 +100 MX35_PAD_DQM0__EMI_DRAM_DQM_0 +101 MX35_PAD_DQM1__EMI_DRAM_DQM_1 +102 MX35_PAD_DQM2__EMI_DRAM_DQM_2 +103 MX35_PAD_DQM3__EMI_DRAM_DQM_3 +104 MX35_PAD_EB0__EMI_EIM_EB0_B +105 MX35_PAD_EB1__EMI_EIM_EB1_B +106 MX35_PAD_OE__EMI_EIM_OE +107 MX35_PAD_CS0__EMI_EIM_CS0 +108 MX35_PAD_CS1__EMI_EIM_CS1 +109 MX35_PAD_CS1__EMI_NANDF_CE3 +110 MX35_PAD_CS2__EMI_EIM_CS2 +111 MX35_PAD_CS3__EMI_EIM_CS3 +112 MX35_PAD_CS4__EMI_EIM_CS4 +113 MX35_PAD_CS4__EMI_DTACK_B +114 MX35_PAD_CS4__EMI_NANDF_CE1 +115 MX35_PAD_CS4__GPIO1_20 +116 MX35_PAD_CS5__EMI_EIM_CS5 +117 MX35_PAD_CS5__CSPI2_SS2 +118 MX35_PAD_CS5__CSPI1_SS2 +119 MX35_PAD_CS5__EMI_NANDF_CE2 +120 MX35_PAD_CS5__GPIO1_21 +121 MX35_PAD_NF_CE0__EMI_NANDF_CE0 +122 MX35_PAD_NF_CE0__GPIO1_22 +123 MX35_PAD_ECB__EMI_EIM_ECB +124 MX35_PAD_LBA__EMI_EIM_LBA +125 MX35_PAD_BCLK__EMI_EIM_BCLK +126 MX35_PAD_RW__EMI_EIM_RW +127 MX35_PAD_RAS__EMI_DRAM_RAS +128 MX35_PAD_CAS__EMI_DRAM_CAS +129 MX35_PAD_SDWE__EMI_DRAM_SDWE +130 MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0 +131 MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1 +132 MX35_PAD_SDCLK__EMI_DRAM_SDCLK +133 MX35_PAD_SDQS0__EMI_DRAM_SDQS_0 +134 MX35_PAD_SDQS1__EMI_DRAM_SDQS_1 +135 MX35_PAD_SDQS2__EMI_DRAM_SDQS_2 +136 MX35_PAD_SDQS3__EMI_DRAM_SDQS_3 +137 MX35_PAD_NFWE_B__EMI_NANDF_WE_B +138 MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3 +139 MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC +140 MX35_PAD_NFWE_B__GPIO2_18 +141 MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0 +142 MX35_PAD_NFRE_B__EMI_NANDF_RE_B +143 MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR +144 MX35_PAD_NFRE_B__IPU_DISPB_BCLK +145 MX35_PAD_NFRE_B__GPIO2_19 +146 MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1 +147 MX35_PAD_NFALE__EMI_NANDF_ALE +148 MX35_PAD_NFALE__USB_TOP_USBH2_STP +149 MX35_PAD_NFALE__IPU_DISPB_CS0 +150 MX35_PAD_NFALE__GPIO2_20 +151 MX35_PAD_NFALE__ARM11P_TOP_TRACE_2 +152 MX35_PAD_NFCLE__EMI_NANDF_CLE +153 MX35_PAD_NFCLE__USB_TOP_USBH2_NXT +154 MX35_PAD_NFCLE__IPU_DISPB_PAR_RS +155 MX35_PAD_NFCLE__GPIO2_21 +156 MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3 +157 MX35_PAD_NFWP_B__EMI_NANDF_WP_B +158 MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7 +159 MX35_PAD_NFWP_B__IPU_DISPB_WR +160 MX35_PAD_NFWP_B__GPIO2_22 +161 MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL +162 MX35_PAD_NFRB__EMI_NANDF_RB +163 MX35_PAD_NFRB__IPU_DISPB_RD +164 MX35_PAD_NFRB__GPIO2_23 +165 MX35_PAD_NFRB__ARM11P_TOP_TRCLK +166 MX35_PAD_D15__EMI_EIM_D_15 +167 MX35_PAD_D14__EMI_EIM_D_14 +168 MX35_PAD_D13__EMI_EIM_D_13 +169 MX35_PAD_D12__EMI_EIM_D_12 +170 MX35_PAD_D11__EMI_EIM_D_11 +171 MX35_PAD_D10__EMI_EIM_D_10 +172 MX35_PAD_D9__EMI_EIM_D_9 +173 MX35_PAD_D8__EMI_EIM_D_8 +174 MX35_PAD_D7__EMI_EIM_D_7 +175 MX35_PAD_D6__EMI_EIM_D_6 +176 MX35_PAD_D5__EMI_EIM_D_5 +177 MX35_PAD_D4__EMI_EIM_D_4 +178 MX35_PAD_D3__EMI_EIM_D_3 +179 MX35_PAD_D2__EMI_EIM_D_2 +180 MX35_PAD_D1__EMI_EIM_D_1 +181 MX35_PAD_D0__EMI_EIM_D_0 +182 MX35_PAD_CSI_D8__IPU_CSI_D_8 +183 MX35_PAD_CSI_D8__KPP_COL_0 +184 MX35_PAD_CSI_D8__GPIO1_20 +185 MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13 +186 MX35_PAD_CSI_D9__IPU_CSI_D_9 +187 MX35_PAD_CSI_D9__KPP_COL_1 +188 MX35_PAD_CSI_D9__GPIO1_21 +189 MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14 +190 MX35_PAD_CSI_D10__IPU_CSI_D_10 +191 MX35_PAD_CSI_D10__KPP_COL_2 +192 MX35_PAD_CSI_D10__GPIO1_22 +193 MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15 +194 MX35_PAD_CSI_D11__IPU_CSI_D_11 +195 MX35_PAD_CSI_D11__KPP_COL_3 +196 MX35_PAD_CSI_D11__GPIO1_23 +197 MX35_PAD_CSI_D12__IPU_CSI_D_12 +198 MX35_PAD_CSI_D12__KPP_ROW_0 +199 MX35_PAD_CSI_D12__GPIO1_24 +200 MX35_PAD_CSI_D13__IPU_CSI_D_13 +201 MX35_PAD_CSI_D13__KPP_ROW_1 +202 MX35_PAD_CSI_D13__GPIO1_25 +203 MX35_PAD_CSI_D14__IPU_CSI_D_14 +204 MX35_PAD_CSI_D14__KPP_ROW_2 +205 MX35_PAD_CSI_D14__GPIO1_26 +206 MX35_PAD_CSI_D15__IPU_CSI_D_15 +207 MX35_PAD_CSI_D15__KPP_ROW_3 +208 MX35_PAD_CSI_D15__GPIO1_27 +209 MX35_PAD_CSI_MCLK__IPU_CSI_MCLK +210 MX35_PAD_CSI_MCLK__GPIO1_28 +211 MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC +212 MX35_PAD_CSI_VSYNC__GPIO1_29 +213 MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC +214 MX35_PAD_CSI_HSYNC__GPIO1_30 +215 MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK +216 MX35_PAD_CSI_PIXCLK__GPIO1_31 +217 MX35_PAD_I2C1_CLK__I2C1_SCL +218 MX35_PAD_I2C1_CLK__GPIO2_24 +219 MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK +220 MX35_PAD_I2C1_DAT__I2C1_SDA +221 MX35_PAD_I2C1_DAT__GPIO2_25 +222 MX35_PAD_I2C2_CLK__I2C2_SCL +223 MX35_PAD_I2C2_CLK__CAN1_TXCAN +224 MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR +225 MX35_PAD_I2C2_CLK__GPIO2_26 +226 MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2 +227 MX35_PAD_I2C2_DAT__I2C2_SDA +228 MX35_PAD_I2C2_DAT__CAN1_RXCAN +229 MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC +230 MX35_PAD_I2C2_DAT__GPIO2_27 +231 MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3 +232 MX35_PAD_STXD4__AUDMUX_AUD4_TXD +233 MX35_PAD_STXD4__GPIO2_28 +234 MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0 +235 MX35_PAD_SRXD4__AUDMUX_AUD4_RXD +236 MX35_PAD_SRXD4__GPIO2_29 +237 MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1 +238 MX35_PAD_SCK4__AUDMUX_AUD4_TXC +239 MX35_PAD_SCK4__GPIO2_30 +240 MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2 +241 MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS +242 MX35_PAD_STXFS4__GPIO2_31 +243 MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3 +244 MX35_PAD_STXD5__AUDMUX_AUD5_TXD +245 MX35_PAD_STXD5__SPDIF_SPDIF_OUT1 +246 MX35_PAD_STXD5__CSPI2_MOSI +247 MX35_PAD_STXD5__GPIO1_0 +248 MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4 +249 MX35_PAD_SRXD5__AUDMUX_AUD5_RXD +250 MX35_PAD_SRXD5__SPDIF_SPDIF_IN1 +251 MX35_PAD_SRXD5__CSPI2_MISO +252 MX35_PAD_SRXD5__GPIO1_1 +253 MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5 +254 MX35_PAD_SCK5__AUDMUX_AUD5_TXC +255 MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK +256 MX35_PAD_SCK5__CSPI2_SCLK +257 MX35_PAD_SCK5__GPIO1_2 +258 MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6 +259 MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS +260 MX35_PAD_STXFS5__CSPI2_RDY +261 MX35_PAD_STXFS5__GPIO1_3 +262 MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7 +263 MX35_PAD_SCKR__ESAI_SCKR +264 MX35_PAD_SCKR__GPIO1_4 +265 MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10 +266 MX35_PAD_FSR__ESAI_FSR +267 MX35_PAD_FSR__GPIO1_5 +268 MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11 +269 MX35_PAD_HCKR__ESAI_HCKR +270 MX35_PAD_HCKR__AUDMUX_AUD5_RXFS +271 MX35_PAD_HCKR__CSPI2_SS0 +272 MX35_PAD_HCKR__IPU_FLASH_STROBE +273 MX35_PAD_HCKR__GPIO1_6 +274 MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12 +275 MX35_PAD_SCKT__ESAI_SCKT +276 MX35_PAD_SCKT__GPIO1_7 +277 MX35_PAD_SCKT__IPU_CSI_D_0 +278 MX35_PAD_SCKT__KPP_ROW_2 +279 MX35_PAD_FST__ESAI_FST +280 MX35_PAD_FST__GPIO1_8 +281 MX35_PAD_FST__IPU_CSI_D_1 +282 MX35_PAD_FST__KPP_ROW_3 +283 MX35_PAD_HCKT__ESAI_HCKT +284 MX35_PAD_HCKT__AUDMUX_AUD5_RXC +285 MX35_PAD_HCKT__GPIO1_9 +286 MX35_PAD_HCKT__IPU_CSI_D_2 +287 MX35_PAD_HCKT__KPP_COL_3 +288 MX35_PAD_TX5_RX0__ESAI_TX5_RX0 +289 MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC +290 MX35_PAD_TX5_RX0__CSPI2_SS2 +291 MX35_PAD_TX5_RX0__CAN2_TXCAN +292 MX35_PAD_TX5_RX0__UART2_DTR +293 MX35_PAD_TX5_RX0__GPIO1_10 +294 MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0 +295 MX35_PAD_TX4_RX1__ESAI_TX4_RX1 +296 MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS +297 MX35_PAD_TX4_RX1__CSPI2_SS3 +298 MX35_PAD_TX4_RX1__CAN2_RXCAN +299 MX35_PAD_TX4_RX1__UART2_DSR +300 MX35_PAD_TX4_RX1__GPIO1_11 +301 MX35_PAD_TX4_RX1__IPU_CSI_D_3 +302 MX35_PAD_TX4_RX1__KPP_ROW_0 +303 MX35_PAD_TX3_RX2__ESAI_TX3_RX2 +304 MX35_PAD_TX3_RX2__I2C3_SCL +305 MX35_PAD_TX3_RX2__EMI_NANDF_CE1 +306 MX35_PAD_TX3_RX2__GPIO1_12 +307 MX35_PAD_TX3_RX2__IPU_CSI_D_4 +308 MX35_PAD_TX3_RX2__KPP_ROW_1 +309 MX35_PAD_TX2_RX3__ESAI_TX2_RX3 +310 MX35_PAD_TX2_RX3__I2C3_SDA +311 MX35_PAD_TX2_RX3__EMI_NANDF_CE2 +312 MX35_PAD_TX2_RX3__GPIO1_13 +313 MX35_PAD_TX2_RX3__IPU_CSI_D_5 +314 MX35_PAD_TX2_RX3__KPP_COL_0 +315 MX35_PAD_TX1__ESAI_TX1 +316 MX35_PAD_TX1__CCM_PMIC_RDY +317 MX35_PAD_TX1__CSPI1_SS2 +318 MX35_PAD_TX1__EMI_NANDF_CE3 +319 MX35_PAD_TX1__UART2_RI +320 MX35_PAD_TX1__GPIO1_14 +321 MX35_PAD_TX1__IPU_CSI_D_6 +322 MX35_PAD_TX1__KPP_COL_1 +323 MX35_PAD_TX0__ESAI_TX0 +324 MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK +325 MX35_PAD_TX0__CSPI1_SS3 +326 MX35_PAD_TX0__EMI_DTACK_B +327 MX35_PAD_TX0__UART2_DCD +328 MX35_PAD_TX0__GPIO1_15 +329 MX35_PAD_TX0__IPU_CSI_D_7 +330 MX35_PAD_TX0__KPP_COL_2 +331 MX35_PAD_CSPI1_MOSI__CSPI1_MOSI +332 MX35_PAD_CSPI1_MOSI__GPIO1_16 +333 MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2 +334 MX35_PAD_CSPI1_MISO__CSPI1_MISO +335 MX35_PAD_CSPI1_MISO__GPIO1_17 +336 MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3 +337 MX35_PAD_CSPI1_SS0__CSPI1_SS0 +338 MX35_PAD_CSPI1_SS0__OWIRE_LINE +339 MX35_PAD_CSPI1_SS0__CSPI2_SS3 +340 MX35_PAD_CSPI1_SS0__GPIO1_18 +341 MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4 +342 MX35_PAD_CSPI1_SS1__CSPI1_SS1 +343 MX35_PAD_CSPI1_SS1__PWM_PWMO +344 MX35_PAD_CSPI1_SS1__CCM_CLK32K +345 MX35_PAD_CSPI1_SS1__GPIO1_19 +346 MX35_PAD_CSPI1_SS1__IPU_DIAGB_29 +347 MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5 +348 MX35_PAD_CSPI1_SCLK__CSPI1_SCLK +349 MX35_PAD_CSPI1_SCLK__GPIO3_4 +350 MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30 +351 MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1 +352 MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY +353 MX35_PAD_CSPI1_SPI_RDY__GPIO3_5 +354 MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31 +355 MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2 +356 MX35_PAD_RXD1__UART1_RXD_MUX +357 MX35_PAD_RXD1__CSPI2_MOSI +358 MX35_PAD_RXD1__KPP_COL_4 +359 MX35_PAD_RXD1__GPIO3_6 +360 MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16 +361 MX35_PAD_TXD1__UART1_TXD_MUX +362 MX35_PAD_TXD1__CSPI2_MISO +363 MX35_PAD_TXD1__KPP_COL_5 +364 MX35_PAD_TXD1__GPIO3_7 +365 MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17 +366 MX35_PAD_RTS1__UART1_RTS +367 MX35_PAD_RTS1__CSPI2_SCLK +368 MX35_PAD_RTS1__I2C3_SCL +369 MX35_PAD_RTS1__IPU_CSI_D_0 +370 MX35_PAD_RTS1__KPP_COL_6 +371 MX35_PAD_RTS1__GPIO3_8 +372 MX35_PAD_RTS1__EMI_NANDF_CE1 +373 MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18 +374 MX35_PAD_CTS1__UART1_CTS +375 MX35_PAD_CTS1__CSPI2_RDY +376 MX35_PAD_CTS1__I2C3_SDA +377 MX35_PAD_CTS1__IPU_CSI_D_1 +378 MX35_PAD_CTS1__KPP_COL_7 +379 MX35_PAD_CTS1__GPIO3_9 +380 MX35_PAD_CTS1__EMI_NANDF_CE2 +381 MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19 +382 MX35_PAD_RXD2__UART2_RXD_MUX +383 MX35_PAD_RXD2__KPP_ROW_4 +384 MX35_PAD_RXD2__GPIO3_10 +385 MX35_PAD_TXD2__UART2_TXD_MUX +386 MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK +387 MX35_PAD_TXD2__KPP_ROW_5 +388 MX35_PAD_TXD2__GPIO3_11 +389 MX35_PAD_RTS2__UART2_RTS +390 MX35_PAD_RTS2__SPDIF_SPDIF_IN1 +391 MX35_PAD_RTS2__CAN2_RXCAN +392 MX35_PAD_RTS2__IPU_CSI_D_2 +393 MX35_PAD_RTS2__KPP_ROW_6 +394 MX35_PAD_RTS2__GPIO3_12 +395 MX35_PAD_RTS2__AUDMUX_AUD5_RXC +396 MX35_PAD_RTS2__UART3_RXD_MUX +397 MX35_PAD_CTS2__UART2_CTS +398 MX35_PAD_CTS2__SPDIF_SPDIF_OUT1 +399 MX35_PAD_CTS2__CAN2_TXCAN +400 MX35_PAD_CTS2__IPU_CSI_D_3 +401 MX35_PAD_CTS2__KPP_ROW_7 +402 MX35_PAD_CTS2__GPIO3_13 +403 MX35_PAD_CTS2__AUDMUX_AUD5_RXFS +404 MX35_PAD_CTS2__UART3_TXD_MUX +405 MX35_PAD_RTCK__ARM11P_TOP_RTCK +406 MX35_PAD_TCK__SJC_TCK +407 MX35_PAD_TMS__SJC_TMS +408 MX35_PAD_TDI__SJC_TDI +409 MX35_PAD_TDO__SJC_TDO +410 MX35_PAD_TRSTB__SJC_TRSTB +411 MX35_PAD_DE_B__SJC_DE_B +412 MX35_PAD_SJC_MOD__SJC_MOD +413 MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR +414 MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR +415 MX35_PAD_USBOTG_PWR__GPIO3_14 +416 MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC +417 MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC +418 MX35_PAD_USBOTG_OC__GPIO3_15 +419 MX35_PAD_LD0__IPU_DISPB_DAT_0 +420 MX35_PAD_LD0__GPIO2_0 +421 MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0 +422 MX35_PAD_LD1__IPU_DISPB_DAT_1 +423 MX35_PAD_LD1__GPIO2_1 +424 MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1 +425 MX35_PAD_LD2__IPU_DISPB_DAT_2 +426 MX35_PAD_LD2__GPIO2_2 +427 MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2 +428 MX35_PAD_LD3__IPU_DISPB_DAT_3 +429 MX35_PAD_LD3__GPIO2_3 +430 MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3 +431 MX35_PAD_LD4__IPU_DISPB_DAT_4 +432 MX35_PAD_LD4__GPIO2_4 +433 MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4 +434 MX35_PAD_LD5__IPU_DISPB_DAT_5 +435 MX35_PAD_LD5__GPIO2_5 +436 MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5 +437 MX35_PAD_LD6__IPU_DISPB_DAT_6 +438 MX35_PAD_LD6__GPIO2_6 +439 MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6 +440 MX35_PAD_LD7__IPU_DISPB_DAT_7 +441 MX35_PAD_LD7__GPIO2_7 +442 MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7 +443 MX35_PAD_LD8__IPU_DISPB_DAT_8 +444 MX35_PAD_LD8__GPIO2_8 +445 MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8 +446 MX35_PAD_LD9__IPU_DISPB_DAT_9 +447 MX35_PAD_LD9__GPIO2_9 +448 MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9 +449 MX35_PAD_LD10__IPU_DISPB_DAT_10 +450 MX35_PAD_LD10__GPIO2_10 +451 MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10 +452 MX35_PAD_LD11__IPU_DISPB_DAT_11 +453 MX35_PAD_LD11__GPIO2_11 +454 MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11 +455 MX35_PAD_LD11__ARM11P_TOP_TRACE_4 +456 MX35_PAD_LD12__IPU_DISPB_DAT_12 +457 MX35_PAD_LD12__GPIO2_12 +458 MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12 +459 MX35_PAD_LD12__ARM11P_TOP_TRACE_5 +460 MX35_PAD_LD13__IPU_DISPB_DAT_13 +461 MX35_PAD_LD13__GPIO2_13 +462 MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13 +463 MX35_PAD_LD13__ARM11P_TOP_TRACE_6 +464 MX35_PAD_LD14__IPU_DISPB_DAT_14 +465 MX35_PAD_LD14__GPIO2_14 +466 MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0 +467 MX35_PAD_LD14__ARM11P_TOP_TRACE_7 +468 MX35_PAD_LD15__IPU_DISPB_DAT_15 +469 MX35_PAD_LD15__GPIO2_15 +470 MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1 +471 MX35_PAD_LD15__ARM11P_TOP_TRACE_8 +472 MX35_PAD_LD16__IPU_DISPB_DAT_16 +473 MX35_PAD_LD16__IPU_DISPB_D12_VSYNC +474 MX35_PAD_LD16__GPIO2_16 +475 MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2 +476 MX35_PAD_LD16__ARM11P_TOP_TRACE_9 +477 MX35_PAD_LD17__IPU_DISPB_DAT_17 +478 MX35_PAD_LD17__IPU_DISPB_CS2 +479 MX35_PAD_LD17__GPIO2_17 +480 MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3 +481 MX35_PAD_LD17__ARM11P_TOP_TRACE_10 +482 MX35_PAD_LD18__IPU_DISPB_DAT_18 +483 MX35_PAD_LD18__IPU_DISPB_D0_VSYNC +484 MX35_PAD_LD18__IPU_DISPB_D12_VSYNC +485 MX35_PAD_LD18__ESDHC3_CMD +486 MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3 +487 MX35_PAD_LD18__GPIO3_24 +488 MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4 +489 MX35_PAD_LD18__ARM11P_TOP_TRACE_11 +490 MX35_PAD_LD19__IPU_DISPB_DAT_19 +491 MX35_PAD_LD19__IPU_DISPB_BCLK +492 MX35_PAD_LD19__IPU_DISPB_CS1 +493 MX35_PAD_LD19__ESDHC3_CLK +494 MX35_PAD_LD19__USB_TOP_USBOTG_DIR +495 MX35_PAD_LD19__GPIO3_25 +496 MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5 +497 MX35_PAD_LD19__ARM11P_TOP_TRACE_12 +498 MX35_PAD_LD20__IPU_DISPB_DAT_20 +499 MX35_PAD_LD20__IPU_DISPB_CS0 +500 MX35_PAD_LD20__IPU_DISPB_SD_CLK +501 MX35_PAD_LD20__ESDHC3_DAT0 +502 MX35_PAD_LD20__GPIO3_26 +503 MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3 +504 MX35_PAD_LD20__ARM11P_TOP_TRACE_13 +505 MX35_PAD_LD21__IPU_DISPB_DAT_21 +506 MX35_PAD_LD21__IPU_DISPB_PAR_RS +507 MX35_PAD_LD21__IPU_DISPB_SER_RS +508 MX35_PAD_LD21__ESDHC3_DAT1 +509 MX35_PAD_LD21__USB_TOP_USBOTG_STP +510 MX35_PAD_LD21__GPIO3_27 +511 MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL +512 MX35_PAD_LD21__ARM11P_TOP_TRACE_14 +513 MX35_PAD_LD22__IPU_DISPB_DAT_22 +514 MX35_PAD_LD22__IPU_DISPB_WR +515 MX35_PAD_LD22__IPU_DISPB_SD_D_I +516 MX35_PAD_LD22__ESDHC3_DAT2 +517 MX35_PAD_LD22__USB_TOP_USBOTG_NXT +518 MX35_PAD_LD22__GPIO3_28 +519 MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR +520 MX35_PAD_LD22__ARM11P_TOP_TRCTL +521 MX35_PAD_LD23__IPU_DISPB_DAT_23 +522 MX35_PAD_LD23__IPU_DISPB_RD +523 MX35_PAD_LD23__IPU_DISPB_SD_D_IO +524 MX35_PAD_LD23__ESDHC3_DAT3 +525 MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7 +526 MX35_PAD_LD23__GPIO3_29 +527 MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS +528 MX35_PAD_LD23__ARM11P_TOP_TRCLK +529 MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC +530 MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO +531 MX35_PAD_D3_HSYNC__GPIO3_30 +532 MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE +533 MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15 +534 MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK +535 MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK +536 MX35_PAD_D3_FPSHIFT__GPIO3_31 +537 MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0 +538 MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16 +539 MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY +540 MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O +541 MX35_PAD_D3_DRDY__GPIO1_0 +542 MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1 +543 MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17 +544 MX35_PAD_CONTRAST__IPU_DISPB_CONTR +545 MX35_PAD_CONTRAST__GPIO1_1 +546 MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2 +547 MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18 +548 MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC +549 MX35_PAD_D3_VSYNC__IPU_DISPB_CS1 +550 MX35_PAD_D3_VSYNC__GPIO1_2 +551 MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD +552 MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19 +553 MX35_PAD_D3_REV__IPU_DISPB_D3_REV +554 MX35_PAD_D3_REV__IPU_DISPB_SER_RS +555 MX35_PAD_D3_REV__GPIO1_3 +556 MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB +557 MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20 +558 MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS +559 MX35_PAD_D3_CLS__IPU_DISPB_CS2 +560 MX35_PAD_D3_CLS__GPIO1_4 +561 MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0 +562 MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21 +563 MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL +564 MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC +565 MX35_PAD_D3_SPL__GPIO1_5 +566 MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1 +567 MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22 +568 MX35_PAD_SD1_CMD__ESDHC1_CMD +569 MX35_PAD_SD1_CMD__MSHC_SCLK +570 MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC +571 MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4 +572 MX35_PAD_SD1_CMD__GPIO1_6 +573 MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL +574 MX35_PAD_SD1_CLK__ESDHC1_CLK +575 MX35_PAD_SD1_CLK__MSHC_BS +576 MX35_PAD_SD1_CLK__IPU_DISPB_BCLK +577 MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5 +578 MX35_PAD_SD1_CLK__GPIO1_7 +579 MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK +580 MX35_PAD_SD1_DATA0__ESDHC1_DAT0 +581 MX35_PAD_SD1_DATA0__MSHC_DATA_0 +582 MX35_PAD_SD1_DATA0__IPU_DISPB_CS0 +583 MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6 +584 MX35_PAD_SD1_DATA0__GPIO1_8 +585 MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23 +586 MX35_PAD_SD1_DATA1__ESDHC1_DAT1 +587 MX35_PAD_SD1_DATA1__MSHC_DATA_1 +588 MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS +589 MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0 +590 MX35_PAD_SD1_DATA1__GPIO1_9 +591 MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24 +592 MX35_PAD_SD1_DATA2__ESDHC1_DAT2 +593 MX35_PAD_SD1_DATA2__MSHC_DATA_2 +594 MX35_PAD_SD1_DATA2__IPU_DISPB_WR +595 MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1 +596 MX35_PAD_SD1_DATA2__GPIO1_10 +597 MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25 +598 MX35_PAD_SD1_DATA3__ESDHC1_DAT3 +599 MX35_PAD_SD1_DATA3__MSHC_DATA_3 +600 MX35_PAD_SD1_DATA3__IPU_DISPB_RD +601 MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2 +602 MX35_PAD_SD1_DATA3__GPIO1_11 +603 MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26 +604 MX35_PAD_SD2_CMD__ESDHC2_CMD +605 MX35_PAD_SD2_CMD__I2C3_SCL +606 MX35_PAD_SD2_CMD__ESDHC1_DAT4 +607 MX35_PAD_SD2_CMD__IPU_CSI_D_2 +608 MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4 +609 MX35_PAD_SD2_CMD__GPIO2_0 +610 MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1 +611 MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC +612 MX35_PAD_SD2_CLK__ESDHC2_CLK +613 MX35_PAD_SD2_CLK__I2C3_SDA +614 MX35_PAD_SD2_CLK__ESDHC1_DAT5 +615 MX35_PAD_SD2_CLK__IPU_CSI_D_3 +616 MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5 +617 MX35_PAD_SD2_CLK__GPIO2_1 +618 MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1 +619 MX35_PAD_SD2_CLK__IPU_DISPB_CS2 +620 MX35_PAD_SD2_DATA0__ESDHC2_DAT0 +621 MX35_PAD_SD2_DATA0__UART3_RXD_MUX +622 MX35_PAD_SD2_DATA0__ESDHC1_DAT6 +623 MX35_PAD_SD2_DATA0__IPU_CSI_D_4 +624 MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6 +625 MX35_PAD_SD2_DATA0__GPIO2_2 +626 MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK +627 MX35_PAD_SD2_DATA1__ESDHC2_DAT1 +628 MX35_PAD_SD2_DATA1__UART3_TXD_MUX +629 MX35_PAD_SD2_DATA1__ESDHC1_DAT7 +630 MX35_PAD_SD2_DATA1__IPU_CSI_D_5 +631 MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0 +632 MX35_PAD_SD2_DATA1__GPIO2_3 +633 MX35_PAD_SD2_DATA2__ESDHC2_DAT2 +634 MX35_PAD_SD2_DATA2__UART3_RTS +635 MX35_PAD_SD2_DATA2__CAN1_RXCAN +636 MX35_PAD_SD2_DATA2__IPU_CSI_D_6 +637 MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1 +638 MX35_PAD_SD2_DATA2__GPIO2_4 +639 MX35_PAD_SD2_DATA3__ESDHC2_DAT3 +640 MX35_PAD_SD2_DATA3__UART3_CTS +641 MX35_PAD_SD2_DATA3__CAN1_TXCAN +642 MX35_PAD_SD2_DATA3__IPU_CSI_D_7 +643 MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2 +644 MX35_PAD_SD2_DATA3__GPIO2_5 +645 MX35_PAD_ATA_CS0__ATA_CS0 +646 MX35_PAD_ATA_CS0__CSPI1_SS3 +647 MX35_PAD_ATA_CS0__IPU_DISPB_CS1 +648 MX35_PAD_ATA_CS0__GPIO2_6 +649 MX35_PAD_ATA_CS0__IPU_DIAGB_0 +650 MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0 +651 MX35_PAD_ATA_CS1__ATA_CS1 +652 MX35_PAD_ATA_CS1__IPU_DISPB_CS2 +653 MX35_PAD_ATA_CS1__CSPI2_SS0 +654 MX35_PAD_ATA_CS1__GPIO2_7 +655 MX35_PAD_ATA_CS1__IPU_DIAGB_1 +656 MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1 +657 MX35_PAD_ATA_DIOR__ATA_DIOR +658 MX35_PAD_ATA_DIOR__ESDHC3_DAT0 +659 MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR +660 MX35_PAD_ATA_DIOR__IPU_DISPB_BE0 +661 MX35_PAD_ATA_DIOR__CSPI2_SS1 +662 MX35_PAD_ATA_DIOR__GPIO2_8 +663 MX35_PAD_ATA_DIOR__IPU_DIAGB_2 +664 MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2 +665 MX35_PAD_ATA_DIOW__ATA_DIOW +666 MX35_PAD_ATA_DIOW__ESDHC3_DAT1 +667 MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP +668 MX35_PAD_ATA_DIOW__IPU_DISPB_BE1 +669 MX35_PAD_ATA_DIOW__CSPI2_MOSI +670 MX35_PAD_ATA_DIOW__GPIO2_9 +671 MX35_PAD_ATA_DIOW__IPU_DIAGB_3 +672 MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3 +673 MX35_PAD_ATA_DMACK__ATA_DMACK +674 MX35_PAD_ATA_DMACK__ESDHC3_DAT2 +675 MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT +676 MX35_PAD_ATA_DMACK__CSPI2_MISO +677 MX35_PAD_ATA_DMACK__GPIO2_10 +678 MX35_PAD_ATA_DMACK__IPU_DIAGB_4 +679 MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0 +680 MX35_PAD_ATA_RESET_B__ATA_RESET_B +681 MX35_PAD_ATA_RESET_B__ESDHC3_DAT3 +682 MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0 +683 MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O +684 MX35_PAD_ATA_RESET_B__CSPI2_RDY +685 MX35_PAD_ATA_RESET_B__GPIO2_11 +686 MX35_PAD_ATA_RESET_B__IPU_DIAGB_5 +687 MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1 +688 MX35_PAD_ATA_IORDY__ATA_IORDY +689 MX35_PAD_ATA_IORDY__ESDHC3_DAT4 +690 MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1 +691 MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO +692 MX35_PAD_ATA_IORDY__ESDHC2_DAT4 +693 MX35_PAD_ATA_IORDY__GPIO2_12 +694 MX35_PAD_ATA_IORDY__IPU_DIAGB_6 +695 MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2 +696 MX35_PAD_ATA_DATA0__ATA_DATA_0 +697 MX35_PAD_ATA_DATA0__ESDHC3_DAT5 +698 MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2 +699 MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC +700 MX35_PAD_ATA_DATA0__ESDHC2_DAT5 +701 MX35_PAD_ATA_DATA0__GPIO2_13 +702 MX35_PAD_ATA_DATA0__IPU_DIAGB_7 +703 MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3 +704 MX35_PAD_ATA_DATA1__ATA_DATA_1 +705 MX35_PAD_ATA_DATA1__ESDHC3_DAT6 +706 MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3 +707 MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK +708 MX35_PAD_ATA_DATA1__ESDHC2_DAT6 +709 MX35_PAD_ATA_DATA1__GPIO2_14 +710 MX35_PAD_ATA_DATA1__IPU_DIAGB_8 +711 MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27 +712 MX35_PAD_ATA_DATA2__ATA_DATA_2 +713 MX35_PAD_ATA_DATA2__ESDHC3_DAT7 +714 MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4 +715 MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS +716 MX35_PAD_ATA_DATA2__ESDHC2_DAT7 +717 MX35_PAD_ATA_DATA2__GPIO2_15 +718 MX35_PAD_ATA_DATA2__IPU_DIAGB_9 +719 MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28 +720 MX35_PAD_ATA_DATA3__ATA_DATA_3 +721 MX35_PAD_ATA_DATA3__ESDHC3_CLK +722 MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5 +723 MX35_PAD_ATA_DATA3__CSPI2_SCLK +724 MX35_PAD_ATA_DATA3__GPIO2_16 +725 MX35_PAD_ATA_DATA3__IPU_DIAGB_10 +726 MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29 +727 MX35_PAD_ATA_DATA4__ATA_DATA_4 +728 MX35_PAD_ATA_DATA4__ESDHC3_CMD +729 MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6 +730 MX35_PAD_ATA_DATA4__GPIO2_17 +731 MX35_PAD_ATA_DATA4__IPU_DIAGB_11 +732 MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30 +733 MX35_PAD_ATA_DATA5__ATA_DATA_5 +734 MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7 +735 MX35_PAD_ATA_DATA5__GPIO2_18 +736 MX35_PAD_ATA_DATA5__IPU_DIAGB_12 +737 MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31 +738 MX35_PAD_ATA_DATA6__ATA_DATA_6 +739 MX35_PAD_ATA_DATA6__CAN1_TXCAN +740 MX35_PAD_ATA_DATA6__UART1_DTR +741 MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD +742 MX35_PAD_ATA_DATA6__GPIO2_19 +743 MX35_PAD_ATA_DATA6__IPU_DIAGB_13 +744 MX35_PAD_ATA_DATA7__ATA_DATA_7 +745 MX35_PAD_ATA_DATA7__CAN1_RXCAN +746 MX35_PAD_ATA_DATA7__UART1_DSR +747 MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD +748 MX35_PAD_ATA_DATA7__GPIO2_20 +749 MX35_PAD_ATA_DATA7__IPU_DIAGB_14 +750 MX35_PAD_ATA_DATA8__ATA_DATA_8 +751 MX35_PAD_ATA_DATA8__UART3_RTS +752 MX35_PAD_ATA_DATA8__UART1_RI +753 MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC +754 MX35_PAD_ATA_DATA8__GPIO2_21 +755 MX35_PAD_ATA_DATA8__IPU_DIAGB_15 +756 MX35_PAD_ATA_DATA9__ATA_DATA_9 +757 MX35_PAD_ATA_DATA9__UART3_CTS +758 MX35_PAD_ATA_DATA9__UART1_DCD +759 MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS +760 MX35_PAD_ATA_DATA9__GPIO2_22 +761 MX35_PAD_ATA_DATA9__IPU_DIAGB_16 +762 MX35_PAD_ATA_DATA10__ATA_DATA_10 +763 MX35_PAD_ATA_DATA10__UART3_RXD_MUX +764 MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC +765 MX35_PAD_ATA_DATA10__GPIO2_23 +766 MX35_PAD_ATA_DATA10__IPU_DIAGB_17 +767 MX35_PAD_ATA_DATA11__ATA_DATA_11 +768 MX35_PAD_ATA_DATA11__UART3_TXD_MUX +769 MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS +770 MX35_PAD_ATA_DATA11__GPIO2_24 +771 MX35_PAD_ATA_DATA11__IPU_DIAGB_18 +772 MX35_PAD_ATA_DATA12__ATA_DATA_12 +773 MX35_PAD_ATA_DATA12__I2C3_SCL +774 MX35_PAD_ATA_DATA12__GPIO2_25 +775 MX35_PAD_ATA_DATA12__IPU_DIAGB_19 +776 MX35_PAD_ATA_DATA13__ATA_DATA_13 +777 MX35_PAD_ATA_DATA13__I2C3_SDA +778 MX35_PAD_ATA_DATA13__GPIO2_26 +779 MX35_PAD_ATA_DATA13__IPU_DIAGB_20 +780 MX35_PAD_ATA_DATA14__ATA_DATA_14 +781 MX35_PAD_ATA_DATA14__IPU_CSI_D_0 +782 MX35_PAD_ATA_DATA14__KPP_ROW_0 +783 MX35_PAD_ATA_DATA14__GPIO2_27 +784 MX35_PAD_ATA_DATA14__IPU_DIAGB_21 +785 MX35_PAD_ATA_DATA15__ATA_DATA_15 +786 MX35_PAD_ATA_DATA15__IPU_CSI_D_1 +787 MX35_PAD_ATA_DATA15__KPP_ROW_1 +788 MX35_PAD_ATA_DATA15__GPIO2_28 +789 MX35_PAD_ATA_DATA15__IPU_DIAGB_22 +790 MX35_PAD_ATA_INTRQ__ATA_INTRQ +791 MX35_PAD_ATA_INTRQ__IPU_CSI_D_2 +792 MX35_PAD_ATA_INTRQ__KPP_ROW_2 +793 MX35_PAD_ATA_INTRQ__GPIO2_29 +794 MX35_PAD_ATA_INTRQ__IPU_DIAGB_23 +795 MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN +796 MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3 +797 MX35_PAD_ATA_BUFF_EN__KPP_ROW_3 +798 MX35_PAD_ATA_BUFF_EN__GPIO2_30 +799 MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24 +800 MX35_PAD_ATA_DMARQ__ATA_DMARQ +801 MX35_PAD_ATA_DMARQ__IPU_CSI_D_4 +802 MX35_PAD_ATA_DMARQ__KPP_COL_0 +803 MX35_PAD_ATA_DMARQ__GPIO2_31 +804 MX35_PAD_ATA_DMARQ__IPU_DIAGB_25 +805 MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4 +806 MX35_PAD_ATA_DA0__ATA_DA_0 +807 MX35_PAD_ATA_DA0__IPU_CSI_D_5 +808 MX35_PAD_ATA_DA0__KPP_COL_1 +809 MX35_PAD_ATA_DA0__GPIO3_0 +810 MX35_PAD_ATA_DA0__IPU_DIAGB_26 +811 MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5 +812 MX35_PAD_ATA_DA1__ATA_DA_1 +813 MX35_PAD_ATA_DA1__IPU_CSI_D_6 +814 MX35_PAD_ATA_DA1__KPP_COL_2 +815 MX35_PAD_ATA_DA1__GPIO3_1 +816 MX35_PAD_ATA_DA1__IPU_DIAGB_27 +817 MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6 +818 MX35_PAD_ATA_DA2__ATA_DA_2 +819 MX35_PAD_ATA_DA2__IPU_CSI_D_7 +820 MX35_PAD_ATA_DA2__KPP_COL_3 +821 MX35_PAD_ATA_DA2__GPIO3_2 +822 MX35_PAD_ATA_DA2__IPU_DIAGB_28 +823 MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7 +824 MX35_PAD_MLB_CLK__MLB_MLBCLK +825 MX35_PAD_MLB_CLK__GPIO3_3 +826 MX35_PAD_MLB_DAT__MLB_MLBDAT +827 MX35_PAD_MLB_DAT__GPIO3_4 +828 MX35_PAD_MLB_SIG__MLB_MLBSIG +829 MX35_PAD_MLB_SIG__GPIO3_5 +830 MX35_PAD_FEC_TX_CLK__FEC_TX_CLK +831 MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4 +832 MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX +833 MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR +834 MX35_PAD_FEC_TX_CLK__CSPI2_MOSI +835 MX35_PAD_FEC_TX_CLK__GPIO3_6 +836 MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC +837 MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0 +838 MX35_PAD_FEC_RX_CLK__FEC_RX_CLK +839 MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5 +840 MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX +841 MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP +842 MX35_PAD_FEC_RX_CLK__CSPI2_MISO +843 MX35_PAD_FEC_RX_CLK__GPIO3_7 +844 MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I +845 MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1 +846 MX35_PAD_FEC_RX_DV__FEC_RX_DV +847 MX35_PAD_FEC_RX_DV__ESDHC1_DAT6 +848 MX35_PAD_FEC_RX_DV__UART3_RTS +849 MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT +850 MX35_PAD_FEC_RX_DV__CSPI2_SCLK +851 MX35_PAD_FEC_RX_DV__GPIO3_8 +852 MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK +853 MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2 +854 MX35_PAD_FEC_COL__FEC_COL +855 MX35_PAD_FEC_COL__ESDHC1_DAT7 +856 MX35_PAD_FEC_COL__UART3_CTS +857 MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0 +858 MX35_PAD_FEC_COL__CSPI2_RDY +859 MX35_PAD_FEC_COL__GPIO3_9 +860 MX35_PAD_FEC_COL__IPU_DISPB_SER_RS +861 MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3 +862 MX35_PAD_FEC_RDATA0__FEC_RDATA_0 +863 MX35_PAD_FEC_RDATA0__PWM_PWMO +864 MX35_PAD_FEC_RDATA0__UART3_DTR +865 MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1 +866 MX35_PAD_FEC_RDATA0__CSPI2_SS0 +867 MX35_PAD_FEC_RDATA0__GPIO3_10 +868 MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1 +869 MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4 +870 MX35_PAD_FEC_TDATA0__FEC_TDATA_0 +871 MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1 +872 MX35_PAD_FEC_TDATA0__UART3_DSR +873 MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2 +874 MX35_PAD_FEC_TDATA0__CSPI2_SS1 +875 MX35_PAD_FEC_TDATA0__GPIO3_11 +876 MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0 +877 MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5 +878 MX35_PAD_FEC_TX_EN__FEC_TX_EN +879 MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1 +880 MX35_PAD_FEC_TX_EN__UART3_RI +881 MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3 +882 MX35_PAD_FEC_TX_EN__GPIO3_12 +883 MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS +884 MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6 +885 MX35_PAD_FEC_MDC__FEC_MDC +886 MX35_PAD_FEC_MDC__CAN2_TXCAN +887 MX35_PAD_FEC_MDC__UART3_DCD +888 MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4 +889 MX35_PAD_FEC_MDC__GPIO3_13 +890 MX35_PAD_FEC_MDC__IPU_DISPB_WR +891 MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7 +892 MX35_PAD_FEC_MDIO__FEC_MDIO +893 MX35_PAD_FEC_MDIO__CAN2_RXCAN +894 MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5 +895 MX35_PAD_FEC_MDIO__GPIO3_14 +896 MX35_PAD_FEC_MDIO__IPU_DISPB_RD +897 MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8 +898 MX35_PAD_FEC_TX_ERR__FEC_TX_ERR +899 MX35_PAD_FEC_TX_ERR__OWIRE_LINE +900 MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK +901 MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6 +902 MX35_PAD_FEC_TX_ERR__GPIO3_15 +903 MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC +904 MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9 +905 MX35_PAD_FEC_RX_ERR__FEC_RX_ERR +906 MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0 +907 MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7 +908 MX35_PAD_FEC_RX_ERR__KPP_COL_4 +909 MX35_PAD_FEC_RX_ERR__GPIO3_16 +910 MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO +911 MX35_PAD_FEC_CRS__FEC_CRS +912 MX35_PAD_FEC_CRS__IPU_CSI_D_1 +913 MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR +914 MX35_PAD_FEC_CRS__KPP_COL_5 +915 MX35_PAD_FEC_CRS__GPIO3_17 +916 MX35_PAD_FEC_CRS__IPU_FLASH_STROBE +917 MX35_PAD_FEC_RDATA1__FEC_RDATA_1 +918 MX35_PAD_FEC_RDATA1__IPU_CSI_D_2 +919 MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC +920 MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC +921 MX35_PAD_FEC_RDATA1__KPP_COL_6 +922 MX35_PAD_FEC_RDATA1__GPIO3_18 +923 MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0 +924 MX35_PAD_FEC_TDATA1__FEC_TDATA_1 +925 MX35_PAD_FEC_TDATA1__IPU_CSI_D_3 +926 MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS +927 MX35_PAD_FEC_TDATA1__KPP_COL_7 +928 MX35_PAD_FEC_TDATA1__GPIO3_19 +929 MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1 +930 MX35_PAD_FEC_RDATA2__FEC_RDATA_2 +931 MX35_PAD_FEC_RDATA2__IPU_CSI_D_4 +932 MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD +933 MX35_PAD_FEC_RDATA2__KPP_ROW_4 +934 MX35_PAD_FEC_RDATA2__GPIO3_20 +935 MX35_PAD_FEC_TDATA2__FEC_TDATA_2 +936 MX35_PAD_FEC_TDATA2__IPU_CSI_D_5 +937 MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD +938 MX35_PAD_FEC_TDATA2__KPP_ROW_5 +939 MX35_PAD_FEC_TDATA2__GPIO3_21 +940 MX35_PAD_FEC_RDATA3__FEC_RDATA_3 +941 MX35_PAD_FEC_RDATA3__IPU_CSI_D_6 +942 MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC +943 MX35_PAD_FEC_RDATA3__KPP_ROW_6 +944 MX35_PAD_FEC_RDATA3__GPIO3_22 +945 MX35_PAD_FEC_TDATA3__FEC_TDATA_3 +946 MX35_PAD_FEC_TDATA3__IPU_CSI_D_7 +947 MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS +948 MX35_PAD_FEC_TDATA3__KPP_ROW_7 +949 MX35_PAD_FEC_TDATA3__GPIO3_23 +950 MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK +951 MX35_PAD_TEST_MODE__TCU_TEST_MODE diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 606b953009c..73aafd96271 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -31,6 +31,14 @@ config PINCTRL_IMX select PINMUX select PINCONF +config PINCTRL_IMX35 + bool "IMX35 pinctrl driver" + depends on OF + depends on SOC_IMX35 + select PINCTRL_IMX + help + Say Y here to enable the imx35 pinctrl driver + config PINCTRL_IMX51 bool "IMX51 pinctrl driver" depends on OF diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 59ef7653798..cda3984951e 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL) += devicetree.o endif obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o +obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o diff --git a/drivers/pinctrl/pinctrl-imx35.c b/drivers/pinctrl/pinctrl-imx35.c new file mode 100644 index 00000000000..82f109e26f2 --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx35.c @@ -0,0 +1,1595 @@ +/* + * imx35 pinctrl driver. + * + * This driver was mostly copied from the imx51 pinctrl driver which has: + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro, Inc. + * + * Author: Dong Aisheng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx35_pads { + MX35_PAD_CAPTURE = 0, + MX35_PAD_COMPARE = 1, + MX35_PAD_WDOG_RST = 2, + MX35_PAD_GPIO1_0 = 3, + MX35_PAD_GPIO1_1 = 4, + MX35_PAD_GPIO2_0 = 5, + MX35_PAD_GPIO3_0 = 6, + MX35_PAD_RESET_IN_B = 7, + MX35_PAD_POR_B = 8, + MX35_PAD_CLKO = 9, + MX35_PAD_BOOT_MODE0 = 10, + MX35_PAD_BOOT_MODE1 = 11, + MX35_PAD_CLK_MODE0 = 12, + MX35_PAD_CLK_MODE1 = 13, + MX35_PAD_POWER_FAIL = 14, + MX35_PAD_VSTBY = 15, + MX35_PAD_A0 = 16, + MX35_PAD_A1 = 17, + MX35_PAD_A2 = 18, + MX35_PAD_A3 = 19, + MX35_PAD_A4 = 20, + MX35_PAD_A5 = 21, + MX35_PAD_A6 = 22, + MX35_PAD_A7 = 23, + MX35_PAD_A8 = 24, + MX35_PAD_A9 = 25, + MX35_PAD_A10 = 26, + MX35_PAD_MA10 = 27, + MX35_PAD_A11 = 28, + MX35_PAD_A12 = 29, + MX35_PAD_A13 = 30, + MX35_PAD_A14 = 31, + MX35_PAD_A15 = 32, + MX35_PAD_A16 = 33, + MX35_PAD_A17 = 34, + MX35_PAD_A18 = 35, + MX35_PAD_A19 = 36, + MX35_PAD_A20 = 37, + MX35_PAD_A21 = 38, + MX35_PAD_A22 = 39, + MX35_PAD_A23 = 40, + MX35_PAD_A24 = 41, + MX35_PAD_A25 = 42, + MX35_PAD_SDBA1 = 43, + MX35_PAD_SDBA0 = 44, + MX35_PAD_SD0 = 45, + MX35_PAD_SD1 = 46, + MX35_PAD_SD2 = 47, + MX35_PAD_SD3 = 48, + MX35_PAD_SD4 = 49, + MX35_PAD_SD5 = 50, + MX35_PAD_SD6 = 51, + MX35_PAD_SD7 = 52, + MX35_PAD_SD8 = 53, + MX35_PAD_SD9 = 54, + MX35_PAD_SD10 = 55, + MX35_PAD_SD11 = 56, + MX35_PAD_SD12 = 57, + MX35_PAD_SD13 = 58, + MX35_PAD_SD14 = 59, + MX35_PAD_SD15 = 60, + MX35_PAD_SD16 = 61, + MX35_PAD_SD17 = 62, + MX35_PAD_SD18 = 63, + MX35_PAD_SD19 = 64, + MX35_PAD_SD20 = 65, + MX35_PAD_SD21 = 66, + MX35_PAD_SD22 = 67, + MX35_PAD_SD23 = 68, + MX35_PAD_SD24 = 69, + MX35_PAD_SD25 = 70, + MX35_PAD_SD26 = 71, + MX35_PAD_SD27 = 72, + MX35_PAD_SD28 = 73, + MX35_PAD_SD29 = 74, + MX35_PAD_SD30 = 75, + MX35_PAD_SD31 = 76, + MX35_PAD_DQM0 = 77, + MX35_PAD_DQM1 = 78, + MX35_PAD_DQM2 = 79, + MX35_PAD_DQM3 = 80, + MX35_PAD_EB0 = 81, + MX35_PAD_EB1 = 82, + MX35_PAD_OE = 83, + MX35_PAD_CS0 = 84, + MX35_PAD_CS1 = 85, + MX35_PAD_CS2 = 86, + MX35_PAD_CS3 = 87, + MX35_PAD_CS4 = 88, + MX35_PAD_CS5 = 89, + MX35_PAD_NF_CE0 = 90, + MX35_PAD_ECB = 91, + MX35_PAD_LBA = 92, + MX35_PAD_BCLK = 93, + MX35_PAD_RW = 94, + MX35_PAD_RAS = 95, + MX35_PAD_CAS = 96, + MX35_PAD_SDWE = 97, + MX35_PAD_SDCKE0 = 98, + MX35_PAD_SDCKE1 = 99, + MX35_PAD_SDCLK = 100, + MX35_PAD_SDQS0 = 101, + MX35_PAD_SDQS1 = 102, + MX35_PAD_SDQS2 = 103, + MX35_PAD_SDQS3 = 104, + MX35_PAD_NFWE_B = 105, + MX35_PAD_NFRE_B = 106, + MX35_PAD_NFALE = 107, + MX35_PAD_NFCLE = 108, + MX35_PAD_NFWP_B = 109, + MX35_PAD_NFRB = 110, + MX35_PAD_D15 = 111, + MX35_PAD_D14 = 112, + MX35_PAD_D13 = 113, + MX35_PAD_D12 = 114, + MX35_PAD_D11 = 115, + MX35_PAD_D10 = 116, + MX35_PAD_D9 = 117, + MX35_PAD_D8 = 118, + MX35_PAD_D7 = 119, + MX35_PAD_D6 = 120, + MX35_PAD_D5 = 121, + MX35_PAD_D4 = 122, + MX35_PAD_D3 = 123, + MX35_PAD_D2 = 124, + MX35_PAD_D1 = 125, + MX35_PAD_D0 = 126, + MX35_PAD_CSI_D8 = 127, + MX35_PAD_CSI_D9 = 128, + MX35_PAD_CSI_D10 = 129, + MX35_PAD_CSI_D11 = 130, + MX35_PAD_CSI_D12 = 131, + MX35_PAD_CSI_D13 = 132, + MX35_PAD_CSI_D14 = 133, + MX35_PAD_CSI_D15 = 134, + MX35_PAD_CSI_MCLK = 135, + MX35_PAD_CSI_VSYNC = 136, + MX35_PAD_CSI_HSYNC = 137, + MX35_PAD_CSI_PIXCLK = 138, + MX35_PAD_I2C1_CLK = 139, + MX35_PAD_I2C1_DAT = 140, + MX35_PAD_I2C2_CLK = 141, + MX35_PAD_I2C2_DAT = 142, + MX35_PAD_STXD4 = 143, + MX35_PAD_SRXD4 = 144, + MX35_PAD_SCK4 = 145, + MX35_PAD_STXFS4 = 146, + MX35_PAD_STXD5 = 147, + MX35_PAD_SRXD5 = 148, + MX35_PAD_SCK5 = 149, + MX35_PAD_STXFS5 = 150, + MX35_PAD_SCKR = 151, + MX35_PAD_FSR = 152, + MX35_PAD_HCKR = 153, + MX35_PAD_SCKT = 154, + MX35_PAD_FST = 155, + MX35_PAD_HCKT = 156, + MX35_PAD_TX5_RX0 = 157, + MX35_PAD_TX4_RX1 = 158, + MX35_PAD_TX3_RX2 = 159, + MX35_PAD_TX2_RX3 = 160, + MX35_PAD_TX1 = 161, + MX35_PAD_TX0 = 162, + MX35_PAD_CSPI1_MOSI = 163, + MX35_PAD_CSPI1_MISO = 164, + MX35_PAD_CSPI1_SS0 = 165, + MX35_PAD_CSPI1_SS1 = 166, + MX35_PAD_CSPI1_SCLK = 167, + MX35_PAD_CSPI1_SPI_RDY = 168, + MX35_PAD_RXD1 = 169, + MX35_PAD_TXD1 = 170, + MX35_PAD_RTS1 = 171, + MX35_PAD_CTS1 = 172, + MX35_PAD_RXD2 = 173, + MX35_PAD_TXD2 = 174, + MX35_PAD_RTS2 = 175, + MX35_PAD_CTS2 = 176, + MX35_PAD_RTCK = 177, + MX35_PAD_TCK = 178, + MX35_PAD_TMS = 179, + MX35_PAD_TDI = 180, + MX35_PAD_TDO = 181, + MX35_PAD_TRSTB = 182, + MX35_PAD_DE_B = 183, + MX35_PAD_SJC_MOD = 184, + MX35_PAD_USBOTG_PWR = 185, + MX35_PAD_USBOTG_OC = 186, + MX35_PAD_LD0 = 187, + MX35_PAD_LD1 = 188, + MX35_PAD_LD2 = 189, + MX35_PAD_LD3 = 190, + MX35_PAD_LD4 = 191, + MX35_PAD_LD5 = 192, + MX35_PAD_LD6 = 193, + MX35_PAD_LD7 = 194, + MX35_PAD_LD8 = 195, + MX35_PAD_LD9 = 196, + MX35_PAD_LD10 = 197, + MX35_PAD_LD11 = 198, + MX35_PAD_LD12 = 199, + MX35_PAD_LD13 = 200, + MX35_PAD_LD14 = 201, + MX35_PAD_LD15 = 202, + MX35_PAD_LD16 = 203, + MX35_PAD_LD17 = 204, + MX35_PAD_LD18 = 205, + MX35_PAD_LD19 = 206, + MX35_PAD_LD20 = 207, + MX35_PAD_LD21 = 208, + MX35_PAD_LD22 = 209, + MX35_PAD_LD23 = 210, + MX35_PAD_D3_HSYNC = 211, + MX35_PAD_D3_FPSHIFT = 212, + MX35_PAD_D3_DRDY = 213, + MX35_PAD_CONTRAST = 214, + MX35_PAD_D3_VSYNC = 215, + MX35_PAD_D3_REV = 216, + MX35_PAD_D3_CLS = 217, + MX35_PAD_D3_SPL = 218, + MX35_PAD_SD1_CMD = 219, + MX35_PAD_SD1_CLK = 220, + MX35_PAD_SD1_DATA0 = 221, + MX35_PAD_SD1_DATA1 = 222, + MX35_PAD_SD1_DATA2 = 223, + MX35_PAD_SD1_DATA3 = 224, + MX35_PAD_SD2_CMD = 225, + MX35_PAD_SD2_CLK = 226, + MX35_PAD_SD2_DATA0 = 227, + MX35_PAD_SD2_DATA1 = 228, + MX35_PAD_SD2_DATA2 = 229, + MX35_PAD_SD2_DATA3 = 230, + MX35_PAD_ATA_CS0 = 231, + MX35_PAD_ATA_CS1 = 232, + MX35_PAD_ATA_DIOR = 233, + MX35_PAD_ATA_DIOW = 234, + MX35_PAD_ATA_DMACK = 235, + MX35_PAD_ATA_RESET_B = 236, + MX35_PAD_ATA_IORDY = 237, + MX35_PAD_ATA_DATA0 = 238, + MX35_PAD_ATA_DATA1 = 239, + MX35_PAD_ATA_DATA2 = 240, + MX35_PAD_ATA_DATA3 = 241, + MX35_PAD_ATA_DATA4 = 242, + MX35_PAD_ATA_DATA5 = 243, + MX35_PAD_ATA_DATA6 = 244, + MX35_PAD_ATA_DATA7 = 245, + MX35_PAD_ATA_DATA8 = 246, + MX35_PAD_ATA_DATA9 = 247, + MX35_PAD_ATA_DATA10 = 248, + MX35_PAD_ATA_DATA11 = 249, + MX35_PAD_ATA_DATA12 = 250, + MX35_PAD_ATA_DATA13 = 251, + MX35_PAD_ATA_DATA14 = 252, + MX35_PAD_ATA_DATA15 = 253, + MX35_PAD_ATA_INTRQ = 254, + MX35_PAD_ATA_BUFF_EN = 255, + MX35_PAD_ATA_DMARQ = 256, + MX35_PAD_ATA_DA0 = 257, + MX35_PAD_ATA_DA1 = 258, + MX35_PAD_ATA_DA2 = 259, + MX35_PAD_MLB_CLK = 260, + MX35_PAD_MLB_DAT = 261, + MX35_PAD_MLB_SIG = 262, + MX35_PAD_FEC_TX_CLK = 263, + MX35_PAD_FEC_RX_CLK = 264, + MX35_PAD_FEC_RX_DV = 265, + MX35_PAD_FEC_COL = 266, + MX35_PAD_FEC_RDATA0 = 267, + MX35_PAD_FEC_TDATA0 = 268, + MX35_PAD_FEC_TX_EN = 269, + MX35_PAD_FEC_MDC = 270, + MX35_PAD_FEC_MDIO = 271, + MX35_PAD_FEC_TX_ERR = 272, + MX35_PAD_FEC_RX_ERR = 273, + MX35_PAD_FEC_CRS = 274, + MX35_PAD_FEC_RDATA1 = 275, + MX35_PAD_FEC_TDATA1 = 276, + MX35_PAD_FEC_RDATA2 = 277, + MX35_PAD_FEC_TDATA2 = 278, + MX35_PAD_FEC_RDATA3 = 279, + MX35_PAD_FEC_TDATA3 = 280, + MX35_PAD_EXT_ARMCLK = 281, + MX35_PAD_TEST_MODE = 282, +}; + +/* imx35 register maps */ +static struct imx_pin_reg imx35_pin_regs[] = { + [0] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 0, 0x0, 0), /* MX35_PAD_CAPTURE__GPT_CAPIN1 */ + [1] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 1, 0x0, 0), /* MX35_PAD_CAPTURE__GPT_CMPOUT2 */ + [2] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 2, 0x7f4, 0), /* MX35_PAD_CAPTURE__CSPI2_SS1 */ + [3] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 3, 0x0, 0), /* MX35_PAD_CAPTURE__EPIT1_EPITO */ + [4] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 4, 0x7d0, 0), /* MX35_PAD_CAPTURE__CCM_CLK32K */ + [5] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 5, 0x850, 0), /* MX35_PAD_CAPTURE__GPIO1_4 */ + [6] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 0, 0x0, 0), /* MX35_PAD_COMPARE__GPT_CMPOUT1 */ + [7] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 1, 0x0, 0), /* MX35_PAD_COMPARE__GPT_CAPIN2 */ + [8] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 2, 0x0, 0), /* MX35_PAD_COMPARE__GPT_CMPOUT3 */ + [9] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 3, 0x0, 0), /* MX35_PAD_COMPARE__EPIT2_EPITO */ + [10] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 5, 0x854, 0), /* MX35_PAD_COMPARE__GPIO1_5 */ + [11] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 7, 0x0, 0), /* MX35_PAD_COMPARE__SDMA_EXTDMA_2 */ + [12] = IMX_PIN_REG(MX35_PAD_WDOG_RST, 0x330, 0x00c, 0, 0x0, 0), /* MX35_PAD_WDOG_RST__WDOG_WDOG_B */ + [13] = IMX_PIN_REG(MX35_PAD_WDOG_RST, 0x330, 0x00c, 3, 0x0, 0), /* MX35_PAD_WDOG_RST__IPU_FLASH_STROBE */ + [14] = IMX_PIN_REG(MX35_PAD_WDOG_RST, 0x330, 0x00c, 5, 0x858, 0), /* MX35_PAD_WDOG_RST__GPIO1_6 */ + [15] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 0, 0x82c, 0), /* MX35_PAD_GPIO1_0__GPIO1_0 */ + [16] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 1, 0x7d4, 0), /* MX35_PAD_GPIO1_0__CCM_PMIC_RDY */ + [17] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 2, 0x990, 0), /* MX35_PAD_GPIO1_0__OWIRE_LINE */ + [18] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 7, 0x0, 0), /* MX35_PAD_GPIO1_0__SDMA_EXTDMA_0 */ + [19] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 0, 0x838, 0), /* MX35_PAD_GPIO1_1__GPIO1_1 */ + [20] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 2, 0x0, 0), /* MX35_PAD_GPIO1_1__PWM_PWMO */ + [21] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 3, 0x7d8, 0), /* MX35_PAD_GPIO1_1__CSPI1_SS2 */ + [22] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 6, 0x0, 0), /* MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT */ + [23] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 7, 0x0, 0), /* MX35_PAD_GPIO1_1__SDMA_EXTDMA_1 */ + [24] = IMX_PIN_REG(MX35_PAD_GPIO2_0, 0x33c, 0x018, 0, 0x868, 0), /* MX35_PAD_GPIO2_0__GPIO2_0 */ + [25] = IMX_PIN_REG(MX35_PAD_GPIO2_0, 0x33c, 0x018, 1, 0x0, 0), /* MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK */ + [26] = IMX_PIN_REG(MX35_PAD_GPIO3_0, 0x340, 0x01c, 0, 0x8e8, 0), /* MX35_PAD_GPIO3_0__GPIO3_0 */ + [27] = IMX_PIN_REG(MX35_PAD_GPIO3_0, 0x340, 0x01c, 1, 0x0, 0), /* MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK */ + [28] = IMX_PIN_REG(MX35_PAD_RESET_IN_B, 0x344, 0x0, 0, 0x0, 0), /* MX35_PAD_RESET_IN_B__CCM_RESET_IN_B */ + [29] = IMX_PIN_REG(MX35_PAD_POR_B, 0x348, 0x0, 0, 0x0, 0), /* MX35_PAD_POR_B__CCM_POR_B */ + [30] = IMX_PIN_REG(MX35_PAD_CLKO, 0x34c, 0x020, 0, 0x0, 0), /* MX35_PAD_CLKO__CCM_CLKO */ + [31] = IMX_PIN_REG(MX35_PAD_CLKO, 0x34c, 0x020, 5, 0x860, 0), /* MX35_PAD_CLKO__GPIO1_8 */ + [32] = IMX_PIN_REG(MX35_PAD_BOOT_MODE0, 0x350, 0x0, 0, 0x0, 0), /* MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0 */ + [33] = IMX_PIN_REG(MX35_PAD_BOOT_MODE1, 0x354, 0x0, 0, 0x0, 0), /* MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1 */ + [34] = IMX_PIN_REG(MX35_PAD_CLK_MODE0, 0x358, 0x0, 0, 0x0, 0), /* MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0 */ + [35] = IMX_PIN_REG(MX35_PAD_CLK_MODE1, 0x35c, 0x0, 0, 0x0, 0), /* MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1 */ + [36] = IMX_PIN_REG(MX35_PAD_POWER_FAIL, 0x360, 0x0, 0, 0x0, 0), /* MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26 */ + [37] = IMX_PIN_REG(MX35_PAD_VSTBY, 0x364, 0x024, 0, 0x0, 0), /* MX35_PAD_VSTBY__CCM_VSTBY */ + [38] = IMX_PIN_REG(MX35_PAD_VSTBY, 0x364, 0x024, 5, 0x85c, 0), /* MX35_PAD_VSTBY__GPIO1_7 */ + [39] = IMX_PIN_REG(MX35_PAD_A0, 0x368, 0x028, 0, 0x0, 0), /* MX35_PAD_A0__EMI_EIM_DA_L_0 */ + [40] = IMX_PIN_REG(MX35_PAD_A1, 0x36c, 0x02c, 0, 0x0, 0), /* MX35_PAD_A1__EMI_EIM_DA_L_1 */ + [41] = IMX_PIN_REG(MX35_PAD_A2, 0x370, 0x030, 0, 0x0, 0), /* MX35_PAD_A2__EMI_EIM_DA_L_2 */ + [42] = IMX_PIN_REG(MX35_PAD_A3, 0x374, 0x034, 0, 0x0, 0), /* MX35_PAD_A3__EMI_EIM_DA_L_3 */ + [43] = IMX_PIN_REG(MX35_PAD_A4, 0x378, 0x038, 0, 0x0, 0), /* MX35_PAD_A4__EMI_EIM_DA_L_4 */ + [44] = IMX_PIN_REG(MX35_PAD_A5, 0x37c, 0x03c, 0, 0x0, 0), /* MX35_PAD_A5__EMI_EIM_DA_L_5 */ + [45] = IMX_PIN_REG(MX35_PAD_A6, 0x380, 0x040, 0, 0x0, 0), /* MX35_PAD_A6__EMI_EIM_DA_L_6 */ + [46] = IMX_PIN_REG(MX35_PAD_A7, 0x384, 0x044, 0, 0x0, 0), /* MX35_PAD_A7__EMI_EIM_DA_L_7 */ + [47] = IMX_PIN_REG(MX35_PAD_A8, 0x388, 0x048, 0, 0x0, 0), /* MX35_PAD_A8__EMI_EIM_DA_H_8 */ + [48] = IMX_PIN_REG(MX35_PAD_A9, 0x38c, 0x04c, 0, 0x0, 0), /* MX35_PAD_A9__EMI_EIM_DA_H_9 */ + [49] = IMX_PIN_REG(MX35_PAD_A10, 0x390, 0x050, 0, 0x0, 0), /* MX35_PAD_A10__EMI_EIM_DA_H_10 */ + [50] = IMX_PIN_REG(MX35_PAD_MA10, 0x394, 0x054, 0, 0x0, 0), /* MX35_PAD_MA10__EMI_MA10 */ + [51] = IMX_PIN_REG(MX35_PAD_A11, 0x398, 0x058, 0, 0x0, 0), /* MX35_PAD_A11__EMI_EIM_DA_H_11 */ + [52] = IMX_PIN_REG(MX35_PAD_A12, 0x39c, 0x05c, 0, 0x0, 0), /* MX35_PAD_A12__EMI_EIM_DA_H_12 */ + [53] = IMX_PIN_REG(MX35_PAD_A13, 0x3a0, 0x060, 0, 0x0, 0), /* MX35_PAD_A13__EMI_EIM_DA_H_13 */ + [54] = IMX_PIN_REG(MX35_PAD_A14, 0x3a4, 0x064, 0, 0x0, 0), /* MX35_PAD_A14__EMI_EIM_DA_H2_14 */ + [55] = IMX_PIN_REG(MX35_PAD_A15, 0x3a8, 0x068, 0, 0x0, 0), /* MX35_PAD_A15__EMI_EIM_DA_H2_15 */ + [56] = IMX_PIN_REG(MX35_PAD_A16, 0x3ac, 0x06c, 0, 0x0, 0), /* MX35_PAD_A16__EMI_EIM_A_16 */ + [57] = IMX_PIN_REG(MX35_PAD_A17, 0x3b0, 0x070, 0, 0x0, 0), /* MX35_PAD_A17__EMI_EIM_A_17 */ + [58] = IMX_PIN_REG(MX35_PAD_A18, 0x3b4, 0x074, 0, 0x0, 0), /* MX35_PAD_A18__EMI_EIM_A_18 */ + [59] = IMX_PIN_REG(MX35_PAD_A19, 0x3b8, 0x078, 0, 0x0, 0), /* MX35_PAD_A19__EMI_EIM_A_19 */ + [60] = IMX_PIN_REG(MX35_PAD_A20, 0x3bc, 0x07c, 0, 0x0, 0), /* MX35_PAD_A20__EMI_EIM_A_20 */ + [61] = IMX_PIN_REG(MX35_PAD_A21, 0x3c0, 0x080, 0, 0x0, 0), /* MX35_PAD_A21__EMI_EIM_A_21 */ + [62] = IMX_PIN_REG(MX35_PAD_A22, 0x3c4, 0x084, 0, 0x0, 0), /* MX35_PAD_A22__EMI_EIM_A_22 */ + [63] = IMX_PIN_REG(MX35_PAD_A23, 0x3c8, 0x088, 0, 0x0, 0), /* MX35_PAD_A23__EMI_EIM_A_23 */ + [64] = IMX_PIN_REG(MX35_PAD_A24, 0x3cc, 0x08c, 0, 0x0, 0), /* MX35_PAD_A24__EMI_EIM_A_24 */ + [65] = IMX_PIN_REG(MX35_PAD_A25, 0x3d0, 0x090, 0, 0x0, 0), /* MX35_PAD_A25__EMI_EIM_A_25 */ + [66] = IMX_PIN_REG(MX35_PAD_SDBA1, 0x3d4, 0x0, 0, 0x0, 0), /* MX35_PAD_SDBA1__EMI_EIM_SDBA1 */ + [67] = IMX_PIN_REG(MX35_PAD_SDBA0, 0x3d8, 0x0, 0, 0x0, 0), /* MX35_PAD_SDBA0__EMI_EIM_SDBA0 */ + [68] = IMX_PIN_REG(MX35_PAD_SD0, 0x3dc, 0x0, 0, 0x0, 0), /* MX35_PAD_SD0__EMI_DRAM_D_0 */ + [69] = IMX_PIN_REG(MX35_PAD_SD1, 0x3e0, 0x0, 0, 0x0, 0), /* MX35_PAD_SD1__EMI_DRAM_D_1 */ + [70] = IMX_PIN_REG(MX35_PAD_SD2, 0x3e4, 0x0, 0, 0x0, 0), /* MX35_PAD_SD2__EMI_DRAM_D_2 */ + [71] = IMX_PIN_REG(MX35_PAD_SD3, 0x3e8, 0x0, 0, 0x0, 0), /* MX35_PAD_SD3__EMI_DRAM_D_3 */ + [72] = IMX_PIN_REG(MX35_PAD_SD4, 0x3ec, 0x0, 0, 0x0, 0), /* MX35_PAD_SD4__EMI_DRAM_D_4 */ + [73] = IMX_PIN_REG(MX35_PAD_SD5, 0x3f0, 0x0, 0, 0x0, 0), /* MX35_PAD_SD5__EMI_DRAM_D_5 */ + [74] = IMX_PIN_REG(MX35_PAD_SD6, 0x3f4, 0x0, 0, 0x0, 0), /* MX35_PAD_SD6__EMI_DRAM_D_6 */ + [75] = IMX_PIN_REG(MX35_PAD_SD7, 0x3f8, 0x0, 0, 0x0, 0), /* MX35_PAD_SD7__EMI_DRAM_D_7 */ + [76] = IMX_PIN_REG(MX35_PAD_SD8, 0x3fc, 0x0, 0, 0x0, 0), /* MX35_PAD_SD8__EMI_DRAM_D_8 */ + [77] = IMX_PIN_REG(MX35_PAD_SD9, 0x400, 0x0, 0, 0x0, 0), /* MX35_PAD_SD9__EMI_DRAM_D_9 */ + [78] = IMX_PIN_REG(MX35_PAD_SD10, 0x404, 0x0, 0, 0x0, 0), /* MX35_PAD_SD10__EMI_DRAM_D_10 */ + [79] = IMX_PIN_REG(MX35_PAD_SD11, 0x408, 0x0, 0, 0x0, 0), /* MX35_PAD_SD11__EMI_DRAM_D_11 */ + [80] = IMX_PIN_REG(MX35_PAD_SD12, 0x40c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD12__EMI_DRAM_D_12 */ + [81] = IMX_PIN_REG(MX35_PAD_SD13, 0x410, 0x0, 0, 0x0, 0), /* MX35_PAD_SD13__EMI_DRAM_D_13 */ + [82] = IMX_PIN_REG(MX35_PAD_SD14, 0x414, 0x0, 0, 0x0, 0), /* MX35_PAD_SD14__EMI_DRAM_D_14 */ + [83] = IMX_PIN_REG(MX35_PAD_SD15, 0x418, 0x0, 0, 0x0, 0), /* MX35_PAD_SD15__EMI_DRAM_D_15 */ + [84] = IMX_PIN_REG(MX35_PAD_SD16, 0x41c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD16__EMI_DRAM_D_16 */ + [85] = IMX_PIN_REG(MX35_PAD_SD17, 0x420, 0x0, 0, 0x0, 0), /* MX35_PAD_SD17__EMI_DRAM_D_17 */ + [86] = IMX_PIN_REG(MX35_PAD_SD18, 0x424, 0x0, 0, 0x0, 0), /* MX35_PAD_SD18__EMI_DRAM_D_18 */ + [87] = IMX_PIN_REG(MX35_PAD_SD19, 0x428, 0x0, 0, 0x0, 0), /* MX35_PAD_SD19__EMI_DRAM_D_19 */ + [88] = IMX_PIN_REG(MX35_PAD_SD20, 0x42c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD20__EMI_DRAM_D_20 */ + [89] = IMX_PIN_REG(MX35_PAD_SD21, 0x430, 0x0, 0, 0x0, 0), /* MX35_PAD_SD21__EMI_DRAM_D_21 */ + [90] = IMX_PIN_REG(MX35_PAD_SD22, 0x434, 0x0, 0, 0x0, 0), /* MX35_PAD_SD22__EMI_DRAM_D_22 */ + [91] = IMX_PIN_REG(MX35_PAD_SD23, 0x438, 0x0, 0, 0x0, 0), /* MX35_PAD_SD23__EMI_DRAM_D_23 */ + [92] = IMX_PIN_REG(MX35_PAD_SD24, 0x43c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD24__EMI_DRAM_D_24 */ + [93] = IMX_PIN_REG(MX35_PAD_SD25, 0x440, 0x0, 0, 0x0, 0), /* MX35_PAD_SD25__EMI_DRAM_D_25 */ + [94] = IMX_PIN_REG(MX35_PAD_SD26, 0x444, 0x0, 0, 0x0, 0), /* MX35_PAD_SD26__EMI_DRAM_D_26 */ + [95] = IMX_PIN_REG(MX35_PAD_SD27, 0x448, 0x0, 0, 0x0, 0), /* MX35_PAD_SD27__EMI_DRAM_D_27 */ + [96] = IMX_PIN_REG(MX35_PAD_SD28, 0x44c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD28__EMI_DRAM_D_28 */ + [97] = IMX_PIN_REG(MX35_PAD_SD29, 0x450, 0x0, 0, 0x0, 0), /* MX35_PAD_SD29__EMI_DRAM_D_29 */ + [98] = IMX_PIN_REG(MX35_PAD_SD30, 0x454, 0x0, 0, 0x0, 0), /* MX35_PAD_SD30__EMI_DRAM_D_30 */ + [99] = IMX_PIN_REG(MX35_PAD_SD31, 0x458, 0x0, 0, 0x0, 0), /* MX35_PAD_SD31__EMI_DRAM_D_31 */ + [100] = IMX_PIN_REG(MX35_PAD_DQM0, 0x45c, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM0__EMI_DRAM_DQM_0 */ + [101] = IMX_PIN_REG(MX35_PAD_DQM1, 0x460, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM1__EMI_DRAM_DQM_1 */ + [102] = IMX_PIN_REG(MX35_PAD_DQM2, 0x464, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM2__EMI_DRAM_DQM_2 */ + [103] = IMX_PIN_REG(MX35_PAD_DQM3, 0x468, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM3__EMI_DRAM_DQM_3 */ + [104] = IMX_PIN_REG(MX35_PAD_EB0, 0x46c, 0x094, 0, 0x0, 0), /* MX35_PAD_EB0__EMI_EIM_EB0_B */ + [105] = IMX_PIN_REG(MX35_PAD_EB1, 0x470, 0x098, 0, 0x0, 0), /* MX35_PAD_EB1__EMI_EIM_EB1_B */ + [106] = IMX_PIN_REG(MX35_PAD_OE, 0x474, 0x09c, 0, 0x0, 0), /* MX35_PAD_OE__EMI_EIM_OE */ + [107] = IMX_PIN_REG(MX35_PAD_CS0, 0x478, 0x0a0, 0, 0x0, 0), /* MX35_PAD_CS0__EMI_EIM_CS0 */ + [108] = IMX_PIN_REG(MX35_PAD_CS1, 0x47c, 0x0a4, 0, 0x0, 0), /* MX35_PAD_CS1__EMI_EIM_CS1 */ + [109] = IMX_PIN_REG(MX35_PAD_CS1, 0x47c, 0x0a4, 3, 0x0, 0), /* MX35_PAD_CS1__EMI_NANDF_CE3 */ + [110] = IMX_PIN_REG(MX35_PAD_CS2, 0x480, 0x0a8, 0, 0x0, 0), /* MX35_PAD_CS2__EMI_EIM_CS2 */ + [111] = IMX_PIN_REG(MX35_PAD_CS3, 0x484, 0x0ac, 0, 0x0, 0), /* MX35_PAD_CS3__EMI_EIM_CS3 */ + [112] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 0, 0x0, 0), /* MX35_PAD_CS4__EMI_EIM_CS4 */ + [113] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 1, 0x800, 0), /* MX35_PAD_CS4__EMI_DTACK_B */ + [114] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 3, 0x0, 0), /* MX35_PAD_CS4__EMI_NANDF_CE1 */ + [115] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 5, 0x83c, 0), /* MX35_PAD_CS4__GPIO1_20 */ + [116] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 0, 0x0, 0), /* MX35_PAD_CS5__EMI_EIM_CS5 */ + [117] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 1, 0x7f8, 0), /* MX35_PAD_CS5__CSPI2_SS2 */ + [118] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 2, 0x7d8, 1), /* MX35_PAD_CS5__CSPI1_SS2 */ + [119] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 3, 0x0, 0), /* MX35_PAD_CS5__EMI_NANDF_CE2 */ + [120] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 5, 0x840, 0), /* MX35_PAD_CS5__GPIO1_21 */ + [121] = IMX_PIN_REG(MX35_PAD_NF_CE0, 0x490, 0x0b8, 0, 0x0, 0), /* MX35_PAD_NF_CE0__EMI_NANDF_CE0 */ + [122] = IMX_PIN_REG(MX35_PAD_NF_CE0, 0x490, 0x0b8, 5, 0x844, 0), /* MX35_PAD_NF_CE0__GPIO1_22 */ + [123] = IMX_PIN_REG(MX35_PAD_ECB, 0x494, 0x0, 0, 0x0, 0), /* MX35_PAD_ECB__EMI_EIM_ECB */ + [124] = IMX_PIN_REG(MX35_PAD_LBA, 0x498, 0x0bc, 0, 0x0, 0), /* MX35_PAD_LBA__EMI_EIM_LBA */ + [125] = IMX_PIN_REG(MX35_PAD_BCLK, 0x49c, 0x0c0, 0, 0x0, 0), /* MX35_PAD_BCLK__EMI_EIM_BCLK */ + [126] = IMX_PIN_REG(MX35_PAD_RW, 0x4a0, 0x0c4, 0, 0x0, 0), /* MX35_PAD_RW__EMI_EIM_RW */ + [127] = IMX_PIN_REG(MX35_PAD_RAS, 0x4a4, 0x0, 0, 0x0, 0), /* MX35_PAD_RAS__EMI_DRAM_RAS */ + [128] = IMX_PIN_REG(MX35_PAD_CAS, 0x4a8, 0x0, 0, 0x0, 0), /* MX35_PAD_CAS__EMI_DRAM_CAS */ + [129] = IMX_PIN_REG(MX35_PAD_SDWE, 0x4ac, 0x0, 0, 0x0, 0), /* MX35_PAD_SDWE__EMI_DRAM_SDWE */ + [130] = IMX_PIN_REG(MX35_PAD_SDCKE0, 0x4b0, 0x0, 0, 0x0, 0), /* MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0 */ + [131] = IMX_PIN_REG(MX35_PAD_SDCKE1, 0x4b4, 0x0, 0, 0x0, 0), /* MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1 */ + [132] = IMX_PIN_REG(MX35_PAD_SDCLK, 0x4b8, 0x0, 0, 0x0, 0), /* MX35_PAD_SDCLK__EMI_DRAM_SDCLK */ + [133] = IMX_PIN_REG(MX35_PAD_SDQS0, 0x4bc, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS0__EMI_DRAM_SDQS_0 */ + [134] = IMX_PIN_REG(MX35_PAD_SDQS1, 0x4c0, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS1__EMI_DRAM_SDQS_1 */ + [135] = IMX_PIN_REG(MX35_PAD_SDQS2, 0x4c4, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS2__EMI_DRAM_SDQS_2 */ + [136] = IMX_PIN_REG(MX35_PAD_SDQS3, 0x4c8, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS3__EMI_DRAM_SDQS_3 */ + [137] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 0, 0x0, 0), /* MX35_PAD_NFWE_B__EMI_NANDF_WE_B */ + [138] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 1, 0x9d8, 0), /* MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3 */ + [139] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 2, 0x924, 0), /* MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC */ + [140] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 5, 0x88c, 0), /* MX35_PAD_NFWE_B__GPIO2_18 */ + [141] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 7, 0x0, 0), /* MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0 */ + [142] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 0, 0x0, 0), /* MX35_PAD_NFRE_B__EMI_NANDF_RE_B */ + [143] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 1, 0x9ec, 0), /* MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR */ + [144] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 2, 0x0, 0), /* MX35_PAD_NFRE_B__IPU_DISPB_BCLK */ + [145] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 5, 0x890, 0), /* MX35_PAD_NFRE_B__GPIO2_19 */ + [146] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 7, 0x0, 0), /* MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1 */ + [147] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 0, 0x0, 0), /* MX35_PAD_NFALE__EMI_NANDF_ALE */ + [148] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 1, 0x0, 0), /* MX35_PAD_NFALE__USB_TOP_USBH2_STP */ + [149] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 2, 0x0, 0), /* MX35_PAD_NFALE__IPU_DISPB_CS0 */ + [150] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 5, 0x898, 0), /* MX35_PAD_NFALE__GPIO2_20 */ + [151] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 7, 0x0, 0), /* MX35_PAD_NFALE__ARM11P_TOP_TRACE_2 */ + [152] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 0, 0x0, 0), /* MX35_PAD_NFCLE__EMI_NANDF_CLE */ + [153] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 1, 0x9f0, 0), /* MX35_PAD_NFCLE__USB_TOP_USBH2_NXT */ + [154] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 2, 0x0, 0), /* MX35_PAD_NFCLE__IPU_DISPB_PAR_RS */ + [155] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 5, 0x89c, 0), /* MX35_PAD_NFCLE__GPIO2_21 */ + [156] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 7, 0x0, 0), /* MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3 */ + [157] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 0, 0x0, 0), /* MX35_PAD_NFWP_B__EMI_NANDF_WP_B */ + [158] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 1, 0x9e8, 0), /* MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7 */ + [159] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 2, 0x0, 0), /* MX35_PAD_NFWP_B__IPU_DISPB_WR */ + [160] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 5, 0x8a0, 0), /* MX35_PAD_NFWP_B__GPIO2_22 */ + [161] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 7, 0x0, 0), /* MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL */ + [162] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 0, 0x0, 0), /* MX35_PAD_NFRB__EMI_NANDF_RB */ + [163] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 2, 0x0, 0), /* MX35_PAD_NFRB__IPU_DISPB_RD */ + [164] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 5, 0x8a4, 0), /* MX35_PAD_NFRB__GPIO2_23 */ + [165] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 7, 0x0, 0), /* MX35_PAD_NFRB__ARM11P_TOP_TRCLK */ + [166] = IMX_PIN_REG(MX35_PAD_D15, 0x4e4, 0x0, 0, 0x0, 0), /* MX35_PAD_D15__EMI_EIM_D_15 */ + [167] = IMX_PIN_REG(MX35_PAD_D14, 0x4e8, 0x0, 0, 0x0, 0), /* MX35_PAD_D14__EMI_EIM_D_14 */ + [168] = IMX_PIN_REG(MX35_PAD_D13, 0x4ec, 0x0, 0, 0x0, 0), /* MX35_PAD_D13__EMI_EIM_D_13 */ + [169] = IMX_PIN_REG(MX35_PAD_D12, 0x4f0, 0x0, 0, 0x0, 0), /* MX35_PAD_D12__EMI_EIM_D_12 */ + [170] = IMX_PIN_REG(MX35_PAD_D11, 0x4f4, 0x0, 0, 0x0, 0), /* MX35_PAD_D11__EMI_EIM_D_11 */ + [171] = IMX_PIN_REG(MX35_PAD_D10, 0x4f8, 0x0, 0, 0x0, 0), /* MX35_PAD_D10__EMI_EIM_D_10 */ + [172] = IMX_PIN_REG(MX35_PAD_D9, 0x4fc, 0x0, 0, 0x0, 0), /* MX35_PAD_D9__EMI_EIM_D_9 */ + [173] = IMX_PIN_REG(MX35_PAD_D8, 0x500, 0x0, 0, 0x0, 0), /* MX35_PAD_D8__EMI_EIM_D_8 */ + [174] = IMX_PIN_REG(MX35_PAD_D7, 0x504, 0x0, 0, 0x0, 0), /* MX35_PAD_D7__EMI_EIM_D_7 */ + [175] = IMX_PIN_REG(MX35_PAD_D6, 0x508, 0x0, 0, 0x0, 0), /* MX35_PAD_D6__EMI_EIM_D_6 */ + [176] = IMX_PIN_REG(MX35_PAD_D5, 0x50c, 0x0, 0, 0x0, 0), /* MX35_PAD_D5__EMI_EIM_D_5 */ + [177] = IMX_PIN_REG(MX35_PAD_D4, 0x510, 0x0, 0, 0x0, 0), /* MX35_PAD_D4__EMI_EIM_D_4 */ + [178] = IMX_PIN_REG(MX35_PAD_D3, 0x514, 0x0, 0, 0x0, 0), /* MX35_PAD_D3__EMI_EIM_D_3 */ + [179] = IMX_PIN_REG(MX35_PAD_D2, 0x518, 0x0, 0, 0x0, 0), /* MX35_PAD_D2__EMI_EIM_D_2 */ + [180] = IMX_PIN_REG(MX35_PAD_D1, 0x51c, 0x0, 0, 0x0, 0), /* MX35_PAD_D1__EMI_EIM_D_1 */ + [181] = IMX_PIN_REG(MX35_PAD_D0, 0x520, 0x0, 0, 0x0, 0), /* MX35_PAD_D0__EMI_EIM_D_0 */ + [182] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 0, 0x0, 0), /* MX35_PAD_CSI_D8__IPU_CSI_D_8 */ + [183] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 1, 0x950, 0), /* MX35_PAD_CSI_D8__KPP_COL_0 */ + [184] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 5, 0x83c, 1), /* MX35_PAD_CSI_D8__GPIO1_20 */ + [185] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 7, 0x0, 0), /* MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13 */ + [186] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 0, 0x0, 0), /* MX35_PAD_CSI_D9__IPU_CSI_D_9 */ + [187] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 1, 0x954, 0), /* MX35_PAD_CSI_D9__KPP_COL_1 */ + [188] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 5, 0x840, 1), /* MX35_PAD_CSI_D9__GPIO1_21 */ + [189] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 7, 0x0, 0), /* MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14 */ + [190] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 0, 0x0, 0), /* MX35_PAD_CSI_D10__IPU_CSI_D_10 */ + [191] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 1, 0x958, 0), /* MX35_PAD_CSI_D10__KPP_COL_2 */ + [192] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 5, 0x844, 1), /* MX35_PAD_CSI_D10__GPIO1_22 */ + [193] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 7, 0x0, 0), /* MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15 */ + [194] = IMX_PIN_REG(MX35_PAD_CSI_D11, 0x530, 0x0ec, 0, 0x0, 0), /* MX35_PAD_CSI_D11__IPU_CSI_D_11 */ + [195] = IMX_PIN_REG(MX35_PAD_CSI_D11, 0x530, 0x0ec, 1, 0x95c, 0), /* MX35_PAD_CSI_D11__KPP_COL_3 */ + [196] = IMX_PIN_REG(MX35_PAD_CSI_D11, 0x530, 0x0ec, 5, 0x0, 0), /* MX35_PAD_CSI_D11__GPIO1_23 */ + [197] = IMX_PIN_REG(MX35_PAD_CSI_D12, 0x534, 0x0f0, 0, 0x0, 0), /* MX35_PAD_CSI_D12__IPU_CSI_D_12 */ + [198] = IMX_PIN_REG(MX35_PAD_CSI_D12, 0x534, 0x0f0, 1, 0x970, 0), /* MX35_PAD_CSI_D12__KPP_ROW_0 */ + [199] = IMX_PIN_REG(MX35_PAD_CSI_D12, 0x534, 0x0f0, 5, 0x0, 0), /* MX35_PAD_CSI_D12__GPIO1_24 */ + [200] = IMX_PIN_REG(MX35_PAD_CSI_D13, 0x538, 0x0f4, 0, 0x0, 0), /* MX35_PAD_CSI_D13__IPU_CSI_D_13 */ + [201] = IMX_PIN_REG(MX35_PAD_CSI_D13, 0x538, 0x0f4, 1, 0x974, 0), /* MX35_PAD_CSI_D13__KPP_ROW_1 */ + [202] = IMX_PIN_REG(MX35_PAD_CSI_D13, 0x538, 0x0f4, 5, 0x0, 0), /* MX35_PAD_CSI_D13__GPIO1_25 */ + [203] = IMX_PIN_REG(MX35_PAD_CSI_D14, 0x53c, 0x0f8, 0, 0x0, 0), /* MX35_PAD_CSI_D14__IPU_CSI_D_14 */ + [204] = IMX_PIN_REG(MX35_PAD_CSI_D14, 0x53c, 0x0f8, 1, 0x978, 0), /* MX35_PAD_CSI_D14__KPP_ROW_2 */ + [205] = IMX_PIN_REG(MX35_PAD_CSI_D14, 0x53c, 0x0f8, 5, 0x0, 0), /* MX35_PAD_CSI_D14__GPIO1_26 */ + [206] = IMX_PIN_REG(MX35_PAD_CSI_D15, 0x540, 0x0fc, 0, 0x97c, 0), /* MX35_PAD_CSI_D15__IPU_CSI_D_15 */ + [207] = IMX_PIN_REG(MX35_PAD_CSI_D15, 0x540, 0x0fc, 1, 0x0, 0), /* MX35_PAD_CSI_D15__KPP_ROW_3 */ + [208] = IMX_PIN_REG(MX35_PAD_CSI_D15, 0x540, 0x0fc, 5, 0x0, 0), /* MX35_PAD_CSI_D15__GPIO1_27 */ + [209] = IMX_PIN_REG(MX35_PAD_CSI_MCLK, 0x544, 0x100, 0, 0x0, 0), /* MX35_PAD_CSI_MCLK__IPU_CSI_MCLK */ + [210] = IMX_PIN_REG(MX35_PAD_CSI_MCLK, 0x544, 0x100, 5, 0x0, 0), /* MX35_PAD_CSI_MCLK__GPIO1_28 */ + [211] = IMX_PIN_REG(MX35_PAD_CSI_VSYNC, 0x548, 0x104, 0, 0x0, 0), /* MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC */ + [212] = IMX_PIN_REG(MX35_PAD_CSI_VSYNC, 0x548, 0x104, 5, 0x0, 0), /* MX35_PAD_CSI_VSYNC__GPIO1_29 */ + [213] = IMX_PIN_REG(MX35_PAD_CSI_HSYNC, 0x54c, 0x108, 0, 0x0, 0), /* MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC */ + [214] = IMX_PIN_REG(MX35_PAD_CSI_HSYNC, 0x54c, 0x108, 5, 0x0, 0), /* MX35_PAD_CSI_HSYNC__GPIO1_30 */ + [215] = IMX_PIN_REG(MX35_PAD_CSI_PIXCLK, 0x550, 0x10c, 0, 0x0, 0), /* MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK */ + [216] = IMX_PIN_REG(MX35_PAD_CSI_PIXCLK, 0x550, 0x10c, 5, 0x0, 0), /* MX35_PAD_CSI_PIXCLK__GPIO1_31 */ + [217] = IMX_PIN_REG(MX35_PAD_I2C1_CLK, 0x554, 0x110, 0, 0x0, 0), /* MX35_PAD_I2C1_CLK__I2C1_SCL */ + [218] = IMX_PIN_REG(MX35_PAD_I2C1_CLK, 0x554, 0x110, 5, 0x8a8, 0), /* MX35_PAD_I2C1_CLK__GPIO2_24 */ + [219] = IMX_PIN_REG(MX35_PAD_I2C1_CLK, 0x554, 0x110, 6, 0x0, 0), /* MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK */ + [220] = IMX_PIN_REG(MX35_PAD_I2C1_DAT, 0x558, 0x114, 0, 0x0, 0), /* MX35_PAD_I2C1_DAT__I2C1_SDA */ + [221] = IMX_PIN_REG(MX35_PAD_I2C1_DAT, 0x558, 0x114, 5, 0x8ac, 0), /* MX35_PAD_I2C1_DAT__GPIO2_25 */ + [222] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 0, 0x0, 0), /* MX35_PAD_I2C2_CLK__I2C2_SCL */ + [223] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 1, 0x0, 0), /* MX35_PAD_I2C2_CLK__CAN1_TXCAN */ + [224] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 2, 0x0, 0), /* MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR */ + [225] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 5, 0x8b0, 0), /* MX35_PAD_I2C2_CLK__GPIO2_26 */ + [226] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 6, 0x0, 0), /* MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2 */ + [227] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 0, 0x0, 0), /* MX35_PAD_I2C2_DAT__I2C2_SDA */ + [228] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 1, 0x7c8, 0), /* MX35_PAD_I2C2_DAT__CAN1_RXCAN */ + [229] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 2, 0x9f4, 0), /* MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC */ + [230] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 5, 0x8b4, 0), /* MX35_PAD_I2C2_DAT__GPIO2_27 */ + [231] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 6, 0x0, 0), /* MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3 */ + [232] = IMX_PIN_REG(MX35_PAD_STXD4, 0x564, 0x120, 0, 0x0, 0), /* MX35_PAD_STXD4__AUDMUX_AUD4_TXD */ + [233] = IMX_PIN_REG(MX35_PAD_STXD4, 0x564, 0x120, 5, 0x8b8, 0), /* MX35_PAD_STXD4__GPIO2_28 */ + [234] = IMX_PIN_REG(MX35_PAD_STXD4, 0x564, 0x120, 7, 0x0, 0), /* MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0 */ + [235] = IMX_PIN_REG(MX35_PAD_SRXD4, 0x568, 0x124, 0, 0x0, 0), /* MX35_PAD_SRXD4__AUDMUX_AUD4_RXD */ + [236] = IMX_PIN_REG(MX35_PAD_SRXD4, 0x568, 0x124, 5, 0x8bc, 0), /* MX35_PAD_SRXD4__GPIO2_29 */ + [237] = IMX_PIN_REG(MX35_PAD_SRXD4, 0x568, 0x124, 7, 0x0, 0), /* MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1 */ + [238] = IMX_PIN_REG(MX35_PAD_SCK4, 0x56c, 0x128, 0, 0x0, 0), /* MX35_PAD_SCK4__AUDMUX_AUD4_TXC */ + [239] = IMX_PIN_REG(MX35_PAD_SCK4, 0x56c, 0x128, 5, 0x8c4, 0), /* MX35_PAD_SCK4__GPIO2_30 */ + [240] = IMX_PIN_REG(MX35_PAD_SCK4, 0x56c, 0x128, 7, 0x0, 0), /* MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2 */ + [241] = IMX_PIN_REG(MX35_PAD_STXFS4, 0x570, 0x12c, 0, 0x0, 0), /* MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS */ + [242] = IMX_PIN_REG(MX35_PAD_STXFS4, 0x570, 0x12c, 5, 0x8c8, 0), /* MX35_PAD_STXFS4__GPIO2_31 */ + [243] = IMX_PIN_REG(MX35_PAD_STXFS4, 0x570, 0x12c, 7, 0x0, 0), /* MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3 */ + [244] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 0, 0x0, 0), /* MX35_PAD_STXD5__AUDMUX_AUD5_TXD */ + [245] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 1, 0x0, 0), /* MX35_PAD_STXD5__SPDIF_SPDIF_OUT1 */ + [246] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 2, 0x7ec, 0), /* MX35_PAD_STXD5__CSPI2_MOSI */ + [247] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 5, 0x82c, 1), /* MX35_PAD_STXD5__GPIO1_0 */ + [248] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 7, 0x0, 0), /* MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4 */ + [249] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 0, 0x0, 0), /* MX35_PAD_SRXD5__AUDMUX_AUD5_RXD */ + [250] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 1, 0x998, 0), /* MX35_PAD_SRXD5__SPDIF_SPDIF_IN1 */ + [251] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 2, 0x7e8, 0), /* MX35_PAD_SRXD5__CSPI2_MISO */ + [252] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 5, 0x838, 1), /* MX35_PAD_SRXD5__GPIO1_1 */ + [253] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 7, 0x0, 0), /* MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5 */ + [254] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 0, 0x0, 0), /* MX35_PAD_SCK5__AUDMUX_AUD5_TXC */ + [255] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 1, 0x994, 0), /* MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK */ + [256] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 2, 0x7e0, 0), /* MX35_PAD_SCK5__CSPI2_SCLK */ + [257] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 5, 0x848, 0), /* MX35_PAD_SCK5__GPIO1_2 */ + [258] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 7, 0x0, 0), /* MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6 */ + [259] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 0, 0x0, 0), /* MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS */ + [260] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 2, 0x7e4, 0), /* MX35_PAD_STXFS5__CSPI2_RDY */ + [261] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 5, 0x84c, 0), /* MX35_PAD_STXFS5__GPIO1_3 */ + [262] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 7, 0x0, 0), /* MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7 */ + [263] = IMX_PIN_REG(MX35_PAD_SCKR, 0x584, 0x140, 0, 0x0, 0), /* MX35_PAD_SCKR__ESAI_SCKR */ + [264] = IMX_PIN_REG(MX35_PAD_SCKR, 0x584, 0x140, 5, 0x850, 1), /* MX35_PAD_SCKR__GPIO1_4 */ + [265] = IMX_PIN_REG(MX35_PAD_SCKR, 0x584, 0x140, 7, 0x0, 0), /* MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10 */ + [266] = IMX_PIN_REG(MX35_PAD_FSR, 0x588, 0x144, 0, 0x0, 0), /* MX35_PAD_FSR__ESAI_FSR */ + [267] = IMX_PIN_REG(MX35_PAD_FSR, 0x588, 0x144, 5, 0x854, 1), /* MX35_PAD_FSR__GPIO1_5 */ + [268] = IMX_PIN_REG(MX35_PAD_FSR, 0x588, 0x144, 7, 0x0, 0), /* MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11 */ + [269] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 0, 0x0, 0), /* MX35_PAD_HCKR__ESAI_HCKR */ + [270] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 1, 0x0, 0), /* MX35_PAD_HCKR__AUDMUX_AUD5_RXFS */ + [271] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 2, 0x7f0, 0), /* MX35_PAD_HCKR__CSPI2_SS0 */ + [272] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 3, 0x0, 0), /* MX35_PAD_HCKR__IPU_FLASH_STROBE */ + [273] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 5, 0x858, 1), /* MX35_PAD_HCKR__GPIO1_6 */ + [274] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 7, 0x0, 0), /* MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12 */ + [275] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 0, 0x0, 0), /* MX35_PAD_SCKT__ESAI_SCKT */ + [276] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 5, 0x85c, 1), /* MX35_PAD_SCKT__GPIO1_7 */ + [277] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 6, 0x930, 0), /* MX35_PAD_SCKT__IPU_CSI_D_0 */ + [278] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 7, 0x978, 1), /* MX35_PAD_SCKT__KPP_ROW_2 */ + [279] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 0, 0x0, 0), /* MX35_PAD_FST__ESAI_FST */ + [280] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 5, 0x860, 1), /* MX35_PAD_FST__GPIO1_8 */ + [281] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 6, 0x934, 0), /* MX35_PAD_FST__IPU_CSI_D_1 */ + [282] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 7, 0x97c, 1), /* MX35_PAD_FST__KPP_ROW_3 */ + [283] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 0, 0x0, 0), /* MX35_PAD_HCKT__ESAI_HCKT */ + [284] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 1, 0x7a8, 0), /* MX35_PAD_HCKT__AUDMUX_AUD5_RXC */ + [285] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 5, 0x864, 0), /* MX35_PAD_HCKT__GPIO1_9 */ + [286] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 6, 0x938, 0), /* MX35_PAD_HCKT__IPU_CSI_D_2 */ + [287] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 7, 0x95c, 1), /* MX35_PAD_HCKT__KPP_COL_3 */ + [288] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 0, 0x0, 0), /* MX35_PAD_TX5_RX0__ESAI_TX5_RX0 */ + [289] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 1, 0x0, 0), /* MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC */ + [290] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 2, 0x7f8, 1), /* MX35_PAD_TX5_RX0__CSPI2_SS2 */ + [291] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 3, 0x0, 0), /* MX35_PAD_TX5_RX0__CAN2_TXCAN */ + [292] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 4, 0x0, 0), /* MX35_PAD_TX5_RX0__UART2_DTR */ + [293] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 5, 0x830, 0), /* MX35_PAD_TX5_RX0__GPIO1_10 */ + [294] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 7, 0x0, 0), /* MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0 */ + [295] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 0, 0x0, 0), /* MX35_PAD_TX4_RX1__ESAI_TX4_RX1 */ + [296] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 1, 0x0, 0), /* MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS */ + [297] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 2, 0x7fc, 0), /* MX35_PAD_TX4_RX1__CSPI2_SS3 */ + [298] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 3, 0x7cc, 0), /* MX35_PAD_TX4_RX1__CAN2_RXCAN */ + [299] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 4, 0x0, 0), /* MX35_PAD_TX4_RX1__UART2_DSR */ + [300] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 5, 0x834, 0), /* MX35_PAD_TX4_RX1__GPIO1_11 */ + [301] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 6, 0x93c, 0), /* MX35_PAD_TX4_RX1__IPU_CSI_D_3 */ + [302] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 7, 0x970, 1), /* MX35_PAD_TX4_RX1__KPP_ROW_0 */ + [303] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 0, 0x0, 0), /* MX35_PAD_TX3_RX2__ESAI_TX3_RX2 */ + [304] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 1, 0x91c, 0), /* MX35_PAD_TX3_RX2__I2C3_SCL */ + [305] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 3, 0x0, 0), /* MX35_PAD_TX3_RX2__EMI_NANDF_CE1 */ + [306] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 5, 0x0, 0), /* MX35_PAD_TX3_RX2__GPIO1_12 */ + [307] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 6, 0x940, 0), /* MX35_PAD_TX3_RX2__IPU_CSI_D_4 */ + [308] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 7, 0x974, 1), /* MX35_PAD_TX3_RX2__KPP_ROW_1 */ + [309] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 0, 0x0, 0), /* MX35_PAD_TX2_RX3__ESAI_TX2_RX3 */ + [310] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 1, 0x920, 0), /* MX35_PAD_TX2_RX3__I2C3_SDA */ + [311] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 3, 0x0, 0), /* MX35_PAD_TX2_RX3__EMI_NANDF_CE2 */ + [312] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 5, 0x0, 0), /* MX35_PAD_TX2_RX3__GPIO1_13 */ + [313] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 6, 0x944, 0), /* MX35_PAD_TX2_RX3__IPU_CSI_D_5 */ + [314] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 7, 0x950, 1), /* MX35_PAD_TX2_RX3__KPP_COL_0 */ + [315] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 0, 0x0, 0), /* MX35_PAD_TX1__ESAI_TX1 */ + [316] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 1, 0x7d4, 1), /* MX35_PAD_TX1__CCM_PMIC_RDY */ + [317] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 2, 0x7d8, 2), /* MX35_PAD_TX1__CSPI1_SS2 */ + [318] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 3, 0x0, 0), /* MX35_PAD_TX1__EMI_NANDF_CE3 */ + [319] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 4, 0x0, 0), /* MX35_PAD_TX1__UART2_RI */ + [320] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 5, 0x0, 0), /* MX35_PAD_TX1__GPIO1_14 */ + [321] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 6, 0x948, 0), /* MX35_PAD_TX1__IPU_CSI_D_6 */ + [322] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 7, 0x954, 1), /* MX35_PAD_TX1__KPP_COL_1 */ + [323] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 0, 0x0, 0), /* MX35_PAD_TX0__ESAI_TX0 */ + [324] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 1, 0x994, 1), /* MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK */ + [325] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 2, 0x7dc, 0), /* MX35_PAD_TX0__CSPI1_SS3 */ + [326] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 3, 0x800, 1), /* MX35_PAD_TX0__EMI_DTACK_B */ + [327] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 4, 0x0, 0), /* MX35_PAD_TX0__UART2_DCD */ + [328] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 5, 0x0, 0), /* MX35_PAD_TX0__GPIO1_15 */ + [329] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 6, 0x94c, 0), /* MX35_PAD_TX0__IPU_CSI_D_7 */ + [330] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 7, 0x958, 1), /* MX35_PAD_TX0__KPP_COL_2 */ + [331] = IMX_PIN_REG(MX35_PAD_CSPI1_MOSI, 0x5b4, 0x170, 0, 0x0, 0), /* MX35_PAD_CSPI1_MOSI__CSPI1_MOSI */ + [332] = IMX_PIN_REG(MX35_PAD_CSPI1_MOSI, 0x5b4, 0x170, 5, 0x0, 0), /* MX35_PAD_CSPI1_MOSI__GPIO1_16 */ + [333] = IMX_PIN_REG(MX35_PAD_CSPI1_MOSI, 0x5b4, 0x170, 7, 0x0, 0), /* MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2 */ + [334] = IMX_PIN_REG(MX35_PAD_CSPI1_MISO, 0x5b8, 0x174, 0, 0x0, 0), /* MX35_PAD_CSPI1_MISO__CSPI1_MISO */ + [335] = IMX_PIN_REG(MX35_PAD_CSPI1_MISO, 0x5b8, 0x174, 5, 0x0, 0), /* MX35_PAD_CSPI1_MISO__GPIO1_17 */ + [336] = IMX_PIN_REG(MX35_PAD_CSPI1_MISO, 0x5b8, 0x174, 7, 0x0, 0), /* MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3 */ + [337] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 0, 0x0, 0), /* MX35_PAD_CSPI1_SS0__CSPI1_SS0 */ + [338] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 1, 0x990, 1), /* MX35_PAD_CSPI1_SS0__OWIRE_LINE */ + [339] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 2, 0x7fc, 1), /* MX35_PAD_CSPI1_SS0__CSPI2_SS3 */ + [340] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 5, 0x0, 0), /* MX35_PAD_CSPI1_SS0__GPIO1_18 */ + [341] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 7, 0x0, 0), /* MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4 */ + [342] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 0, 0x0, 0), /* MX35_PAD_CSPI1_SS1__CSPI1_SS1 */ + [343] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 1, 0x0, 0), /* MX35_PAD_CSPI1_SS1__PWM_PWMO */ + [344] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 2, 0x7d0, 1), /* MX35_PAD_CSPI1_SS1__CCM_CLK32K */ + [345] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 5, 0x0, 0), /* MX35_PAD_CSPI1_SS1__GPIO1_19 */ + [346] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 6, 0x0, 0), /* MX35_PAD_CSPI1_SS1__IPU_DIAGB_29 */ + [347] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 7, 0x0, 0), /* MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5 */ + [348] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 0, 0x0, 0), /* MX35_PAD_CSPI1_SCLK__CSPI1_SCLK */ + [349] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 5, 0x904, 0), /* MX35_PAD_CSPI1_SCLK__GPIO3_4 */ + [350] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 6, 0x0, 0), /* MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30 */ + [351] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 7, 0x0, 0), /* MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1 */ + [352] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 0, 0x0, 0), /* MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY */ + [353] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 5, 0x908, 0), /* MX35_PAD_CSPI1_SPI_RDY__GPIO3_5 */ + [354] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 6, 0x0, 0), /* MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31 */ + [355] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 7, 0x0, 0), /* MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2 */ + [356] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 0, 0x0, 0), /* MX35_PAD_RXD1__UART1_RXD_MUX */ + [357] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 1, 0x7ec, 1), /* MX35_PAD_RXD1__CSPI2_MOSI */ + [358] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 4, 0x960, 0), /* MX35_PAD_RXD1__KPP_COL_4 */ + [359] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 5, 0x90c, 0), /* MX35_PAD_RXD1__GPIO3_6 */ + [360] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 7, 0x0, 0), /* MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16 */ + [361] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 0, 0x0, 0), /* MX35_PAD_TXD1__UART1_TXD_MUX */ + [362] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 1, 0x7e8, 1), /* MX35_PAD_TXD1__CSPI2_MISO */ + [363] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 4, 0x964, 0), /* MX35_PAD_TXD1__KPP_COL_5 */ + [364] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 5, 0x910, 0), /* MX35_PAD_TXD1__GPIO3_7 */ + [365] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 7, 0x0, 0), /* MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17 */ + [366] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 0, 0x0, 0), /* MX35_PAD_RTS1__UART1_RTS */ + [367] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 1, 0x7e0, 1), /* MX35_PAD_RTS1__CSPI2_SCLK */ + [368] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 2, 0x91c, 1), /* MX35_PAD_RTS1__I2C3_SCL */ + [369] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 3, 0x930, 1), /* MX35_PAD_RTS1__IPU_CSI_D_0 */ + [370] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 4, 0x968, 0), /* MX35_PAD_RTS1__KPP_COL_6 */ + [371] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 5, 0x914, 0), /* MX35_PAD_RTS1__GPIO3_8 */ + [372] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 6, 0x0, 0), /* MX35_PAD_RTS1__EMI_NANDF_CE1 */ + [373] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 7, 0x0, 0), /* MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18 */ + [374] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 0, 0x0, 0), /* MX35_PAD_CTS1__UART1_CTS */ + [375] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 1, 0x7e4, 1), /* MX35_PAD_CTS1__CSPI2_RDY */ + [376] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 2, 0x920, 1), /* MX35_PAD_CTS1__I2C3_SDA */ + [377] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 3, 0x934, 1), /* MX35_PAD_CTS1__IPU_CSI_D_1 */ + [378] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 4, 0x96c, 0), /* MX35_PAD_CTS1__KPP_COL_7 */ + [379] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 5, 0x918, 0), /* MX35_PAD_CTS1__GPIO3_9 */ + [380] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 6, 0x0, 0), /* MX35_PAD_CTS1__EMI_NANDF_CE2 */ + [381] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 7, 0x0, 0), /* MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19 */ + [382] = IMX_PIN_REG(MX35_PAD_RXD2, 0x5dc, 0x198, 0, 0x0, 0), /* MX35_PAD_RXD2__UART2_RXD_MUX */ + [383] = IMX_PIN_REG(MX35_PAD_RXD2, 0x5dc, 0x198, 4, 0x980, 0), /* MX35_PAD_RXD2__KPP_ROW_4 */ + [384] = IMX_PIN_REG(MX35_PAD_RXD2, 0x5dc, 0x198, 5, 0x8ec, 0), /* MX35_PAD_RXD2__GPIO3_10 */ + [385] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 0, 0x0, 0), /* MX35_PAD_TXD2__UART2_TXD_MUX */ + [386] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 1, 0x994, 2), /* MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK */ + [387] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 4, 0x984, 0), /* MX35_PAD_TXD2__KPP_ROW_5 */ + [388] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 5, 0x8f0, 0), /* MX35_PAD_TXD2__GPIO3_11 */ + [389] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 0, 0x0, 0), /* MX35_PAD_RTS2__UART2_RTS */ + [390] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 1, 0x998, 1), /* MX35_PAD_RTS2__SPDIF_SPDIF_IN1 */ + [391] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 2, 0x7cc, 1), /* MX35_PAD_RTS2__CAN2_RXCAN */ + [392] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 3, 0x938, 1), /* MX35_PAD_RTS2__IPU_CSI_D_2 */ + [393] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 4, 0x988, 0), /* MX35_PAD_RTS2__KPP_ROW_6 */ + [394] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 5, 0x8f4, 0), /* MX35_PAD_RTS2__GPIO3_12 */ + [395] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 6, 0x0, 0), /* MX35_PAD_RTS2__AUDMUX_AUD5_RXC */ + [396] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 7, 0x9a0, 0), /* MX35_PAD_RTS2__UART3_RXD_MUX */ + [397] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 0, 0x0, 0), /* MX35_PAD_CTS2__UART2_CTS */ + [398] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 1, 0x0, 0), /* MX35_PAD_CTS2__SPDIF_SPDIF_OUT1 */ + [399] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 2, 0x0, 0), /* MX35_PAD_CTS2__CAN2_TXCAN */ + [400] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 3, 0x93c, 1), /* MX35_PAD_CTS2__IPU_CSI_D_3 */ + [401] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 4, 0x98c, 0), /* MX35_PAD_CTS2__KPP_ROW_7 */ + [402] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 5, 0x8f8, 0), /* MX35_PAD_CTS2__GPIO3_13 */ + [403] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 6, 0x0, 0), /* MX35_PAD_CTS2__AUDMUX_AUD5_RXFS */ + [404] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 7, 0x0, 0), /* MX35_PAD_CTS2__UART3_TXD_MUX */ + [405] = IMX_PIN_REG(MX35_PAD_RTCK, 0x5ec, 0x0, 0, 0x0, 0), /* MX35_PAD_RTCK__ARM11P_TOP_RTCK */ + [406] = IMX_PIN_REG(MX35_PAD_TCK, 0x5f0, 0x0, 0, 0x0, 0), /* MX35_PAD_TCK__SJC_TCK */ + [407] = IMX_PIN_REG(MX35_PAD_TMS, 0x5f4, 0x0, 0, 0x0, 0), /* MX35_PAD_TMS__SJC_TMS */ + [408] = IMX_PIN_REG(MX35_PAD_TDI, 0x5f8, 0x0, 0, 0x0, 0), /* MX35_PAD_TDI__SJC_TDI */ + [409] = IMX_PIN_REG(MX35_PAD_TDO, 0x5fc, 0x0, 0, 0x0, 0), /* MX35_PAD_TDO__SJC_TDO */ + [410] = IMX_PIN_REG(MX35_PAD_TRSTB, 0x600, 0x0, 0, 0x0, 0), /* MX35_PAD_TRSTB__SJC_TRSTB */ + [411] = IMX_PIN_REG(MX35_PAD_DE_B, 0x604, 0x0, 0, 0x0, 0), /* MX35_PAD_DE_B__SJC_DE_B */ + [412] = IMX_PIN_REG(MX35_PAD_SJC_MOD, 0x608, 0x0, 0, 0x0, 0), /* MX35_PAD_SJC_MOD__SJC_MOD */ + [413] = IMX_PIN_REG(MX35_PAD_USBOTG_PWR, 0x60c, 0x1a8, 0, 0x0, 0), /* MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR */ + [414] = IMX_PIN_REG(MX35_PAD_USBOTG_PWR, 0x60c, 0x1a8, 1, 0x0, 0), /* MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR */ + [415] = IMX_PIN_REG(MX35_PAD_USBOTG_PWR, 0x60c, 0x1a8, 5, 0x8fc, 0), /* MX35_PAD_USBOTG_PWR__GPIO3_14 */ + [416] = IMX_PIN_REG(MX35_PAD_USBOTG_OC, 0x610, 0x1ac, 0, 0x0, 0), /* MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC */ + [417] = IMX_PIN_REG(MX35_PAD_USBOTG_OC, 0x610, 0x1ac, 1, 0x9f4, 1), /* MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC */ + [418] = IMX_PIN_REG(MX35_PAD_USBOTG_OC, 0x610, 0x1ac, 5, 0x900, 0), /* MX35_PAD_USBOTG_OC__GPIO3_15 */ + [419] = IMX_PIN_REG(MX35_PAD_LD0, 0x614, 0x1b0, 0, 0x0, 0), /* MX35_PAD_LD0__IPU_DISPB_DAT_0 */ + [420] = IMX_PIN_REG(MX35_PAD_LD0, 0x614, 0x1b0, 5, 0x868, 1), /* MX35_PAD_LD0__GPIO2_0 */ + [421] = IMX_PIN_REG(MX35_PAD_LD0, 0x614, 0x1b0, 6, 0x0, 0), /* MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0 */ + [422] = IMX_PIN_REG(MX35_PAD_LD1, 0x618, 0x1b4, 0, 0x0, 0), /* MX35_PAD_LD1__IPU_DISPB_DAT_1 */ + [423] = IMX_PIN_REG(MX35_PAD_LD1, 0x618, 0x1b4, 5, 0x894, 0), /* MX35_PAD_LD1__GPIO2_1 */ + [424] = IMX_PIN_REG(MX35_PAD_LD1, 0x618, 0x1b4, 6, 0x0, 0), /* MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1 */ + [425] = IMX_PIN_REG(MX35_PAD_LD2, 0x61c, 0x1b8, 0, 0x0, 0), /* MX35_PAD_LD2__IPU_DISPB_DAT_2 */ + [426] = IMX_PIN_REG(MX35_PAD_LD2, 0x61c, 0x1b8, 5, 0x8c0, 0), /* MX35_PAD_LD2__GPIO2_2 */ + [427] = IMX_PIN_REG(MX35_PAD_LD2, 0x61c, 0x1b8, 6, 0x0, 0), /* MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2 */ + [428] = IMX_PIN_REG(MX35_PAD_LD3, 0x620, 0x1bc, 0, 0x0, 0), /* MX35_PAD_LD3__IPU_DISPB_DAT_3 */ + [429] = IMX_PIN_REG(MX35_PAD_LD3, 0x620, 0x1bc, 5, 0x8cc, 0), /* MX35_PAD_LD3__GPIO2_3 */ + [430] = IMX_PIN_REG(MX35_PAD_LD3, 0x620, 0x1bc, 6, 0x0, 0), /* MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3 */ + [431] = IMX_PIN_REG(MX35_PAD_LD4, 0x624, 0x1c0, 0, 0x0, 0), /* MX35_PAD_LD4__IPU_DISPB_DAT_4 */ + [432] = IMX_PIN_REG(MX35_PAD_LD4, 0x624, 0x1c0, 5, 0x8d0, 0), /* MX35_PAD_LD4__GPIO2_4 */ + [433] = IMX_PIN_REG(MX35_PAD_LD4, 0x624, 0x1c0, 6, 0x0, 0), /* MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4 */ + [434] = IMX_PIN_REG(MX35_PAD_LD5, 0x628, 0x1c4, 0, 0x0, 0), /* MX35_PAD_LD5__IPU_DISPB_DAT_5 */ + [435] = IMX_PIN_REG(MX35_PAD_LD5, 0x628, 0x1c4, 5, 0x8d4, 0), /* MX35_PAD_LD5__GPIO2_5 */ + [436] = IMX_PIN_REG(MX35_PAD_LD5, 0x628, 0x1c4, 6, 0x0, 0), /* MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5 */ + [437] = IMX_PIN_REG(MX35_PAD_LD6, 0x62c, 0x1c8, 0, 0x0, 0), /* MX35_PAD_LD6__IPU_DISPB_DAT_6 */ + [438] = IMX_PIN_REG(MX35_PAD_LD6, 0x62c, 0x1c8, 5, 0x8d8, 0), /* MX35_PAD_LD6__GPIO2_6 */ + [439] = IMX_PIN_REG(MX35_PAD_LD6, 0x62c, 0x1c8, 6, 0x0, 0), /* MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6 */ + [440] = IMX_PIN_REG(MX35_PAD_LD7, 0x630, 0x1cc, 0, 0x0, 0), /* MX35_PAD_LD7__IPU_DISPB_DAT_7 */ + [441] = IMX_PIN_REG(MX35_PAD_LD7, 0x630, 0x1cc, 5, 0x8dc, 0), /* MX35_PAD_LD7__GPIO2_7 */ + [442] = IMX_PIN_REG(MX35_PAD_LD7, 0x630, 0x1cc, 6, 0x0, 0), /* MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7 */ + [443] = IMX_PIN_REG(MX35_PAD_LD8, 0x634, 0x1d0, 0, 0x0, 0), /* MX35_PAD_LD8__IPU_DISPB_DAT_8 */ + [444] = IMX_PIN_REG(MX35_PAD_LD8, 0x634, 0x1d0, 5, 0x8e0, 0), /* MX35_PAD_LD8__GPIO2_8 */ + [445] = IMX_PIN_REG(MX35_PAD_LD8, 0x634, 0x1d0, 6, 0x0, 0), /* MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8 */ + [446] = IMX_PIN_REG(MX35_PAD_LD9, 0x638, 0x1d4, 0, 0x0, 0), /* MX35_PAD_LD9__IPU_DISPB_DAT_9 */ + [447] = IMX_PIN_REG(MX35_PAD_LD9, 0x638, 0x1d4, 5, 0x8e4, 0), /* MX35_PAD_LD9__GPIO2_9 */ + [448] = IMX_PIN_REG(MX35_PAD_LD9, 0x638, 0x1d4, 6, 0x0, 0), /* MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9 */ + [449] = IMX_PIN_REG(MX35_PAD_LD10, 0x63c, 0x1d8, 0, 0x0, 0), /* MX35_PAD_LD10__IPU_DISPB_DAT_10 */ + [450] = IMX_PIN_REG(MX35_PAD_LD10, 0x63c, 0x1d8, 5, 0x86c, 0), /* MX35_PAD_LD10__GPIO2_10 */ + [451] = IMX_PIN_REG(MX35_PAD_LD10, 0x63c, 0x1d8, 6, 0x0, 0), /* MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10 */ + [452] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 0, 0x0, 0), /* MX35_PAD_LD11__IPU_DISPB_DAT_11 */ + [453] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 5, 0x870, 0), /* MX35_PAD_LD11__GPIO2_11 */ + [454] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 6, 0x0, 0), /* MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11 */ + [455] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 7, 0x0, 0), /* MX35_PAD_LD11__ARM11P_TOP_TRACE_4 */ + [456] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 0, 0x0, 0), /* MX35_PAD_LD12__IPU_DISPB_DAT_12 */ + [457] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 5, 0x874, 0), /* MX35_PAD_LD12__GPIO2_12 */ + [458] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 6, 0x0, 0), /* MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12 */ + [459] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 7, 0x0, 0), /* MX35_PAD_LD12__ARM11P_TOP_TRACE_5 */ + [460] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 0, 0x0, 0), /* MX35_PAD_LD13__IPU_DISPB_DAT_13 */ + [461] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 5, 0x878, 0), /* MX35_PAD_LD13__GPIO2_13 */ + [462] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 6, 0x0, 0), /* MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13 */ + [463] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 7, 0x0, 0), /* MX35_PAD_LD13__ARM11P_TOP_TRACE_6 */ + [464] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 0, 0x0, 0), /* MX35_PAD_LD14__IPU_DISPB_DAT_14 */ + [465] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 5, 0x87c, 0), /* MX35_PAD_LD14__GPIO2_14 */ + [466] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 6, 0x0, 0), /* MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0 */ + [467] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 7, 0x0, 0), /* MX35_PAD_LD14__ARM11P_TOP_TRACE_7 */ + [468] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 0, 0x0, 0), /* MX35_PAD_LD15__IPU_DISPB_DAT_15 */ + [469] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 5, 0x880, 0), /* MX35_PAD_LD15__GPIO2_15 */ + [470] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 6, 0x0, 0), /* MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1 */ + [471] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 7, 0x0, 0), /* MX35_PAD_LD15__ARM11P_TOP_TRACE_8 */ + [472] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 0, 0x0, 0), /* MX35_PAD_LD16__IPU_DISPB_DAT_16 */ + [473] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 2, 0x928, 0), /* MX35_PAD_LD16__IPU_DISPB_D12_VSYNC */ + [474] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 5, 0x884, 0), /* MX35_PAD_LD16__GPIO2_16 */ + [475] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 6, 0x0, 0), /* MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2 */ + [476] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 7, 0x0, 0), /* MX35_PAD_LD16__ARM11P_TOP_TRACE_9 */ + [477] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 0, 0x0, 0), /* MX35_PAD_LD17__IPU_DISPB_DAT_17 */ + [478] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 2, 0x0, 0), /* MX35_PAD_LD17__IPU_DISPB_CS2 */ + [479] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 5, 0x888, 0), /* MX35_PAD_LD17__GPIO2_17 */ + [480] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 6, 0x0, 0), /* MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3 */ + [481] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 7, 0x0, 0), /* MX35_PAD_LD17__ARM11P_TOP_TRACE_10 */ + [482] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 0, 0x0, 0), /* MX35_PAD_LD18__IPU_DISPB_DAT_18 */ + [483] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 1, 0x924, 1), /* MX35_PAD_LD18__IPU_DISPB_D0_VSYNC */ + [484] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 2, 0x928, 1), /* MX35_PAD_LD18__IPU_DISPB_D12_VSYNC */ + [485] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 3, 0x818, 0), /* MX35_PAD_LD18__ESDHC3_CMD */ + [486] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 4, 0x9b0, 0), /* MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3 */ + [487] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 5, 0x0, 0), /* MX35_PAD_LD18__GPIO3_24 */ + [488] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 6, 0x0, 0), /* MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4 */ + [489] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 7, 0x0, 0), /* MX35_PAD_LD18__ARM11P_TOP_TRACE_11 */ + [490] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 0, 0x0, 0), /* MX35_PAD_LD19__IPU_DISPB_DAT_19 */ + [491] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 1, 0x0, 0), /* MX35_PAD_LD19__IPU_DISPB_BCLK */ + [492] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 2, 0x0, 0), /* MX35_PAD_LD19__IPU_DISPB_CS1 */ + [493] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 3, 0x814, 0), /* MX35_PAD_LD19__ESDHC3_CLK */ + [494] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 4, 0x9c4, 0), /* MX35_PAD_LD19__USB_TOP_USBOTG_DIR */ + [495] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 5, 0x0, 0), /* MX35_PAD_LD19__GPIO3_25 */ + [496] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 6, 0x0, 0), /* MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5 */ + [497] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 7, 0x0, 0), /* MX35_PAD_LD19__ARM11P_TOP_TRACE_12 */ + [498] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 0, 0x0, 0), /* MX35_PAD_LD20__IPU_DISPB_DAT_20 */ + [499] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 1, 0x0, 0), /* MX35_PAD_LD20__IPU_DISPB_CS0 */ + [500] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 2, 0x0, 0), /* MX35_PAD_LD20__IPU_DISPB_SD_CLK */ + [501] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 3, 0x81c, 0), /* MX35_PAD_LD20__ESDHC3_DAT0 */ + [502] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 5, 0x0, 0), /* MX35_PAD_LD20__GPIO3_26 */ + [503] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 6, 0x0, 0), /* MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3 */ + [504] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 7, 0x0, 0), /* MX35_PAD_LD20__ARM11P_TOP_TRACE_13 */ + [505] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 0, 0x0, 0), /* MX35_PAD_LD21__IPU_DISPB_DAT_21 */ + [506] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 1, 0x0, 0), /* MX35_PAD_LD21__IPU_DISPB_PAR_RS */ + [507] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 2, 0x0, 0), /* MX35_PAD_LD21__IPU_DISPB_SER_RS */ + [508] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 3, 0x820, 0), /* MX35_PAD_LD21__ESDHC3_DAT1 */ + [509] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 4, 0x0, 0), /* MX35_PAD_LD21__USB_TOP_USBOTG_STP */ + [510] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 5, 0x0, 0), /* MX35_PAD_LD21__GPIO3_27 */ + [511] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 6, 0x0, 0), /* MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL */ + [512] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 7, 0x0, 0), /* MX35_PAD_LD21__ARM11P_TOP_TRACE_14 */ + [513] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 0, 0x0, 0), /* MX35_PAD_LD22__IPU_DISPB_DAT_22 */ + [514] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 1, 0x0, 0), /* MX35_PAD_LD22__IPU_DISPB_WR */ + [515] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 2, 0x92c, 0), /* MX35_PAD_LD22__IPU_DISPB_SD_D_I */ + [516] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 3, 0x824, 0), /* MX35_PAD_LD22__ESDHC3_DAT2 */ + [517] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 4, 0x9c8, 0), /* MX35_PAD_LD22__USB_TOP_USBOTG_NXT */ + [518] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 5, 0x0, 0), /* MX35_PAD_LD22__GPIO3_28 */ + [519] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 6, 0x0, 0), /* MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR */ + [520] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 7, 0x0, 0), /* MX35_PAD_LD22__ARM11P_TOP_TRCTL */ + [521] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 0, 0x0, 0), /* MX35_PAD_LD23__IPU_DISPB_DAT_23 */ + [522] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 1, 0x0, 0), /* MX35_PAD_LD23__IPU_DISPB_RD */ + [523] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 2, 0x92c, 1), /* MX35_PAD_LD23__IPU_DISPB_SD_D_IO */ + [524] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 3, 0x828, 0), /* MX35_PAD_LD23__ESDHC3_DAT3 */ + [525] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 4, 0x9c0, 0), /* MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7 */ + [526] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 5, 0x0, 0), /* MX35_PAD_LD23__GPIO3_29 */ + [527] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 6, 0x0, 0), /* MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS */ + [528] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 7, 0x0, 0), /* MX35_PAD_LD23__ARM11P_TOP_TRCLK */ + [529] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 0, 0x0, 0), /* MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC */ + [530] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 2, 0x92c, 2), /* MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO */ + [531] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 5, 0x0, 0), /* MX35_PAD_D3_HSYNC__GPIO3_30 */ + [532] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 6, 0x0, 0), /* MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE */ + [533] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 7, 0x0, 0), /* MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15 */ + [534] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 0, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK */ + [535] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 2, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK */ + [536] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 5, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__GPIO3_31 */ + [537] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 6, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0 */ + [538] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 7, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16 */ + [539] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 0, 0x0, 0), /* MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY */ + [540] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 2, 0x0, 0), /* MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O */ + [541] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 5, 0x82c, 2), /* MX35_PAD_D3_DRDY__GPIO1_0 */ + [542] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 6, 0x0, 0), /* MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1 */ + [543] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 7, 0x0, 0), /* MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17 */ + [544] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 0, 0x0, 0), /* MX35_PAD_CONTRAST__IPU_DISPB_CONTR */ + [545] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 5, 0x838, 2), /* MX35_PAD_CONTRAST__GPIO1_1 */ + [546] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 6, 0x0, 0), /* MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2 */ + [547] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 7, 0x0, 0), /* MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18 */ + [548] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 0, 0x0, 0), /* MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC */ + [549] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 2, 0x0, 0), /* MX35_PAD_D3_VSYNC__IPU_DISPB_CS1 */ + [550] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 5, 0x848, 1), /* MX35_PAD_D3_VSYNC__GPIO1_2 */ + [551] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 6, 0x0, 0), /* MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD */ + [552] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 7, 0x0, 0), /* MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19 */ + [553] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 0, 0x0, 0), /* MX35_PAD_D3_REV__IPU_DISPB_D3_REV */ + [554] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 2, 0x0, 0), /* MX35_PAD_D3_REV__IPU_DISPB_SER_RS */ + [555] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 5, 0x84c, 1), /* MX35_PAD_D3_REV__GPIO1_3 */ + [556] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 6, 0x0, 0), /* MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB */ + [557] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 7, 0x0, 0), /* MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20 */ + [558] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 0, 0x0, 0), /* MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS */ + [559] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 2, 0x0, 0), /* MX35_PAD_D3_CLS__IPU_DISPB_CS2 */ + [560] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 5, 0x850, 2), /* MX35_PAD_D3_CLS__GPIO1_4 */ + [561] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 6, 0x0, 0), /* MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0 */ + [562] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 7, 0x0, 0), /* MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21 */ + [563] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 0, 0x0, 0), /* MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL */ + [564] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 2, 0x928, 2), /* MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC */ + [565] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 5, 0x854, 2), /* MX35_PAD_D3_SPL__GPIO1_5 */ + [566] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 6, 0x0, 0), /* MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1 */ + [567] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 7, 0x0, 0), /* MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22 */ + [568] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 0, 0x0, 0), /* MX35_PAD_SD1_CMD__ESDHC1_CMD */ + [569] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 1, 0x0, 0), /* MX35_PAD_SD1_CMD__MSHC_SCLK */ + [570] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 3, 0x924, 2), /* MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC */ + [571] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 4, 0x9b4, 0), /* MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4 */ + [572] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 5, 0x858, 2), /* MX35_PAD_SD1_CMD__GPIO1_6 */ + [573] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 7, 0x0, 0), /* MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL */ + [574] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 0, 0x0, 0), /* MX35_PAD_SD1_CLK__ESDHC1_CLK */ + [575] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 1, 0x0, 0), /* MX35_PAD_SD1_CLK__MSHC_BS */ + [576] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 3, 0x0, 0), /* MX35_PAD_SD1_CLK__IPU_DISPB_BCLK */ + [577] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 4, 0x9b8, 0), /* MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5 */ + [578] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 5, 0x85c, 2), /* MX35_PAD_SD1_CLK__GPIO1_7 */ + [579] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 7, 0x0, 0), /* MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK */ + [580] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 0, 0x0, 0), /* MX35_PAD_SD1_DATA0__ESDHC1_DAT0 */ + [581] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 1, 0x0, 0), /* MX35_PAD_SD1_DATA0__MSHC_DATA_0 */ + [582] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 3, 0x0, 0), /* MX35_PAD_SD1_DATA0__IPU_DISPB_CS0 */ + [583] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 4, 0x9bc, 0), /* MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6 */ + [584] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 5, 0x860, 2), /* MX35_PAD_SD1_DATA0__GPIO1_8 */ + [585] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 7, 0x0, 0), /* MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23 */ + [586] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 0, 0x0, 0), /* MX35_PAD_SD1_DATA1__ESDHC1_DAT1 */ + [587] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 1, 0x0, 0), /* MX35_PAD_SD1_DATA1__MSHC_DATA_1 */ + [588] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 3, 0x0, 0), /* MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS */ + [589] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 4, 0x9a4, 0), /* MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0 */ + [590] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 5, 0x864, 1), /* MX35_PAD_SD1_DATA1__GPIO1_9 */ + [591] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 7, 0x0, 0), /* MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24 */ + [592] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 0, 0x0, 0), /* MX35_PAD_SD1_DATA2__ESDHC1_DAT2 */ + [593] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 1, 0x0, 0), /* MX35_PAD_SD1_DATA2__MSHC_DATA_2 */ + [594] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 3, 0x0, 0), /* MX35_PAD_SD1_DATA2__IPU_DISPB_WR */ + [595] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 4, 0x9a8, 0), /* MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1 */ + [596] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 5, 0x830, 1), /* MX35_PAD_SD1_DATA2__GPIO1_10 */ + [597] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 7, 0x0, 0), /* MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25 */ + [598] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 0, 0x0, 0), /* MX35_PAD_SD1_DATA3__ESDHC1_DAT3 */ + [599] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 1, 0x0, 0), /* MX35_PAD_SD1_DATA3__MSHC_DATA_3 */ + [600] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 3, 0x0, 0), /* MX35_PAD_SD1_DATA3__IPU_DISPB_RD */ + [601] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 4, 0x9ac, 0), /* MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2 */ + [602] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 5, 0x834, 1), /* MX35_PAD_SD1_DATA3__GPIO1_11 */ + [603] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 7, 0x0, 0), /* MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26 */ + [604] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 0, 0x0, 0), /* MX35_PAD_SD2_CMD__ESDHC2_CMD */ + [605] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 1, 0x91c, 2), /* MX35_PAD_SD2_CMD__I2C3_SCL */ + [606] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 2, 0x804, 0), /* MX35_PAD_SD2_CMD__ESDHC1_DAT4 */ + [607] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 3, 0x938, 2), /* MX35_PAD_SD2_CMD__IPU_CSI_D_2 */ + [608] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 4, 0x9dc, 0), /* MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4 */ + [609] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 5, 0x868, 2), /* MX35_PAD_SD2_CMD__GPIO2_0 */ + [610] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 6, 0x0, 0), /* MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1 */ + [611] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 7, 0x928, 3), /* MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC */ + [612] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 0, 0x0, 0), /* MX35_PAD_SD2_CLK__ESDHC2_CLK */ + [613] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 1, 0x920, 2), /* MX35_PAD_SD2_CLK__I2C3_SDA */ + [614] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 2, 0x808, 0), /* MX35_PAD_SD2_CLK__ESDHC1_DAT5 */ + [615] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 3, 0x93c, 2), /* MX35_PAD_SD2_CLK__IPU_CSI_D_3 */ + [616] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 4, 0x9e0, 0), /* MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5 */ + [617] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 5, 0x894, 1), /* MX35_PAD_SD2_CLK__GPIO2_1 */ + [618] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 6, 0x998, 2), /* MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1 */ + [619] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 7, 0x0, 0), /* MX35_PAD_SD2_CLK__IPU_DISPB_CS2 */ + [620] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 0, 0x0, 0), /* MX35_PAD_SD2_DATA0__ESDHC2_DAT0 */ + [621] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 1, 0x9a0, 1), /* MX35_PAD_SD2_DATA0__UART3_RXD_MUX */ + [622] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 2, 0x80c, 0), /* MX35_PAD_SD2_DATA0__ESDHC1_DAT6 */ + [623] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 3, 0x940, 1), /* MX35_PAD_SD2_DATA0__IPU_CSI_D_4 */ + [624] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 4, 0x9e4, 0), /* MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6 */ + [625] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 5, 0x8c0, 1), /* MX35_PAD_SD2_DATA0__GPIO2_2 */ + [626] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 6, 0x994, 3), /* MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK */ + [627] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 0, 0x0, 0), /* MX35_PAD_SD2_DATA1__ESDHC2_DAT1 */ + [628] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 1, 0x0, 0), /* MX35_PAD_SD2_DATA1__UART3_TXD_MUX */ + [629] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 2, 0x810, 0), /* MX35_PAD_SD2_DATA1__ESDHC1_DAT7 */ + [630] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 3, 0x944, 1), /* MX35_PAD_SD2_DATA1__IPU_CSI_D_5 */ + [631] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 4, 0x9cc, 0), /* MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0 */ + [632] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 5, 0x8cc, 1), /* MX35_PAD_SD2_DATA1__GPIO2_3 */ + [633] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 0, 0x0, 0), /* MX35_PAD_SD2_DATA2__ESDHC2_DAT2 */ + [634] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 1, 0x99c, 0), /* MX35_PAD_SD2_DATA2__UART3_RTS */ + [635] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 2, 0x7c8, 1), /* MX35_PAD_SD2_DATA2__CAN1_RXCAN */ + [636] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 3, 0x948, 1), /* MX35_PAD_SD2_DATA2__IPU_CSI_D_6 */ + [637] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 4, 0x9d0, 0), /* MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1 */ + [638] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 5, 0x8d0, 1), /* MX35_PAD_SD2_DATA2__GPIO2_4 */ + [639] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 0, 0x0, 0), /* MX35_PAD_SD2_DATA3__ESDHC2_DAT3 */ + [640] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 1, 0x0, 0), /* MX35_PAD_SD2_DATA3__UART3_CTS */ + [641] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 2, 0x0, 0), /* MX35_PAD_SD2_DATA3__CAN1_TXCAN */ + [642] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 3, 0x94c, 1), /* MX35_PAD_SD2_DATA3__IPU_CSI_D_7 */ + [643] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 4, 0x9d4, 0), /* MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2 */ + [644] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 5, 0x8d4, 1), /* MX35_PAD_SD2_DATA3__GPIO2_5 */ + [645] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 0, 0x0, 0), /* MX35_PAD_ATA_CS0__ATA_CS0 */ + [646] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 1, 0x7dc, 1), /* MX35_PAD_ATA_CS0__CSPI1_SS3 */ + [647] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 3, 0x0, 0), /* MX35_PAD_ATA_CS0__IPU_DISPB_CS1 */ + [648] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 5, 0x8d8, 1), /* MX35_PAD_ATA_CS0__GPIO2_6 */ + [649] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 6, 0x0, 0), /* MX35_PAD_ATA_CS0__IPU_DIAGB_0 */ + [650] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 7, 0x0, 0), /* MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0 */ + [651] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 0, 0x0, 0), /* MX35_PAD_ATA_CS1__ATA_CS1 */ + [652] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 3, 0x0, 0), /* MX35_PAD_ATA_CS1__IPU_DISPB_CS2 */ + [653] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 4, 0x7f0, 1), /* MX35_PAD_ATA_CS1__CSPI2_SS0 */ + [654] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 5, 0x8dc, 1), /* MX35_PAD_ATA_CS1__GPIO2_7 */ + [655] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 6, 0x0, 0), /* MX35_PAD_ATA_CS1__IPU_DIAGB_1 */ + [656] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 7, 0x0, 0), /* MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1 */ + [657] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 0, 0x0, 0), /* MX35_PAD_ATA_DIOR__ATA_DIOR */ + [658] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 1, 0x81c, 1), /* MX35_PAD_ATA_DIOR__ESDHC3_DAT0 */ + [659] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 2, 0x9c4, 1), /* MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR */ + [660] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 3, 0x0, 0), /* MX35_PAD_ATA_DIOR__IPU_DISPB_BE0 */ + [661] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 4, 0x7f4, 1), /* MX35_PAD_ATA_DIOR__CSPI2_SS1 */ + [662] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 5, 0x8e0, 1), /* MX35_PAD_ATA_DIOR__GPIO2_8 */ + [663] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 6, 0x0, 0), /* MX35_PAD_ATA_DIOR__IPU_DIAGB_2 */ + [664] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 7, 0x0, 0), /* MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2 */ + [665] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 0, 0x0, 0), /* MX35_PAD_ATA_DIOW__ATA_DIOW */ + [666] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 1, 0x820, 1), /* MX35_PAD_ATA_DIOW__ESDHC3_DAT1 */ + [667] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 2, 0x0, 0), /* MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP */ + [668] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 3, 0x0, 0), /* MX35_PAD_ATA_DIOW__IPU_DISPB_BE1 */ + [669] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 4, 0x7ec, 2), /* MX35_PAD_ATA_DIOW__CSPI2_MOSI */ + [670] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 5, 0x8e4, 1), /* MX35_PAD_ATA_DIOW__GPIO2_9 */ + [671] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 6, 0x0, 0), /* MX35_PAD_ATA_DIOW__IPU_DIAGB_3 */ + [672] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 7, 0x0, 0), /* MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3 */ + [673] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 0, 0x0, 0), /* MX35_PAD_ATA_DMACK__ATA_DMACK */ + [674] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 1, 0x824, 1), /* MX35_PAD_ATA_DMACK__ESDHC3_DAT2 */ + [675] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 2, 0x9c8, 1), /* MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT */ + [676] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 4, 0x7e8, 2), /* MX35_PAD_ATA_DMACK__CSPI2_MISO */ + [677] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 5, 0x86c, 1), /* MX35_PAD_ATA_DMACK__GPIO2_10 */ + [678] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 6, 0x0, 0), /* MX35_PAD_ATA_DMACK__IPU_DIAGB_4 */ + [679] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 7, 0x0, 0), /* MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0 */ + [680] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 0, 0x0, 0), /* MX35_PAD_ATA_RESET_B__ATA_RESET_B */ + [681] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 1, 0x828, 1), /* MX35_PAD_ATA_RESET_B__ESDHC3_DAT3 */ + [682] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 2, 0x9a4, 1), /* MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0 */ + [683] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 3, 0x0, 0), /* MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O */ + [684] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 4, 0x7e4, 2), /* MX35_PAD_ATA_RESET_B__CSPI2_RDY */ + [685] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 5, 0x870, 1), /* MX35_PAD_ATA_RESET_B__GPIO2_11 */ + [686] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 6, 0x0, 0), /* MX35_PAD_ATA_RESET_B__IPU_DIAGB_5 */ + [687] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 7, 0x0, 0), /* MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1 */ + [688] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 0, 0x0, 0), /* MX35_PAD_ATA_IORDY__ATA_IORDY */ + [689] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 1, 0x0, 0), /* MX35_PAD_ATA_IORDY__ESDHC3_DAT4 */ + [690] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 2, 0x9a8, 1), /* MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1 */ + [691] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 3, 0x92c, 3), /* MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO */ + [692] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 4, 0x0, 0), /* MX35_PAD_ATA_IORDY__ESDHC2_DAT4 */ + [693] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 5, 0x874, 1), /* MX35_PAD_ATA_IORDY__GPIO2_12 */ + [694] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 6, 0x0, 0), /* MX35_PAD_ATA_IORDY__IPU_DIAGB_6 */ + [695] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 7, 0x0, 0), /* MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2 */ + [696] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 0, 0x0, 0), /* MX35_PAD_ATA_DATA0__ATA_DATA_0 */ + [697] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 1, 0x0, 0), /* MX35_PAD_ATA_DATA0__ESDHC3_DAT5 */ + [698] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 2, 0x9ac, 1), /* MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2 */ + [699] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 3, 0x928, 4), /* MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC */ + [700] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 4, 0x0, 0), /* MX35_PAD_ATA_DATA0__ESDHC2_DAT5 */ + [701] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 5, 0x878, 1), /* MX35_PAD_ATA_DATA0__GPIO2_13 */ + [702] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 6, 0x0, 0), /* MX35_PAD_ATA_DATA0__IPU_DIAGB_7 */ + [703] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 7, 0x0, 0), /* MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3 */ + [704] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 0, 0x0, 0), /* MX35_PAD_ATA_DATA1__ATA_DATA_1 */ + [705] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 1, 0x0, 0), /* MX35_PAD_ATA_DATA1__ESDHC3_DAT6 */ + [706] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 2, 0x9b0, 1), /* MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3 */ + [707] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 3, 0x0, 0), /* MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK */ + [708] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 4, 0x0, 0), /* MX35_PAD_ATA_DATA1__ESDHC2_DAT6 */ + [709] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 5, 0x87c, 1), /* MX35_PAD_ATA_DATA1__GPIO2_14 */ + [710] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 6, 0x0, 0), /* MX35_PAD_ATA_DATA1__IPU_DIAGB_8 */ + [711] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 7, 0x0, 0), /* MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27 */ + [712] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 0, 0x0, 0), /* MX35_PAD_ATA_DATA2__ATA_DATA_2 */ + [713] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 1, 0x0, 0), /* MX35_PAD_ATA_DATA2__ESDHC3_DAT7 */ + [714] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 2, 0x9b4, 1), /* MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4 */ + [715] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 3, 0x0, 0), /* MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS */ + [716] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 4, 0x0, 0), /* MX35_PAD_ATA_DATA2__ESDHC2_DAT7 */ + [717] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 5, 0x880, 1), /* MX35_PAD_ATA_DATA2__GPIO2_15 */ + [718] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 6, 0x0, 0), /* MX35_PAD_ATA_DATA2__IPU_DIAGB_9 */ + [719] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 7, 0x0, 0), /* MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28 */ + [720] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 0, 0x0, 0), /* MX35_PAD_ATA_DATA3__ATA_DATA_3 */ + [721] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 1, 0x814, 1), /* MX35_PAD_ATA_DATA3__ESDHC3_CLK */ + [722] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 2, 0x9b8, 1), /* MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5 */ + [723] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 4, 0x7e0, 2), /* MX35_PAD_ATA_DATA3__CSPI2_SCLK */ + [724] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 5, 0x884, 1), /* MX35_PAD_ATA_DATA3__GPIO2_16 */ + [725] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 6, 0x0, 0), /* MX35_PAD_ATA_DATA3__IPU_DIAGB_10 */ + [726] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 7, 0x0, 0), /* MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29 */ + [727] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 0, 0x0, 0), /* MX35_PAD_ATA_DATA4__ATA_DATA_4 */ + [728] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 1, 0x818, 1), /* MX35_PAD_ATA_DATA4__ESDHC3_CMD */ + [729] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 2, 0x9bc, 1), /* MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6 */ + [730] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 5, 0x888, 1), /* MX35_PAD_ATA_DATA4__GPIO2_17 */ + [731] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 6, 0x0, 0), /* MX35_PAD_ATA_DATA4__IPU_DIAGB_11 */ + [732] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 7, 0x0, 0), /* MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30 */ + [733] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 0, 0x0, 0), /* MX35_PAD_ATA_DATA5__ATA_DATA_5 */ + [734] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 2, 0x9c0, 1), /* MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7 */ + [735] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 5, 0x88c, 1), /* MX35_PAD_ATA_DATA5__GPIO2_18 */ + [736] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 6, 0x0, 0), /* MX35_PAD_ATA_DATA5__IPU_DIAGB_12 */ + [737] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 7, 0x0, 0), /* MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31 */ + [738] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 0, 0x0, 0), /* MX35_PAD_ATA_DATA6__ATA_DATA_6 */ + [739] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 1, 0x0, 0), /* MX35_PAD_ATA_DATA6__CAN1_TXCAN */ + [740] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 2, 0x0, 0), /* MX35_PAD_ATA_DATA6__UART1_DTR */ + [741] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 3, 0x7b4, 0), /* MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD */ + [742] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 5, 0x890, 1), /* MX35_PAD_ATA_DATA6__GPIO2_19 */ + [743] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 6, 0x0, 0), /* MX35_PAD_ATA_DATA6__IPU_DIAGB_13 */ + [744] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 0, 0x0, 0), /* MX35_PAD_ATA_DATA7__ATA_DATA_7 */ + [745] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 1, 0x7c8, 2), /* MX35_PAD_ATA_DATA7__CAN1_RXCAN */ + [746] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 2, 0x0, 0), /* MX35_PAD_ATA_DATA7__UART1_DSR */ + [747] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 3, 0x7b0, 0), /* MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD */ + [748] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 5, 0x898, 1), /* MX35_PAD_ATA_DATA7__GPIO2_20 */ + [749] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 6, 0x0, 0), /* MX35_PAD_ATA_DATA7__IPU_DIAGB_14 */ + [750] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 0, 0x0, 0), /* MX35_PAD_ATA_DATA8__ATA_DATA_8 */ + [751] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 1, 0x99c, 1), /* MX35_PAD_ATA_DATA8__UART3_RTS */ + [752] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 2, 0x0, 0), /* MX35_PAD_ATA_DATA8__UART1_RI */ + [753] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 3, 0x7c0, 0), /* MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC */ + [754] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 5, 0x89c, 1), /* MX35_PAD_ATA_DATA8__GPIO2_21 */ + [755] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 6, 0x0, 0), /* MX35_PAD_ATA_DATA8__IPU_DIAGB_15 */ + [756] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 0, 0x0, 0), /* MX35_PAD_ATA_DATA9__ATA_DATA_9 */ + [757] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 1, 0x0, 0), /* MX35_PAD_ATA_DATA9__UART3_CTS */ + [758] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 2, 0x0, 0), /* MX35_PAD_ATA_DATA9__UART1_DCD */ + [759] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 3, 0x7c4, 0), /* MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS */ + [760] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 5, 0x8a0, 1), /* MX35_PAD_ATA_DATA9__GPIO2_22 */ + [761] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 6, 0x0, 0), /* MX35_PAD_ATA_DATA9__IPU_DIAGB_16 */ + [762] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 0, 0x0, 0), /* MX35_PAD_ATA_DATA10__ATA_DATA_10 */ + [763] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 1, 0x9a0, 2), /* MX35_PAD_ATA_DATA10__UART3_RXD_MUX */ + [764] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 3, 0x7b8, 0), /* MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC */ + [765] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 5, 0x8a4, 1), /* MX35_PAD_ATA_DATA10__GPIO2_23 */ + [766] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 6, 0x0, 0), /* MX35_PAD_ATA_DATA10__IPU_DIAGB_17 */ + [767] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 0, 0x0, 0), /* MX35_PAD_ATA_DATA11__ATA_DATA_11 */ + [768] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 1, 0x0, 0), /* MX35_PAD_ATA_DATA11__UART3_TXD_MUX */ + [769] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 3, 0x7bc, 0), /* MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS */ + [770] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 5, 0x8a8, 1), /* MX35_PAD_ATA_DATA11__GPIO2_24 */ + [771] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 6, 0x0, 0), /* MX35_PAD_ATA_DATA11__IPU_DIAGB_18 */ + [772] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 0, 0x0, 0), /* MX35_PAD_ATA_DATA12__ATA_DATA_12 */ + [773] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 1, 0x91c, 3), /* MX35_PAD_ATA_DATA12__I2C3_SCL */ + [774] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 5, 0x8ac, 1), /* MX35_PAD_ATA_DATA12__GPIO2_25 */ + [775] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 6, 0x0, 0), /* MX35_PAD_ATA_DATA12__IPU_DIAGB_19 */ + [776] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 0, 0x0, 0), /* MX35_PAD_ATA_DATA13__ATA_DATA_13 */ + [777] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 1, 0x920, 3), /* MX35_PAD_ATA_DATA13__I2C3_SDA */ + [778] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 5, 0x8b0, 1), /* MX35_PAD_ATA_DATA13__GPIO2_26 */ + [779] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 6, 0x0, 0), /* MX35_PAD_ATA_DATA13__IPU_DIAGB_20 */ + [780] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 0, 0x0, 0), /* MX35_PAD_ATA_DATA14__ATA_DATA_14 */ + [781] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 1, 0x930, 2), /* MX35_PAD_ATA_DATA14__IPU_CSI_D_0 */ + [782] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 3, 0x970, 2), /* MX35_PAD_ATA_DATA14__KPP_ROW_0 */ + [783] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 5, 0x8b4, 1), /* MX35_PAD_ATA_DATA14__GPIO2_27 */ + [784] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 6, 0x0, 0), /* MX35_PAD_ATA_DATA14__IPU_DIAGB_21 */ + [785] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 0, 0x0, 0), /* MX35_PAD_ATA_DATA15__ATA_DATA_15 */ + [786] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 1, 0x934, 2), /* MX35_PAD_ATA_DATA15__IPU_CSI_D_1 */ + [787] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 3, 0x974, 2), /* MX35_PAD_ATA_DATA15__KPP_ROW_1 */ + [788] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 5, 0x8b8, 1), /* MX35_PAD_ATA_DATA15__GPIO2_28 */ + [789] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 6, 0x0, 0), /* MX35_PAD_ATA_DATA15__IPU_DIAGB_22 */ + [790] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 0, 0x0, 0), /* MX35_PAD_ATA_INTRQ__ATA_INTRQ */ + [791] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 1, 0x938, 3), /* MX35_PAD_ATA_INTRQ__IPU_CSI_D_2 */ + [792] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 3, 0x978, 2), /* MX35_PAD_ATA_INTRQ__KPP_ROW_2 */ + [793] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 5, 0x8bc, 1), /* MX35_PAD_ATA_INTRQ__GPIO2_29 */ + [794] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 6, 0x0, 0), /* MX35_PAD_ATA_INTRQ__IPU_DIAGB_23 */ + [795] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 0, 0x0, 0), /* MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN */ + [796] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 1, 0x93c, 3), /* MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3 */ + [797] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 3, 0x97c, 2), /* MX35_PAD_ATA_BUFF_EN__KPP_ROW_3 */ + [798] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 5, 0x8c4, 1), /* MX35_PAD_ATA_BUFF_EN__GPIO2_30 */ + [799] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 6, 0x0, 0), /* MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24 */ + [800] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 0, 0x0, 0), /* MX35_PAD_ATA_DMARQ__ATA_DMARQ */ + [801] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 1, 0x940, 2), /* MX35_PAD_ATA_DMARQ__IPU_CSI_D_4 */ + [802] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 3, 0x950, 2), /* MX35_PAD_ATA_DMARQ__KPP_COL_0 */ + [803] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 5, 0x8c8, 1), /* MX35_PAD_ATA_DMARQ__GPIO2_31 */ + [804] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 6, 0x0, 0), /* MX35_PAD_ATA_DMARQ__IPU_DIAGB_25 */ + [805] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 7, 0x0, 0), /* MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4 */ + [806] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 0, 0x0, 0), /* MX35_PAD_ATA_DA0__ATA_DA_0 */ + [807] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 1, 0x944, 2), /* MX35_PAD_ATA_DA0__IPU_CSI_D_5 */ + [808] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 3, 0x954, 2), /* MX35_PAD_ATA_DA0__KPP_COL_1 */ + [809] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 5, 0x8e8, 1), /* MX35_PAD_ATA_DA0__GPIO3_0 */ + [810] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 6, 0x0, 0), /* MX35_PAD_ATA_DA0__IPU_DIAGB_26 */ + [811] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 7, 0x0, 0), /* MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5 */ + [812] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 0, 0x0, 0), /* MX35_PAD_ATA_DA1__ATA_DA_1 */ + [813] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 1, 0x948, 2), /* MX35_PAD_ATA_DA1__IPU_CSI_D_6 */ + [814] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 3, 0x958, 2), /* MX35_PAD_ATA_DA1__KPP_COL_2 */ + [815] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 5, 0x0, 0), /* MX35_PAD_ATA_DA1__GPIO3_1 */ + [816] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 6, 0x0, 0), /* MX35_PAD_ATA_DA1__IPU_DIAGB_27 */ + [817] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 7, 0x0, 0), /* MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6 */ + [818] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 0, 0x0, 0), /* MX35_PAD_ATA_DA2__ATA_DA_2 */ + [819] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 1, 0x94c, 2), /* MX35_PAD_ATA_DA2__IPU_CSI_D_7 */ + [820] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 3, 0x95c, 2), /* MX35_PAD_ATA_DA2__KPP_COL_3 */ + [821] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 5, 0x0, 0), /* MX35_PAD_ATA_DA2__GPIO3_2 */ + [822] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 6, 0x0, 0), /* MX35_PAD_ATA_DA2__IPU_DIAGB_28 */ + [823] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 7, 0x0, 0), /* MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7 */ + [824] = IMX_PIN_REG(MX35_PAD_MLB_CLK, 0x738, 0x2d4, 0, 0x0, 0), /* MX35_PAD_MLB_CLK__MLB_MLBCLK */ + [825] = IMX_PIN_REG(MX35_PAD_MLB_CLK, 0x738, 0x2d4, 5, 0x0, 0), /* MX35_PAD_MLB_CLK__GPIO3_3 */ + [826] = IMX_PIN_REG(MX35_PAD_MLB_DAT, 0x73c, 0x2d8, 0, 0x0, 0), /* MX35_PAD_MLB_DAT__MLB_MLBDAT */ + [827] = IMX_PIN_REG(MX35_PAD_MLB_DAT, 0x73c, 0x2d8, 5, 0x904, 1), /* MX35_PAD_MLB_DAT__GPIO3_4 */ + [828] = IMX_PIN_REG(MX35_PAD_MLB_SIG, 0x740, 0x2dc, 0, 0x0, 0), /* MX35_PAD_MLB_SIG__MLB_MLBSIG */ + [829] = IMX_PIN_REG(MX35_PAD_MLB_SIG, 0x740, 0x2dc, 5, 0x908, 1), /* MX35_PAD_MLB_SIG__GPIO3_5 */ + [830] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 0, 0x0, 0), /* MX35_PAD_FEC_TX_CLK__FEC_TX_CLK */ + [831] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 1, 0x804, 1), /* MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4 */ + [832] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 2, 0x9a0, 3), /* MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX */ + [833] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 3, 0x9ec, 1), /* MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR */ + [834] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 4, 0x7ec, 3), /* MX35_PAD_FEC_TX_CLK__CSPI2_MOSI */ + [835] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 5, 0x90c, 1), /* MX35_PAD_FEC_TX_CLK__GPIO3_6 */ + [836] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 6, 0x928, 5), /* MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC */ + [837] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 7, 0x0, 0), /* MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0 */ + [838] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 0, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__FEC_RX_CLK */ + [839] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 1, 0x808, 1), /* MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5 */ + [840] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 2, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX */ + [841] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 3, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP */ + [842] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 4, 0x7e8, 3), /* MX35_PAD_FEC_RX_CLK__CSPI2_MISO */ + [843] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 5, 0x910, 1), /* MX35_PAD_FEC_RX_CLK__GPIO3_7 */ + [844] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 6, 0x92c, 4), /* MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I */ + [845] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 7, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1 */ + [846] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 0, 0x0, 0), /* MX35_PAD_FEC_RX_DV__FEC_RX_DV */ + [847] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 1, 0x80c, 1), /* MX35_PAD_FEC_RX_DV__ESDHC1_DAT6 */ + [848] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 2, 0x99c, 2), /* MX35_PAD_FEC_RX_DV__UART3_RTS */ + [849] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 3, 0x9f0, 1), /* MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT */ + [850] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 4, 0x7e0, 3), /* MX35_PAD_FEC_RX_DV__CSPI2_SCLK */ + [851] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 5, 0x914, 1), /* MX35_PAD_FEC_RX_DV__GPIO3_8 */ + [852] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 6, 0x0, 0), /* MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK */ + [853] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 7, 0x0, 0), /* MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2 */ + [854] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 0, 0x0, 0), /* MX35_PAD_FEC_COL__FEC_COL */ + [855] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 1, 0x810, 1), /* MX35_PAD_FEC_COL__ESDHC1_DAT7 */ + [856] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 2, 0x0, 0), /* MX35_PAD_FEC_COL__UART3_CTS */ + [857] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 3, 0x9cc, 1), /* MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0 */ + [858] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 4, 0x7e4, 3), /* MX35_PAD_FEC_COL__CSPI2_RDY */ + [859] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 5, 0x918, 1), /* MX35_PAD_FEC_COL__GPIO3_9 */ + [860] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 6, 0x0, 0), /* MX35_PAD_FEC_COL__IPU_DISPB_SER_RS */ + [861] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 7, 0x0, 0), /* MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3 */ + [862] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA0__FEC_RDATA_0 */ + [863] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 1, 0x0, 0), /* MX35_PAD_FEC_RDATA0__PWM_PWMO */ + [864] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 2, 0x0, 0), /* MX35_PAD_FEC_RDATA0__UART3_DTR */ + [865] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 3, 0x9d0, 1), /* MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1 */ + [866] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 4, 0x7f0, 2), /* MX35_PAD_FEC_RDATA0__CSPI2_SS0 */ + [867] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 5, 0x8ec, 1), /* MX35_PAD_FEC_RDATA0__GPIO3_10 */ + [868] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 6, 0x0, 0), /* MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1 */ + [869] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 7, 0x0, 0), /* MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4 */ + [870] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA0__FEC_TDATA_0 */ + [871] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 1, 0x0, 0), /* MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1 */ + [872] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 2, 0x0, 0), /* MX35_PAD_FEC_TDATA0__UART3_DSR */ + [873] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 3, 0x9d4, 1), /* MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2 */ + [874] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 4, 0x7f4, 2), /* MX35_PAD_FEC_TDATA0__CSPI2_SS1 */ + [875] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 5, 0x8f0, 1), /* MX35_PAD_FEC_TDATA0__GPIO3_11 */ + [876] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 6, 0x0, 0), /* MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0 */ + [877] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 7, 0x0, 0), /* MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5 */ + [878] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 0, 0x0, 0), /* MX35_PAD_FEC_TX_EN__FEC_TX_EN */ + [879] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 1, 0x998, 3), /* MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1 */ + [880] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 2, 0x0, 0), /* MX35_PAD_FEC_TX_EN__UART3_RI */ + [881] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 3, 0x9d8, 1), /* MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3 */ + [882] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 5, 0x8f4, 1), /* MX35_PAD_FEC_TX_EN__GPIO3_12 */ + [883] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 6, 0x0, 0), /* MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS */ + [884] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 7, 0x0, 0), /* MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6 */ + [885] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 0, 0x0, 0), /* MX35_PAD_FEC_MDC__FEC_MDC */ + [886] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 1, 0x0, 0), /* MX35_PAD_FEC_MDC__CAN2_TXCAN */ + [887] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 2, 0x0, 0), /* MX35_PAD_FEC_MDC__UART3_DCD */ + [888] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 3, 0x9dc, 1), /* MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4 */ + [889] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 5, 0x8f8, 1), /* MX35_PAD_FEC_MDC__GPIO3_13 */ + [890] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 6, 0x0, 0), /* MX35_PAD_FEC_MDC__IPU_DISPB_WR */ + [891] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 7, 0x0, 0), /* MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7 */ + [892] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 0, 0x0, 0), /* MX35_PAD_FEC_MDIO__FEC_MDIO */ + [893] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 1, 0x7cc, 2), /* MX35_PAD_FEC_MDIO__CAN2_RXCAN */ + [894] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 3, 0x9e0, 1), /* MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5 */ + [895] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 5, 0x8fc, 1), /* MX35_PAD_FEC_MDIO__GPIO3_14 */ + [896] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 6, 0x0, 0), /* MX35_PAD_FEC_MDIO__IPU_DISPB_RD */ + [897] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 7, 0x0, 0), /* MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8 */ + [898] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 0, 0x0, 0), /* MX35_PAD_FEC_TX_ERR__FEC_TX_ERR */ + [899] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 1, 0x990, 2), /* MX35_PAD_FEC_TX_ERR__OWIRE_LINE */ + [900] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 2, 0x994, 4), /* MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK */ + [901] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 3, 0x9e4, 1), /* MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6 */ + [902] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 5, 0x900, 1), /* MX35_PAD_FEC_TX_ERR__GPIO3_15 */ + [903] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 6, 0x924, 3), /* MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC */ + [904] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 7, 0x0, 0), /* MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9 */ + [905] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 0, 0x0, 0), /* MX35_PAD_FEC_RX_ERR__FEC_RX_ERR */ + [906] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 1, 0x930, 3), /* MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0 */ + [907] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 3, 0x9e8, 1), /* MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7 */ + [908] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 4, 0x960, 1), /* MX35_PAD_FEC_RX_ERR__KPP_COL_4 */ + [909] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 5, 0x0, 0), /* MX35_PAD_FEC_RX_ERR__GPIO3_16 */ + [910] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 6, 0x92c, 5), /* MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO */ + [911] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 0, 0x0, 0), /* MX35_PAD_FEC_CRS__FEC_CRS */ + [912] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 1, 0x934, 3), /* MX35_PAD_FEC_CRS__IPU_CSI_D_1 */ + [913] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 3, 0x0, 0), /* MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR */ + [914] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 4, 0x964, 1), /* MX35_PAD_FEC_CRS__KPP_COL_5 */ + [915] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 5, 0x0, 0), /* MX35_PAD_FEC_CRS__GPIO3_17 */ + [916] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 6, 0x0, 0), /* MX35_PAD_FEC_CRS__IPU_FLASH_STROBE */ + [917] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA1__FEC_RDATA_1 */ + [918] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 1, 0x938, 4), /* MX35_PAD_FEC_RDATA1__IPU_CSI_D_2 */ + [919] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 2, 0x0, 0), /* MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC */ + [920] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 3, 0x9f4, 2), /* MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC */ + [921] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 4, 0x968, 1), /* MX35_PAD_FEC_RDATA1__KPP_COL_6 */ + [922] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 5, 0x0, 0), /* MX35_PAD_FEC_RDATA1__GPIO3_18 */ + [923] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 6, 0x0, 0), /* MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0 */ + [924] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA1__FEC_TDATA_1 */ + [925] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 1, 0x93c, 4), /* MX35_PAD_FEC_TDATA1__IPU_CSI_D_3 */ + [926] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 2, 0x7bc, 1), /* MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS */ + [927] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 4, 0x96c, 1), /* MX35_PAD_FEC_TDATA1__KPP_COL_7 */ + [928] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 5, 0x0, 0), /* MX35_PAD_FEC_TDATA1__GPIO3_19 */ + [929] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 6, 0x0, 0), /* MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1 */ + [930] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA2__FEC_RDATA_2 */ + [931] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 1, 0x940, 3), /* MX35_PAD_FEC_RDATA2__IPU_CSI_D_4 */ + [932] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 2, 0x7b4, 1), /* MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD */ + [933] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 4, 0x980, 1), /* MX35_PAD_FEC_RDATA2__KPP_ROW_4 */ + [934] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 5, 0x0, 0), /* MX35_PAD_FEC_RDATA2__GPIO3_20 */ + [935] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA2__FEC_TDATA_2 */ + [936] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 1, 0x944, 3), /* MX35_PAD_FEC_TDATA2__IPU_CSI_D_5 */ + [937] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 2, 0x7b0, 1), /* MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD */ + [938] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 4, 0x984, 1), /* MX35_PAD_FEC_TDATA2__KPP_ROW_5 */ + [939] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 5, 0x0, 0), /* MX35_PAD_FEC_TDATA2__GPIO3_21 */ + [940] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA3__FEC_RDATA_3 */ + [941] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 1, 0x948, 3), /* MX35_PAD_FEC_RDATA3__IPU_CSI_D_6 */ + [942] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 2, 0x7c0, 1), /* MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC */ + [943] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 4, 0x988, 1), /* MX35_PAD_FEC_RDATA3__KPP_ROW_6 */ + [944] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 6, 0x0, 0), /* MX35_PAD_FEC_RDATA3__GPIO3_22 */ + [945] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA3__FEC_TDATA_3 */ + [946] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 1, 0x94c, 3), /* MX35_PAD_FEC_TDATA3__IPU_CSI_D_7 */ + [947] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 2, 0x7c4, 1), /* MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS */ + [948] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 4, 0x98c, 1), /* MX35_PAD_FEC_TDATA3__KPP_ROW_7 */ + [949] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 5, 0x0, 0), /* MX35_PAD_FEC_TDATA3__GPIO3_23 */ + [950] = IMX_PIN_REG(MX35_PAD_EXT_ARMCLK, 0x78c, 0x0, 0, 0x0, 0), /* MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK */ + [951] = IMX_PIN_REG(MX35_PAD_TEST_MODE, 0x790, 0x0, 0, 0x0, 0), /* MX35_PAD_TEST_MODE__TCU_TEST_MODE */ +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx35_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX35_PAD_CAPTURE), + IMX_PINCTRL_PIN(MX35_PAD_COMPARE), + IMX_PINCTRL_PIN(MX35_PAD_WDOG_RST), + IMX_PINCTRL_PIN(MX35_PAD_GPIO1_0), + IMX_PINCTRL_PIN(MX35_PAD_GPIO1_1), + IMX_PINCTRL_PIN(MX35_PAD_GPIO2_0), + IMX_PINCTRL_PIN(MX35_PAD_GPIO3_0), + IMX_PINCTRL_PIN(MX35_PAD_RESET_IN_B), + IMX_PINCTRL_PIN(MX35_PAD_POR_B), + IMX_PINCTRL_PIN(MX35_PAD_CLKO), + IMX_PINCTRL_PIN(MX35_PAD_BOOT_MODE0), + IMX_PINCTRL_PIN(MX35_PAD_BOOT_MODE1), + IMX_PINCTRL_PIN(MX35_PAD_CLK_MODE0), + IMX_PINCTRL_PIN(MX35_PAD_CLK_MODE1), + IMX_PINCTRL_PIN(MX35_PAD_POWER_FAIL), + IMX_PINCTRL_PIN(MX35_PAD_VSTBY), + IMX_PINCTRL_PIN(MX35_PAD_A0), + IMX_PINCTRL_PIN(MX35_PAD_A1), + IMX_PINCTRL_PIN(MX35_PAD_A2), + IMX_PINCTRL_PIN(MX35_PAD_A3), + IMX_PINCTRL_PIN(MX35_PAD_A4), + IMX_PINCTRL_PIN(MX35_PAD_A5), + IMX_PINCTRL_PIN(MX35_PAD_A6), + IMX_PINCTRL_PIN(MX35_PAD_A7), + IMX_PINCTRL_PIN(MX35_PAD_A8), + IMX_PINCTRL_PIN(MX35_PAD_A9), + IMX_PINCTRL_PIN(MX35_PAD_A10), + IMX_PINCTRL_PIN(MX35_PAD_MA10), + IMX_PINCTRL_PIN(MX35_PAD_A11), + IMX_PINCTRL_PIN(MX35_PAD_A12), + IMX_PINCTRL_PIN(MX35_PAD_A13), + IMX_PINCTRL_PIN(MX35_PAD_A14), + IMX_PINCTRL_PIN(MX35_PAD_A15), + IMX_PINCTRL_PIN(MX35_PAD_A16), + IMX_PINCTRL_PIN(MX35_PAD_A17), + IMX_PINCTRL_PIN(MX35_PAD_A18), + IMX_PINCTRL_PIN(MX35_PAD_A19), + IMX_PINCTRL_PIN(MX35_PAD_A20), + IMX_PINCTRL_PIN(MX35_PAD_A21), + IMX_PINCTRL_PIN(MX35_PAD_A22), + IMX_PINCTRL_PIN(MX35_PAD_A23), + IMX_PINCTRL_PIN(MX35_PAD_A24), + IMX_PINCTRL_PIN(MX35_PAD_A25), + IMX_PINCTRL_PIN(MX35_PAD_SDBA1), + IMX_PINCTRL_PIN(MX35_PAD_SDBA0), + IMX_PINCTRL_PIN(MX35_PAD_SD0), + IMX_PINCTRL_PIN(MX35_PAD_SD1), + IMX_PINCTRL_PIN(MX35_PAD_SD2), + IMX_PINCTRL_PIN(MX35_PAD_SD3), + IMX_PINCTRL_PIN(MX35_PAD_SD4), + IMX_PINCTRL_PIN(MX35_PAD_SD5), + IMX_PINCTRL_PIN(MX35_PAD_SD6), + IMX_PINCTRL_PIN(MX35_PAD_SD7), + IMX_PINCTRL_PIN(MX35_PAD_SD8), + IMX_PINCTRL_PIN(MX35_PAD_SD9), + IMX_PINCTRL_PIN(MX35_PAD_SD10), + IMX_PINCTRL_PIN(MX35_PAD_SD11), + IMX_PINCTRL_PIN(MX35_PAD_SD12), + IMX_PINCTRL_PIN(MX35_PAD_SD13), + IMX_PINCTRL_PIN(MX35_PAD_SD14), + IMX_PINCTRL_PIN(MX35_PAD_SD15), + IMX_PINCTRL_PIN(MX35_PAD_SD16), + IMX_PINCTRL_PIN(MX35_PAD_SD17), + IMX_PINCTRL_PIN(MX35_PAD_SD18), + IMX_PINCTRL_PIN(MX35_PAD_SD19), + IMX_PINCTRL_PIN(MX35_PAD_SD20), + IMX_PINCTRL_PIN(MX35_PAD_SD21), + IMX_PINCTRL_PIN(MX35_PAD_SD22), + IMX_PINCTRL_PIN(MX35_PAD_SD23), + IMX_PINCTRL_PIN(MX35_PAD_SD24), + IMX_PINCTRL_PIN(MX35_PAD_SD25), + IMX_PINCTRL_PIN(MX35_PAD_SD26), + IMX_PINCTRL_PIN(MX35_PAD_SD27), + IMX_PINCTRL_PIN(MX35_PAD_SD28), + IMX_PINCTRL_PIN(MX35_PAD_SD29), + IMX_PINCTRL_PIN(MX35_PAD_SD30), + IMX_PINCTRL_PIN(MX35_PAD_SD31), + IMX_PINCTRL_PIN(MX35_PAD_DQM0), + IMX_PINCTRL_PIN(MX35_PAD_DQM1), + IMX_PINCTRL_PIN(MX35_PAD_DQM2), + IMX_PINCTRL_PIN(MX35_PAD_DQM3), + IMX_PINCTRL_PIN(MX35_PAD_EB0), + IMX_PINCTRL_PIN(MX35_PAD_EB1), + IMX_PINCTRL_PIN(MX35_PAD_OE), + IMX_PINCTRL_PIN(MX35_PAD_CS0), + IMX_PINCTRL_PIN(MX35_PAD_CS1), + IMX_PINCTRL_PIN(MX35_PAD_CS2), + IMX_PINCTRL_PIN(MX35_PAD_CS3), + IMX_PINCTRL_PIN(MX35_PAD_CS4), + IMX_PINCTRL_PIN(MX35_PAD_CS5), + IMX_PINCTRL_PIN(MX35_PAD_NF_CE0), + IMX_PINCTRL_PIN(MX35_PAD_ECB), + IMX_PINCTRL_PIN(MX35_PAD_LBA), + IMX_PINCTRL_PIN(MX35_PAD_BCLK), + IMX_PINCTRL_PIN(MX35_PAD_RW), + IMX_PINCTRL_PIN(MX35_PAD_RAS), + IMX_PINCTRL_PIN(MX35_PAD_CAS), + IMX_PINCTRL_PIN(MX35_PAD_SDWE), + IMX_PINCTRL_PIN(MX35_PAD_SDCKE0), + IMX_PINCTRL_PIN(MX35_PAD_SDCKE1), + IMX_PINCTRL_PIN(MX35_PAD_SDCLK), + IMX_PINCTRL_PIN(MX35_PAD_SDQS0), + IMX_PINCTRL_PIN(MX35_PAD_SDQS1), + IMX_PINCTRL_PIN(MX35_PAD_SDQS2), + IMX_PINCTRL_PIN(MX35_PAD_SDQS3), + IMX_PINCTRL_PIN(MX35_PAD_NFWE_B), + IMX_PINCTRL_PIN(MX35_PAD_NFRE_B), + IMX_PINCTRL_PIN(MX35_PAD_NFALE), + IMX_PINCTRL_PIN(MX35_PAD_NFCLE), + IMX_PINCTRL_PIN(MX35_PAD_NFWP_B), + IMX_PINCTRL_PIN(MX35_PAD_NFRB), + IMX_PINCTRL_PIN(MX35_PAD_D15), + IMX_PINCTRL_PIN(MX35_PAD_D14), + IMX_PINCTRL_PIN(MX35_PAD_D13), + IMX_PINCTRL_PIN(MX35_PAD_D12), + IMX_PINCTRL_PIN(MX35_PAD_D11), + IMX_PINCTRL_PIN(MX35_PAD_D10), + IMX_PINCTRL_PIN(MX35_PAD_D9), + IMX_PINCTRL_PIN(MX35_PAD_D8), + IMX_PINCTRL_PIN(MX35_PAD_D7), + IMX_PINCTRL_PIN(MX35_PAD_D6), + IMX_PINCTRL_PIN(MX35_PAD_D5), + IMX_PINCTRL_PIN(MX35_PAD_D4), + IMX_PINCTRL_PIN(MX35_PAD_D3), + IMX_PINCTRL_PIN(MX35_PAD_D2), + IMX_PINCTRL_PIN(MX35_PAD_D1), + IMX_PINCTRL_PIN(MX35_PAD_D0), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D8), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D9), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D10), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D11), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D12), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D13), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D14), + IMX_PINCTRL_PIN(MX35_PAD_CSI_D15), + IMX_PINCTRL_PIN(MX35_PAD_CSI_MCLK), + IMX_PINCTRL_PIN(MX35_PAD_CSI_VSYNC), + IMX_PINCTRL_PIN(MX35_PAD_CSI_HSYNC), + IMX_PINCTRL_PIN(MX35_PAD_CSI_PIXCLK), + IMX_PINCTRL_PIN(MX35_PAD_I2C1_CLK), + IMX_PINCTRL_PIN(MX35_PAD_I2C1_DAT), + IMX_PINCTRL_PIN(MX35_PAD_I2C2_CLK), + IMX_PINCTRL_PIN(MX35_PAD_I2C2_DAT), + IMX_PINCTRL_PIN(MX35_PAD_STXD4), + IMX_PINCTRL_PIN(MX35_PAD_SRXD4), + IMX_PINCTRL_PIN(MX35_PAD_SCK4), + IMX_PINCTRL_PIN(MX35_PAD_STXFS4), + IMX_PINCTRL_PIN(MX35_PAD_STXD5), + IMX_PINCTRL_PIN(MX35_PAD_SRXD5), + IMX_PINCTRL_PIN(MX35_PAD_SCK5), + IMX_PINCTRL_PIN(MX35_PAD_STXFS5), + IMX_PINCTRL_PIN(MX35_PAD_SCKR), + IMX_PINCTRL_PIN(MX35_PAD_FSR), + IMX_PINCTRL_PIN(MX35_PAD_HCKR), + IMX_PINCTRL_PIN(MX35_PAD_SCKT), + IMX_PINCTRL_PIN(MX35_PAD_FST), + IMX_PINCTRL_PIN(MX35_PAD_HCKT), + IMX_PINCTRL_PIN(MX35_PAD_TX5_RX0), + IMX_PINCTRL_PIN(MX35_PAD_TX4_RX1), + IMX_PINCTRL_PIN(MX35_PAD_TX3_RX2), + IMX_PINCTRL_PIN(MX35_PAD_TX2_RX3), + IMX_PINCTRL_PIN(MX35_PAD_TX1), + IMX_PINCTRL_PIN(MX35_PAD_TX0), + IMX_PINCTRL_PIN(MX35_PAD_CSPI1_MOSI), + IMX_PINCTRL_PIN(MX35_PAD_CSPI1_MISO), + IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SS0), + IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SS1), + IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SCLK), + IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SPI_RDY), + IMX_PINCTRL_PIN(MX35_PAD_RXD1), + IMX_PINCTRL_PIN(MX35_PAD_TXD1), + IMX_PINCTRL_PIN(MX35_PAD_RTS1), + IMX_PINCTRL_PIN(MX35_PAD_CTS1), + IMX_PINCTRL_PIN(MX35_PAD_RXD2), + IMX_PINCTRL_PIN(MX35_PAD_TXD2), + IMX_PINCTRL_PIN(MX35_PAD_RTS2), + IMX_PINCTRL_PIN(MX35_PAD_CTS2), + IMX_PINCTRL_PIN(MX35_PAD_RTCK), + IMX_PINCTRL_PIN(MX35_PAD_TCK), + IMX_PINCTRL_PIN(MX35_PAD_TMS), + IMX_PINCTRL_PIN(MX35_PAD_TDI), + IMX_PINCTRL_PIN(MX35_PAD_TDO), + IMX_PINCTRL_PIN(MX35_PAD_TRSTB), + IMX_PINCTRL_PIN(MX35_PAD_DE_B), + IMX_PINCTRL_PIN(MX35_PAD_SJC_MOD), + IMX_PINCTRL_PIN(MX35_PAD_USBOTG_PWR), + IMX_PINCTRL_PIN(MX35_PAD_USBOTG_OC), + IMX_PINCTRL_PIN(MX35_PAD_LD0), + IMX_PINCTRL_PIN(MX35_PAD_LD1), + IMX_PINCTRL_PIN(MX35_PAD_LD2), + IMX_PINCTRL_PIN(MX35_PAD_LD3), + IMX_PINCTRL_PIN(MX35_PAD_LD4), + IMX_PINCTRL_PIN(MX35_PAD_LD5), + IMX_PINCTRL_PIN(MX35_PAD_LD6), + IMX_PINCTRL_PIN(MX35_PAD_LD7), + IMX_PINCTRL_PIN(MX35_PAD_LD8), + IMX_PINCTRL_PIN(MX35_PAD_LD9), + IMX_PINCTRL_PIN(MX35_PAD_LD10), + IMX_PINCTRL_PIN(MX35_PAD_LD11), + IMX_PINCTRL_PIN(MX35_PAD_LD12), + IMX_PINCTRL_PIN(MX35_PAD_LD13), + IMX_PINCTRL_PIN(MX35_PAD_LD14), + IMX_PINCTRL_PIN(MX35_PAD_LD15), + IMX_PINCTRL_PIN(MX35_PAD_LD16), + IMX_PINCTRL_PIN(MX35_PAD_LD17), + IMX_PINCTRL_PIN(MX35_PAD_LD18), + IMX_PINCTRL_PIN(MX35_PAD_LD19), + IMX_PINCTRL_PIN(MX35_PAD_LD20), + IMX_PINCTRL_PIN(MX35_PAD_LD21), + IMX_PINCTRL_PIN(MX35_PAD_LD22), + IMX_PINCTRL_PIN(MX35_PAD_LD23), + IMX_PINCTRL_PIN(MX35_PAD_D3_HSYNC), + IMX_PINCTRL_PIN(MX35_PAD_D3_FPSHIFT), + IMX_PINCTRL_PIN(MX35_PAD_D3_DRDY), + IMX_PINCTRL_PIN(MX35_PAD_CONTRAST), + IMX_PINCTRL_PIN(MX35_PAD_D3_VSYNC), + IMX_PINCTRL_PIN(MX35_PAD_D3_REV), + IMX_PINCTRL_PIN(MX35_PAD_D3_CLS), + IMX_PINCTRL_PIN(MX35_PAD_D3_SPL), + IMX_PINCTRL_PIN(MX35_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX35_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(MX35_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX35_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA0), + IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA1), + IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA2), + IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA3), + IMX_PINCTRL_PIN(MX35_PAD_ATA_CS0), + IMX_PINCTRL_PIN(MX35_PAD_ATA_CS1), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DIOR), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DIOW), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DMACK), + IMX_PINCTRL_PIN(MX35_PAD_ATA_RESET_B), + IMX_PINCTRL_PIN(MX35_PAD_ATA_IORDY), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA0), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA1), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA2), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA3), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA4), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA5), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA6), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA7), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA8), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA9), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA10), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA11), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA12), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA13), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA14), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA15), + IMX_PINCTRL_PIN(MX35_PAD_ATA_INTRQ), + IMX_PINCTRL_PIN(MX35_PAD_ATA_BUFF_EN), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DMARQ), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DA0), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DA1), + IMX_PINCTRL_PIN(MX35_PAD_ATA_DA2), + IMX_PINCTRL_PIN(MX35_PAD_MLB_CLK), + IMX_PINCTRL_PIN(MX35_PAD_MLB_DAT), + IMX_PINCTRL_PIN(MX35_PAD_MLB_SIG), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TX_CLK), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RX_CLK), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RX_DV), + IMX_PINCTRL_PIN(MX35_PAD_FEC_COL), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA0), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA0), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TX_EN), + IMX_PINCTRL_PIN(MX35_PAD_FEC_MDC), + IMX_PINCTRL_PIN(MX35_PAD_FEC_MDIO), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TX_ERR), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RX_ERR), + IMX_PINCTRL_PIN(MX35_PAD_FEC_CRS), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA1), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA1), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA2), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA2), + IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA3), + IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA3), + IMX_PINCTRL_PIN(MX35_PAD_EXT_ARMCLK), + IMX_PINCTRL_PIN(MX35_PAD_TEST_MODE), +}; + +static struct imx_pinctrl_soc_info imx35_pinctrl_info = { + .pins = imx35_pinctrl_pads, + .npins = ARRAY_SIZE(imx35_pinctrl_pads), + .pin_regs = imx35_pin_regs, + .npin_regs = ARRAY_SIZE(imx35_pin_regs), +}; + +static struct of_device_id imx35_pinctrl_of_match[] __devinitdata = { + { .compatible = "fsl,imx35-iomuxc", }, + { /* sentinel */ } +}; + +static int __devinit imx35_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx35_pinctrl_info); +} + +static struct platform_driver imx35_pinctrl_driver = { + .driver = { + .name = "imx35-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx35_pinctrl_of_match), + }, + .probe = imx35_pinctrl_probe, + .remove = __devexit_p(imx_pinctrl_remove), +}; + +static int __init imx35_pinctrl_init(void) +{ + return platform_driver_register(&imx35_pinctrl_driver); +} +arch_initcall(imx35_pinctrl_init); + +static void __exit imx35_pinctrl_exit(void) +{ + platform_driver_unregister(&imx35_pinctrl_driver); +} +module_exit(imx35_pinctrl_exit); +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("Freescale IMX35 pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 965505015beccc4ec900798070165875b8e8dccf Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sat, 25 Aug 2012 20:23:39 +0000 Subject: netfilter: remove xt_NOTRACK It was scheduled to be removed for a long time. Cc: Pablo Neira Ayuso Cc: Patrick McHardy Cc: "David S. Miller" Cc: netfilter@vger.kernel.org Signed-off-by: Cong Wang Signed-off-by: Pablo Neira Ayuso --- Documentation/feature-removal-schedule.txt | 8 ----- arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/mips/configs/ar7_defconfig | 1 - arch/mips/configs/bcm47xx_defconfig | 1 - arch/mips/configs/ip22_defconfig | 1 - arch/mips/configs/jazz_defconfig | 1 - arch/mips/configs/malta_defconfig | 1 - arch/mips/configs/markeins_defconfig | 1 - arch/mips/configs/nlm_xlp_defconfig | 1 - arch/mips/configs/nlm_xlr_defconfig | 1 - arch/mips/configs/rm200_defconfig | 1 - arch/powerpc/configs/pmac32_defconfig | 1 - arch/powerpc/configs/ppc64_defconfig | 1 - arch/powerpc/configs/ppc64e_defconfig | 1 - arch/powerpc/configs/ppc6xx_defconfig | 1 - arch/tile/configs/tilegx_defconfig | 1 - arch/tile/configs/tilepro_defconfig | 1 - net/netfilter/Kconfig | 13 -------- net/netfilter/Makefile | 1 - net/netfilter/xt_NOTRACK.c | 53 ------------------------------ 31 files changed, 102 deletions(-) delete mode 100644 net/netfilter/xt_NOTRACK.c (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index afaff312bf4..b4aab82f52f 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -353,14 +353,6 @@ Why: Internal alias support has been present in module-init-tools for some Who: Wey-Yi Guy ---------------------------- - -What: xt_NOTRACK -Files: net/netfilter/xt_NOTRACK.c -When: April 2011 -Why: Superseded by xt_CT -Who: Netfilter developer team - ---------------------------- What: IRQF_DISABLED diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index e93fdae10b2..90d3109c82f 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -67,7 +67,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 66b26c1e848..8f4f657fdbc 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -67,7 +67,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 15133251598..4571d33903f 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -65,7 +65,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index 67bb6fc117f..12f211733ba 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -65,7 +65,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 3e35ce5fa46..215389a5407 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -66,7 +66,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index ae81e2d190c..cb9dfb30b67 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -61,7 +61,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 55d394edf63..8d5def4a31e 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -80,7 +80,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index af773743ee1..e2af46f530c 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -64,7 +64,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index cdb70d66e53..7c9402b2097 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -65,7 +65,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index 46bed78d065..19d23db690a 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -61,7 +61,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 86f7772bafb..ca6c0b4cab7 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -62,7 +62,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 288261456e1..c80941c7759 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -62,7 +62,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/mips/configs/ar7_defconfig b/arch/mips/configs/ar7_defconfig index 6cd5a519ce5..80e012fa409 100644 --- a/arch/mips/configs/ar7_defconfig +++ b/arch/mips/configs/ar7_defconfig @@ -56,7 +56,6 @@ CONFIG_NF_CONNTRACK_MARK=y CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_IRC=m CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_LIMIT=m CONFIG_NETFILTER_XT_MATCH_MAC=m diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index ad15fb10322..b6fde2bb51b 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -96,7 +96,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index d1606569b00..936ec5a5ed8 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -87,7 +87,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig index 92a60aecad5..0315ee37a20 100644 --- a/arch/mips/configs/jazz_defconfig +++ b/arch/mips/configs/jazz_defconfig @@ -60,7 +60,6 @@ CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 5527abbb7de..cd732e5b4fd 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -86,7 +86,6 @@ CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m diff --git a/arch/mips/configs/markeins_defconfig b/arch/mips/configs/markeins_defconfig index 9c9a123016c..636f82b89fd 100644 --- a/arch/mips/configs/markeins_defconfig +++ b/arch/mips/configs/markeins_defconfig @@ -59,7 +59,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig index 28c6b276c21..84624b17b76 100644 --- a/arch/mips/configs/nlm_xlp_defconfig +++ b/arch/mips/configs/nlm_xlp_defconfig @@ -108,7 +108,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig index 138f698d7c0..44b473420d5 100644 --- a/arch/mips/configs/nlm_xlr_defconfig +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -109,7 +109,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 2c0230e76d2..59d9d2fdcd4 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -68,7 +68,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index f8b394a76ac..29767a8dfea 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -55,7 +55,6 @@ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index db27c82e054..06b56245d78 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -92,7 +92,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig index 7bd1763877b..f55c27609fc 100644 --- a/arch/powerpc/configs/ppc64e_defconfig +++ b/arch/powerpc/configs/ppc64e_defconfig @@ -66,7 +66,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index c47f2becfbc..be1cb6ea3a3 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -167,7 +167,6 @@ CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig index 0270620a169..8c5eff6d6df 100644 --- a/arch/tile/configs/tilegx_defconfig +++ b/arch/tile/configs/tilegx_defconfig @@ -134,7 +134,6 @@ CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TEE=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig index c11de27a9bc..e7a3dfcbcda 100644 --- a/arch/tile/configs/tilepro_defconfig +++ b/arch/tile/configs/tilepro_defconfig @@ -132,7 +132,6 @@ CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m CONFIG_NETFILTER_XT_TARGET_TEE=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TRACE=m diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 052836e2490..3f4b3b4a776 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -670,19 +670,6 @@ config NETFILTER_XT_TARGET_NFQUEUE To compile it as a module, choose M here. If unsure, say N. -config NETFILTER_XT_TARGET_NOTRACK - tristate '"NOTRACK" target support' - depends on IP_NF_RAW || IP6_NF_RAW - depends on NF_CONNTRACK - help - The NOTRACK target allows a select rule to specify - which packets *not* to enter the conntrack/NAT - subsystem with all the consequences (no ICMP error tracking, - no protocol helpers for the selected packets). - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - config NETFILTER_XT_TARGET_RATEEST tristate '"RATEEST" target support' depends on NETFILTER_ADVANCED diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 403ea812588..98244d4c75f 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -85,7 +85,6 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o -obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c deleted file mode 100644 index 9d782181b6c..00000000000 --- a/net/netfilter/xt_NOTRACK.c +++ /dev/null @@ -1,53 +0,0 @@ -/* This is a module which is used for setting up fake conntracks - * on packets so that they are not seen by the conntrack/NAT code. - */ -#include -#include - -#include -#include - -MODULE_DESCRIPTION("Xtables: Disabling connection tracking for packets"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("ipt_NOTRACK"); -MODULE_ALIAS("ip6t_NOTRACK"); - -static unsigned int -notrack_tg(struct sk_buff *skb, const struct xt_action_param *par) -{ - /* Previously seen (loopback)? Ignore. */ - if (skb->nfct != NULL) - return XT_CONTINUE; - - /* Attach fake conntrack entry. - If there is a real ct entry correspondig to this packet, - it'll hang aroun till timing out. We don't deal with it - for performance reasons. JK */ - skb->nfct = &nf_ct_untracked_get()->ct_general; - skb->nfctinfo = IP_CT_NEW; - nf_conntrack_get(skb->nfct); - - return XT_CONTINUE; -} - -static struct xt_target notrack_tg_reg __read_mostly = { - .name = "NOTRACK", - .revision = 0, - .family = NFPROTO_UNSPEC, - .target = notrack_tg, - .table = "raw", - .me = THIS_MODULE, -}; - -static int __init notrack_tg_init(void) -{ - return xt_register_target(¬rack_tg_reg); -} - -static void __exit notrack_tg_exit(void) -{ - xt_unregister_target(¬rack_tg_reg); -} - -module_init(notrack_tg_init); -module_exit(notrack_tg_exit); -- cgit v1.2.3-70-g09d2 From 62d6ae880e3e76098d5e345decd2dce443975889 Mon Sep 17 00:00:00 2001 From: Carsten Emde Date: Thu, 19 Jul 2012 20:34:10 +0000 Subject: Honor state disabling in the cpuidle ladder governor There are two cpuidle governors ladder and menu. While the ladder governor is always available, if CONFIG_CPU_IDLE is selected, the menu governor additionally requires CONFIG_NO_HZ. A particular C state can be disabled by writing to the sysfs file /sys/devices/system/cpu/cpuN/cpuidle/stateN/disable, but this mechanism is only implemented in the menu governor. Thus, in a system where CONFIG_NO_HZ is not selected, the ladder governor becomes default and always will walk through all sleep states - irrespective of whether the C state was disabled via sysfs or not. The only way to select a specific C state was to write the related latency to /dev/cpu_dma_latency and keep the file open as long as this setting was required - not very practical and not suitable for setting a single core in an SMP system. With this patch, the ladder governor only will promote to the next C state, if it has not been disabled, and it will demote, if the current C state was disabled. Note that the patch does not make the setting of the sysfs variable "disable" coherent, i.e. if one is disabling a light state, then all deeper states are disabled as well, but the "disable" variable does not reflect it. Likewise, if one enables a deep state but a lighter state still is disabled, then this has no effect. A related section has been added to the documentation. Signed-off-by: Carsten Emde Signed-off-by: Rafael J. Wysocki --- Documentation/cpuidle/sysfs.txt | 10 +++++++++- drivers/cpuidle/governors/ladder.c | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt index 9d28a3406e7..b6f44f490ed 100644 --- a/Documentation/cpuidle/sysfs.txt +++ b/Documentation/cpuidle/sysfs.txt @@ -76,9 +76,17 @@ total 0 * desc : Small description about the idle state (string) -* disable : Option to disable this idle state (bool) +* disable : Option to disable this idle state (bool) -> see note below * latency : Latency to exit out of this idle state (in microseconds) * name : Name of the idle state (string) * power : Power consumed while in this idle state (in milliwatts) * time : Total time spent in this idle state (in microseconds) * usage : Number of times this state was entered (count) + +Note: +The behavior and the effect of the disable variable depends on the +implementation of a particular governor. In the ladder governor, for +example, it is not coherent, i.e. if one is disabling a light state, +then all deeper states are disabled as well, but the disable variable +does not reflect it. Likewise, if one enables a deep state but a lighter +state still is disabled, then this has no effect. diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index b6a09ea859b..2aef26c520b 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -88,6 +88,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, /* consider promotion */ if (last_idx < drv->state_count - 1 && + !dev->states_usage[last_idx + 1].disable && last_residency > last_state->threshold.promotion_time && drv->states[last_idx + 1].exit_latency <= latency_req) { last_state->stats.promotion_count++; @@ -100,7 +101,8 @@ static int ladder_select_state(struct cpuidle_driver *drv, /* consider demotion */ if (last_idx > CPUIDLE_DRIVER_STATE_START && - drv->states[last_idx].exit_latency > latency_req) { + (dev->states_usage[last_idx].disable || + drv->states[last_idx].exit_latency > latency_req)) { int i; for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) { -- cgit v1.2.3-70-g09d2 From e6027b467cd5b117b9ae2957c197a7cda9f5b932 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sat, 28 Jul 2012 12:07:34 +0200 Subject: mmc: pxa-mci: add DT bindings Signed-off-by: Daniel Mack Signed-off-by: Chris Ball --- Documentation/devicetree/bindings/mmc/pxa-mmc.txt | 25 +++++++++++ drivers/mmc/host/pxamci.c | 52 +++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/pxa-mmc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/pxa-mmc.txt b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt new file mode 100644 index 00000000000..b7025de7dce --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt @@ -0,0 +1,25 @@ +* PXA MMC drivers + +Driver bindings for the PXA MCI (MMC/SDIO) interfaces + +Required properties: +- compatible: Should be "marvell,pxa-mmc". +- vmmc-supply: A regulator for VMMC + +Optional properties: +- marvell,detect-delay-ms: sets the detection delay timeout in ms. +- marvell,gpio-power: GPIO spec for the card power enable pin + +This file documents differences between the core properties in mmc.txt +and the properties used by the pxa-mmc driver. + +Examples: + +mmc0: mmc@41100000 { + compatible = "marvell,pxa-mmc"; + reg = <0x41100000 0x1000>; + interrupts = <23>; + cd-gpios = <&gpio 23 0>; + wp-gpios = <&gpio 24 0>; +}; + diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index cb2dc0e75ba..11df8006d47 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include @@ -573,6 +576,50 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid) return IRQ_HANDLED; } +#ifdef CONFIG_OF +static const struct of_device_id pxa_mmc_dt_ids[] = { + { .compatible = "marvell,pxa-mmc" }, + { } +}; + +MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); + +static int __devinit pxamci_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct pxamci_platform_data *pdata; + u32 tmp; + + if (!np) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->gpio_card_detect = + of_get_named_gpio(np, "cd-gpios", 0); + pdata->gpio_card_ro = + of_get_named_gpio(np, "wp-gpios", 0); + + /* pxa-mmc specific */ + pdata->gpio_power = + of_get_named_gpio(np, "pxa-mmc,gpio-power", 0); + + if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0) + pdata->detect_delay_ms = tmp; + + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static int __devinit pxamci_of_init(struct platform_device *pdev) +{ + return 0; +} +#endif + static int pxamci_probe(struct platform_device *pdev) { struct mmc_host *mmc; @@ -580,6 +627,10 @@ static int pxamci_probe(struct platform_device *pdev) struct resource *r, *dmarx, *dmatx; int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; + ret = pxamci_of_init(pdev); + if (ret) + return ret; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!r || irq < 0) @@ -866,6 +917,7 @@ static struct platform_driver pxamci_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pxa_mmc_dt_ids), #ifdef CONFIG_PM .pm = &pxamci_pm_ops, #endif -- cgit v1.2.3-70-g09d2 From e919fd200033e80b26f152d22c00a8fae7f8d548 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 24 Jul 2012 15:30:03 +0200 Subject: mmc: atmel-mci: add device tree support Signed-off-by: Ludovic Desroches Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Chris Ball --- .../devicetree/bindings/mmc/atmel-hsmci.txt | 68 +++++++++++++++++ drivers/mmc/host/atmel-mci.c | 85 +++++++++++++++++++++- 2 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/atmel-hsmci.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt new file mode 100644 index 00000000000..0a85c70cd30 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt @@ -0,0 +1,68 @@ +* Atmel High Speed MultiMedia Card Interface + +This controller on atmel products provides an interface for MMC, SD and SDIO +types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the atmel-mci driver. + +1) MCI node + +Required properties: +- compatible: should be "atmel,hsmci" +- #address-cells: should be one. The cell is the slot id. +- #size-cells: should be zero. +- at least one slot node + +The node contains child nodes for each slot that the platform uses + +Example MCI node: + +mmc0: mmc@f0008000 { + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4>; + #address-cells = <1>; + #size-cells = <0>; + + [ child node definitions...] +}; + +2) slot nodes + +Required properties: +- reg: should contain the slot id. +- bus-width: number of data lines connected to the controller + +Optional properties: +- cd-gpios: specify GPIOs for card detection +- cd-inverted: invert the value of external card detect gpio line +- wp-gpios: specify GPIOs for write protection + +Example slot node: + +slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 0> + cd-inverted; +}; + +Example full MCI node: +mmc0: mmc@f0008000 { + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4>; + #address-cells = <1>; + #size-cells = <0>; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 0> + cd-inverted; + }; + slot@1 { + reg = <1>; + bus-width = <4>; + }; +}; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index a53c7c478e0..8c72828239b 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -500,6 +503,70 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); } +#if defined(CONFIG_OF) +static const struct of_device_id atmci_dt_ids[] = { + { .compatible = "atmel,hsmci" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmci_dt_ids); + +static struct mci_platform_data __devinit* +atmci_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *cnp; + struct mci_platform_data *pdata; + u32 slot_id; + + if (!np) { + dev_err(&pdev->dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + for_each_child_of_node(np, cnp) { + if (of_property_read_u32(cnp, "reg", &slot_id)) { + dev_warn(&pdev->dev, "reg property is missing for %s\n", + cnp->full_name); + continue; + } + + if (slot_id >= ATMCI_MAX_NR_SLOTS) { + dev_warn(&pdev->dev, "can't have more than %d slots\n", + ATMCI_MAX_NR_SLOTS); + break; + } + + if (of_property_read_u32(cnp, "bus-width", + &pdata->slot[slot_id].bus_width)) + pdata->slot[slot_id].bus_width = 1; + + pdata->slot[slot_id].detect_pin = + of_get_named_gpio(cnp, "cd-gpios", 0); + + pdata->slot[slot_id].detect_is_active_high = + of_property_read_bool(cnp, "cd-inverted"); + + pdata->slot[slot_id].wp_pin = + of_get_named_gpio(cnp, "wp-gpios", 0); + } + + return pdata; +} +#else /* CONFIG_OF */ +static inline struct mci_platform_data* +atmci_of_init(struct platform_device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static inline unsigned int atmci_get_version(struct atmel_mci *host) { return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; @@ -2046,6 +2113,13 @@ static int __init atmci_init_slot(struct atmel_mci *host, slot->sdc_reg = sdc_reg; slot->sdio_irq = sdio_irq; + dev_dbg(&mmc->class_dev, + "slot[%u]: bus_width=%u, detect_pin=%d, " + "detect_is_active_high=%s, wp_pin=%d\n", + id, slot_data->bus_width, slot_data->detect_pin, + slot_data->detect_is_active_high ? "true" : "false", + slot_data->wp_pin); + mmc->ops = &atmci_ops; mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); mmc->f_max = host->bus_hz / 2; @@ -2268,8 +2342,14 @@ static int __init atmci_probe(struct platform_device *pdev) if (!regs) return -ENXIO; pdata = pdev->dev.platform_data; - if (!pdata) - return -ENXIO; + if (!pdata) { + pdata = atmci_of_init(pdev); + if (IS_ERR(pdata)) { + dev_err(&pdev->dev, "platform data not available\n"); + return PTR_ERR(pdata); + } + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -2487,6 +2567,7 @@ static struct platform_driver atmci_driver = { .driver = { .name = "atmel_mci", .pm = ATMCI_PM_OPS, + .of_match_table = of_match_ptr(atmci_dt_ids), }, }; -- cgit v1.2.3-70-g09d2 From 4ee7ed0de9929f6f194d7a0ae867371ea47866fe Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 31 Jul 2012 10:12:59 +0200 Subject: mmc: sdhci-dove: DT support for sdhci-dove This patch adds device tree support and binding documentation for sdhci-dove. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Chris Ball --- Documentation/devicetree/bindings/mmc/sdhci-dove.txt | 14 ++++++++++++++ drivers/mmc/host/sdhci-dove.c | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-dove.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/sdhci-dove.txt b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt new file mode 100644 index 00000000000..ae9aab9abcd --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt @@ -0,0 +1,14 @@ +* Marvell sdhci-dove controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers. + +- compatible: Should be "marvell,dove-sdhci". + +Example: + +sdio0: sdio@92000 { + compatible = "marvell,dove-sdhci"; + reg = <0x92000 0x100>; + interrupts = <35>; +}; diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index a6e53a1ebb0..90140eb03e3 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -126,11 +127,18 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev) return sdhci_pltfm_unregister(pdev); } +static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = { + { .compatible = "marvell,dove-sdhci", }, + {} +}; +MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table); + static struct platform_driver sdhci_dove_driver = { .driver = { .name = "sdhci-dove", .owner = THIS_MODULE, .pm = SDHCI_PLTFM_PMOPS, + .of_match_table = of_match_ptr(sdhci_dove_of_match_table), }, .probe = sdhci_dove_probe, .remove = __devexit_p(sdhci_dove_remove), -- cgit v1.2.3-70-g09d2 From abe1e05da365350ac282ba5f6831aae13d97074e Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 22 Aug 2012 13:21:01 -0400 Subject: mmc: dt: Add card-detection properties to core binding. Signed-off-by: Chris Ball --- Documentation/devicetree/bindings/mmc/mmc.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index 8a6811f4a02..8e2e0ba2f48 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -9,12 +9,17 @@ Interpreted by the OF core: Required properties: - bus-width: Number of data lines, can be <1>, <4>, or <8> +Card detection: +If no property below is supplied, standard SDHCI card detect is used. +Only one of the properties in this section should be supplied: + - broken-cd: There is no card detection available; polling must be used. + - cd-gpios: Specify GPIOs for card detection, see gpio binding + - non-removable: non-removable slot (like eMMC); assume always present. + Optional properties: -- cd-gpios: Specify GPIOs for card detection, see gpio binding - wp-gpios: Specify GPIOs for write protection, see gpio binding - cd-inverted: when present, polarity on the cd gpio line is inverted - wp-inverted: when present, polarity on the wp gpio line is inverted -- non-removable: non-removable slot (like eMMC) - max-frequency: maximum operating clock frequency Example: -- cgit v1.2.3-70-g09d2 From 6e2187bf59a1452ed26a2f3baf6e4900c62fcd6c Mon Sep 17 00:00:00 2001 From: Ninja Tekkaman Date: Tue, 28 Aug 2012 22:03:13 +0800 Subject: Chinese translation of Documentation/gpio.txt This is a Chinese translated version of Documentation/gpio.txt Signed-off-by: Fu Wei Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman --- Documentation/zh_CN/gpio.txt | 662 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 662 insertions(+) create mode 100644 Documentation/zh_CN/gpio.txt (limited to 'Documentation') diff --git a/Documentation/zh_CN/gpio.txt b/Documentation/zh_CN/gpio.txt new file mode 100644 index 00000000000..04843872b50 --- /dev/null +++ b/Documentation/zh_CN/gpio.txt @@ -0,0 +1,662 @@ +Chinese translated version of Documentation/gpio.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Grant Likely + Linus Walleij +Chinese maintainer: Fu Wei +--------------------------------------------------------------------- +Documentation/gpio.txt 的中文翻译 + +如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 +交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 +译存在问题,请联系中文版维护者。 +英文版维护者: Grant Likely + Linus Walleij +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei + + +以下为正文 +--------------------------------------------------------------------- +GPIO 接口 + +本文档提供了一个在Linux下访问GPIO的公约概述。 + +这些函数以 gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的 +__gpio_* 前缀。 + + +什么是GPIO? +========== +"通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可 +由多种芯片提供,且对于从事嵌入式和定制硬件的 Linux 开发者来说是 +比较熟悉。每个GPIO 都代表一个连接到特定引脚或球栅阵列(BGA)封装中 +“球珠”的一个位。电路板原理图显示了 GPIO 与外部硬件的连接关系。 +驱动可以编写成通用代码,以使板级启动代码可传递引脚配置数据给驱动。 + +片上系统 (SOC) 处理器对 GPIO 有很大的依赖。在某些情况下,每个 +非专用引脚都可配置为 GPIO,且大多数芯片都最少有一些 GPIO。 +可编程逻辑器件(类似 FPGA) 可以方便地提供 GPIO。像电源管理和 +音频编解码器这样的多功能芯片经常留有一些这样的引脚来帮助那些引脚 +匮乏的 SOC。同时还有通过 I2C 或 SPI 串行总线连接的“GPIO扩展器” +芯片。大多数 PC 的南桥有一些拥有 GPIO 能力的引脚 (只有BIOS +固件才知道如何使用他们)。 + +GPIO 的实际功能因系统而异。通常用法有: + + - 输出值可写 (高电平=1,低电平=0)。一些芯片也有如何驱动这些值的选项, + 例如只允许输出一个值、支持“线与”及其他取值类似的模式(值得注意的是 + “开漏”信号) + + - 输入值可读(1、0)。一些芯片支持引脚在配置为“输出”时回读,这对于类似 + “线与”的情况(以支持双向信号)是非常有用的。GPIO 控制器可能有输入 + 去毛刺/消抖逻辑,这有时需要软件控制。 + + - 输入通常可作为 IRQ 信号,一般是沿触发,但有时是电平触发。这样的 IRQ + 可能配置为系统唤醒事件,以将系统从低功耗状态下唤醒。 + + - 通常一个 GPIO 根据不同产品电路板的需求,可以配置为输入或输出,也有仅 + 支持单向的。 + + - 大部分 GPIO 可以在持有自旋锁时访问,但是通常由串行总线扩展的 GPIO + 不允许持有自旋锁。但某些系统也支持这种类型。 + +对于给定的电路板,每个 GPIO 都用于某个特定的目的,如监控 MMC/SD 卡的 +插入/移除、检测卡的写保护状态、驱动 LED、配置收发器、模拟串行总线、 +复位硬件看门狗、感知开关状态等等。 + + +GPIO 公约 +========= +注意,这个叫做“公约”,因为这不是强制性的,不遵循这个公约是无伤大雅的, +因为此时可移植性并不重要。GPIO 常用于板级特定的电路逻辑,甚至可能 +随着电路板的版本而改变,且不可能在不同走线的电路板上使用。仅有在少数 +功能上才具有可移植性,其他功能是平台特定。这也是由于“胶合”的逻辑造成的。 + +此外,这不需要任何的执行框架,只是一个接口。某个平台可能通过一个简单地 +访问芯片寄存器的内联函数来实现它,其他平台可能通过委托一系列不同的GPIO +控制器的抽象函数来实现它。(有一些可选的代码能支持这种策略的实现,本文档 +后面会介绍,但作为 GPIO 接口的客户端驱动程序必须与它的实现无关。) + +也就是说,如果在他们的平台上支持这个公约,驱动应尽可能的使用它。平台 +必须在 Kconfig 中声明对 GENERIC_GPIO的支持 (布尔型 true),并提供 +一个 文件。那些调用标准 GPIO 函数的驱动应该在 Kconfig +入口中声明依赖GENERIC_GPIO。当驱动包含文件: + + #include + +则 GPIO 函数是可用,无论是“真实代码”还是经优化过的语句。如果你遵守 +这个公约,当你的代码完成后,对其他的开发者来说会更容易看懂和维护。 + +注意,这些操作包含所用平台的 I/O 屏障代码,驱动无须显式地调用他们。 + + +标识 GPIO +--------- +GPIO 是通过无符号整型来标识的,范围是 0 到 MAX_INT。保留“负”数 +用于其他目的,例如标识信号“在这个板子上不可用”或指示错误。未接触底层 +硬件的代码会忽略这些整数。 + +平台会定义这些整数的用法,且通常使用 #define 来定义 GPIO,这样 +板级特定的启动代码可以直接关联相应的原理图。相对来说,驱动应该仅使用 +启动代码传递过来的 GPIO 编号,使用 platform_data 保存板级特定 +引脚配置数据 (同时还有其他须要的板级特定数据),避免可能出现的问题。 + +例如一个平台使用编号 32-159 来标识 GPIO,而在另一个平台使用编号0-63 +标识一组 GPIO 控制器,64-79标识另一类 GPIO 控制器,且在一个含有 +FPGA 的特定板子上使用 80-95。编号不一定要连续,那些平台中,也可以 +使用编号2000-2063来标识一个 I2C 接口的 GPIO 扩展器中的 GPIO。 + +如果你要初始化一个带有无效 GPIO 编号的结构体,可以使用一些负编码 +(如"-EINVAL"),那将使其永远不会是有效。来测试这样一个结构体中的编号 +是否关联一个 GPIO,你可使用以下断言: + + int gpio_is_valid(int number); + +如果编号不存在,则请求和释放 GPIO 的函数将拒绝执行相关操作(见下文)。 +其他编号也可能被拒绝,比如一个编号可能存在,但暂时在给定的电路上不可用。 + +一个平台是否支持多个 GPIO 控制器为平台特定的实现问题,就像是否可以 +在 GPIO 编号空间中有“空洞”和是否可以在运行时添加新的控制器一样。 +这些问题会影响其他事情,包括相邻的 GPIO 编号是否存在等。 + +使用 GPIO +--------- +对于一个 GPIO,系统应该做的第一件事情就是通过 gpio_request() +函数分配他,见下文。 + +而接下来要做的是标识它的方向,这通常是在板级启动代码中为 GPIO 设置 +一个 platform_device 时做的。 + + /* 设置为输入或输出, 返回 0 或负的错误代码 */ + int gpio_direction_input(unsigned gpio); + int gpio_direction_output(unsigned gpio, int value); + +返回值为零代表成功,否则返回一个负的错误代码。这个返回值需要检查,因为 +get/set(获取/设置)函数调用没法返回错误,且有可能是配置错误。通常, +你应该在进程上下文中调用这些函数。然而,对于自旋锁安全的 GPIO,在板子 +启动的早期、进程启动前使用他们也是可以的。 + +对于作为输出的 GPIO,为其提供初始输出值,对于避免在系统启动期间出现 +信号毛刺是很有帮助的。 + +为了与传统的 GPIO 接口兼容, 在设置一个 GPIO 方向时,如果它还未被申请, +则隐含了申请那个 GPIO 的操作(见下文)。这种兼容性正在从可选的 gpiolib +框架中移除。 + +如果这个 GPIO 编码不存在,或者特定的 GPIO 不能用于那种模式,则方向 +设置可能失败。依赖启动固件来正确地设置方向通常是一个坏主意,因为它可能 +除了启动Linux,并没有做更多的验证工作。(同理, 板子的启动代码可能需要 +将这个复用的引脚设置为 GPIO,并正确地配置上拉/下拉电阻。) + + +访问自旋锁安全的 GPIO +------------------- +大多数 GPIO 控制器可以通过内存读/写指令来访问。这些指令不会休眠,可以 +安全地在硬(非线程)中断例程和类似的上下文中完成。 + +对于那些用 gpio_cansleep()测试总是返回失败的 GPIO(见下文),使用 +以下的函数访问: + + /* GPIO 输入:返回零或非零 */ + int gpio_get_value(unsigned gpio); + + /* GPIO 输入 */ + void gpio_set_value(unsigned gpio, int value); + +返回值是布尔值,零表示低电平,非零表示高电平。当读取一个输出引脚的值时, +返回值应该是引脚上的值。这个值不总是和输出值相符,因为存在开漏输出信号和 +输出潜伏期的问题。 + +以上的 get/set 函数不会对早期已经通过 gpio_direction_*()报告“无效的 +GPIO”返回错误。此外,还需要注意的是并不是所有平台都可以从输出引脚中读取 +数据的,那些引脚也不总是返回零。且对那些无法安全访问(可能会休眠)的 GPIO +(见下文)使用这些函数是错误的。 + +在 GPIO 编号(还有输出、值)为常数的情况下,鼓励通过平台特定的实现来优化 +这两个函数来访问 GPIO 值。这种情况(读写一个硬件寄存器)下只需要几条指令 +是很正常的,且无须自旋锁。这种优化函数比起那些在子程序上花费许多指令的 +函数可以使得模拟接口(译者注:例如 GPIO 模拟 I2C、1-wire 或 SPI)的 +应用(在空间和时间上都)更具效率。 + + +访问可能休眠的 GPIO +----------------- +某些 GPIO 控制器必须通过基于总线(如 I2C 或 SPI)的消息访问。读或写这些 +GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其反馈。期间需要 +休眠,这不能在 IRQ 例程(中断上下文)中执行。 + +支持此类 GPIO 的平台通过以下函数返回非零值来区分出这种 GPIO。(此函数需要 +一个之前通过 gpio_request 分配到的有效 GPIO 编号): + + int gpio_cansleep(unsigned gpio); + +为了访问这种 GPIO,内核定义了一套不同的函数: + + /* GPIO 输入:返回零或非零 ,可能会休眠 */ + int gpio_get_value_cansleep(unsigned gpio); + + /* GPIO 输入,可能会休眠 */ + void gpio_set_value_cansleep(unsigned gpio, int value); + + +访问这样的 GPIO 需要一个允许休眠的上下文,例如线程 IRQ 处理例程,并用以上的 +访问函数替换那些没有 cansleep()后缀的自旋锁安全访问函数。 + +除了这些访问函数可能休眠,且它们操作的 GPIO 不能在硬件 IRQ 处理例程中访问的 +事实,这些处理例程实际上和自旋锁安全的函数是一样的。 + +** 除此之外 ** 调用设置和配置此类 GPIO 的函数也必须在允许休眠的上下文中, +因为它们可能也需要访问 GPIO 控制器芯片: (这些设置函数通常在板级启动代码或者 +驱动探测/断开代码中,所以这是一个容易满足的约束条件。) + + gpio_direction_input() + gpio_direction_output() + gpio_request() + +## gpio_request_one() +## gpio_request_array() +## gpio_free_array() + + gpio_free() + gpio_set_debounce() + + + +声明和释放 GPIO +---------------------------- +为了有助于捕获系统配置错误,定义了两个函数。 + + /* 申请 GPIO, 返回 0 或负的错误代码. + * 非空标签可能有助于诊断. + */ + int gpio_request(unsigned gpio, const char *label); + + /* 释放之前声明的 GPIO */ + void gpio_free(unsigned gpio); + +将无效的 GPIO 编码传递给 gpio_request()会导致失败,申请一个已使用这个 +函数声明过的 GPIO 也会失败。gpio_request()的返回值必须检查。你应该在 +进程上下文中调用这些函数。然而,对于自旋锁安全的 GPIO,在板子启动的早期、 +进入进程之前是可以申请的。 + +这个函数完成两个基本的目标。一是标识那些实际上已作为 GPIO 使用的信号线, +这样便于更好地诊断;系统可能需要服务几百个潜在的 GPIO,但是对于任何一个 +给定的电路板通常只有一些被使用。另一个目的是捕获冲突,查明错误:如两个或 +更多驱动错误地认为他们已经独占了某个信号线,或是错误地认为移除一个管理着 +某个已激活信号的驱动是安全的。也就是说,申请 GPIO 的作用类似一种锁机制。 + +某些平台可能也使用 GPIO 作为电源管理激活信号(例如通过关闭未使用芯片区和 +简单地关闭未使用时钟)。 + +对于 GPIO 使用 pinctrl 子系统已知的引脚,子系统应该被告知其使用情况; +一个 gpiolib 驱动的 .request()操作应调用 pinctrl_request_gpio(), +而 gpiolib 驱动的 .free()操作应调用 pinctrl_free_gpio()。pinctrl +子系统允许 pinctrl_request_gpio()在某个引脚或引脚组以复用形式“属于” +一个设备时都成功返回。 + +任何须将 GPIO 信号导向适当引脚的引脚复用硬件的编程应该发生在 GPIO +驱动的 .direction_input()或 .direction_output()函数中,以及 +任何输出 GPIO 值的设置之后。这样可使从引脚特殊功能到 GPIO 的转换 +不会在引脚产生毛刺波形。有时当用一个 GPIO 实现其信号驱动一个非 GPIO +硬件模块的解决方案时,就需要这种机制。 + +某些平台允许部分或所有 GPIO 信号使用不同的引脚。类似的,GPIO 或引脚的 +其他方面也需要配置,如上拉/下拉。平台软件应该在对这些 GPIO 调用 +gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映射表, +使得 GPIO 的用户无须关注这些细节。 + +还有一个值得注意的是在释放 GPIO 前,你必须停止使用它。 + + +注意:申请一个 GPIO 并没有以任何方式配置它,只不过标识那个 GPIO 处于使用 +状态。必须有另外的代码来处理引脚配置(如控制 GPIO 使用的引脚、上拉/下拉)。 +考虑到大多数情况下声明 GPIO 之后就会立即配置它们,所以定义了以下三个辅助函数: + + /* 申请一个 GPIO 信号, 同时通过特定的'flags'初始化配置, + * 其他和 gpio_request()的参数和返回值相同 + * + */ + int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); + + /* 在单个函数中申请多个 GPIO + */ + int gpio_request_array(struct gpio *array, size_t num); + + /* 在单个函数中释放多个 GPIO + */ + void gpio_free_array(struct gpio *array, size_t num); + +这里 'flags' 当前定义可指定以下属性: + + * GPIOF_DIR_IN - 配置方向为输入 + * GPIOF_DIR_OUT - 配置方向为输出 + + * GPIOF_INIT_LOW - 在作为输出时,初始值为低电平 + * GPIOF_INIT_HIGH - 在作为输出时,初始值为高电平 + * GPIOF_OPEN_DRAIN - gpio引脚为开漏信号 + * GPIOF_OPEN_SOURCE - gpio引脚为源极开路信号 + + * GPIOF_EXPORT_DIR_FIXED - 将 gpio 导出到 sysfs,并保持方向 + * GPIOF_EXPORT_DIR_CHANGEABLE - 同样是导出, 但允许改变方向 + +因为 GPIOF_INIT_* 仅有在配置为输出的时候才存在,所以有效的组合为: + + * GPIOF_IN - 配置为输入 + * GPIOF_OUT_INIT_LOW - 配置为输出,并初始化为低电平 + * GPIOF_OUT_INIT_HIGH - 配置为输出,并初始化为高电平 + +当设置 flag 为 GPIOF_OPEN_DRAIN 时,则假设引脚是开漏信号。这样的引脚 +将不会在输出模式下置1。这样的引脚需要连接上拉电阻。通过使能这个标志,gpio库 +将会在被要求输出模式下置1时将引脚变为输入状态来使引脚置高。引脚在输出模式下 +通过置0使其输出低电平。 + +当设置 flag 为 GPIOF_OPEN_SOURCE 时,则假设引脚为源极开路信号。这样的引脚 +将不会在输出模式下置0。这样的引脚需要连接下拉电阻。通过使能这个标志,gpio库 +将会在被要求输出模式下置0时将引脚变为输入状态来使引脚置低。引脚在输出模式下 +通过置1使其输出高电平。 + +将来这些标志可能扩展到支持更多的属性。 + +更进一步,为了更简单地声明/释放多个 GPIO,'struct gpio'被引进来封装所有 +这三个领域: + + struct gpio { + unsigned gpio; + unsigned long flags; + const char *label; + }; + +一个典型的用例: + + static struct gpio leds_gpios[] = { + { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默认开启 */ + { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* 默认关闭 */ + { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* 默认关闭 */ + { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* 默认关闭 */ + { ... }, + }; + + err = gpio_request_one(31, GPIOF_IN, "Reset Button"); + if (err) + ... + + err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios)); + if (err) + ... + + gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios)); + + +GPIO 映射到 IRQ +-------------------- +GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上不同的命名空间 +(GPIO 0 不一定使用 IRQ 0)。你可以通过以下函数在它们之间实现映射: + + /* 映射 GPIO 编号到 IRQ 编号 */ + int gpio_to_irq(unsigned gpio); + + /* 映射 IRQ 编号到 GPIO 编号 (尽量避免使用) */ + int irq_to_gpio(unsigned irq); + +它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。 +(例如,某些 GPIO 无法做为 IRQ 使用。)以下的编号错误是未经检测的:使用一个 +未通过 gpio_direction_input()配置为输入的 GPIO 编号,或者使用一个 +并非来源于gpio_to_irq()的 IRQ 编号。 + +这两个映射函数可能会在信号编号的加减计算过程上花些时间。它们不可休眠。 + +gpio_to_irq()返回的非错误值可以传递给 request_irq()或者 free_irq()。 +它们通常通过板级特定的初始化代码存放到平台设备的 IRQ 资源中。注意:IRQ +触发选项是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力 +也是如此。 + +irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所使用, +比如在 IRQ 是沿触发时初始化或更新驱动状态。注意某些平台不支持反映射,所以 +你应该尽量避免使用它。 + +它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。 +(例如,某些 GPIO 无法做为 IRQ 使用。)以下的编号错误是未经检测的: +使用一个未通过 gpio_direction_input()配置为输入的 GPIO 编号, +或者使用一个并非来源于gpio_to_irq()的 IRQ 编号。 + + +模拟开漏信号 +---------------------------- +有时在只有低电平信号作为实际驱动结果(译者注:多个输出连接于一点,逻辑电平 +结果为所有输出的逻辑与)的时候,共享的信号线需要使用“开漏”信号。(该术语 +适用于 CMOS 管;而 TTL 用“集电极开路”。)一个上拉电阻使信号为高电平。这 +有时被称为“线与”。实际上,从负逻辑(低电平为真)的角度来看,这是一个“线或”。 + +一个开漏信号的常见例子是共享的低电平使能 IRQ 信号线。此外,有时双向数据总线 +信号也使用漏极开路信号。 + +某些 GPIO 控制器直接支持开漏输出,还有许多不支持。当你需要开漏信号,但 +硬件又不直接支持的时候,一个常用的方法是用任何即可作输入也可作输出的 GPIO +引脚来模拟: + + LOW: gpio_direction_output(gpio, 0) ... 这代码驱动信号并覆盖 + 上拉配置。 + + HIGH: gpio_direction_input(gpio) ... 这代码关闭输出,所以上拉电阻 + (或其他的一些器件)控制了信号。 + +如果你将信号线“驱动”为高电平,但是 gpio_get_value(gpio)报告了一个 +低电平(在适当的上升时间后),你就可以知道是其他的一些组件将共享信号线拉低了。 +这不一定是错误的。一个常见的例子就是 I2C 时钟的延长:一个需要较慢时钟的 +从设备延迟 SCK 的上升沿,而 I2C 主设备相应地调整其信号传输速率。 + + +这些公约忽略了什么? +================ +这些公约忽略的最大一件事就是引脚复用,因为这属于高度芯片特定的属性且 +没有可移植性。某个平台可能不需要明确的复用信息;有的对于任意给定的引脚 +可能只有两个功能选项;有的可能每个引脚有八个功能选项;有的可能可以将 +几个引脚中的任何一个作为给定的 GPIO。(是的,这些例子都来自于当前运行 +Linux 的系统。) + +在某些系统中,与引脚复用相关的是配置和使能集成的上、下拉模式。并不是所有 +平台都支持这种模式,或者不会以相同的方式来支持这种模式;且任何给定的电路板 +可能使用外置的上拉(或下拉)电阻,这时芯片上的就不应该使用。(当一个电路需要 +5kOhm 的拉动电阻,芯片上的 100 kOhm 电阻就不能做到。)同样的,驱动能力 +(2 mA vs 20 mA)和电压(1.8V vs 3.3V)是平台特定问题,就像模型一样在 +可配置引脚和 GPIO 之间(没)有一一对应的关系。 + +还有其他一些系统特定的机制没有在这里指出,例如上述的输入去毛刺和线与输出 +选项。硬件可能支持批量读或写 GPIO,但是那一般是配置相关的:对于处于同一 +块区(bank)的GPIO。(GPIO 通常以 16 或 32 个组成一个区块,一个给定的 +片上系统一般有几个这样的区块。)某些系统可以通过输出 GPIO 触发 IRQ, +或者从并非以 GPIO 管理的引脚取值。这些机制的相关代码没有必要具有可移植性。 + +当前,动态定义 GPIO 并不是标准的,例如作为配置一个带有某些 GPIO 扩展器的 +附加电路板的副作用。 + +GPIO 实现者的框架 (可选) +===================== +前面提到了,有一个可选的实现框架,让平台使用相同的编程接口,更加简单地支持 +不同种类的 GPIO 控制器。这个框架称为"gpiolib"。 + +作为一个辅助调试功能,如果 debugfs 可用,就会有一个 /sys/kernel/debug/gpio +文件。通过这个框架,它可以列出所有注册的控制器,以及当前正在使用中的 GPIO +的状态。 + + +控制器驱动: gpio_chip +------------------- +在框架中每个 GPIO 控制器都包装为一个 "struct gpio_chip",他包含了 +该类型的每个控制器的常用信息: + + - 设置 GPIO 方向的方法 + - 用于访问 GPIO 值的方法 + - 告知调用其方法是否可能休眠的标志 + - 可选的 debugfs 信息导出方法 (显示类似上拉配置一样的额外状态) + - 诊断标签 + +也包含了来自 device.platform_data 的每个实例的数据:它第一个 GPIO 的 +编号和它可用的 GPIO 的数量。 + +实现 gpio_chip 的代码应支持多控制器实例,这可能使用驱动模型。那些代码要 +配置每个 gpio_chip,并发起gpiochip_add()。卸载一个 GPIO 控制器很少见, +但在必要的时候可以使用 gpiochip_remove()。 + +大部分 gpio_chip 是一个实例特定结构体的一部分,而并不将 GPIO 接口单独 +暴露出来,比如编址、电源管理等。类似编解码器这样的芯片会有复杂的非 GPIO +状态。 + +任何一个 debugfs 信息导出方法通常应该忽略还未申请作为 GPIO 的信号线。 +他们可以使用 gpiochip_is_requested()测试,当这个 GPIO 已经申请过了 +就返回相关的标签,否则返回 NULL。 + + +平台支持 +------- +为了支持这个框架,一个平台的 Kconfig 文件将会 "select"(选择) +ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并让它的 + 包含 ,同时定义三个方法: +gpio_get_value()、gpio_set_value()和 gpio_cansleep()。 + +它也应提供一个 ARCH_NR_GPIOS 的定义值,这样可以更好地反映该平台 GPIO +的实际数量,节省静态表的空间。(这个定义值应该包含片上系统内建 GPIO 和 +GPIO 扩展器中的数据。) + +ARCH_REQUIRE_GPIOLIB 意味着 gpiolib 核心在这个构架中将总是编译进内核。 + +ARCH_WANT_OPTIONAL_GPIOLIB 意味着 gpiolib 核心默认关闭,且用户可以 +使能它,并将其编译进内核(可选)。 + +如果这些选项都没被选择,该平台就不通过 GPIO-lib 支持 GPIO,且代码不可以 +被用户使能。 + +以下这些方法的实现可以直接使用框架代码,并总是通过 gpio_chip 调度: + + #define gpio_get_value __gpio_get_value + #define gpio_set_value __gpio_set_value + #define gpio_cansleep __gpio_cansleep + +这些定义可以用更理想的实现方法替代,那就是使用经过逻辑优化的内联函数来访问 +基于特定片上系统的 GPIO。例如,若引用 GPIO 的(寄存器地址)是常量“12”, +读取或设置它可能只需少则两或三个指令,且不会休眠。当这样的优化无法实现时, +那些函数必须使用框架提供的代码,那就至少要几十条指令才可以实现。对于用 GPIO +模拟的 I/O 接口, 如此精简指令是很有意义的。 + +对于片上系统,平台特定代码为片上 GPIO 每个区(bank)定义并注册 gpio_chip +实例。那些 GPIO 应该根据芯片厂商的文档进行编码/标签,并直接和电路板原理图 +对应。他们应该开始于零并终止于平台特定的限制。这些 GPIO(代码)通常从 +arch_initcall()或者更早的地方集成进平台初始化代码,使这些 GPIO 总是可用, +且他们通常可以作为 IRQ 使用。 + +板级支持 +------- +对于外部 GPIO 控制器(例如 I2C 或 SPI 扩展器、专用芯片、多功能器件、FPGA +或 CPLD),大多数常用板级特定代码都可以注册控制器设备,并保证他们的驱动知道 +gpiochip_add()所使用的 GPIO 编号。他们的起始编号通常跟在平台特定的 GPIO +编号之后。 + +例如板级启动代码应该创建结构体指明芯片公开的 GPIO 范围,并使用 platform_data +将其传递给每个 GPIO 扩展器芯片。然后芯片驱动中的 probe()例程可以将这个 +数据传递给 gpiochip_add()。 + +初始化顺序很重要。例如,如果一个设备依赖基于 I2C 的(扩展)GPIO,那么它的 +probe()例程就应该在那个 GPIO 有效以后才可以被调用。这意味着设备应该在 +GPIO 可以工作之后才可被注册。解决这类依赖的的一种方法是让这种 gpio_chip +控制器向板级特定代码提供 setup()和 teardown()回调函数。一旦所有必须的 +资源可用之后,这些板级特定的回调函数将会注册设备,并可以在这些 GPIO 控制器 +设备变成无效时移除它们。 + + +用户空间的 Sysfs 接口(可选) +======================== +使用“gpiolib”实现框架的平台可以选择配置一个 GPIO 的 sysfs 用户接口。 +这不同于 debugfs 接口,因为它提供的是对 GPIO方向和值的控制,而不只显示 +一个GPIO 的状态摘要。此外,它可以出现在没有调试支持的产品级系统中。 + +例如,通过适当的系统硬件文档,用户空间可以知道 GIOP #23 控制 Flash +存储器的写保护(用于保护其中 Bootloader 分区)。产品的系统升级可能需要 +临时解除这个保护:首先导入一个 GPIO,改变其输出状态,然后在重新使能写保护 +前升级代码。通常情况下,GPIO #23 是不会被触及的,并且内核也不需要知道他。 + +根据适当的硬件文档,某些系统的用户空间 GPIO 可以用于确定系统配置数据, +这些数据是标准内核不知道的。在某些任务中,简单的用户空间 GPIO 驱动可能是 +系统真正需要的。 + +注意:标准内核驱动中已经存在通用的“LED 和按键”GPIO 任务,分别是: +"leds-gpio" 和 "gpio_keys"。请使用这些来替代直接访问 GPIO,因为集成在 +内核框架中的这类驱动比你在用户空间的代码更好。 + + +Sysfs 中的路径 +-------------- +在/sys/class/gpio 中有 3 类入口: + + - 用于在用户空间控制 GPIO 的控制接口; + + - GPIOs 本身;以及 + + - GPIO 控制器 ("gpio_chip" 实例)。 + +除了这些标准的文件,还包含“device”符号链接。 + +控制接口是只写的: + + /sys/class/gpio/ + + "export" ... 用户空间可以通过写其编号到这个文件,要求内核导出 + 一个 GPIO 的控制到用户空间。 + + 例如: 如果内核代码没有申请 GPIO #19,"echo 19 > export" + 将会为 GPIO #19 创建一个 "gpio19" 节点。 + + "unexport" ... 导出到用户空间的逆操作。 + + 例如: "echo 19 > unexport" 将会移除使用"export"文件导出的 + "gpio19" 节点。 + +GPIO 信号的路径类似 /sys/class/gpio/gpio42/ (对于 GPIO #42 来说), +并有如下的读/写属性: + + /sys/class/gpio/gpioN/ + + "direction" ... 读取得到 "in" 或 "out"。这个值通常运行写入。 + 写入"out" 时,其引脚的默认输出为低电平。为了确保无故障运行, + "low" 或 "high" 的电平值应该写入 GPIO 的配置,作为初始输出值。 + + 注意:如果内核不支持改变 GPIO 的方向,或者在导出时内核代码没有 + 明确允许用户空间可以重新配置 GPIO 方向,那么这个属性将不存在。 + + "value" ... 读取得到 0 (低电平) 或 1 (高电平)。如果 GPIO 配置为 + 输出,这个值允许写操作。任何非零值都以高电平看待。 + + 如果引脚可以配置为中断信号,且如果已经配置了产生中断的模式 + (见"edge"的描述),你可以对这个文件使用轮询操作(poll(2)), + 且轮询操作会在任何中断触发时返回。如果你使用轮询操作(poll(2)), + 请在 events 中设置 POLLPRI 和 POLLERR。如果你使用轮询操作 + (select(2)),请在 exceptfds 设置你期望的文件描述符。在 + 轮询操作(poll(2))返回之后,既可以通过 lseek(2)操作读取 + sysfs 文件的开始部分,也可以关闭这个文件并重新打开它来读取数据。 + + "edge" ... 读取得到“none”、“rising”、“falling”或者“both”。 + 将这些字符串写入这个文件可以选择沿触发模式,会使得轮询操作 + (select(2))在"value"文件中返回。 + + 这个文件仅有在这个引脚可以配置为可产生中断输入引脚时,才存在。 + + "active_low" ... 读取得到 0 (假) 或 1 (真)。写入任何非零值可以 + 翻转这个属性的(读写)值。已存在或之后通过"edge"属性设置了"rising" + 和 "falling" 沿触发模式的轮询操作(poll(2))将会遵循这个设置。 + +GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO +开始实现控制的控制器),并有着以下只读属性: + + /sys/class/gpio/gpiochipN/ + + "base" ... 与以上的 N 相同,代表此芯片管理的第一个 GPIO 的编号 + + "label" ... 用于诊断 (并不总是只有唯一值) + + "ngpio" ... 此控制器所管理的 GPIO 数量(而 GPIO 编号从 N 到 + N + ngpio - 1) + +大多数情况下,电路板的文档应当标明每个 GPIO 的使用目的。但是那些编号并不总是 +固定的,例如在扩展卡上的 GPIO会根据所使用的主板或所在堆叠架构中其他的板子而 +有所不同。在这种情况下,你可能需要使用 gpiochip 节点(尽可能地结合电路图)来 +确定给定信号所用的 GPIO 编号。 + + +从内核代码中导出 +------------- +内核代码可以明确地管理那些已通过 gpio_request()申请的 GPIO 的导出: + + /* 导出 GPIO 到用户空间 */ + int gpio_export(unsigned gpio, bool direction_may_change); + + /* gpio_export()的逆操作 */ + void gpio_unexport(); + + /* 创建一个 sysfs 连接到已导出的 GPIO 节点 */ + int gpio_export_link(struct device *dev, const char *name, + unsigned gpio) + + /* 改变 sysfs 中的一个 GPIO 节点的极性 */ + int gpio_sysfs_set_active_low(unsigned gpio, int value); + +在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs +接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间 +破坏重要的系统状态。 + +这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口, +与文档配合作为板级支持包的一部分。 + +在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方 +创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的 +名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。 + +驱动可以使用 gpio_sysfs_set_active_low() 来在用户空间隐藏电路板之间 +GPIO 线的极性差异。这个仅对 sysfs 接口起作用。极性的改变可以在 gpio_export() +前后进行,且之前使能的轮询操作(poll(2))支持(上升或下降沿)将会被重新配置来遵循 +这个设置。 -- cgit v1.2.3-70-g09d2 From ae6480eca04712dfe901280ceb6d04e687dd0284 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Tue, 28 Aug 2012 12:45:41 -0400 Subject: Documentation: Fix "struct kobj_type" to include newer members. kobj_type replaced by verbatim copy-and-paste from kobject.h. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index 49578cf1aea..c5182bb2c16 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -284,9 +284,11 @@ instead, it is associated with the ktype. So let us introduce struct kobj_type: struct kobj_type { - void (*release)(struct kobject *); + void (*release)(struct kobject *kobj); const struct sysfs_ops *sysfs_ops; - struct attribute **default_attrs; + struct attribute **default_attrs; + const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); + const void *(*namespace)(struct kobject *kobj); }; This structure is used to describe a particular type of kobject (or, more -- cgit v1.2.3-70-g09d2 From b5ced6b3653afc7bd361735a1ade9d8739b9ebe5 Mon Sep 17 00:00:00 2001 From: Ninja Tekkaman Date: Wed, 29 Aug 2012 12:54:41 +0800 Subject: Documentation: Chinese translation of Documentation/filesystems/sysfs.txt This is a Chinese translated version of Documentation/filesystems/sysfs.txt Signed-off-by: Fu Wei Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman --- Documentation/zh_CN/filesystems/sysfs.txt | 372 ++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 Documentation/zh_CN/filesystems/sysfs.txt (limited to 'Documentation') diff --git a/Documentation/zh_CN/filesystems/sysfs.txt b/Documentation/zh_CN/filesystems/sysfs.txt new file mode 100644 index 00000000000..e230eaa3312 --- /dev/null +++ b/Documentation/zh_CN/filesystems/sysfs.txt @@ -0,0 +1,372 @@ +Chinese translated version of Documentation/filesystems/sysfs.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Patrick Mochel + Mike Murphy +Chinese maintainer: Fu Wei +--------------------------------------------------------------------- +Documentation/filesystems/sysfs.txt 的中文翻译 + +如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 +交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 +译存在问题,请联系中文版维护者。 +英文版维护者: Patrick Mochel + Mike Murphy +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei + + +以下为正文 +--------------------------------------------------------------------- +sysfs - 用于导出内核对象(kobject)的文件系统 + +Patrick Mochel +Mike Murphy + +修订: 16 August 2011 +原始版本: 10 January 2003 + + +sysfs 简介: +~~~~~~~~~~ + +sysfs 是一个最初基于 ramfs 且位于内存的文件系统。它提供导出内核 +数据结构及其属性,以及它们之间的关联到用户空间的方法。 + +sysfs 始终与 kobject 的底层结构紧密相关。请阅读 +Documentation/kobject.txt 文档以获得更多关于 kobject 接口的 +信息。 + + +使用 sysfs +~~~~~~~~~~~ + +只要内核配置中定义了 CONFIG_SYSFS ,sysfs 总是被编译进内核。你可 +通过以下命令挂载它: + + mount -t sysfs sysfs /sys + + +创建目录 +~~~~~~~~ + +任何 kobject 在系统中注册,就会有一个目录在 sysfs 中被创建。这个 +目录是作为该 kobject 的父对象所在目录的子目录创建的,以准确地传递 +内核的对象层次到用户空间。sysfs 中的顶层目录代表着内核对象层次的 +共同祖先;例如:某些对象属于某个子系统。 + +Sysfs 在与其目录关联的 sysfs_dirent 对象中内部保存一个指向实现 +目录的 kobject 的指针。以前,这个 kobject 指针被 sysfs 直接用于 +kobject 文件打开和关闭的引用计数。而现在的 sysfs 实现中,kobject +引用计数只能通过 sysfs_schedule_callback() 函数直接修改。 + + +属性 +~~~~ + +kobject 的属性可在文件系统中以普通文件的形式导出。Sysfs 为属性定义 +了面向文件 I/O 操作的方法,以提供对内核属性的读写。 + + +属性应为 ASCII 码文本文件。以一个文件只存储一个属性值为宜。但一个 +文件只包含一个属性值可能影响效率,所以一个包含相同数据类型的属性值 +数组也被广泛地接受。 + +混合类型、表达多行数据以及一些怪异的数据格式会遭到强烈反对。这样做是 +很丢脸的,而且其代码会在未通知作者的情况下被重写。 + + +一个简单的属性结构定义如下: + +struct attribute { + char * name; + struct module *owner; + umode_t mode; +}; + + +int sysfs_create_file(struct kobject * kobj, const struct attribute * attr); +void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr); + + +一个单独的属性结构并不包含读写其属性值的方法。子系统最好为增删特定 +对象类型的属性定义自己的属性结构体和封装函数。 + +例如:驱动程序模型定义的 device_attribute 结构体如下: + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +}; + +int device_create_file(struct device *, const struct device_attribute *); +void device_remove_file(struct device *, const struct device_attribute *); + +为了定义设备属性,同时定义了一下辅助宏: + +#define DEVICE_ATTR(_name, _mode, _show, _store) \ +struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) + +例如:声明 + +static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo); + +等同于如下代码: + +static struct device_attribute dev_attr_foo = { + .attr = { + .name = "foo", + .mode = S_IWUSR | S_IRUGO, + .show = show_foo, + .store = store_foo, + }, +}; + + +子系统特有的回调函数 +~~~~~~~~~~~~~~~~~~~ + +当一个子系统定义一个新的属性类型时,必须实现一系列的 sysfs 操作, +以帮助读写调用实现属性所有者的显示和储存方法。 + +struct sysfs_ops { + ssize_t (*show)(struct kobject *, struct attribute *, char *); + ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); +}; + +[子系统应已经定义了一个 struct kobj_type 结构体作为这个类型的 +描述符,并在此保存 sysfs_ops 的指针。更多的信息参见 kobject 的 +文档] + +sysfs 会为这个类型调用适当的方法。当一个文件被读写时,这个方法会 +将一般的kobject 和 attribute 结构体指针转换为适当的指针类型后 +调用相关联的函数。 + + +示例: + +#define to_dev(obj) container_of(obj, struct device, kobj) +#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) + +static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct device_attribute *dev_attr = to_dev_attr(attr); + struct device *dev = to_dev(kobj); + ssize_t ret = -EIO; + + if (dev_attr->show) + ret = dev_attr->show(dev, dev_attr, buf); + if (ret >= (ssize_t)PAGE_SIZE) { + print_symbol("dev_attr_show: %s returned bad count\n", + (unsigned long)dev_attr->show); + } + return ret; +} + + + +读写属性数据 +~~~~~~~~~~~~ + +在声明属性时,必须指定 show() 或 store() 方法,以实现属性的 +读或写。这些方法的类型应该和以下的设备属性定义一样简单。 + +ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +也就是说,他们应只以一个处理对象、一个属性和一个缓冲指针作为参数。 + +sysfs 会分配一个大小为 (PAGE_SIZE) 的缓冲区并传递给这个方法。 +Sysfs 将会为每次读写操作调用一次这个方法。这使得这些方法在执行时 +会出现以下的行为: + +- 在读方面(read(2)),show() 方法应该填充整个缓冲区。回想属性 + 应只导出了一个属性值或是一个同类型属性值的数组,所以这个代价将 + 不会不太高。 + + 这使得用户空间可以局部地读和任意的向前搜索整个文件。如果用户空间 + 向后搜索到零或使用‘0’偏移执行一个pread(2)操作,show()方法将 + 再次被调用,以重新填充缓存。 + +- 在写方面(write(2)),sysfs 希望在第一次写操作时得到整个缓冲区。 + 之后 Sysfs 传递整个缓冲区给 store() 方法。 + + 当要写 sysfs 文件时,用户空间进程应首先读取整个文件,修该想要 + 改变的值,然后回写整个缓冲区。 + + 在读写属性值时,属性方法的执行应操作相同的缓冲区。 + +注记: + +- 写操作导致的 show() 方法重载,会忽略当前文件位置。 + +- 缓冲区应总是 PAGE_SIZE 大小。对于i386,这个值为4096。 + +- show() 方法应该返回写入缓冲区的字节数,也就是 snprintf()的 + 返回值。 + +- show() 应始终使用 snprintf()。 + +- store() 应返回缓冲区的已用字节数。如果整个缓存都已填满,只需返回 + count 参数。 + +- show() 或 store() 可以返回错误值。当得到一个非法值,必须返回一个 + 错误值。 + +- 一个传递给方法的对象将会通过 sysfs 调用对象内嵌的引用计数固定在 + 内存中。尽管如此,对象代表的物理实体(如设备)可能已不存在。如有必要, + 应该实现一个检测机制。 + +一个简单的(未经实验证实的)设备属性实现如下: + +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name); +} + +static ssize_t store_name(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + snprintf(dev->name, sizeof(dev->name), "%.*s", + (int)min(count, sizeof(dev->name) - 1), buf); + return count; +} + +static DEVICE_ATTR(name, S_IRUGO, show_name, store_name); + + +(注意:真正的实现不允许用户空间设置设备名。) + +顶层目录布局 +~~~~~~~~~~~~ + +sysfs 目录的安排显示了内核数据结构之间的关系。 + +顶层 sysfs 目录如下: + +block/ +bus/ +class/ +dev/ +devices/ +firmware/ +net/ +fs/ + +devices/ 包含了一个设备树的文件系统表示。他直接映射了内部的内核 +设备树,反映了设备的层次结构。 + +bus/ 包含了内核中各种总线类型的平面目录布局。每个总线目录包含两个 +子目录: + + devices/ + drivers/ + +devices/ 包含了系统中出现的每个设备的符号链接,他们指向 root/ 下的 +设备目录。 + +drivers/ 包含了每个已为特定总线上的设备而挂载的驱动程序的目录(这里 +假定驱动没有跨越多个总线类型)。 + +fs/ 包含了一个为文件系统设立的目录。现在每个想要导出属性的文件系统必须 +在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse.txt)。 + +dev/ 包含两个子目录: char/ 和 block/。在这两个子目录中,有以 +: 格式命名的符号链接。这些符号链接指向 sysfs 目录 +中相应的设备。/sys/dev 提供一个通过一个 stat(2) 操作结果,查找 +设备 sysfs 接口快捷的方法。 + +更多有关 driver-model 的特性信息可以在 Documentation/driver-model/ +中找到。 + + +TODO: 完成这一节。 + + +当前接口 +~~~~~~~~ + +以下的接口层普遍存在于当前的sysfs中: + +- 设备 (include/linux/device.h) +---------------------------------- +结构体: + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +}; + +声明: + +DEVICE_ATTR(_name, _mode, _show, _store); + +增/删属性: + +int device_create_file(struct device *dev, const struct device_attribute * attr); +void device_remove_file(struct device *dev, const struct device_attribute * attr); + + +- 总线驱动程序 (include/linux/device.h) +-------------------------------------- +结构体: + +struct bus_attribute { + struct attribute attr; + ssize_t (*show)(struct bus_type *, char * buf); + ssize_t (*store)(struct bus_type *, const char * buf, size_t count); +}; + +声明: + +BUS_ATTR(_name, _mode, _show, _store) + +增/删属性: + +int bus_create_file(struct bus_type *, struct bus_attribute *); +void bus_remove_file(struct bus_type *, struct bus_attribute *); + + +- 设备驱动程序 (include/linux/device.h) +----------------------------------------- + +结构体: + +struct driver_attribute { + struct attribute attr; + ssize_t (*show)(struct device_driver *, char * buf); + ssize_t (*store)(struct device_driver *, const char * buf, + size_t count); +}; + +声明: + +DRIVER_ATTR(_name, _mode, _show, _store) + +增/删属性: + +int driver_create_file(struct device_driver *, const struct driver_attribute *); +void driver_remove_file(struct device_driver *, const struct driver_attribute *); + + +文档 +~~~~ + +sysfs 目录结构以及其中包含的属性定义了一个内核与用户空间之间的 ABI。 +对于任何 ABI,其自身的稳定和适当的文档是非常重要的。所有新的 sysfs +属性必须在 Documentation/ABI 中有文档。详见 Documentation/ABI/README。 -- cgit v1.2.3-70-g09d2 From 8db0f9343a2a9e965257de159a140cf995f113fb Mon Sep 17 00:00:00 2001 From: Ninja Tekkaman Date: Sun, 2 Sep 2012 00:51:51 +0800 Subject: Documentation: Chinese translation of Documentation/video4linux/v4l2-framework.txt This is a Chinese translated version of Documentation/video4linux/v4l2-framework.txt Signed-off-by: Fu Wei Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman --- Documentation/zh_CN/video4linux/v4l2-framework.txt | 983 +++++++++++++++++++++ 1 file changed, 983 insertions(+) create mode 100644 Documentation/zh_CN/video4linux/v4l2-framework.txt (limited to 'Documentation') diff --git a/Documentation/zh_CN/video4linux/v4l2-framework.txt b/Documentation/zh_CN/video4linux/v4l2-framework.txt new file mode 100644 index 00000000000..3e74f13af42 --- /dev/null +++ b/Documentation/zh_CN/video4linux/v4l2-framework.txt @@ -0,0 +1,983 @@ +Chinese translated version of Documentation/video4linux/v4l2-framework.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Mauro Carvalho Chehab +Chinese maintainer: Fu Wei +--------------------------------------------------------------------- +Documentation/video4linux/v4l2-framework.txt 的中文翻译 + +如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 +交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 +译存在问题,请联系中文版维护者。 +英文版维护者: Mauro Carvalho Chehab +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei + + +以下为正文 +--------------------------------------------------------------------- +V4L2 驱动框架概览 +============== + +本文档描述 V4L2 框架所提供的各种结构和它们之间的关系。 + + +介绍 +---- + +大部分现代 V4L2 设备由多个 IC 组成,在 /dev 下导出多个设备节点, +并同时创建非 V4L2 设备(如 DVB、ALSA、FB、I2C 和红外输入设备)。 +由于这种硬件的复杂性,V4L2 驱动也变得非常复杂。 + +尤其是 V4L2 必须支持 IC 实现音视频的多路复用和编解码,这就更增加了其 +复杂性。通常这些 IC 通过一个或多个 I2C 总线连接到主桥驱动器,但也可 +使用其他总线。这些设备称为“子设备”。 + +长期以来,这个框架仅限于通过 video_device 结构体创建 V4L 设备节点, +并使用 video_buf 处理视频缓冲(注:本文不讨论 video_buf 框架)。 + +这意味着所有驱动必须自己设置设备实例并连接到子设备。其中一部分要正确地 +完成是比较复杂的,使得许多驱动都没有正确地实现。 + +由于框架的缺失,有很多通用代码都不可重复利用。 + +因此,这个框架构建所有驱动都需要的基本结构块,而统一的框架将使通用代码 +创建成实用函数并在所有驱动中共享变得更加容易。 + + +驱动结构 +------- + +所有 V4L2 驱动都有如下结构: + +1) 每个设备实例的结构体--包含其设备状态。 + +2) 初始化和控制子设备的方法(如果有)。 + +3) 创建 V4L2 设备节点 (/dev/videoX、/dev/vbiX 和 /dev/radioX) + 并跟踪设备节点的特定数据。 + +4) 特定文件句柄结构体--包含每个文件句柄的数据。 + +5) 视频缓冲处理。 + +以下是它们的初略关系图: + + device instances(设备实例) + | + +-sub-device instances(子设备实例) + | + \-V4L2 device nodes(V4L2 设备节点) + | + \-filehandle instances(文件句柄实例) + + +框架结构 +------- + +该框架非常类似驱动结构:它有一个 v4l2_device 结构用于保存设备 +实例的数据;一个 v4l2_subdev 结构体代表子设备实例;video_device +结构体保存 V4L2 设备节点的数据;将来 v4l2_fh 结构体将跟踪文件句柄 +实例(暂未尚未实现)。 + +V4L2 框架也可与媒体框架整合(可选的)。如果驱动设置了 v4l2_device +结构体的 mdev 域,子设备和视频节点的入口将自动出现在媒体框架中。 + + +v4l2_device 结构体 +---------------- + +每个设备实例都通过 v4l2_device (v4l2-device.h)结构体来表示。 +简单设备可以仅分配这个结构体,但在大多数情况下,都会将这个结构体 +嵌入到一个更大的结构体中。 + +你必须注册这个设备实例: + + v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev); + +注册操作将会初始化 v4l2_device 结构体。如果 dev->driver_data 域 +为 NULL,就将其指向 v4l2_dev。 + +需要与媒体框架整合的驱动必须手动设置 dev->driver_data,指向包含 +v4l2_device 结构体实例的驱动特定设备结构体。这可以在注册 V4L2 设备 +实例前通过 dev_set_drvdata() 函数完成。同时必须设置 v4l2_device +结构体的 mdev 域,指向适当的初始化并注册过的 media_device 实例。 + +如果 v4l2_dev->name 为空,则它将被设置为从 dev 中衍生出的值(为了 +更加精确,形式为驱动名后跟 bus_id)。如果你在调用 v4l2_device_register +前已经设置好了,则不会被修改。如果 dev 为 NULL,则你*必须*在调用 +v4l2_device_register 前设置 v4l2_dev->name。 + +你可以基于驱动名和驱动的全局 atomic_t 类型的实例编号,通过 +v4l2_device_set_name() 设置 name。这样会生成类似 ivtv0、ivtv1 等 +名字。若驱动名以数字结尾,则会在编号和驱动名间插入一个破折号,如: +cx18-0、cx18-1 等。此函数返回实例编号。 + +第一个 “dev” 参数通常是一个指向 pci_dev、usb_interface 或 +platform_device 的指针。很少使其为 NULL,除非是一个ISA设备或者 +当一个设备创建了多个 PCI 设备,使得 v4l2_dev 无法与一个特定的父设备 +关联。 + +你也可以提供一个 notify() 回调,使子设备可以调用它实现事件通知。 +但这个设置与子设备相关。子设备支持的任何通知必须在 +include/media/.h 中定义一个消息头。 + +注销 v4l2_device 使用如下函数: + + v4l2_device_unregister(struct v4l2_device *v4l2_dev); + +如果 dev->driver_data 域指向 v4l2_dev,将会被重置为 NULL。注销同时 +会自动从设备中注销所有子设备。 + +如果你有一个热插拔设备(如USB设备),则当断开发生时,父设备将无效。 +由于 v4l2_device 有一个指向父设备的指针必须被清除,同时标志父设备 +已消失,所以必须调用以下函数: + + v4l2_device_disconnect(struct v4l2_device *v4l2_dev); + +这个函数并*不*注销子设备,因此你依然要调用 v4l2_device_unregister() +函数。如果你的驱动器并非热插拔的,就没有必要调用 v4l2_device_disconnect()。 + +有时你需要遍历所有被特定驱动注册的设备。这通常发生在多个设备驱动使用 +同一个硬件的情况下。如:ivtvfb 驱动是一个使用 ivtv 硬件的帧缓冲驱动, +同时 alsa 驱动也使用此硬件。 + +你可以使用如下例程遍历所有注册的设备: + +static int callback(struct device *dev, void *p) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + + /* 测试这个设备是否已经初始化 */ + if (v4l2_dev == NULL) + return 0; + ... + return 0; +} + +int iterate(void *p) +{ + struct device_driver *drv; + int err; + + /* 在PCI 总线上查找ivtv驱动。 + pci_bus_type是全局的. 对于USB总线使用usb_bus_type。 */ + drv = driver_find("ivtv", &pci_bus_type); + /* 遍历所有的ivtv设备实例 */ + err = driver_for_each_device(drv, NULL, p, callback); + put_driver(drv); + return err; +} + +有时你需要一个设备实例的运行计数。这个通常用于映射一个设备实例到一个 +模块选择数组的索引。 + +推荐方法如下: + +static atomic_t drv_instance = ATOMIC_INIT(0); + +static int __devinit drv_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + ... + state->instance = atomic_inc_return(&drv_instance) - 1; +} + +如果你有多个设备节点,对于热插拔设备,知道何时注销 v4l2_device 结构体 +就比较困难。为此 v4l2_device 有引用计数支持。当调用 video_register_device +时增加引用计数,而设备节点释放时减小引用计数。当引用计数为零,则 +v4l2_device 的release() 回调将被执行。你就可以在此时做最后的清理工作。 + +如果创建了其他设备节点(比如 ALSA),则你可以通过以下函数手动增减 +引用计数: + +void v4l2_device_get(struct v4l2_device *v4l2_dev); + +或: + +int v4l2_device_put(struct v4l2_device *v4l2_dev); + +由于引用技术初始化为 1 ,你也需要在 disconnect() 回调(对于 USB 设备)中 +调用 v4l2_device_put,或者 remove() 回调(例如对于 PCI 设备),否则 +引用计数将永远不会为 0 。 + +v4l2_subdev结构体 +------------------ + +许多驱动需要与子设备通信。这些设备可以完成各种任务,但通常他们负责 +音视频复用和编解码。如网络摄像头的子设备通常是传感器和摄像头控制器。 + +这些一般为 I2C 接口设备,但并不一定都是。为了给驱动提供调用子设备的 +统一接口,v4l2_subdev 结构体(v4l2-subdev.h)产生了。 + +每个子设备驱动都必须有一个 v4l2_subdev 结构体。这个结构体可以单独 +代表一个简单的子设备,也可以嵌入到一个更大的结构体中,与更多设备状态 +信息保存在一起。通常有一个下级设备结构体(比如:i2c_client)包含了 +内核创建的设备数据。建议使用 v4l2_set_subdevdata() 将这个结构体的 +指针保存在 v4l2_subdev 的私有数据域(dev_priv)中。这使得通过 v4l2_subdev +找到实际的低层总线特定设备数据变得容易。 + +你同时需要一个从低层结构体获取 v4l2_subdev 指针的方法。对于常用的 +i2c_client 结构体,i2c_set_clientdata() 函数可用于保存一个 v4l2_subdev +指针;对于其他总线你可能需要使用其他相关函数。 + +桥驱动中也应保存每个子设备的私有数据,比如一个指向特定桥的各设备私有 +数据的指针。为此 v4l2_subdev 结构体提供主机私有数据域(host_priv), +并可通过 v4l2_get_subdev_hostdata() 和 v4l2_set_subdev_hostdata() +访问。 + +从总线桥驱动的视角,驱动加载子设备模块并以某种方式获得 v4l2_subdev +结构体指针。对于 i2c 总线设备相对简单:调用 i2c_get_clientdata()。 +对于其他总线也需要做类似的操作。针对 I2C 总线上的子设备辅助函数帮你 +完成了大部分复杂的工作。 + +每个 v4l2_subdev 都包含子设备驱动需要实现的函数指针(如果对此设备 +不适用,可为NULL)。由于子设备可完成许多不同的工作,而在一个庞大的 +函数指针结构体中通常仅有少数有用的函数实现其功能肯定不合适。所以, +函数指针根据其实现的功能被分类,每一类都有自己的函数指针结构体。 + +顶层函数指针结构体包含了指向各类函数指针结构体的指针,如果子设备驱动 +不支持该类函数中的任何一个功能,则指向该类结构体的指针为NULL。 + +这些结构体定义如下: + +struct v4l2_subdev_core_ops { + int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip); + int (*log_status)(struct v4l2_subdev *sd); + int (*init)(struct v4l2_subdev *sd, u32 val); + ... +}; + +struct v4l2_subdev_tuner_ops { + ... +}; + +struct v4l2_subdev_audio_ops { + ... +}; + +struct v4l2_subdev_video_ops { + ... +}; + +struct v4l2_subdev_pad_ops { + ... +}; + +struct v4l2_subdev_ops { + const struct v4l2_subdev_core_ops *core; + const struct v4l2_subdev_tuner_ops *tuner; + const struct v4l2_subdev_audio_ops *audio; + const struct v4l2_subdev_video_ops *video; + const struct v4l2_subdev_pad_ops *video; +}; + +其中 core(核心)函数集通常可用于所有子设备,其他类别的实现依赖于 +子设备。如视频设备可能不支持音频操作函数,反之亦然。 + +这样的设置在限制了函数指针数量的同时,还使增加新的操作函数和分类 +变得较为容易。 + +子设备驱动可使用如下函数初始化 v4l2_subdev 结构体: + + v4l2_subdev_init(sd, &ops); + +然后,你必须用一个唯一的名字初始化 subdev->name,并初始化模块的 +owner 域。若使用 i2c 辅助函数,这些都会帮你处理好。 + +若需同媒体框架整合,你必须调用 media_entity_init() 初始化 v4l2_subdev +结构体中的 media_entity 结构体(entity 域): + + struct media_pad *pads = &my_sd->pads; + int err; + + err = media_entity_init(&sd->entity, npads, pads, 0); + +pads 数组必须预先初始化。无须手动设置 media_entity 的 type 和 +name 域,但如有必要,revision 域必须初始化。 + +当(任何)子设备节点被打开/关闭,对 entity 的引用将被自动获取/释放。 + +在子设备被注销之后,不要忘记清理 media_entity 结构体: + + media_entity_cleanup(&sd->entity); + +如果子设备驱动趋向于处理视频并整合进了媒体框架,必须使用 v4l2_subdev_pad_ops +替代 v4l2_subdev_video_ops 实现格式相关的功能。 + +这种情况下,子设备驱动应该设置 link_validate 域,以提供它自身的链接 +验证函数。链接验证函数应对管道(两端链接的都是 V4L2 子设备)中的每个 +链接调用。驱动还要负责验证子设备和视频节点间格式配置的正确性。 + +如果 link_validate 操作没有设置,默认的 v4l2_subdev_link_validate_default() +函数将会被调用。这个函数保证宽、高和媒体总线像素格式在链接的收发两端 +都一致。子设备驱动除了它们自己的检测外,也可以自由使用这个函数以执行 +上面提到的检查。 + +设备(桥)驱动程序必须向 v4l2_device 注册 v4l2_subdev: + + int err = v4l2_device_register_subdev(v4l2_dev, sd); + +如果子设备模块在它注册前消失,这个操作可能失败。在这个函数成功返回后, +subdev->dev 域就指向了 v4l2_device。 + +如果 v4l2_device 父设备的 mdev 域为非 NULL 值,则子设备实体将被自动 +注册为媒体设备。 + +注销子设备则可用如下函数: + + v4l2_device_unregister_subdev(sd); + +此后,子设备模块就可卸载,且 sd->dev == NULL。 + +注册之设备后,可通过以下方式直接调用其操作函数: + + err = sd->ops->core->g_chip_ident(sd, &chip); + +但使用如下宏会比较容易且合适: + + err = v4l2_subdev_call(sd, core, g_chip_ident, &chip); + +这个宏将会做 NULL 指针检查,如果 subdev 为 NULL,则返回-ENODEV;如果 +subdev->core 或 subdev->core->g_chip_ident 为 NULL,则返回 -ENOIOCTLCMD; +否则将返回 subdev->ops->core->g_chip_ident ops 调用的实际结果。 + +有时也可能同时调用所有或一系列子设备的某个操作函数: + + v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip); + +任何不支持此操作的子设备都会被跳过,并忽略错误返回值。但如果你需要 +检查出错码,则可使用如下函数: + + err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip); + +除 -ENOIOCTLCMD 外的任何错误都会跳出循环并返回错误值。如果(除 -ENOIOCTLCMD +外)没有错误发生,则返回 0。 + +对于以上两个函数的第二个参数为组 ID。如果为 0,则所有子设备都会执行 +这个操作。如果为非 0 值,则只有那些组 ID 匹配的子设备才会执行此操作。 +在桥驱动注册一个子设备前,可以设置 sd->grp_id 为任何期望值(默认值为 +0)。这个值属于桥驱动,且子设备驱动将不会修改和使用它。 + +组 ID 赋予了桥驱动更多对于如何调用回调的控制。例如,电路板上有多个 +音频芯片,每个都有改变音量的能力。但当用户想要改变音量的时候,通常 +只有一个会被实际使用。你可以对这样的子设备设置组 ID 为(例如 AUDIO_CONTROLLER) +并在调用 v4l2_device_call_all() 时指定它为组 ID 值。这就保证了只有 +需要的子设备才会执行这个回调。 + +如果子设备需要通知它的 v4l2_device 父设备一个事件,可以调用 +v4l2_subdev_notify(sd, notification, arg)。这个宏检查是否有一个 +notify() 回调被注册,如果没有,返回 -ENODEV。否则返回 notify() 调用 +结果。 + +使用 v4l2_subdev 的好处在于它是一个通用结构体,且不包含任何底层硬件 +信息。所有驱动可以包含多个 I2C 总线的子设备,但也有子设备是通过 GPIO +控制。这个区别仅在配置设备时有关系,一旦子设备注册完成,对于 v4l2 +子系统来说就完全透明了。 + + +V4L2 子设备用户空间API +-------------------- + +除了通过 v4l2_subdev_ops 结构导出的内核 API,V4L2 子设备也可以直接 +通过用户空间应用程序来控制。 + +可以在 /dev 中创建名为 v4l-subdevX 设备节点,以通过其直接访问子设备。 +如果子设备支持用户空间直接配置,必须在注册前设置 V4L2_SUBDEV_FL_HAS_DEVNODE +标志。 + +注册子设备之后, v4l2_device 驱动会通过调用 v4l2_device_register_subdev_nodes() +函数为所有已注册并设置了 V4L2_SUBDEV_FL_HAS_DEVNODE 的子设备创建 +设备节点。这些设备节点会在子设备注销时自动删除。 + +这些设备节点处理 V4L2 API 的一个子集。 + +VIDIOC_QUERYCTRL +VIDIOC_QUERYMENU +VIDIOC_G_CTRL +VIDIOC_S_CTRL +VIDIOC_G_EXT_CTRLS +VIDIOC_S_EXT_CTRLS +VIDIOC_TRY_EXT_CTRLS + + 这些 ioctls 控制与 V4L2 中定义的一致。他们行为相同,唯一的 + 不同是他们只处理子设备的控制实现。根据驱动程序,这些控制也 + 可以通过一个(或多个) V4L2 设备节点访问。 + +VIDIOC_DQEVENT +VIDIOC_SUBSCRIBE_EVENT +VIDIOC_UNSUBSCRIBE_EVENT + + 这些 ioctls 事件与 V4L2 中定义的一致。他们行为相同,唯一的 + 不同是他们只处理子设备产生的事件。根据驱动程序,这些事件也 + 可以通过一个(或多个) V4L2 设备节点上报。 + + 要使用事件通知的子设备驱动,在注册子设备前必须在 v4l2_subdev::flags + 中设置 V4L2_SUBDEV_USES_EVENTS 并在 v4l2_subdev::nevents + 中初始化事件队列深度。注册完成后,事件会在 v4l2_subdev::devnode + 设备节点中像通常一样被排队。 + + 为正确支持事件机制,poll() 文件操作也应被实现。 + +私有 ioctls + + 不在以上列表中的所有 ioctls 会通过 core::ioctl 操作直接传递 + 给子设备驱动。 + + +I2C 子设备驱动 +------------- + +由于这些驱动很常见,所以内特提供了特定的辅助函数(v4l2-common.h)让这些 +设备的使用更加容易。 + +添加 v4l2_subdev 支持的推荐方法是让 I2C 驱动将 v4l2_subdev 结构体 +嵌入到为每个 I2C 设备实例创建的状态结构体中。而最简单的设备没有状态 +结构体,此时可以直接创建一个 v4l2_subdev 结构体。 + +一个典型的状态结构体如下所示(‘chipname’用芯片名代替): + +struct chipname_state { + struct v4l2_subdev sd; + ... /* 附加的状态域*/ +}; + +初始化 v4l2_subdev 结构体的方法如下: + + v4l2_i2c_subdev_init(&state->sd, client, subdev_ops); + +这个函数将填充 v4l2_subdev 结构体中的所有域,并保证 v4l2_subdev 和 +i2c_client 都指向彼此。 + +同时,你也应该为从 v4l2_subdev 指针找到 chipname_state 结构体指针 +添加一个辅助内联函数。 + +static inline struct chipname_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct chipname_state, sd); +} + +使用以下函数可以通过 v4l2_subdev 结构体指针获得 i2c_client 结构体 +指针: + + struct i2c_client *client = v4l2_get_subdevdata(sd); + +而以下函数则相反,通过 i2c_client 结构体指针获得 v4l2_subdev 结构体 +指针: + + struct v4l2_subdev *sd = i2c_get_clientdata(client); + +当 remove()函数被调用前,必须保证先调用 v4l2_device_unregister_subdev(sd)。 +此操作将会从桥驱动中注销子设备。即使子设备没有注册,调用此函数也是 +安全的。 + +必须这样做的原因是:当桥驱动注销 i2c 适配器时,remove()回调函数 +会被那个适配器上的 i2c 设备调用。此后,相应的 v4l2_subdev 结构体 +就不存在了,所有它们必须先被注销。在 remove()回调函数中调用 +v4l2_device_unregister_subdev(sd),可以保证执行总是正确的。 + + +桥驱动也有一些辅组函数可用: + +struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter, + "module_foo", "chipid", 0x36, NULL); + +这个函数会加载给定的模块(如果没有模块需要加载,可以为 NULL), +并用给定的 i2c 适配器结构体指针(i2c_adapter)和 器件地址(chip/address) +作为参数调用 i2c_new_device()。如果一切顺利,则就在 v4l2_device +中注册了子设备。 + +你也可以利用 v4l2_i2c_new_subdev()的最后一个参数,传递一个可能的 +I2C 地址数组,让函数自动探测。这些探测地址只有在前一个参数为 0 的 +情况下使用。非零参数意味着你知道准确的 i2c 地址,所以此时无须进行 +探测。 + +如果出错,两个函数都返回 NULL。 + +注意:传递给 v4l2_i2c_new_subdev()的 chipid 通常与模块名一致。 +它允许你指定一个芯片的变体,比如“saa7114”或“saa7115”。一般通过 +i2c 驱动自动探测。chipid 的使用是在今后需要深入了解的事情。这个与 +i2c 驱动不同,较容易混淆。要知道支持哪些芯片变体,你可以查阅 i2c +驱动代码的 i2c_device_id 表,上面列出了所有可能支持的芯片。 + +还有两个辅助函数: + +v4l2_i2c_new_subdev_cfg:这个函数添加新的 irq 和 platform_data +参数,并有‘addr’和‘probed_addrs’参数:如果 addr 非零,则被使用 +(不探测变体),否则 probed_addrs 中的地址将用于自动探测。 + +例如:以下代码将会探测地址(0x10): + +struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, + "module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10)); + +v4l2_i2c_new_subdev_board 使用一个 i2c_board_info 结构体,将其 +替代 irq、platform_data 和 add r参数传递给 i2c 驱动。 + +如果子设备支持 s_config 核心操作,这个操作会在子设备配置好之后以 irq 和 +platform_data 为参数调用。早期的 v4l2_i2c_new_(probed_)subdev 函数 +同样也会调用 s_config,但仅在 irq 为 0 且 platform_data 为 NULL 时。 + +video_device结构体 +----------------- + +在 /dev 目录下的实际设备节点根据 video_device 结构体(v4l2-dev.h) +创建。此结构体既可以动态分配也可以嵌入到一个更大的结构体中。 + +动态分配方法如下: + + struct video_device *vdev = video_device_alloc(); + + if (vdev == NULL) + return -ENOMEM; + + vdev->release = video_device_release; + +如果将其嵌入到一个大结构体中,则必须自己实现 release()回调。 + + struct video_device *vdev = &my_vdev->vdev; + + vdev->release = my_vdev_release; + +release()回调必须被设置,且在最后一个 video_device 用户退出之后 +被调用。 + +默认的 video_device_release()回调只是调用 kfree 来释放之前分配的 +内存。 + +你应该设置这些域: + +- v4l2_dev: 设置为 v4l2_device 父设备。 + +- name: 设置为唯一的描述性设备名。 + +- fops: 设置为已有的 v4l2_file_operations 结构体。 + +- ioctl_ops: 如果你使用v4l2_ioctl_ops 来简化 ioctl 的维护 + (强烈建议使用,且将来可能变为强制性的!),然后设置你自己的 + v4l2_ioctl_ops 结构体. + +- lock: 如果你要在驱动中实现所有的锁操作,则设为 NULL 。否则 + 就要设置一个指向 struct mutex_lock 结构体的指针,这个锁将 + 在 unlocked_ioctl 文件操作被调用前由内核获得,并在调用返回后 + 释放。详见下一节。 + +- prio: 保持对优先级的跟踪。用于实现 VIDIOC_G/S_PRIORITY。如果 + 设置为 NULL,则会使用 v4l2_device 中的 v4l2_prio_state 结构体。 + 如果要对每个设备节点(组)实现独立的优先级,可以将其指向自己 + 实现的 v4l2_prio_state 结构体。 + +- parent: 仅在使用 NULL 作为父设备结构体参数注册 v4l2_device 时 + 设置此参数。只有在一个硬件设备包含多一个 PCI 设备,共享同一个 + v4l2_device 核心时才会发生。 + + cx88 驱动就是一个例子:一个 v4l2_device 结构体核心,被一个裸的 + 视频 PCI 设备(cx8800)和一个 MPEG PCI 设备(cx8802)共用。由于 + v4l2_device 无法与特定的 PCI 设备关联,所有没有设置父设备。但当 + video_device 配置后,就知道使用哪个父 PCI 设备了。 + +- flags:可选。如果你要让框架处理设置 VIDIOC_G/S_PRIORITY ioctls, + 请设置 V4L2_FL_USE_FH_PRIO。这要求你使用 v4l2_fh 结构体。 + 一旦所有驱动使用了核心的优先级处理,最终这个标志将消失。但现在它 + 必须被显式设置。 + +如果你使用 v4l2_ioctl_ops,则应该在 v4l2_file_operations 结构体中 +设置 .unlocked_ioctl 指向 video_ioctl2。 + +请勿使用 .ioctl!它已被废弃,今后将消失。 + +某些情况下你要告诉核心:你在 v4l2_ioctl_ops 指定的某个函数应被忽略。 +你可以在 video_device_register 被调用前通过以下函数标记这个 ioctls。 + +void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd); + +基于外部因素(例如某个板卡已被使用),在不创建新结构体的情况下,你想 +要关闭 v4l2_ioctl_ops 中某个特性往往需要这个机制。 + +v4l2_file_operations 结构体是 file_operations 的一个子集。其主要 +区别在于:因 inode 参数从未被使用,它将被忽略。 + +如果需要与媒体框架整合,你必须通过调用 media_entity_init() 初始化 +嵌入在 video_device 结构体中的 media_entity(entity 域)结构体: + + struct media_pad *pad = &my_vdev->pad; + int err; + + err = media_entity_init(&vdev->entity, 1, pad, 0); + +pads 数组必须预先初始化。没有必要手动设置 media_entity 的 type 和 +name 域。 + +当(任何)子设备节点被打开/关闭,对 entity 的引用将被自动获取/释放。 + +v4l2_file_operations 与锁 +-------------------------- + +你可以在 video_device 结构体中设置一个指向 mutex_lock 的指针。通常 +这既可是一个顶层互斥锁也可为设备节点自身的互斥锁。默认情况下,此锁 +用于 unlocked_ioctl,但为了使用 ioctls 你通过以下函数可禁用锁定: + + void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd); + +例如: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF); + +你必须在注册 video_device 前调用这个函数。 + +特别是对于 USB 驱动程序,某些命令(如设置控制)需要很长的时间,可能 +需要自行为缓冲区队列的 ioctls 实现锁定。 + +如果你需要更细粒度的锁,你必须设置 mutex_lock 为 NULL,并完全自己实现 +锁机制。 + +这完全由驱动开发者决定使用何种方法。然而,如果你的驱动存在长延时操作 +(例如,改变 USB 摄像头的曝光时间可能需要较长时间),而你又想让用户 +在等待长延时操作完成期间做其他的事,则你最好自己实现锁机制。 + +如果指定一个锁,则所有 ioctl 操作将在这个锁的作用下串行执行。如果你 +使用 videobuf,则必须将同一个锁传递给 videobuf 队列初始化函数;如 +videobuf 必须等待一帧的到达,则可临时解锁并在这之后重新上锁。如果驱动 +也在代码执行期间等待,则可做同样的工作(临时解锁,再上锁)让其他进程 +可以在第一个进程阻塞时访问设备节点。 + +在使用 videobuf2 的情况下,必须实现 wait_prepare 和 wait_finish 回调 +在适当的时候解锁/加锁。进一步来说,如果你在 video_device 结构体中使用 +锁,则必须在 wait_prepare 和 wait_finish 中对这个互斥锁进行解锁/加锁。 + +热插拔的断开实现也必须在调用 v4l2_device_disconnect 前获得锁。 + +video_device注册 +--------------- + +接下来你需要注册视频设备:这会为你创建一个字符设备。 + + err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (err) { + video_device_release(vdev); /* or kfree(my_vdev); */ + return err; + } + +如果 v4l2_device 父设备的 mdev 域为非 NULL 值,视频设备实体将自动 +注册为媒体设备。 + +注册哪种设备是根据类型(type)参数。存在以下类型: + +VFL_TYPE_GRABBER: 用于视频输入/输出设备的 videoX +VFL_TYPE_VBI: 用于垂直消隐数据的 vbiX (例如,隐藏式字幕,图文电视) +VFL_TYPE_RADIO: 用于广播调谐器的 radioX + +最后一个参数让你确定一个所控制设备的设备节点号数量(例如 videoX 中的 X)。 +通常你可以传入-1,让 v4l2 框架自己选择第一个空闲的编号。但是有时用户 +需要选择一个特定的节点号。驱动允许用户通过驱动模块参数选择一个特定的 +设备节点号是很普遍的。这个编号将会传递给这个函数,且 video_register_device +将会试图选择这个设备节点号。如果这个编号被占用,下一个空闲的设备节点 +编号将被选中,并向内核日志中发送一个警告信息。 + +另一个使用场景是当驱动创建多个设备时。这种情况下,对不同的视频设备在 +编号上使用不同的范围是很有用的。例如,视频捕获设备从 0 开始,视频 +输出设备从 16 开始。所以你可以使用最后一个参数来指定设备节点号最小值, +而 v4l2 框架会试图选择第一个的空闲编号(等于或大于你提供的编号)。 +如果失败,则它会就选择第一个空闲的编号。 + +由于这种情况下,你会忽略无法选择特定设备节点号的警告,则可调用 +video_register_device_no_warn() 函数避免警告信息的产生。 + +只要设备节点被创建,一些属性也会同时创建。在 /sys/class/video4linux +目录中你会找到这些设备。例如进入其中的 video0 目录,你会看到‘name’和 +‘index’属性。‘name’属性值就是 video_device 结构体中的‘name’域。 + +‘index’属性值就是设备节点的索引值:每次调用 video_register_device(), +索引值都递增 1 。第一个视频设备节点总是从索引值 0 开始。 + +用户可以设置 udev 规则,利用索引属性生成花哨的设备名(例如:用‘mpegX’ +代表 MPEG 视频捕获设备节点)。 + +在设备成功注册后,就可以使用这些域: + +- vfl_type: 传递给 video_register_device 的设备类型。 +- minor: 已指派的次设备号。 +- num: 设备节点编号 (例如 videoX 中的 X)。 +- index: 设备索引号。 + +如果注册失败,你必须调用 video_device_release() 来释放已分配的 +video_device 结构体;如果 video_device 是嵌入在自己创建的结构体中, +你也必须释放它。vdev->release() 回调不会在注册失败之后被调用, +你也不应试图在注册失败后注销设备。 + + +video_device 注销 +---------------- + +当视频设备节点已被移除,不论是卸载驱动还是USB设备断开,你都应注销 +它们: + + video_unregister_device(vdev); + +这个操作将从 sysfs 中移除设备节点(导致 udev 将其从 /dev 中移除)。 + +video_unregister_device() 返回之后,就无法完成打开操作。尽管如此, +USB 设备的情况则不同,某些应用程序可能依然打开着其中一个已注销设备 +节点。所以在注销之后,所有文件操作(当然除了 release )也应返回错误值。 + +当最后一个视频设备节点的用户退出,则 vdev->release() 回调会被调用, +并且你可以做最后的清理操作。 + +不要忘记清理与视频设备相关的媒体入口(如果被初始化过): + + media_entity_cleanup(&vdev->entity); + +这可以在 release 回调中完成。 + + +video_device 辅助函数 +--------------------- + +一些有用的辅助函数如下: + +- file/video_device 私有数据 + +你可以用以下函数在 video_device 结构体中设置/获取驱动私有数据: + +void *video_get_drvdata(struct video_device *vdev); +void video_set_drvdata(struct video_device *vdev, void *data); + +注意:在调用 video_register_device() 前执行 video_set_drvdata() +是安全的。 + +而以下函数: + +struct video_device *video_devdata(struct file *file); + +返回 file 结构体中拥有的的 video_device 指针。 + +video_drvdata 辅助函数结合了 video_get_drvdata 和 video_devdata +的功能: + +void *video_drvdata(struct file *file); + +你可以使用如下代码从 video_device 结构体中获取 v4l2_device 结构体 +指针: + +struct v4l2_device *v4l2_dev = vdev->v4l2_dev; + +- 设备节点名 + +video_device 设备节点在内核中的名称可以通过以下函数获得 + +const char *video_device_node_name(struct video_device *vdev); + +这个名字被用户空间工具(例如 udev)作为提示信息使用。应尽可能使用 +此功能,而非访问 video_device::num 和 video_device::minor 域。 + + +视频缓冲辅助函数 +--------------- + +v4l2 核心 API 提供了一个处理视频缓冲的标准方法(称为“videobuf”)。 +这些方法使驱动可以通过统一的方式实现 read()、mmap() 和 overlay()。 +目前在设备上支持视频缓冲的方法有分散/聚集 DMA(videobuf-dma-sg)、 +线性 DMA(videobuf-dma-contig)以及大多用于 USB 设备的用 vmalloc +分配的缓冲(videobuf-vmalloc)。 + +请参阅 Documentation/video4linux/videobuf,以获得更多关于 videobuf +层的使用信息。 + +v4l2_fh 结构体 +------------- + +v4l2_fh 结构体提供一个保存用于 V4L2 框架的文件句柄特定数据的简单方法。 +如果 video_device 的 flag 设置了 V4L2_FL_USE_FH_PRIO 标志,新驱动 +必须使用 v4l2_fh 结构体,因为它也用于实现优先级处理(VIDIOC_G/S_PRIORITY)。 + +v4l2_fh 的用户(位于 V4l2 框架中,并非驱动)可通过测试 +video_device->flags 中的 V4L2_FL_USES_V4L2_FH 位得知驱动是否使用 +v4l2_fh 作为他的 file->private_data 指针。这个位会在调用 v4l2_fh_init() +时被设置。 + +v4l2_fh 结构体作为驱动自身文件句柄结构体的一部分被分配,且驱动在 +其打开函数中将 file->private_data 指向它。 + +在许多情况下,v4l2_fh 结构体会嵌入到一个更大的结构体中。这钟情况下, +应该在 open() 中调用 v4l2_fh_init+v4l2_fh_add,并在 release() 中 +调用 v4l2_fh_del+v4l2_fh_exit。 + +驱动可以通过使用 container_of 宏提取他们自己的文件句柄结构体。例如: + +struct my_fh { + int blah; + struct v4l2_fh fh; +}; + +... + +int my_open(struct file *file) +{ + struct my_fh *my_fh; + struct video_device *vfd; + int ret; + + ... + + my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL); + + ... + + v4l2_fh_init(&my_fh->fh, vfd); + + ... + + file->private_data = &my_fh->fh; + v4l2_fh_add(&my_fh->fh); + return 0; +} + +int my_release(struct file *file) +{ + struct v4l2_fh *fh = file->private_data; + struct my_fh *my_fh = container_of(fh, struct my_fh, fh); + + ... + v4l2_fh_del(&my_fh->fh); + v4l2_fh_exit(&my_fh->fh); + kfree(my_fh); + return 0; +} + +以下是 v4l2_fh 函数使用的简介: + +void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) + + 初始化文件句柄。这*必须*在驱动的 v4l2_file_operations->open() + 函数中执行。 + +void v4l2_fh_add(struct v4l2_fh *fh) + + 添加一个 v4l2_fh 到 video_device 文件句柄列表。一旦文件句柄 + 初始化完成就必须调用。 + +void v4l2_fh_del(struct v4l2_fh *fh) + + 从 video_device() 中解除文件句柄的关联。文件句柄的退出函数也 + 将被调用。 + +void v4l2_fh_exit(struct v4l2_fh *fh) + + 清理文件句柄。在清理完 v4l2_fh 后,相关内存会被释放。 + + +如果 v4l2_fh 不是嵌入在其他结构体中的,则可以用这些辅助函数: + +int v4l2_fh_open(struct file *filp) + + 分配一个 v4l2_fh 结构体空间,初始化并将其添加到 file 结构体相关的 + video_device 结构体中。 + +int v4l2_fh_release(struct file *filp) + + 从 file 结构体相关的 video_device 结构体中删除 v4l2_fh ,清理 + v4l2_fh 并释放空间。 + +这两个函数可以插入到 v4l2_file_operation 的 open() 和 release() +操作中。 + + +某些驱动需要在第一个文件句柄打开和最后一个文件句柄关闭的时候做些 +工作。所以加入了两个辅助函数以检查 v4l2_fh 结构体是否是相关设备 +节点打开的唯一文件句柄。 + +int v4l2_fh_is_singular(struct v4l2_fh *fh) + + 如果此文件句柄是唯一打开的文件句柄,则返回 1 ,否则返回 0 。 + +int v4l2_fh_is_singular_file(struct file *filp) + + 功能相同,但通过 filp->private_data 调用 v4l2_fh_is_singular。 + + +V4L2 事件机制 +----------- + +V4L2 事件机制提供了一个通用的方法将事件传递到用户空间。驱动必须使用 +v4l2_fh 才能支持 V4L2 事件机制。 + + +事件通过一个类型和选择 ID 来定义。ID 对应一个 V4L2 对象,例如 +一个控制 ID。如果未使用,则 ID 为 0。 + +当用户订阅一个事件,驱动会为此分配一些 kevent 结构体。所以每个 +事件组(类型、ID)都会有自己的一套 kevent 结构体。这保证了如果 +一个驱动短时间内产生了许多同类事件,不会覆盖其他类型的事件。 + +但如果你收到的事件数量大于同类事件 kevent 的保存数量,则最早的 +事件将被丢弃,并加入新事件。 + +此外,v4l2_subscribed_event 结构体内部有可供驱动设置的 merge() 和 +replace() 回调,这些回调会在新事件产生且没有多余空间的时候被调用。 +replace() 回调让你可以将早期事件的净荷替换为新事件的净荷,将早期 +净荷的相关数据合并到替换进来的新净荷中。当该类型的事件仅分配了一个 +kevent 结构体时,它将被调用。merge() 回调让你可以合并最早的事件净荷 +到在它之后的那个事件净荷中。当该类型的事件分配了两个或更多 kevent +结构体时,它将被调用。 + +这种方法不会有状态信息丢失,只会导致中间步骤信息丢失。 + + +关于 replace/merge 回调的一个不错的例子在 v4l2-event.c 中:用于 +控制事件的 ctrls_replace() 和 ctrls_merge() 回调。 + +注意:这些回调可以在中断上下文中调用,所以它们必须尽快完成并退出。 + +有用的函数: + +void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev) + + 将事件加入视频设备的队列。驱动仅负责填充 type 和 data 域。 + 其他域由 V4L2 填充。 + +int v4l2_event_subscribe(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub, unsigned elems, + const struct v4l2_subscribed_event_ops *ops) + + video_device->ioctl_ops->vidioc_subscribe_event 必须检测驱动能 + 产生特定 id 的事件。然后调用 v4l2_event_subscribe() 来订阅该事件。 + + elems 参数是该事件的队列大小。若为 0,V4L2 框架将会(根据事件类型) + 填充默认值。 + + ops 参数允许驱动指定一系列回调: + * add: 当添加一个新监听者时调用(重复订阅同一个事件,此回调 + 仅被执行一次)。 + * del: 当一个监听者停止监听时调用。 + * replace: 用‘新’事件替换‘早期‘事件。 + * merge: 将‘早期‘事件合并到‘新’事件中。 + 这四个调用都是可选的,如果不想指定任何回调,则 ops 可为 NULL。 + +int v4l2_event_unsubscribe(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) + + v4l2_ioctl_ops 结构体中的 vidioc_unsubscribe_event 回调函数。 + 驱动程序可以直接使用 v4l2_event_unsubscribe() 实现退订事件过程。 + + 特殊的 V4L2_EVENT_ALL 类型,可用于退订所有事件。驱动可能在特殊 + 情况下需要做此操作。 + +int v4l2_event_pending(struct v4l2_fh *fh) + + 返回未决事件的数量。有助于实现轮询(poll)操作。 + +事件通过 poll 系统调用传递到用户空间。驱动可用 +v4l2_fh->wait (wait_queue_head_t 类型)作为参数调用 poll_wait()。 + +事件分为标准事件和私有事件。新的标准事件必须使用可用的最小事件类型 +编号。驱动必须从他们本类型的编号起始处分配事件。类型的编号起始为 +V4L2_EVENT_PRIVATE_START + n * 1000 ,其中 n 为可用最小编号。每个 +类型中的第一个事件类型编号是为以后的使用保留的,所以第一个可用事件 +类型编号是‘class base + 1’。 + +V4L2 事件机制的使用实例可以在 OMAP3 ISP 的驱动 +(drivers/media/video/omap3isp)中找到。 -- cgit v1.2.3-70-g09d2 From f28d5a01562d38332987069178305e88b03d64f6 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Thu, 23 Aug 2012 09:11:43 +0900 Subject: extcon: fix typos in sys-class-extcon Signed-off-by: Peter Meerwald Signed-off-by: Chanwoo Choi Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-extcon | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-extcon b/Documentation/ABI/testing/sysfs-class-extcon index 20ab361bd8c..57a72623291 100644 --- a/Documentation/ABI/testing/sysfs-class-extcon +++ b/Documentation/ABI/testing/sysfs-class-extcon @@ -13,7 +13,7 @@ Description: accessory cables have such capability. For example, the 30-pin port of Nuri board (/arch/arm/mach-exynos) may have both HDMI and Charger attached, or analog audio, - video, and USB cables attached simulteneously. + video, and USB cables attached simultaneously. If there are cables mutually exclusive with each other, such binary relations may be expressed with extcon_dev's @@ -35,7 +35,7 @@ Description: The /sys/class/extcon/.../state shows and stores the cable attach/detach information of the corresponding extcon object. If the extcon object has an optional callback "show_state" - defined, the showing function is overriden with the optional + defined, the showing function is overridden with the optional callback. If the default callback for showing function is used, the @@ -46,19 +46,19 @@ Description: TA=1 EAR_JACK=0 # - In this example, the extcon device have USB_OTG and TA + In this example, the extcon device has USB_OTG and TA cables attached and HDMI and EAR_JACK cables detached. In order to update the state of an extcon device, enter a hex - state number starting with 0x. - echo 0xHEX > state + state number starting with 0x: + # echo 0xHEX > state - This updates the whole state of the extcon dev. + This updates the whole state of the extcon device. Inputs of all the methods are required to meet the - mutually_exclusive contidions if they exist. + mutually_exclusive conditions if they exist. It is recommended to use this "global" state interface if - you need to enter the value atomically. The later state + you need to set the value atomically. The later state interface associated with each cable cannot update multiple cable states of an extcon device simultaneously. @@ -73,7 +73,7 @@ What: /sys/class/extcon/.../cable.x/state Date: February 2012 Contact: MyungJoo Ham Description: - The /sys/class/extcon/.../cable.x/name shows and stores the + The /sys/class/extcon/.../cable.x/state shows and stores the state of cable "x" (integer between 0 and 31) of an extcon device. The state value is either 0 (detached) or 1 (attached). @@ -83,8 +83,8 @@ Date: December 2011 Contact: MyungJoo Ham Description: Shows the relations of mutually exclusiveness. For example, - if the mutually_exclusive array of extcon_dev is - {0x3, 0x5, 0xC, 0x0}, the, the output is: + if the mutually_exclusive array of extcon device is + {0x3, 0x5, 0xC, 0x0}, then the output is: # ls mutually_exclusive/ 0x3 0x5 -- cgit v1.2.3-70-g09d2 From 0bf5a8be4723fd5f243d9d1ed8e6eb9d81f31cf2 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Wed, 22 Aug 2012 12:00:39 +0530 Subject: lis3lv02d: Add STMicroelectronics lis331dlh digital accelerometer This patch adds support for lis331dlh digital accelerometer to the lis3lv02d driver family. Adds ID field for detecting the lis331dlh module, based on this ID field lis3lv02d driver will export the lis331dlh module functionality. Signed-off-by: AnilKumar Ch Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/lis3lv02d | 3 ++- drivers/misc/lis3lv02d/lis3lv02d.c | 42 +++++++++++++++++++++++++++++++- drivers/misc/lis3lv02d/lis3lv02d.h | 44 +++++++++++++++++++++++++++++----- drivers/misc/lis3lv02d/lis3lv02d_i2c.c | 7 +++++- 4 files changed, 87 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/misc-devices/lis3lv02d b/Documentation/misc-devices/lis3lv02d index f1a4ec840f8..af815b9ba41 100644 --- a/Documentation/misc-devices/lis3lv02d +++ b/Documentation/misc-devices/lis3lv02d @@ -4,7 +4,8 @@ Kernel driver lis3lv02d Supported chips: * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision) - * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) + * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and + LIS331DLH (16 bits) Authors: Yan Burman diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index a981e2a42f9..9d37c576d52 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -80,6 +80,14 @@ #define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024) #define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY) +/* + * LIS3331DLH spec says 1LSBs corresponds 4G/1024 -> 1LSB is 1000/1024 mG. + * Sensitivity values for +/-2G, outdata in 12 bits for +/-2G scale. so 4 + * bits adjustment is required + */ +#define LIS3DLH_SENSITIVITY_2G ((LIS3_ACCURACY * 1000) / 1024) +#define SHIFT_ADJ_2G 4 + #define LIS3_DEFAULT_FUZZ_12B 3 #define LIS3_DEFAULT_FLAT_12B 3 #define LIS3_DEFAULT_FUZZ_8B 1 @@ -135,6 +143,19 @@ static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg) return (s16)((hi << 8) | lo); } +/* 12bits for 2G range, 13 bits for 4G range and 14 bits for 8G range */ +static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg) +{ + u8 lo, hi; + int v; + + lis3->read(lis3, reg - 1, &lo); + lis3->read(lis3, reg, &hi); + v = (int) ((hi << 8) | lo); + + return (s16) v >> lis3->shift_adj; +} + /** * lis3lv02d_get_axis - For the given axis, give the value converted * @axis: 1,2,3 - can also be negative @@ -195,6 +216,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) static int lis3_12_rates[4] = {40, 160, 640, 2560}; static int lis3_8_rates[2] = {100, 400}; static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; +static int lis3_3dlh_rates[4] = {50, 100, 400, 1000}; /* ODR is Output Data Rate */ static int lis3lv02d_get_odr(struct lis3lv02d *lis3) @@ -267,7 +289,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); } - if (lis3->whoami == WAI_3DC) { + if ((lis3->whoami == WAI_3DC) || (lis3->whoami == WAI_3DLH)) { ctlreg = CTRL_REG4; selftest = CTRL4_ST0; } else { @@ -398,9 +420,17 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3) lis3->read(lis3, CTRL_REG2, ®); if (lis3->whoami == WAI_12B) reg |= CTRL2_BDU | CTRL2_BOOT; + else if (lis3->whoami == WAI_3DLH) + reg |= CTRL2_BOOT_3DLH; else reg |= CTRL2_BOOT_8B; lis3->write(lis3, CTRL_REG2, reg); + + if (lis3->whoami == WAI_3DLH) { + lis3->read(lis3, CTRL_REG4, ®); + reg |= CTRL4_BDU; + lis3->write(lis3, CTRL_REG4, reg); + } } err = lis3lv02d_get_pwron_wait(lis3); @@ -956,6 +986,16 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3) lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; lis3->scale = LIS3_SENSITIVITY_8B; break; + case WAI_3DLH: + pr_info("16 bits 3DLH sensor found\n"); + lis3->read_data = lis3lv02d_read_16; + lis3->mdps_max_val = 2048; /* 12 bits for 2G */ + lis3->shift_adj = SHIFT_ADJ_2G; + lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; + lis3->odrs = lis3_3dlh_rates; + lis3->odr_mask = CTRL1_DR0 | CTRL1_DR1; + lis3->scale = LIS3DLH_SENSITIVITY_2G; + break; default: pr_err("unknown sensor type 0x%X\n", lis3->whoami); return -EINVAL; diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h index 2b1482ad3f1..c1a545e136a 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.h +++ b/drivers/misc/lis3lv02d/lis3lv02d.h @@ -26,12 +26,12 @@ /* * This driver tries to support the "digital" accelerometer chips from * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL, - * LIS35DE, or LIS202DL. They are very similar in terms of programming, with - * almost the same registers. In addition to differing on physical properties, - * they differ on the number of axes (2/3), precision (8/12 bits), and special - * features (freefall detection, click...). Unfortunately, not all the - * differences can be probed via a register. - * They can be connected either via I²C or SPI. + * LIS331DLH, LIS35DE, or LIS202DL. They are very similar in terms of + * programming, with almost the same registers. In addition to differing + * on physical properties, they differ on the number of axes (2/3), + * precision (8/12 bits), and special features (freefall detection, + * click...). Unfortunately, not all the differences can be probed via + * a register. They can be connected either via I²C or SPI. */ #include @@ -96,12 +96,22 @@ enum lis3lv02d_reg { }; enum lis3_who_am_i { + WAI_3DLH = 0x32, /* 16 bits: LIS331DLH */ WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */ WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */ WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */ WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ }; +enum lis3_type { + LIS3DC, + HP3DC, + LIS3LV02D, + LIS2302D, + LIS331DLF, + LIS331DLH, +}; + enum lis3lv02d_ctrl1_12b { CTRL1_Xen = 0x01, CTRL1_Yen = 0x02, @@ -129,6 +139,27 @@ enum lis3lv02d_ctrl1_3dc { CTRL1_ODR3 = 0x80, }; +enum lis331dlh_ctrl1 { + CTRL1_DR0 = 0x08, + CTRL1_DR1 = 0x10, + CTRL1_PM0 = 0x20, + CTRL1_PM1 = 0x40, + CTRL1_PM2 = 0x80, +}; + +enum lis331dlh_ctrl2 { + CTRL2_HPEN1 = 0x04, + CTRL2_HPEN2 = 0x08, + CTRL2_FDS_3DLH = 0x10, + CTRL2_BOOT_3DLH = 0x80, +}; + +enum lis331dlh_ctrl4 { + CTRL4_STSIGN = 0x08, + CTRL4_BLE = 0x40, + CTRL4_BDU = 0x80, +}; + enum lis3lv02d_ctrl2 { CTRL2_DAS = 0x01, CTRL2_SIM = 0x02, @@ -279,6 +310,7 @@ struct lis3lv02d { int data_ready_count[2]; atomic_t wake_thread; unsigned char irq_cfg; + unsigned int shift_adj; struct lis3lv02d_platform_data *pdata; /* for passing board config */ struct mutex mutex; /* Serialize poll and selftest */ diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index e8c0019da97..15255eb8ac8 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -90,7 +90,11 @@ static int lis3_i2c_init(struct lis3lv02d *lis3) if (ret < 0) return ret; - reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + if (lis3->whoami == WAI_3DLH) + reg |= CTRL1_PM0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + else + reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + return lis3->write(lis3, CTRL_REG1, reg); } @@ -232,6 +236,7 @@ static int lis3_i2c_runtime_resume(struct device *dev) static const struct i2c_device_id lis3lv02d_id[] = { {"lis3lv02d", 0 }, + {"lis331dlh", LIS331DLH}, {} }; -- cgit v1.2.3-70-g09d2 From d6ae0d578d24303941c1424b049d2cae28277666 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 22 Aug 2012 12:03:57 -0700 Subject: misc/at25, dt: Improve at25 SPI eeprom device tree bindings. Commit 002176db (misc: at25: Parse dt settings) added device tree bindings the differ significantly in style from the I2C EEPROM bindings and don't seem well vetted. Here I deprecate (but still support) the "at25,*" properties, and add what I hope is a better alternative. These new bindings also happen to be deployed in the field and were previously submitted for consideration here: https://lists.ozlabs.org/pipermail/devicetree-discuss/2012-May/015556.html The advantages of the new bindings are that they are similar to the I2C EEPROMs and they don't conflate read-only and the address width modes in a binary encoded blob. Signed-off-by: David Daney Cc: Alexandre Pereira da Silva Cc: Greg Kroah-Hartman Cc: Michael Hennerich Cc: Axel Lin Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/misc/at25.txt | 34 +++++++--- drivers/misc/eeprom/at25.c | 83 +++++++++++++++++-------- 2 files changed, 82 insertions(+), 35 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/misc/at25.txt b/Documentation/devicetree/bindings/misc/at25.txt index ab3c327929d..1d3447165c3 100644 --- a/Documentation/devicetree/bindings/misc/at25.txt +++ b/Documentation/devicetree/bindings/misc/at25.txt @@ -1,21 +1,35 @@ -Atmel AT25 eeprom +EEPROMs (SPI) compatible with Atmel at25. Required properties: - compatible : "atmel,at25". - reg : chip select number - spi-max-frequency : max spi frequency to use +- pagesize : size of the eeprom page +- size : total eeprom size in bytes +- address-width : number of address bits (one of 8, 16, or 24) +Optional properties: +- spi-cpha : SPI shifted clock phase, as per spi-bus bindings. +- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings. +- read-only : this parameter-less property disables writes to the eeprom + +Obsolete legacy properties are can be used in place of "size", "pagesize", +"address-width", and "read-only": - at25,byte-len : total eeprom size in bytes - at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h - at25,page-size : size of the eeprom page -Examples: -at25@0 { - compatible = "atmel,at25"; - reg = <0> - spi-max-frequency = <5000000>; +Additional compatible properties are also allowed. + +Example: + at25@0 { + compatible = "atmel,at25", "st,m95256"; + reg = <0> + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; - at25,byte-len = <0x8000>; - at25,addr-mode = <2>; - at25,page-size = <64>; -}; + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 25003d6ceb5..4ed93dd5411 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -302,6 +302,61 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf, /*-------------------------------------------------------------------------*/ +static int at25_np_to_chip(struct device *dev, + struct device_node *np, + struct spi_eeprom *chip) +{ + u32 val; + + memset(chip, 0, sizeof(*chip)); + strncpy(chip->name, np->name, sizeof(chip->name)); + + if (of_property_read_u32(np, "size", &val) == 0 || + of_property_read_u32(np, "at25,byte-len", &val) == 0) { + chip->byte_len = val; + } else { + dev_err(dev, "Error: missing \"size\" property\n"); + return -ENODEV; + } + + if (of_property_read_u32(np, "pagesize", &val) == 0 || + of_property_read_u32(np, "at25,page-size", &val) == 0) { + chip->page_size = (u16)val; + } else { + dev_err(dev, "Error: missing \"pagesize\" property\n"); + return -ENODEV; + } + + if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) { + chip->flags = (u16)val; + } else { + if (of_property_read_u32(np, "address-width", &val)) { + dev_err(dev, + "Error: missing \"address-width\" property\n"); + return -ENODEV; + } + switch (val) { + case 8: + chip->flags |= EE_ADDR1; + break; + case 16: + chip->flags |= EE_ADDR2; + break; + case 24: + chip->flags |= EE_ADDR3; + break; + default: + dev_err(dev, + "Error: bad \"address-width\" property: %u\n", + val); + return -ENODEV; + } + if (of_find_property(np, "read-only", NULL)) + chip->flags |= EE_READONLY; + } + return 0; +} + static int at25_probe(struct spi_device *spi) { struct at25_data *at25 = NULL; @@ -314,33 +369,11 @@ static int at25_probe(struct spi_device *spi) /* Chip description */ if (!spi->dev.platform_data) { if (np) { - u32 val; - - memset(&chip, 0, sizeof(chip)); - strncpy(chip.name, np->name, 10); - - err = of_property_read_u32(np, "at25,byte-len", &val); - if (err) { - dev_dbg(&spi->dev, "invalid chip dt description\n"); - goto fail; - } - chip.byte_len = val; - - err = of_property_read_u32(np, "at25,addr-mode", &val); - if (err) { - dev_dbg(&spi->dev, "invalid chip dt description\n"); - goto fail; - } - chip.flags = (u16)val; - - err = of_property_read_u32(np, "at25,page-size", &val); - if (err) { - dev_dbg(&spi->dev, "invalid chip dt description\n"); + err = at25_np_to_chip(&spi->dev, np, &chip); + if (err) goto fail; - } - chip.page_size = (u16)val; } else { - dev_dbg(&spi->dev, "no chip description\n"); + dev_err(&spi->dev, "Error: no chip description\n"); err = -ENODEV; goto fail; } -- cgit v1.2.3-70-g09d2 From 38ab18caa0ad9c844ba60f9618c5de6d6954da3e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Sep 2012 11:04:36 +0200 Subject: spi: spi-gpio: Add DT bindings This patch adds DT bindings to the spi-gpio driver and some documentation about how to use it. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-gpio.txt | 29 +++++++ drivers/spi/spi-gpio.c | 99 +++++++++++++++++++++- 2 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/spi-gpio.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt new file mode 100644 index 00000000000..8a824be1575 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-gpio.txt @@ -0,0 +1,29 @@ +SPI-GPIO devicetree bindings + +Required properties: + + - compatible: should be set to "spi-gpio" + - #address-cells: should be set to <0x1> + - ranges + - gpio-sck: GPIO spec for the SCK line to use + - gpio-miso: GPIO spec for the MISO line to use + - gpio-mosi: GPIO spec for the MOSI line to use + - cs-gpios: GPIOs to use for chipselect lines + - num-chipselects: number of chipselect lines + +Example: + + spi { + compatible = "spi-gpio"; + #address-cells = <0x1>; + ranges; + + gpio-sck = <&gpio 95 0>; + gpio-miso = <&gpio 98 0>; + gpio-mosi = <&gpio 97 0>; + cs-gpios = <&gpio 125 0>; + num-chipselects = <1>; + + /* clients */ + }; + diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index ff7263ce12c..aed16159584 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -232,13 +234,27 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) static int spi_gpio_setup(struct spi_device *spi) { - unsigned int cs = (unsigned int) spi->controller_data; + unsigned int cs; int status = 0; struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + struct device_node *np = spi->master->dev.of_node; if (spi->bits_per_word > 32) return -EINVAL; + if (np) { + /* + * In DT environments, the CS GPIOs have already been + * initialized from the "cs-gpios" property of the node. + */ + cs = spi_gpio->cs_gpios[spi->chip_select]; + } else { + /* + * ... otherwise, take it from spi->controller_data + */ + cs = (unsigned int) spi->controller_data; + } + if (!spi->controller_state) { if (cs != SPI_GPIO_NO_CHIPSELECT) { status = gpio_request(cs, dev_name(&spi->dev)); @@ -250,6 +266,7 @@ static int spi_gpio_setup(struct spi_device *spi) } if (!status) { status = spi_bitbang_setup(spi); + /* in case it was initialized from static board data */ spi_gpio->cs_gpios[spi->chip_select] = cs; } @@ -326,6 +343,55 @@ done: return value; } +#ifdef CONFIG_OF +static struct of_device_id spi_gpio_dt_ids[] = { + { .compatible = "spi-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); + +static int spi_gpio_probe_dt(struct platform_device *pdev) +{ + int ret; + u32 tmp; + struct spi_gpio_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(spi_gpio_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->sck = of_get_named_gpio(np, "gpio-sck", 0); + pdata->miso = of_get_named_gpio(np, "gpio-miso", 0); + pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0); + + ret = of_property_read_u32(np, "num-chipselects", &tmp); + if (ret < 0) { + dev_err(&pdev->dev, "num-chipselects property not found\n"); + goto error_free; + } + + pdata->num_chipselect = tmp; + pdev->dev.platform_data = pdata; + + return 1; + +error_free: + devm_kfree(&pdev->dev, pdata); + return ret; +} +#else +static inline int spi_probe_dt(struct platform_device *) +{ + return 0; +} +#endif + static int __devinit spi_gpio_probe(struct platform_device *pdev) { int status; @@ -333,6 +399,13 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev) struct spi_gpio *spi_gpio; struct spi_gpio_platform_data *pdata; u16 master_flags = 0; + bool use_of = 0; + + status = spi_gpio_probe_dt(pdev); + if (status < 0) + return status; + if (status > 0) + use_of = 1; pdata = pdev->dev.platform_data; #ifdef GENERIC_BITBANG @@ -362,6 +435,23 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev) master->num_chipselect = SPI_N_CHIPSEL; master->setup = spi_gpio_setup; master->cleanup = spi_gpio_cleanup; +#ifdef CONFIG_OF + master->dev.of_node = pdev->dev.of_node; + + if (use_of) { + int i; + struct device_node *np = pdev->dev.of_node; + + /* + * In DT environments, take the CS GPIO from the "cs-gpios" + * property of the node. + */ + + for (i = 0; i < SPI_N_CHIPSEL; i++) + spi_gpio->cs_gpios[i] = + of_get_named_gpio(np, "cs-gpios", i); + } +#endif spi_gpio->bitbang.master = spi_master_get(master); spi_gpio->bitbang.chipselect = spi_gpio_chipselect; @@ -422,8 +512,11 @@ static int __devexit spi_gpio_remove(struct platform_device *pdev) MODULE_ALIAS("platform:" DRIVER_NAME); static struct platform_driver spi_gpio_driver = { - .driver.name = DRIVER_NAME, - .driver.owner = THIS_MODULE, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(spi_gpio_dt_ids), + }, .probe = spi_gpio_probe, .remove = __devexit_p(spi_gpio_remove), }; -- cgit v1.2.3-70-g09d2 From e64d07a2dae569fc3c938adac777562a1d6f151e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 22 Aug 2012 22:38:35 +0200 Subject: spi/mxs: Make the SPI block clock speed configurable via DT Add "clock-frequency" property, which allows configuring the SPI block's base speed. Signed-off-by: Marek Vasut Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mxs-spi.txt | 4 ++++ drivers/spi/spi-mxs.c | 21 +++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/mxs-spi.txt b/Documentation/devicetree/bindings/spi/mxs-spi.txt index c36296f5ad2..e2e13957c2a 100644 --- a/Documentation/devicetree/bindings/spi/mxs-spi.txt +++ b/Documentation/devicetree/bindings/spi/mxs-spi.txt @@ -6,6 +6,10 @@ Required properties: - interrupts: Should contain SSP interrupts (error irq first, dma irq second) - fsl,ssp-dma-channel: APBX DMA channel for the SSP +Optional properties: +- clock-frequency : Input clock frequency to the SPI block in Hz. + Default is 160000000 Hz. + Example: ssp0: ssp@80010000 { diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 556e5ef907f..edf1360ab09 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -520,10 +520,17 @@ static int __devinit mxs_spi_probe(struct platform_device *pdev) struct pinctrl *pinctrl; struct clk *clk; void __iomem *base; - int devid, dma_channel; + int devid, dma_channel, clk_freq; int ret = 0, irq_err, irq_dma; dma_cap_mask_t mask; + /* + * Default clock speed for the SPI core. 160MHz seems to + * work reasonably well with most SPI flashes, so use this + * as a default. Override with "clock-frequency" DT prop. + */ + const int clk_freq_default = 160000000; + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_err = platform_get_irq(pdev, 0); irq_dma = platform_get_irq(pdev, 1); @@ -555,12 +562,18 @@ static int __devinit mxs_spi_probe(struct platform_device *pdev) "Failed to get DMA channel\n"); return -EINVAL; } + + ret = of_property_read_u32(np, "clock-frequency", + &clk_freq); + if (ret) + clk_freq = clk_freq_default; } else { dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmares) return -EINVAL; devid = pdev->id_entry->driver_data; dma_channel = dmares->start; + clk_freq = clk_freq_default; } master = spi_alloc_master(&pdev->dev, sizeof(*spi)); @@ -598,12 +611,8 @@ static int __devinit mxs_spi_probe(struct platform_device *pdev) goto out_master_free; } - /* - * Crank up the clock to 120MHz, this will be further divided onto a - * proper speed. - */ clk_prepare_enable(ssp->clk); - clk_set_rate(ssp->clk, 120 * 1000 * 1000); + clk_set_rate(ssp->clk, clk_freq); ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; stmp_reset_block(ssp->base); -- cgit v1.2.3-70-g09d2 From 9394b80c35760d13492a3a895add2891bc64bf86 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 4 Sep 2012 14:43:39 -0600 Subject: regulator: tps6586x: add support for SYS rail Device have SYS rail which is always ON. It is system power bus. LDO5 and LDO_RTC get powered through this rail internally. Add support for this rail and make the LDO5/LDO_RTC supply by it. Update document accordingly. [swarren: Instantiate the sys regulator from board-harmony-power.c to avoid regression.] Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/tps6586x.txt | 65 +++++++++++++--------- arch/arm/mach-tegra/board-harmony-power.c | 12 +++- drivers/mfd/tps6586x.c | 13 +++++ drivers/regulator/tps6586x-regulator.c | 20 ++++++- include/linux/mfd/tps6586x.h | 1 + 5 files changed, 81 insertions(+), 30 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt index da80c2ae091..a2436e1edfc 100644 --- a/Documentation/devicetree/bindings/regulator/tps6586x.txt +++ b/Documentation/devicetree/bindings/regulator/tps6586x.txt @@ -8,7 +8,8 @@ Required properties: - gpio-controller: mark the device as a GPIO controller - regulators: list of regulators provided by this controller, must have property "regulator-compatible" to match their hardware counterparts: - sm[0-2], ldo[0-9] and ldo_rtc + sys, sm[0-2], ldo[0-9] and ldo_rtc +- sys-supply: The input supply for SYS. - vin-sm0-supply: The input supply for the SM0. - vin-sm1-supply: The input supply for the SM1. - vin-sm2-supply: The input supply for the SM2. @@ -20,6 +21,9 @@ Required properties: Each regulator is defined using the standard binding for regulators. +Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver + take care of making proper parent child relationship. + Example: pmu: tps6586x@34 { @@ -30,6 +34,7 @@ Example: #gpio-cells = <2>; gpio-controller; + sys-supply = <&some_reg>; vin-sm0-supply = <&some_reg>; vin-sm1-supply = <&some_reg>; vin-sm2-supply = <&some_reg>; @@ -43,8 +48,16 @@ Example: #address-cells = <1>; #size-cells = <0>; - sm0_reg: regulator@0 { + sys_reg: regulator@0 { reg = <0>; + regulator-compatible = "sys"; + regulator-name = "vdd_sys"; + regulator-boot-on; + regulator-always-on; + }; + + sm0_reg: regulator@1 { + reg = <1>; regulator-compatible = "sm0"; regulator-min-microvolt = < 725000>; regulator-max-microvolt = <1500000>; @@ -52,8 +65,8 @@ Example: regulator-always-on; }; - sm1_reg: regulator@1 { - reg = <1>; + sm1_reg: regulator@2 { + reg = <2>; regulator-compatible = "sm1"; regulator-min-microvolt = < 725000>; regulator-max-microvolt = <1500000>; @@ -61,8 +74,8 @@ Example: regulator-always-on; }; - sm2_reg: regulator@2 { - reg = <2>; + sm2_reg: regulator@3 { + reg = <3>; regulator-compatible = "sm2"; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <4550000>; @@ -70,72 +83,72 @@ Example: regulator-always-on; }; - ldo0_reg: regulator@3 { - reg = <3>; + ldo0_reg: regulator@4 { + reg = <4>; regulator-compatible = "ldo0"; regulator-name = "PCIE CLK"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; - ldo1_reg: regulator@4 { - reg = <4>; + ldo1_reg: regulator@5 { + reg = <5>; regulator-compatible = "ldo1"; regulator-min-microvolt = < 725000>; regulator-max-microvolt = <1500000>; }; - ldo2_reg: regulator@5 { - reg = <5>; + ldo2_reg: regulator@6 { + reg = <6>; regulator-compatible = "ldo2"; regulator-min-microvolt = < 725000>; regulator-max-microvolt = <1500000>; }; - ldo3_reg: regulator@6 { - reg = <6>; + ldo3_reg: regulator@7 { + reg = <7>; regulator-compatible = "ldo3"; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <3300000>; }; - ldo4_reg: regulator@7 { - reg = <7>; + ldo4_reg: regulator@8 { + reg = <8>; regulator-compatible = "ldo4"; regulator-min-microvolt = <1700000>; regulator-max-microvolt = <2475000>; }; - ldo5_reg: regulator@8 { - reg = <8>; + ldo5_reg: regulator@9 { + reg = <9>; regulator-compatible = "ldo5"; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <3300000>; }; - ldo6_reg: regulator@9 { - reg = <9>; + ldo6_reg: regulator@10 { + reg = <10>; regulator-compatible = "ldo6"; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <3300000>; }; - ldo7_reg: regulator@10 { - reg = <10>; + ldo7_reg: regulator@11 { + reg = <11>; regulator-compatible = "ldo7"; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <3300000>; }; - ldo8_reg: regulator@11 { - reg = <11>; + ldo8_reg: regulator@12 { + reg = <12>; regulator-compatible = "ldo8"; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <3300000>; }; - ldo9_reg: regulator@12 { - reg = <12>; + ldo9_reg: regulator@13 { + reg = <13>; regulator-compatible = "ldo9"; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c index b7344beec10..94486e7e9df 100644 --- a/arch/arm/mach-tegra/board-harmony-power.c +++ b/arch/arm/mach-tegra/board-harmony-power.c @@ -67,6 +67,13 @@ static struct regulator_init_data ldo0_data = { }, \ } +static struct regulator_init_data sys_data = { + .supply_regulator = "vdd_5v0", + .constraints = { + .name = "vdd_sys", + }, +}; + HARMONY_REGULATOR_INIT(sm0, "vdd_sm0", "vdd_sys", 725, 1500, 1); HARMONY_REGULATOR_INIT(sm1, "vdd_sm1", "vdd_sys", 725, 1500, 1); HARMONY_REGULATOR_INIT(sm2, "vdd_sm2", "vdd_sys", 3000, 4550, 1); @@ -74,7 +81,7 @@ HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500, 1); HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500, 0); HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300, 1); HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475, 1); -HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL, 1250, 3300, 1); +HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", "vdd_sys", 1250, 3300, 1); HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300, 0); HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300, 0); HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300, 0); @@ -88,6 +95,7 @@ HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300, 1); } static struct tps6586x_subdev_info tps_devs[] = { + TPS_REG(SYS, &sys_data), TPS_REG(SM_0, &sm0_data), TPS_REG(SM_1, &sm1_data), TPS_REG(SM_2, &sm2_data), @@ -120,7 +128,7 @@ static struct i2c_board_info __initdata harmony_regulators[] = { int __init harmony_regulator_init(void) { - regulator_register_always_on(0, "vdd_sys", + regulator_register_always_on(0, "vdd_5v0", NULL, 0, 5000000); if (machine_is_harmony()) { diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 353c3481212..380a3c886d3 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -346,6 +347,7 @@ failed: #ifdef CONFIG_OF static struct of_regulator_match tps6586x_matches[] = { + { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, @@ -369,6 +371,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien struct tps6586x_platform_data *pdata; struct tps6586x_subdev_info *devs; struct device_node *regs; + const char *sys_rail_name = NULL; unsigned int count; unsigned int i, j; int err; @@ -391,12 +394,22 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien return NULL; for (i = 0, j = 0; i < num && j < count; i++) { + struct regulator_init_data *reg_idata; + if (!tps6586x_matches[i].init_data) continue; + reg_idata = tps6586x_matches[i].init_data; devs[j].name = "tps6586x-regulator"; devs[j].platform_data = tps6586x_matches[i].init_data; devs[j].id = (int)tps6586x_matches[i].driver_data; + if (devs[j].id == TPS6586X_ID_SYS) + sys_rail_name = reg_idata->constraints.name; + + if ((devs[j].id == TPS6586X_ID_LDO_5) || + (devs[j].id == TPS6586X_ID_LDO_RTC)) + reg_idata->supply_regulator = sys_rail_name; + devs[j].of_node = tps6586x_matches[i].of_node; j++; } diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 19241fc3005..82125269b66 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -162,6 +162,9 @@ static struct regulator_ops tps6586x_regulator_ops = { .disable = tps6586x_regulator_disable, }; +static struct regulator_ops tps6586x_sys_regulator_ops = { +}; + static const unsigned int tps6586x_ldo0_voltages[] = { 1200000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000, }; @@ -230,15 +233,28 @@ static const unsigned int tps6586x_dvm_voltages[] = { TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ } +#define TPS6586X_SYS_REGULATOR() \ +{ \ + .desc = { \ + .supply_name = "sys", \ + .name = "REG-SYS", \ + .ops = &tps6586x_sys_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = TPS6586X_ID_SYS, \ + .owner = THIS_MODULE, \ + }, \ +} + static struct tps6586x_regulator tps6586x_regulator[] = { + TPS6586X_SYS_REGULATOR(), TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0), TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2), - TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), + TPS6586X_LDO(LDO_5, "REG-SYS", ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), - TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), + TPS6586X_LDO(LDO_RTC, "REG-SYS", ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index f350fd0ba1d..94514710a03 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -14,6 +14,7 @@ #define TPS6586X_SLEW_RATE_MASK 0x07 enum { + TPS6586X_ID_SYS, TPS6586X_ID_SM_0, TPS6586X_ID_SM_1, TPS6586X_ID_SM_2, -- cgit v1.2.3-70-g09d2 From 68a5059ecf82cc9d52a86fb523584b4d485f1bbe Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sun, 26 Aug 2012 14:40:07 +0800 Subject: block: remove the deprecated ub driver It was scheduled to be removed in 3.6. Acked-by: Pete Zaitcev Cc: Jens Axboe Cc: Sebastian Andrzej Siewior Signed-off-by: Cong Wang Signed-off-by: Greg Kroah-Hartman --- Documentation/feature-removal-schedule.txt | 11 - drivers/block/Kconfig | 12 - drivers/block/Makefile | 1 - drivers/block/ub.c | 2474 ---------------------------- 4 files changed, 2498 deletions(-) delete mode 100644 drivers/block/ub.c (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index afaff312bf4..b9aa38bca04 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -495,17 +495,6 @@ Who: Bjorn Helgaas ---------------------------- -What: Low Performance USB Block driver ("CONFIG_BLK_DEV_UB") -When: 3.6 -Why: This driver provides support for USB storage devices like "USB - sticks". As of now, it is deactivated in Debian, Fedora and - Ubuntu. All current users can switch over to usb-storage - (CONFIG_USB_STORAGE) which only drawback is the additional SCSI - stack. -Who: Sebastian Andrzej Siewior - ----------------------------- - What: get_robust_list syscall When: 2013 Why: There appear to be no production users of the get_robust_list syscall, diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index a796407123c..f529407db93 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -353,18 +353,6 @@ config BLK_DEV_SX8 Use devices /dev/sx8/$N and /dev/sx8/$Np$M. -config BLK_DEV_UB - tristate "Low Performance USB Block driver (deprecated)" - depends on USB - help - This driver supports certain USB attached storage devices - such as flash keys. - - If you enable this driver, it is recommended to avoid conflicts - with usb-storage by enabling USB_LIBUSUAL. - - If unsure, say N. - config BLK_DEV_RAM tristate "RAM block device support" ---help--- diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 5b795059f8f..17e82df3df7 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o -obj-$(CONFIG_BLK_DEV_UB) += ub.o obj-$(CONFIG_BLK_DEV_HD) += hd.o obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o diff --git a/drivers/block/ub.c b/drivers/block/ub.c deleted file mode 100644 index fcec0225ac7..00000000000 --- a/drivers/block/ub.c +++ /dev/null @@ -1,2474 +0,0 @@ -/* - * The low performance USB storage driver (ub). - * - * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com) - * - * This work is a part of Linux kernel, is derived from it, - * and is not licensed separately. See file COPYING for details. - * - * TODO (sorted by decreasing priority) - * -- Return sense now that rq allows it (we always auto-sense anyway). - * -- set readonly flag for CDs, set removable flag for CF readers - * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) - * -- verify the 13 conditions and do bulk resets - * -- highmem - * -- move top_sense and work_bcs into separate allocations (if they survive) - * for cache purists and esoteric architectures. - * -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ? - * -- prune comments, they are too volumnous - * -- Resove XXX's - * -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "ub" - -#define UB_MAJOR 180 - -/* - * The command state machine is the key model for understanding of this driver. - * - * The general rule is that all transitions are done towards the bottom - * of the diagram, thus preventing any loops. - * - * An exception to that is how the STAT state is handled. A counter allows it - * to be re-entered along the path marked with [C]. - * - * +--------+ - * ! INIT ! - * +--------+ - * ! - * ub_scsi_cmd_start fails ->--------------------------------------\ - * ! ! - * V ! - * +--------+ ! - * ! CMD ! ! - * +--------+ ! - * ! +--------+ ! - * was -EPIPE -->-------------------------------->! CLEAR ! ! - * ! +--------+ ! - * ! ! ! - * was error -->------------------------------------- ! --------->\ - * ! ! ! - * /--<-- cmd->dir == NONE ? ! ! - * ! ! ! ! - * ! V ! ! - * ! +--------+ ! ! - * ! ! DATA ! ! ! - * ! +--------+ ! ! - * ! ! +---------+ ! ! - * ! was -EPIPE -->--------------->! CLR2STS ! ! ! - * ! ! +---------+ ! ! - * ! ! ! ! ! - * ! ! was error -->---- ! --------->\ - * ! was error -->--------------------- ! ------------- ! --------->\ - * ! ! ! ! ! - * ! V ! ! ! - * \--->+--------+ ! ! ! - * ! STAT !<--------------------------/ ! ! - * /--->+--------+ ! ! - * ! ! ! ! - * [C] was -EPIPE -->-----------\ ! ! - * ! ! ! ! ! - * +<---- len == 0 ! ! ! - * ! ! ! ! ! - * ! was error -->--------------------------------------!---------->\ - * ! ! ! ! ! - * +<---- bad CSW ! ! ! - * +<---- bad tag ! ! ! - * ! ! V ! ! - * ! ! +--------+ ! ! - * ! ! ! CLRRS ! ! ! - * ! ! +--------+ ! ! - * ! ! ! ! ! - * \------- ! --------------------[C]--------\ ! ! - * ! ! ! ! - * cmd->error---\ +--------+ ! ! - * ! +--------------->! SENSE !<----------/ ! - * STAT_FAIL----/ +--------+ ! - * ! ! V - * ! V +--------+ - * \--------------------------------\--------------------->! DONE ! - * +--------+ - */ - -/* - * This many LUNs per USB device. - * Every one of them takes a host, see UB_MAX_HOSTS. - */ -#define UB_MAX_LUNS 9 - -/* - */ - -#define UB_PARTS_PER_LUN 8 - -#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ - -#define UB_SENSE_SIZE 18 - -/* - */ -struct ub_dev; - -#define UB_MAX_REQ_SG 9 /* cdrecord requires 32KB and maybe a header */ -#define UB_MAX_SECTORS 64 - -/* - * A second is more than enough for a 32K transfer (UB_MAX_SECTORS) - * even if a webcam hogs the bus, but some devices need time to spin up. - */ -#define UB_URB_TIMEOUT (HZ*2) -#define UB_DATA_TIMEOUT (HZ*5) /* ZIP does spin-ups in the data phase */ -#define UB_STAT_TIMEOUT (HZ*5) /* Same spinups and eject for a dataless cmd. */ -#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ - -/* - * An instance of a SCSI command in transit. - */ -#define UB_DIR_NONE 0 -#define UB_DIR_READ 1 -#define UB_DIR_ILLEGAL2 2 -#define UB_DIR_WRITE 3 - -#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ - (((c)==UB_DIR_READ)? 'r': 'n')) - -enum ub_scsi_cmd_state { - UB_CMDST_INIT, /* Initial state */ - UB_CMDST_CMD, /* Command submitted */ - UB_CMDST_DATA, /* Data phase */ - UB_CMDST_CLR2STS, /* Clearing before requesting status */ - UB_CMDST_STAT, /* Status phase */ - UB_CMDST_CLEAR, /* Clearing a stall (halt, actually) */ - UB_CMDST_CLRRS, /* Clearing before retrying status */ - UB_CMDST_SENSE, /* Sending Request Sense */ - UB_CMDST_DONE /* Final state */ -}; - -struct ub_scsi_cmd { - unsigned char cdb[UB_MAX_CDB_SIZE]; - unsigned char cdb_len; - - unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ - enum ub_scsi_cmd_state state; - unsigned int tag; - struct ub_scsi_cmd *next; - - int error; /* Return code - valid upon done */ - unsigned int act_len; /* Return size */ - unsigned char key, asc, ascq; /* May be valid if error==-EIO */ - - int stat_count; /* Retries getting status. */ - unsigned int timeo; /* jiffies until rq->timeout changes */ - - unsigned int len; /* Requested length */ - unsigned int current_sg; - unsigned int nsg; /* sgv[nsg] */ - struct scatterlist sgv[UB_MAX_REQ_SG]; - - struct ub_lun *lun; - void (*done)(struct ub_dev *, struct ub_scsi_cmd *); - void *back; -}; - -struct ub_request { - struct request *rq; - unsigned int current_try; - unsigned int nsg; /* sgv[nsg] */ - struct scatterlist sgv[UB_MAX_REQ_SG]; -}; - -/* - */ -struct ub_capacity { - unsigned long nsec; /* Linux size - 512 byte sectors */ - unsigned int bsize; /* Linux hardsect_size */ - unsigned int bshift; /* Shift between 512 and hard sects */ -}; - -/* - * This is a direct take-off from linux/include/completion.h - * The difference is that I do not wait on this thing, just poll. - * When I want to wait (ub_probe), I just use the stock completion. - * - * Note that INIT_COMPLETION takes no lock. It is correct. But why - * in the bloody hell that thing takes struct instead of pointer to struct - * is quite beyond me. I just copied it from the stock completion. - */ -struct ub_completion { - unsigned int done; - spinlock_t lock; -}; - -static DEFINE_MUTEX(ub_mutex); -static inline void ub_init_completion(struct ub_completion *x) -{ - x->done = 0; - spin_lock_init(&x->lock); -} - -#define UB_INIT_COMPLETION(x) ((x).done = 0) - -static void ub_complete(struct ub_completion *x) -{ - unsigned long flags; - - spin_lock_irqsave(&x->lock, flags); - x->done++; - spin_unlock_irqrestore(&x->lock, flags); -} - -static int ub_is_completed(struct ub_completion *x) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&x->lock, flags); - ret = x->done; - spin_unlock_irqrestore(&x->lock, flags); - return ret; -} - -/* - */ -struct ub_scsi_cmd_queue { - int qlen, qmax; - struct ub_scsi_cmd *head, *tail; -}; - -/* - * The block device instance (one per LUN). - */ -struct ub_lun { - struct ub_dev *udev; - struct list_head link; - struct gendisk *disk; - int id; /* Host index */ - int num; /* LUN number */ - char name[16]; - - int changed; /* Media was changed */ - int removable; - int readonly; - - struct ub_request urq; - - /* Use Ingo's mempool if or when we have more than one command. */ - /* - * Currently we never need more than one command for the whole device. - * However, giving every LUN a command is a cheap and automatic way - * to enforce fairness between them. - */ - int cmda[1]; - struct ub_scsi_cmd cmdv[1]; - - struct ub_capacity capacity; -}; - -/* - * The USB device instance. - */ -struct ub_dev { - spinlock_t *lock; - atomic_t poison; /* The USB device is disconnected */ - int openc; /* protected by ub_lock! */ - /* kref is too implicit for our taste */ - int reset; /* Reset is running */ - int bad_resid; - unsigned int tagcnt; - char name[12]; - struct usb_device *dev; - struct usb_interface *intf; - - struct list_head luns; - - unsigned int send_bulk_pipe; /* cached pipe values */ - unsigned int recv_bulk_pipe; - unsigned int send_ctrl_pipe; - unsigned int recv_ctrl_pipe; - - struct tasklet_struct tasklet; - - struct ub_scsi_cmd_queue cmd_queue; - struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */ - unsigned char top_sense[UB_SENSE_SIZE]; - - struct ub_completion work_done; - struct urb work_urb; - struct timer_list work_timer; - int last_pipe; /* What might need clearing */ - __le32 signature; /* Learned signature */ - struct bulk_cb_wrap work_bcb; - struct bulk_cs_wrap work_bcs; - struct usb_ctrlrequest work_cr; - - struct work_struct reset_work; - wait_queue_head_t reset_wait; -}; - -/* - */ -static void ub_cleanup(struct ub_dev *sc); -static int ub_request_fn_1(struct ub_lun *lun, struct request *rq); -static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq); -static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq); -static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_end_rq(struct request *rq, unsigned int status); -static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, - struct ub_request *urq, struct ub_scsi_cmd *cmd); -static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_urb_complete(struct urb *urb); -static void ub_scsi_action(unsigned long _dev); -static void ub_scsi_dispatch(struct ub_dev *sc); -static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); -static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, - int stalled_pipe); -static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); -static void ub_reset_enter(struct ub_dev *sc, int try); -static void ub_reset_task(struct work_struct *work); -static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun); -static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, - struct ub_capacity *ret); -static int ub_sync_reset(struct ub_dev *sc); -static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe); -static int ub_probe_lun(struct ub_dev *sc, int lnum); - -/* - */ -#ifdef CONFIG_USB_LIBUSUAL - -#define ub_usb_ids usb_storage_usb_ids -#else - -static const struct usb_device_id ub_usb_ids[] = { - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, ub_usb_ids); -#endif /* CONFIG_USB_LIBUSUAL */ - -/* - * Find me a way to identify "next free minor" for add_disk(), - * and the array disappears the next day. However, the number of - * hosts has something to do with the naming and /proc/partitions. - * This has to be thought out in detail before changing. - * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. - */ -#define UB_MAX_HOSTS 26 -static char ub_hostv[UB_MAX_HOSTS]; - -#define UB_QLOCK_NUM 5 -static spinlock_t ub_qlockv[UB_QLOCK_NUM]; -static int ub_qlock_next = 0; - -static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */ - -/* - * The id allocator. - * - * This also stores the host for indexing by minor, which is somewhat dirty. - */ -static int ub_id_get(void) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&ub_lock, flags); - for (i = 0; i < UB_MAX_HOSTS; i++) { - if (ub_hostv[i] == 0) { - ub_hostv[i] = 1; - spin_unlock_irqrestore(&ub_lock, flags); - return i; - } - } - spin_unlock_irqrestore(&ub_lock, flags); - return -1; -} - -static void ub_id_put(int id) -{ - unsigned long flags; - - if (id < 0 || id >= UB_MAX_HOSTS) { - printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id); - return; - } - - spin_lock_irqsave(&ub_lock, flags); - if (ub_hostv[id] == 0) { - spin_unlock_irqrestore(&ub_lock, flags); - printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id); - return; - } - ub_hostv[id] = 0; - spin_unlock_irqrestore(&ub_lock, flags); -} - -/* - * This is necessitated by the fact that blk_cleanup_queue does not - * necesserily destroy the queue. Instead, it may merely decrease q->refcnt. - * Since our blk_init_queue() passes a spinlock common with ub_dev, - * we have life time issues when ub_cleanup frees ub_dev. - */ -static spinlock_t *ub_next_lock(void) -{ - unsigned long flags; - spinlock_t *ret; - - spin_lock_irqsave(&ub_lock, flags); - ret = &ub_qlockv[ub_qlock_next]; - ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM; - spin_unlock_irqrestore(&ub_lock, flags); - return ret; -} - -/* - * Downcount for deallocation. This rides on two assumptions: - * - once something is poisoned, its refcount cannot grow - * - opens cannot happen at this time (del_gendisk was done) - * If the above is true, we can drop the lock, which we need for - * blk_cleanup_queue(): the silly thing may attempt to sleep. - * [Actually, it never needs to sleep for us, but it calls might_sleep()] - */ -static void ub_put(struct ub_dev *sc) -{ - unsigned long flags; - - spin_lock_irqsave(&ub_lock, flags); - --sc->openc; - if (sc->openc == 0 && atomic_read(&sc->poison)) { - spin_unlock_irqrestore(&ub_lock, flags); - ub_cleanup(sc); - } else { - spin_unlock_irqrestore(&ub_lock, flags); - } -} - -/* - * Final cleanup and deallocation. - */ -static void ub_cleanup(struct ub_dev *sc) -{ - struct list_head *p; - struct ub_lun *lun; - struct request_queue *q; - - while (!list_empty(&sc->luns)) { - p = sc->luns.next; - lun = list_entry(p, struct ub_lun, link); - list_del(p); - - /* I don't think queue can be NULL. But... Stolen from sx8.c */ - if ((q = lun->disk->queue) != NULL) - blk_cleanup_queue(q); - /* - * If we zero disk->private_data BEFORE put_disk, we have - * to check for NULL all over the place in open, release, - * check_media and revalidate, because the block level - * semaphore is well inside the put_disk. - * But we cannot zero after the call, because *disk is gone. - * The sd.c is blatantly racy in this area. - */ - /* disk->private_data = NULL; */ - put_disk(lun->disk); - lun->disk = NULL; - - ub_id_put(lun->id); - kfree(lun); - } - - usb_set_intfdata(sc->intf, NULL); - usb_put_intf(sc->intf); - usb_put_dev(sc->dev); - kfree(sc); -} - -/* - * The "command allocator". - */ -static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun) -{ - struct ub_scsi_cmd *ret; - - if (lun->cmda[0]) - return NULL; - ret = &lun->cmdv[0]; - lun->cmda[0] = 1; - return ret; -} - -static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd) -{ - if (cmd != &lun->cmdv[0]) { - printk(KERN_WARNING "%s: releasing a foreign cmd %p\n", - lun->name, cmd); - return; - } - if (!lun->cmda[0]) { - printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name); - return; - } - lun->cmda[0] = 0; -} - -/* - * The command queue. - */ -static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_scsi_cmd_queue *t = &sc->cmd_queue; - - if (t->qlen++ == 0) { - t->head = cmd; - t->tail = cmd; - } else { - t->tail->next = cmd; - t->tail = cmd; - } - - if (t->qlen > t->qmax) - t->qmax = t->qlen; -} - -static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_scsi_cmd_queue *t = &sc->cmd_queue; - - if (t->qlen++ == 0) { - t->head = cmd; - t->tail = cmd; - } else { - cmd->next = t->head; - t->head = cmd; - } - - if (t->qlen > t->qmax) - t->qmax = t->qlen; -} - -static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc) -{ - struct ub_scsi_cmd_queue *t = &sc->cmd_queue; - struct ub_scsi_cmd *cmd; - - if (t->qlen == 0) - return NULL; - if (--t->qlen == 0) - t->tail = NULL; - cmd = t->head; - t->head = cmd->next; - cmd->next = NULL; - return cmd; -} - -#define ub_cmdq_peek(sc) ((sc)->cmd_queue.head) - -/* - * The request function is our main entry point - */ - -static void ub_request_fn(struct request_queue *q) -{ - struct ub_lun *lun = q->queuedata; - struct request *rq; - - while ((rq = blk_peek_request(q)) != NULL) { - if (ub_request_fn_1(lun, rq) != 0) { - blk_stop_queue(q); - break; - } - } -} - -static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) -{ - struct ub_dev *sc = lun->udev; - struct ub_scsi_cmd *cmd; - struct ub_request *urq; - int n_elem; - - if (atomic_read(&sc->poison)) { - blk_start_request(rq); - ub_end_rq(rq, DID_NO_CONNECT << 16); - return 0; - } - - if (lun->changed && rq->cmd_type != REQ_TYPE_BLOCK_PC) { - blk_start_request(rq); - ub_end_rq(rq, SAM_STAT_CHECK_CONDITION); - return 0; - } - - if (lun->urq.rq != NULL) - return -1; - if ((cmd = ub_get_cmd(lun)) == NULL) - return -1; - memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - - blk_start_request(rq); - - urq = &lun->urq; - memset(urq, 0, sizeof(struct ub_request)); - urq->rq = rq; - - /* - * get scatterlist from block layer - */ - sg_init_table(&urq->sgv[0], UB_MAX_REQ_SG); - n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]); - if (n_elem < 0) { - /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */ - printk(KERN_INFO "%s: failed request map (%d)\n", - lun->name, n_elem); - goto drop; - } - if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ - printk(KERN_WARNING "%s: request with %d segments\n", - lun->name, n_elem); - goto drop; - } - urq->nsg = n_elem; - - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - ub_cmd_build_packet(sc, lun, cmd, urq); - } else { - ub_cmd_build_block(sc, lun, cmd, urq); - } - cmd->state = UB_CMDST_INIT; - cmd->lun = lun; - cmd->done = ub_rw_cmd_done; - cmd->back = urq; - - cmd->tag = sc->tagcnt++; - if (ub_submit_scsi(sc, cmd) != 0) - goto drop; - - return 0; - -drop: - ub_put_cmd(lun, cmd); - ub_end_rq(rq, DID_ERROR << 16); - return 0; -} - -static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq) -{ - struct request *rq = urq->rq; - unsigned int block, nblks; - - if (rq_data_dir(rq) == WRITE) - cmd->dir = UB_DIR_WRITE; - else - cmd->dir = UB_DIR_READ; - - cmd->nsg = urq->nsg; - memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg); - - /* - * build the command - * - * The call to blk_queue_logical_block_size() guarantees that request - * is aligned, but it is given in terms of 512 byte units, always. - */ - block = blk_rq_pos(rq) >> lun->capacity.bshift; - nblks = blk_rq_sectors(rq) >> lun->capacity.bshift; - - cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10; - /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ - cmd->cdb[2] = block >> 24; - cmd->cdb[3] = block >> 16; - cmd->cdb[4] = block >> 8; - cmd->cdb[5] = block; - cmd->cdb[7] = nblks >> 8; - cmd->cdb[8] = nblks; - cmd->cdb_len = 10; - - cmd->len = blk_rq_bytes(rq); -} - -static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq) -{ - struct request *rq = urq->rq; - - if (blk_rq_bytes(rq) == 0) { - cmd->dir = UB_DIR_NONE; - } else { - if (rq_data_dir(rq) == WRITE) - cmd->dir = UB_DIR_WRITE; - else - cmd->dir = UB_DIR_READ; - } - - cmd->nsg = urq->nsg; - memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg); - - memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); - cmd->cdb_len = rq->cmd_len; - - cmd->len = blk_rq_bytes(rq); - - /* - * To reapply this to every URB is not as incorrect as it looks. - * In return, we avoid any complicated tracking calculations. - */ - cmd->timeo = rq->timeout; -} - -static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_lun *lun = cmd->lun; - struct ub_request *urq = cmd->back; - struct request *rq; - unsigned int scsi_status; - - rq = urq->rq; - - if (cmd->error == 0) { - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - if (cmd->act_len >= rq->resid_len) - rq->resid_len = 0; - else - rq->resid_len -= cmd->act_len; - scsi_status = 0; - } else { - if (cmd->act_len != cmd->len) { - scsi_status = SAM_STAT_CHECK_CONDITION; - } else { - scsi_status = 0; - } - } - } else { - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */ - memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE); - rq->sense_len = UB_SENSE_SIZE; - if (sc->top_sense[0] != 0) - scsi_status = SAM_STAT_CHECK_CONDITION; - else - scsi_status = DID_ERROR << 16; - } else { - if (cmd->error == -EIO && - (cmd->key == 0 || - cmd->key == MEDIUM_ERROR || - cmd->key == UNIT_ATTENTION)) { - if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) - return; - } - scsi_status = SAM_STAT_CHECK_CONDITION; - } - } - - urq->rq = NULL; - - ub_put_cmd(lun, cmd); - ub_end_rq(rq, scsi_status); - blk_start_queue(lun->disk->queue); -} - -static void ub_end_rq(struct request *rq, unsigned int scsi_status) -{ - int error; - - if (scsi_status == 0) { - error = 0; - } else { - error = -EIO; - rq->errors = scsi_status; - } - __blk_end_request_all(rq, error); -} - -static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, - struct ub_request *urq, struct ub_scsi_cmd *cmd) -{ - - if (atomic_read(&sc->poison)) - return -ENXIO; - - ub_reset_enter(sc, urq->current_try); - - if (urq->current_try >= 3) - return -EIO; - urq->current_try++; - - /* Remove this if anyone complains of flooding. */ - printk(KERN_DEBUG "%s: dir %c len/act %d/%d " - "[sense %x %02x %02x] retry %d\n", - sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len, - cmd->key, cmd->asc, cmd->ascq, urq->current_try); - - memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - ub_cmd_build_block(sc, lun, cmd, urq); - - cmd->state = UB_CMDST_INIT; - cmd->lun = lun; - cmd->done = ub_rw_cmd_done; - cmd->back = urq; - - cmd->tag = sc->tagcnt++; - -#if 0 /* Wasteful */ - return ub_submit_scsi(sc, cmd); -#else - ub_cmdq_add(sc, cmd); - return 0; -#endif -} - -/* - * Submit a regular SCSI operation (not an auto-sense). - * - * The Iron Law of Good Submit Routine is: - * Zero return - callback is done, Nonzero return - callback is not done. - * No exceptions. - * - * Host is assumed locked. - */ -static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - - if (cmd->state != UB_CMDST_INIT || - (cmd->dir != UB_DIR_NONE && cmd->len == 0)) { - return -EINVAL; - } - - ub_cmdq_add(sc, cmd); - /* - * We can call ub_scsi_dispatch(sc) right away here, but it's a little - * safer to jump to a tasklet, in case upper layers do something silly. - */ - tasklet_schedule(&sc->tasklet); - return 0; -} - -/* - * Submit the first URB for the queued command. - * This function does not deal with queueing in any way. - */ -static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct bulk_cb_wrap *bcb; - int rc; - - bcb = &sc->work_bcb; - - /* - * ``If the allocation length is eighteen or greater, and a device - * server returns less than eithteen bytes of data, the application - * client should assume that the bytes not transferred would have been - * zeroes had the device server returned those bytes.'' - * - * We zero sense for all commands so that when a packet request - * fails it does not return a stale sense. - */ - memset(&sc->top_sense, 0, UB_SENSE_SIZE); - - /* set up the command wrapper */ - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->Tag = cmd->tag; /* Endianness is not important */ - bcb->DataTransferLength = cpu_to_le32(cmd->len); - bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0; - bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0; - bcb->Length = cmd->cdb_len; - - /* copy the command payload */ - memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE); - - UB_INIT_COMPLETION(sc->work_done); - - sc->last_pipe = sc->send_bulk_pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, - bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - /* XXX Clear stalls */ - ub_complete(&sc->work_done); - return rc; - } - - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); - - cmd->state = UB_CMDST_CMD; - return 0; -} - -/* - * Timeout handler. - */ -static void ub_urb_timeout(unsigned long arg) -{ - struct ub_dev *sc = (struct ub_dev *) arg; - unsigned long flags; - - spin_lock_irqsave(sc->lock, flags); - if (!ub_is_completed(&sc->work_done)) - usb_unlink_urb(&sc->work_urb); - spin_unlock_irqrestore(sc->lock, flags); -} - -/* - * Completion routine for the work URB. - * - * This can be called directly from usb_submit_urb (while we have - * the sc->lock taken) and from an interrupt (while we do NOT have - * the sc->lock taken). Therefore, bounce this off to a tasklet. - */ -static void ub_urb_complete(struct urb *urb) -{ - struct ub_dev *sc = urb->context; - - ub_complete(&sc->work_done); - tasklet_schedule(&sc->tasklet); -} - -static void ub_scsi_action(unsigned long _dev) -{ - struct ub_dev *sc = (struct ub_dev *) _dev; - unsigned long flags; - - spin_lock_irqsave(sc->lock, flags); - ub_scsi_dispatch(sc); - spin_unlock_irqrestore(sc->lock, flags); -} - -static void ub_scsi_dispatch(struct ub_dev *sc) -{ - struct ub_scsi_cmd *cmd; - int rc; - - while (!sc->reset && (cmd = ub_cmdq_peek(sc)) != NULL) { - if (cmd->state == UB_CMDST_DONE) { - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); - } else if (cmd->state == UB_CMDST_INIT) { - if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) - break; - cmd->error = rc; - cmd->state = UB_CMDST_DONE; - } else { - if (!ub_is_completed(&sc->work_done)) - break; - del_timer(&sc->work_timer); - ub_scsi_urb_compl(sc, cmd); - } - } -} - -static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct urb *urb = &sc->work_urb; - struct bulk_cs_wrap *bcs; - int endp; - int len; - int rc; - - if (atomic_read(&sc->poison)) { - ub_state_done(sc, cmd, -ENODEV); - return; - } - - endp = usb_pipeendpoint(sc->last_pipe); - if (usb_pipein(sc->last_pipe)) - endp |= USB_DIR_IN; - - if (cmd->state == UB_CMDST_CLEAR) { - if (urb->status == -EPIPE) { - /* - * STALL while clearning STALL. - * The control pipe clears itself - nothing to do. - */ - printk(KERN_NOTICE "%s: stall on control pipe\n", - sc->name); - goto Bad_End; - } - - /* - * We ignore the result for the halt clear. - */ - - usb_reset_endpoint(sc->dev, endp); - - ub_state_sense(sc, cmd); - - } else if (cmd->state == UB_CMDST_CLR2STS) { - if (urb->status == -EPIPE) { - printk(KERN_NOTICE "%s: stall on control pipe\n", - sc->name); - goto Bad_End; - } - - /* - * We ignore the result for the halt clear. - */ - - usb_reset_endpoint(sc->dev, endp); - - ub_state_stat(sc, cmd); - - } else if (cmd->state == UB_CMDST_CLRRS) { - if (urb->status == -EPIPE) { - printk(KERN_NOTICE "%s: stall on control pipe\n", - sc->name); - goto Bad_End; - } - - /* - * We ignore the result for the halt clear. - */ - - usb_reset_endpoint(sc->dev, endp); - - ub_state_stat_counted(sc, cmd); - - } else if (cmd->state == UB_CMDST_CMD) { - switch (urb->status) { - case 0: - break; - case -EOVERFLOW: - goto Bad_End; - case -EPIPE: - rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); - if (rc != 0) { - printk(KERN_NOTICE "%s: " - "unable to submit clear (%d)\n", - sc->name, rc); - /* - * This is typically ENOMEM or some other such shit. - * Retrying is pointless. Just do Bad End on it... - */ - ub_state_done(sc, cmd, rc); - return; - } - cmd->state = UB_CMDST_CLEAR; - return; - case -ESHUTDOWN: /* unplug */ - case -EILSEQ: /* unplug timeout on uhci */ - ub_state_done(sc, cmd, -ENODEV); - return; - default: - goto Bad_End; - } - if (urb->actual_length != US_BULK_CB_WRAP_LEN) { - goto Bad_End; - } - - if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) { - ub_state_stat(sc, cmd); - return; - } - - // udelay(125); // usb-storage has this - ub_data_start(sc, cmd); - - } else if (cmd->state == UB_CMDST_DATA) { - if (urb->status == -EPIPE) { - rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); - if (rc != 0) { - printk(KERN_NOTICE "%s: " - "unable to submit clear (%d)\n", - sc->name, rc); - ub_state_done(sc, cmd, rc); - return; - } - cmd->state = UB_CMDST_CLR2STS; - return; - } - if (urb->status == -EOVERFLOW) { - /* - * A babble? Failure, but we must transfer CSW now. - */ - cmd->error = -EOVERFLOW; /* A cheap trick... */ - ub_state_stat(sc, cmd); - return; - } - - if (cmd->dir == UB_DIR_WRITE) { - /* - * Do not continue writes in case of a failure. - * Doing so would cause sectors to be mixed up, - * which is worse than sectors lost. - * - * We must try to read the CSW, or many devices - * get confused. - */ - len = urb->actual_length; - if (urb->status != 0 || - len != cmd->sgv[cmd->current_sg].length) { - cmd->act_len += len; - - cmd->error = -EIO; - ub_state_stat(sc, cmd); - return; - } - - } else { - /* - * If an error occurs on read, we record it, and - * continue to fetch data in order to avoid bubble. - * - * As a small shortcut, we stop if we detect that - * a CSW mixed into data. - */ - if (urb->status != 0) - cmd->error = -EIO; - - len = urb->actual_length; - if (urb->status != 0 || - len != cmd->sgv[cmd->current_sg].length) { - if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN) - goto Bad_End; - } - } - - cmd->act_len += urb->actual_length; - - if (++cmd->current_sg < cmd->nsg) { - ub_data_start(sc, cmd); - return; - } - ub_state_stat(sc, cmd); - - } else if (cmd->state == UB_CMDST_STAT) { - if (urb->status == -EPIPE) { - rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); - if (rc != 0) { - printk(KERN_NOTICE "%s: " - "unable to submit clear (%d)\n", - sc->name, rc); - ub_state_done(sc, cmd, rc); - return; - } - - /* - * Having a stall when getting CSW is an error, so - * make sure uppper levels are not oblivious to it. - */ - cmd->error = -EIO; /* A cheap trick... */ - - cmd->state = UB_CMDST_CLRRS; - return; - } - - /* Catch everything, including -EOVERFLOW and other nasties. */ - if (urb->status != 0) - goto Bad_End; - - if (urb->actual_length == 0) { - ub_state_stat_counted(sc, cmd); - return; - } - - /* - * Check the returned Bulk protocol status. - * The status block has to be validated first. - */ - - bcs = &sc->work_bcs; - - if (sc->signature == cpu_to_le32(0)) { - /* - * This is the first reply, so do not perform the check. - * Instead, remember the signature the device uses - * for future checks. But do not allow a nul. - */ - sc->signature = bcs->Signature; - if (sc->signature == cpu_to_le32(0)) { - ub_state_stat_counted(sc, cmd); - return; - } - } else { - if (bcs->Signature != sc->signature) { - ub_state_stat_counted(sc, cmd); - return; - } - } - - if (bcs->Tag != cmd->tag) { - /* - * This usually happens when we disagree with the - * device's microcode about something. For instance, - * a few of them throw this after timeouts. They buffer - * commands and reply at commands we timed out before. - * Without flushing these replies we loop forever. - */ - ub_state_stat_counted(sc, cmd); - return; - } - - if (!sc->bad_resid) { - len = le32_to_cpu(bcs->Residue); - if (len != cmd->len - cmd->act_len) { - /* - * Only start ignoring if this cmd ended well. - */ - if (cmd->len == cmd->act_len) { - printk(KERN_NOTICE "%s: " - "bad residual %d of %d, ignoring\n", - sc->name, len, cmd->len); - sc->bad_resid = 1; - } - } - } - - switch (bcs->Status) { - case US_BULK_STAT_OK: - break; - case US_BULK_STAT_FAIL: - ub_state_sense(sc, cmd); - return; - case US_BULK_STAT_PHASE: - goto Bad_End; - default: - printk(KERN_INFO "%s: unknown CSW status 0x%x\n", - sc->name, bcs->Status); - ub_state_done(sc, cmd, -EINVAL); - return; - } - - /* Not zeroing error to preserve a babble indicator */ - if (cmd->error != 0) { - ub_state_sense(sc, cmd); - return; - } - cmd->state = UB_CMDST_DONE; - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); - - } else if (cmd->state == UB_CMDST_SENSE) { - ub_state_done(sc, cmd, -EIO); - - } else { - printk(KERN_WARNING "%s: wrong command state %d\n", - sc->name, cmd->state); - ub_state_done(sc, cmd, -EINVAL); - return; - } - return; - -Bad_End: /* Little Excel is dead */ - ub_state_done(sc, cmd, -EIO); -} - -/* - * Factorization helper for the command state machine: - * Initiate a data segment transfer. - */ -static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct scatterlist *sg = &cmd->sgv[cmd->current_sg]; - int pipe; - int rc; - - UB_INIT_COMPLETION(sc->work_done); - - if (cmd->dir == UB_DIR_READ) - pipe = sc->recv_bulk_pipe; - else - pipe = sc->send_bulk_pipe; - sc->last_pipe = pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg), - sg->length, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - /* XXX Clear stalls */ - ub_complete(&sc->work_done); - ub_state_done(sc, cmd, rc); - return; - } - - if (cmd->timeo) - sc->work_timer.expires = jiffies + cmd->timeo; - else - sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT; - add_timer(&sc->work_timer); - - cmd->state = UB_CMDST_DATA; -} - -/* - * Factorization helper for the command state machine: - * Finish the command. - */ -static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) -{ - - cmd->error = rc; - cmd->state = UB_CMDST_DONE; - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); -} - -/* - * Factorization helper for the command state machine: - * Submit a CSW read. - */ -static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - int rc; - - UB_INIT_COMPLETION(sc->work_done); - - sc->last_pipe = sc->recv_bulk_pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, - &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - /* XXX Clear stalls */ - ub_complete(&sc->work_done); - ub_state_done(sc, cmd, rc); - return -1; - } - - if (cmd->timeo) - sc->work_timer.expires = jiffies + cmd->timeo; - else - sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; - add_timer(&sc->work_timer); - return 0; -} - -/* - * Factorization helper for the command state machine: - * Submit a CSW read and go to STAT state. - */ -static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - - if (__ub_state_stat(sc, cmd) != 0) - return; - - cmd->stat_count = 0; - cmd->state = UB_CMDST_STAT; -} - -/* - * Factorization helper for the command state machine: - * Submit a CSW read and go to STAT state with counter (along [C] path). - */ -static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - - if (++cmd->stat_count >= 4) { - ub_state_sense(sc, cmd); - return; - } - - if (__ub_state_stat(sc, cmd) != 0) - return; - - cmd->state = UB_CMDST_STAT; -} - -/* - * Factorization helper for the command state machine: - * Submit a REQUEST SENSE and go to SENSE state. - */ -static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_scsi_cmd *scmd; - struct scatterlist *sg; - int rc; - - if (cmd->cdb[0] == REQUEST_SENSE) { - rc = -EPIPE; - goto error; - } - - scmd = &sc->top_rqs_cmd; - memset(scmd, 0, sizeof(struct ub_scsi_cmd)); - scmd->cdb[0] = REQUEST_SENSE; - scmd->cdb[4] = UB_SENSE_SIZE; - scmd->cdb_len = 6; - scmd->dir = UB_DIR_READ; - scmd->state = UB_CMDST_INIT; - scmd->nsg = 1; - sg = &scmd->sgv[0]; - sg_init_table(sg, UB_MAX_REQ_SG); - sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE, - (unsigned long)sc->top_sense & (PAGE_SIZE-1)); - scmd->len = UB_SENSE_SIZE; - scmd->lun = cmd->lun; - scmd->done = ub_top_sense_done; - scmd->back = cmd; - - scmd->tag = sc->tagcnt++; - - cmd->state = UB_CMDST_SENSE; - - ub_cmdq_insert(sc, scmd); - return; - -error: - ub_state_done(sc, cmd, rc); -} - -/* - * A helper for the command's state machine: - * Submit a stall clear. - */ -static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, - int stalled_pipe) -{ - int endp; - struct usb_ctrlrequest *cr; - int rc; - - endp = usb_pipeendpoint(stalled_pipe); - if (usb_pipein (stalled_pipe)) - endp |= USB_DIR_IN; - - cr = &sc->work_cr; - cr->bRequestType = USB_RECIP_ENDPOINT; - cr->bRequest = USB_REQ_CLEAR_FEATURE; - cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); - cr->wIndex = cpu_to_le16(endp); - cr->wLength = cpu_to_le16(0); - - UB_INIT_COMPLETION(sc->work_done); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, - (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - ub_complete(&sc->work_done); - return rc; - } - - sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&sc->work_timer); - return 0; -} - -/* - */ -static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) -{ - unsigned char *sense = sc->top_sense; - struct ub_scsi_cmd *cmd; - - /* - * Find the command which triggered the unit attention or a check, - * save the sense into it, and advance its state machine. - */ - if ((cmd = ub_cmdq_peek(sc)) == NULL) { - printk(KERN_WARNING "%s: sense done while idle\n", sc->name); - return; - } - if (cmd != scmd->back) { - printk(KERN_WARNING "%s: " - "sense done for wrong command 0x%x\n", - sc->name, cmd->tag); - return; - } - if (cmd->state != UB_CMDST_SENSE) { - printk(KERN_WARNING "%s: sense done with bad cmd state %d\n", - sc->name, cmd->state); - return; - } - - /* - * Ignoring scmd->act_len, because the buffer was pre-zeroed. - */ - cmd->key = sense[2] & 0x0F; - cmd->asc = sense[12]; - cmd->ascq = sense[13]; - - ub_scsi_urb_compl(sc, cmd); -} - -/* - * Reset management - */ - -static void ub_reset_enter(struct ub_dev *sc, int try) -{ - - if (sc->reset) { - /* This happens often on multi-LUN devices. */ - return; - } - sc->reset = try + 1; - -#if 0 /* Not needed because the disconnect waits for us. */ - unsigned long flags; - spin_lock_irqsave(&ub_lock, flags); - sc->openc++; - spin_unlock_irqrestore(&ub_lock, flags); -#endif - -#if 0 /* We let them stop themselves. */ - struct ub_lun *lun; - list_for_each_entry(lun, &sc->luns, link) { - blk_stop_queue(lun->disk->queue); - } -#endif - - schedule_work(&sc->reset_work); -} - -static void ub_reset_task(struct work_struct *work) -{ - struct ub_dev *sc = container_of(work, struct ub_dev, reset_work); - unsigned long flags; - struct ub_lun *lun; - int rc; - - if (!sc->reset) { - printk(KERN_WARNING "%s: Running reset unrequested\n", - sc->name); - return; - } - - if (atomic_read(&sc->poison)) { - ; - } else if ((sc->reset & 1) == 0) { - ub_sync_reset(sc); - msleep(700); /* usb-storage sleeps 6s (!) */ - ub_probe_clear_stall(sc, sc->recv_bulk_pipe); - ub_probe_clear_stall(sc, sc->send_bulk_pipe); - } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) { - ; - } else { - rc = usb_lock_device_for_reset(sc->dev, sc->intf); - if (rc < 0) { - printk(KERN_NOTICE - "%s: usb_lock_device_for_reset failed (%d)\n", - sc->name, rc); - } else { - rc = usb_reset_device(sc->dev); - if (rc < 0) { - printk(KERN_NOTICE "%s: " - "usb_lock_device_for_reset failed (%d)\n", - sc->name, rc); - } - usb_unlock_device(sc->dev); - } - } - - /* - * In theory, no commands can be running while reset is active, - * so nobody can ask for another reset, and so we do not need any - * queues of resets or anything. We do need a spinlock though, - * to interact with block layer. - */ - spin_lock_irqsave(sc->lock, flags); - sc->reset = 0; - tasklet_schedule(&sc->tasklet); - list_for_each_entry(lun, &sc->luns, link) { - blk_start_queue(lun->disk->queue); - } - wake_up(&sc->reset_wait); - spin_unlock_irqrestore(sc->lock, flags); -} - -/* - * XXX Reset brackets are too much hassle to implement, so just stub them - * in order to prevent forced unbinding (which deadlocks solid when our - * ->disconnect method waits for the reset to complete and this kills keventd). - * - * XXX Tell Alan to move usb_unlock_device inside of usb_reset_device, - * or else the post_reset is invoked, and restats I/O on a locked device. - */ -static int ub_pre_reset(struct usb_interface *iface) { - return 0; -} - -static int ub_post_reset(struct usb_interface *iface) { - return 0; -} - -/* - * This is called from a process context. - */ -static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun) -{ - - lun->readonly = 0; /* XXX Query this from the device */ - - lun->capacity.nsec = 0; - lun->capacity.bsize = 512; - lun->capacity.bshift = 0; - - if (ub_sync_tur(sc, lun) != 0) - return; /* Not ready */ - lun->changed = 0; - - if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) { - /* - * The retry here means something is wrong, either with the - * device, with the transport, or with our code. - * We keep this because sd.c has retries for capacity. - */ - if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) { - lun->capacity.nsec = 0; - lun->capacity.bsize = 512; - lun->capacity.bshift = 0; - } - } -} - -/* - * The open funcion. - * This is mostly needed to keep refcounting, but also to support - * media checks on removable media drives. - */ -static int ub_bd_open(struct block_device *bdev, fmode_t mode) -{ - struct ub_lun *lun = bdev->bd_disk->private_data; - struct ub_dev *sc = lun->udev; - unsigned long flags; - int rc; - - spin_lock_irqsave(&ub_lock, flags); - if (atomic_read(&sc->poison)) { - spin_unlock_irqrestore(&ub_lock, flags); - return -ENXIO; - } - sc->openc++; - spin_unlock_irqrestore(&ub_lock, flags); - - if (lun->removable || lun->readonly) - check_disk_change(bdev); - - /* - * The sd.c considers ->media_present and ->changed not equivalent, - * under some pretty murky conditions (a failure of READ CAPACITY). - * We may need it one day. - */ - if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) { - rc = -ENOMEDIUM; - goto err_open; - } - - if (lun->readonly && (mode & FMODE_WRITE)) { - rc = -EROFS; - goto err_open; - } - - return 0; - -err_open: - ub_put(sc); - return rc; -} - -static int ub_bd_unlocked_open(struct block_device *bdev, fmode_t mode) -{ - int ret; - - mutex_lock(&ub_mutex); - ret = ub_bd_open(bdev, mode); - mutex_unlock(&ub_mutex); - - return ret; -} - - -/* - */ -static int ub_bd_release(struct gendisk *disk, fmode_t mode) -{ - struct ub_lun *lun = disk->private_data; - struct ub_dev *sc = lun->udev; - - mutex_lock(&ub_mutex); - ub_put(sc); - mutex_unlock(&ub_mutex); - - return 0; -} - -/* - * The ioctl interface. - */ -static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - void __user *usermem = (void __user *) arg; - int ret; - - mutex_lock(&ub_mutex); - ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem); - mutex_unlock(&ub_mutex); - - return ret; -} - -/* - * This is called by check_disk_change if we reported a media change. - * The main onjective here is to discover the features of the media such as - * the capacity, read-only status, etc. USB storage generally does not - * need to be spun up, but if we needed it, this would be the place. - * - * This call can sleep. - * - * The return code is not used. - */ -static int ub_bd_revalidate(struct gendisk *disk) -{ - struct ub_lun *lun = disk->private_data; - - ub_revalidate(lun->udev, lun); - - /* XXX Support sector size switching like in sr.c */ - blk_queue_logical_block_size(disk->queue, lun->capacity.bsize); - set_capacity(disk, lun->capacity.nsec); - // set_disk_ro(sdkp->disk, lun->readonly); - - return 0; -} - -/* - * The check is called by the block layer to verify if the media - * is still available. It is supposed to be harmless, lightweight and - * non-intrusive in case the media was not changed. - * - * This call can sleep. - * - * The return code is bool! - */ -static unsigned int ub_bd_check_events(struct gendisk *disk, - unsigned int clearing) -{ - struct ub_lun *lun = disk->private_data; - - if (!lun->removable) - return 0; - - /* - * We clean checks always after every command, so this is not - * as dangerous as it looks. If the TEST_UNIT_READY fails here, - * the device is actually not ready with operator or software - * intervention required. One dangerous item might be a drive which - * spins itself down, and come the time to write dirty pages, this - * will fail, then block layer discards the data. Since we never - * spin drives up, such devices simply cannot be used with ub anyway. - */ - if (ub_sync_tur(lun->udev, lun) != 0) { - lun->changed = 1; - return DISK_EVENT_MEDIA_CHANGE; - } - - return lun->changed ? DISK_EVENT_MEDIA_CHANGE : 0; -} - -static const struct block_device_operations ub_bd_fops = { - .owner = THIS_MODULE, - .open = ub_bd_unlocked_open, - .release = ub_bd_release, - .ioctl = ub_bd_ioctl, - .check_events = ub_bd_check_events, - .revalidate_disk = ub_bd_revalidate, -}; - -/* - * Common ->done routine for commands executed synchronously. - */ -static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct completion *cop = cmd->back; - complete(cop); -} - -/* - * Test if the device has a check condition on it, synchronously. - */ -static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun) -{ - struct ub_scsi_cmd *cmd; - enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) }; - unsigned long flags; - struct completion compl; - int rc; - - init_completion(&compl); - - rc = -ENOMEM; - if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) - goto err_alloc; - - cmd->cdb[0] = TEST_UNIT_READY; - cmd->cdb_len = 6; - cmd->dir = UB_DIR_NONE; - cmd->state = UB_CMDST_INIT; - cmd->lun = lun; /* This may be NULL, but that's ok */ - cmd->done = ub_probe_done; - cmd->back = &compl; - - spin_lock_irqsave(sc->lock, flags); - cmd->tag = sc->tagcnt++; - - rc = ub_submit_scsi(sc, cmd); - spin_unlock_irqrestore(sc->lock, flags); - - if (rc != 0) - goto err_submit; - - wait_for_completion(&compl); - - rc = cmd->error; - - if (rc == -EIO && cmd->key != 0) /* Retries for benh's key */ - rc = cmd->key; - -err_submit: - kfree(cmd); -err_alloc: - return rc; -} - -/* - * Read the SCSI capacity synchronously (for probing). - */ -static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, - struct ub_capacity *ret) -{ - struct ub_scsi_cmd *cmd; - struct scatterlist *sg; - char *p; - enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 }; - unsigned long flags; - unsigned int bsize, shift; - unsigned long nsec; - struct completion compl; - int rc; - - init_completion(&compl); - - rc = -ENOMEM; - if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) - goto err_alloc; - p = (char *)cmd + sizeof(struct ub_scsi_cmd); - - cmd->cdb[0] = 0x25; - cmd->cdb_len = 10; - cmd->dir = UB_DIR_READ; - cmd->state = UB_CMDST_INIT; - cmd->nsg = 1; - sg = &cmd->sgv[0]; - sg_init_table(sg, UB_MAX_REQ_SG); - sg_set_page(sg, virt_to_page(p), 8, (unsigned long)p & (PAGE_SIZE-1)); - cmd->len = 8; - cmd->lun = lun; - cmd->done = ub_probe_done; - cmd->back = &compl; - - spin_lock_irqsave(sc->lock, flags); - cmd->tag = sc->tagcnt++; - - rc = ub_submit_scsi(sc, cmd); - spin_unlock_irqrestore(sc->lock, flags); - - if (rc != 0) - goto err_submit; - - wait_for_completion(&compl); - - if (cmd->error != 0) { - rc = -EIO; - goto err_read; - } - if (cmd->act_len != 8) { - rc = -EIO; - goto err_read; - } - - /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */ - nsec = be32_to_cpu(*(__be32 *)p) + 1; - bsize = be32_to_cpu(*(__be32 *)(p + 4)); - switch (bsize) { - case 512: shift = 0; break; - case 1024: shift = 1; break; - case 2048: shift = 2; break; - case 4096: shift = 3; break; - default: - rc = -EDOM; - goto err_inv_bsize; - } - - ret->bsize = bsize; - ret->bshift = shift; - ret->nsec = nsec << shift; - rc = 0; - -err_inv_bsize: -err_read: -err_submit: - kfree(cmd); -err_alloc: - return rc; -} - -/* - */ -static void ub_probe_urb_complete(struct urb *urb) -{ - struct completion *cop = urb->context; - complete(cop); -} - -static void ub_probe_timeout(unsigned long arg) -{ - struct completion *cop = (struct completion *) arg; - complete(cop); -} - -/* - * Reset with a Bulk reset. - */ -static int ub_sync_reset(struct ub_dev *sc) -{ - int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber; - struct usb_ctrlrequest *cr; - struct completion compl; - struct timer_list timer; - int rc; - - init_completion(&compl); - - cr = &sc->work_cr; - cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - cr->bRequest = US_BULK_RESET_REQUEST; - cr->wValue = cpu_to_le16(0); - cr->wIndex = cpu_to_le16(ifnum); - cr->wLength = cpu_to_le16(0); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, - (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { - printk(KERN_WARNING - "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc); - return rc; - } - - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - - wait_for_completion(&compl); - - del_timer_sync(&timer); - usb_kill_urb(&sc->work_urb); - - return sc->work_urb.status; -} - -/* - * Get number of LUNs by the way of Bulk GetMaxLUN command. - */ -static int ub_sync_getmaxlun(struct ub_dev *sc) -{ - int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber; - unsigned char *p; - enum { ALLOC_SIZE = 1 }; - struct usb_ctrlrequest *cr; - struct completion compl; - struct timer_list timer; - int nluns; - int rc; - - init_completion(&compl); - - rc = -ENOMEM; - if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) - goto err_alloc; - *p = 55; - - cr = &sc->work_cr; - cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - cr->bRequest = US_BULK_GET_MAX_LUN; - cr->wValue = cpu_to_le16(0); - cr->wIndex = cpu_to_le16(ifnum); - cr->wLength = cpu_to_le16(1); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe, - (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) - goto err_submit; - - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - - wait_for_completion(&compl); - - del_timer_sync(&timer); - usb_kill_urb(&sc->work_urb); - - if ((rc = sc->work_urb.status) < 0) - goto err_io; - - if (sc->work_urb.actual_length != 1) { - nluns = 0; - } else { - if ((nluns = *p) == 55) { - nluns = 0; - } else { - /* GetMaxLUN returns the maximum LUN number */ - nluns += 1; - if (nluns > UB_MAX_LUNS) - nluns = UB_MAX_LUNS; - } - } - - kfree(p); - return nluns; - -err_io: -err_submit: - kfree(p); -err_alloc: - return rc; -} - -/* - * Clear initial stalls. - */ -static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) -{ - int endp; - struct usb_ctrlrequest *cr; - struct completion compl; - struct timer_list timer; - int rc; - - init_completion(&compl); - - endp = usb_pipeendpoint(stalled_pipe); - if (usb_pipein (stalled_pipe)) - endp |= USB_DIR_IN; - - cr = &sc->work_cr; - cr->bRequestType = USB_RECIP_ENDPOINT; - cr->bRequest = USB_REQ_CLEAR_FEATURE; - cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); - cr->wIndex = cpu_to_le16(endp); - cr->wLength = cpu_to_le16(0); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, - (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { - printk(KERN_WARNING - "%s: Unable to submit a probe clear (%d)\n", sc->name, rc); - return rc; - } - - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - - wait_for_completion(&compl); - - del_timer_sync(&timer); - usb_kill_urb(&sc->work_urb); - - usb_reset_endpoint(sc->dev, endp); - - return 0; -} - -/* - * Get the pipe settings. - */ -static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, - struct usb_interface *intf) -{ - struct usb_host_interface *altsetting = intf->cur_altsetting; - struct usb_endpoint_descriptor *ep_in = NULL; - struct usb_endpoint_descriptor *ep_out = NULL; - struct usb_endpoint_descriptor *ep; - int i; - - /* - * Find the endpoints we need. - * We are expecting a minimum of 2 endpoints - in and out (bulk). - * We will ignore any others. - */ - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - ep = &altsetting->endpoint[i].desc; - - /* Is it a BULK endpoint? */ - if (usb_endpoint_xfer_bulk(ep)) { - /* BULK in or out? */ - if (usb_endpoint_dir_in(ep)) { - if (ep_in == NULL) - ep_in = ep; - } else { - if (ep_out == NULL) - ep_out = ep; - } - } - } - - if (ep_in == NULL || ep_out == NULL) { - printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name); - return -ENODEV; - } - - /* Calculate and store the pipe values */ - sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0); - sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0); - sc->send_bulk_pipe = usb_sndbulkpipe(dev, - usb_endpoint_num(ep_out)); - sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, - usb_endpoint_num(ep_in)); - - return 0; -} - -/* - * Probing is done in the process context, which allows us to cheat - * and not to build a state machine for the discovery. - */ -static int ub_probe(struct usb_interface *intf, - const struct usb_device_id *dev_id) -{ - struct ub_dev *sc; - int nluns; - int rc; - int i; - - if (usb_usual_check_type(dev_id, USB_US_TYPE_UB)) - return -ENXIO; - - rc = -ENOMEM; - if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL) - goto err_core; - sc->lock = ub_next_lock(); - INIT_LIST_HEAD(&sc->luns); - usb_init_urb(&sc->work_urb); - tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); - atomic_set(&sc->poison, 0); - INIT_WORK(&sc->reset_work, ub_reset_task); - init_waitqueue_head(&sc->reset_wait); - - init_timer(&sc->work_timer); - sc->work_timer.data = (unsigned long) sc; - sc->work_timer.function = ub_urb_timeout; - - ub_init_completion(&sc->work_done); - sc->work_done.done = 1; /* A little yuk, but oh well... */ - - sc->dev = interface_to_usbdev(intf); - sc->intf = intf; - // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usb_set_intfdata(intf, sc); - usb_get_dev(sc->dev); - /* - * Since we give the interface struct to the block level through - * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent - * oopses on close after a disconnect (kernels 2.6.16 and up). - */ - usb_get_intf(sc->intf); - - snprintf(sc->name, 12, DRV_NAME "(%d.%d)", - sc->dev->bus->busnum, sc->dev->devnum); - - /* XXX Verify that we can handle the device (from descriptors) */ - - if (ub_get_pipes(sc, sc->dev, intf) != 0) - goto err_dev_desc; - - /* - * At this point, all USB initialization is done, do upper layer. - * We really hate halfway initialized structures, so from the - * invariants perspective, this ub_dev is fully constructed at - * this point. - */ - - /* - * This is needed to clear toggles. It is a problem only if we do - * `rmmod ub && modprobe ub` without disconnects, but we like that. - */ -#if 0 /* iPod Mini fails if we do this (big white iPod works) */ - ub_probe_clear_stall(sc, sc->recv_bulk_pipe); - ub_probe_clear_stall(sc, sc->send_bulk_pipe); -#endif - - /* - * The way this is used by the startup code is a little specific. - * A SCSI check causes a USB stall. Our common case code sees it - * and clears the check, after which the device is ready for use. - * But if a check was not present, any command other than - * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE). - * - * If we neglect to clear the SCSI check, the first real command fails - * (which is the capacity readout). We clear that and retry, but why - * causing spurious retries for no reason. - * - * Revalidation may start with its own TEST_UNIT_READY, but that one - * has to succeed, so we clear checks with an additional one here. - * In any case it's not our business how revaliadation is implemented. - */ - for (i = 0; i < 3; i++) { /* Retries for the schwag key from KS'04 */ - if ((rc = ub_sync_tur(sc, NULL)) <= 0) break; - if (rc != 0x6) break; - msleep(10); - } - - nluns = 1; - for (i = 0; i < 3; i++) { - if ((rc = ub_sync_getmaxlun(sc)) < 0) - break; - if (rc != 0) { - nluns = rc; - break; - } - msleep(100); - } - - for (i = 0; i < nluns; i++) { - ub_probe_lun(sc, i); - } - return 0; - -err_dev_desc: - usb_set_intfdata(intf, NULL); - usb_put_intf(sc->intf); - usb_put_dev(sc->dev); - kfree(sc); -err_core: - return rc; -} - -static int ub_probe_lun(struct ub_dev *sc, int lnum) -{ - struct ub_lun *lun; - struct request_queue *q; - struct gendisk *disk; - int rc; - - rc = -ENOMEM; - if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL) - goto err_alloc; - lun->num = lnum; - - rc = -ENOSR; - if ((lun->id = ub_id_get()) == -1) - goto err_id; - - lun->udev = sc; - - snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)", - lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num); - - lun->removable = 1; /* XXX Query this from the device */ - lun->changed = 1; /* ub_revalidate clears only */ - ub_revalidate(sc, lun); - - rc = -ENOMEM; - if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL) - goto err_diskalloc; - - sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a'); - disk->major = UB_MAJOR; - disk->first_minor = lun->id * UB_PARTS_PER_LUN; - disk->fops = &ub_bd_fops; - disk->private_data = lun; - disk->driverfs_dev = &sc->intf->dev; - - rc = -ENOMEM; - if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL) - goto err_blkqinit; - - disk->queue = q; - - blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); - blk_queue_max_segments(q, UB_MAX_REQ_SG); - blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */ - blk_queue_max_hw_sectors(q, UB_MAX_SECTORS); - blk_queue_logical_block_size(q, lun->capacity.bsize); - - lun->disk = disk; - q->queuedata = lun; - list_add(&lun->link, &sc->luns); - - set_capacity(disk, lun->capacity.nsec); - if (lun->removable) - disk->flags |= GENHD_FL_REMOVABLE; - - add_disk(disk); - - return 0; - -err_blkqinit: - put_disk(disk); -err_diskalloc: - ub_id_put(lun->id); -err_id: - kfree(lun); -err_alloc: - return rc; -} - -static void ub_disconnect(struct usb_interface *intf) -{ - struct ub_dev *sc = usb_get_intfdata(intf); - struct ub_lun *lun; - unsigned long flags; - - /* - * Prevent ub_bd_release from pulling the rug from under us. - * XXX This is starting to look like a kref. - * XXX Why not to take this ref at probe time? - */ - spin_lock_irqsave(&ub_lock, flags); - sc->openc++; - spin_unlock_irqrestore(&ub_lock, flags); - - /* - * Fence stall clearings, operations triggered by unlinkings and so on. - * We do not attempt to unlink any URBs, because we do not trust the - * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. - */ - atomic_set(&sc->poison, 1); - - /* - * Wait for reset to end, if any. - */ - wait_event(sc->reset_wait, !sc->reset); - - /* - * Blow away queued commands. - * - * Actually, this never works, because before we get here - * the HCD terminates outstanding URB(s). It causes our - * SCSI command queue to advance, commands fail to submit, - * and the whole queue drains. So, we just use this code to - * print warnings. - */ - spin_lock_irqsave(sc->lock, flags); - { - struct ub_scsi_cmd *cmd; - int cnt = 0; - while ((cmd = ub_cmdq_peek(sc)) != NULL) { - cmd->error = -ENOTCONN; - cmd->state = UB_CMDST_DONE; - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); - cnt++; - } - if (cnt != 0) { - printk(KERN_WARNING "%s: " - "%d was queued after shutdown\n", sc->name, cnt); - } - } - spin_unlock_irqrestore(sc->lock, flags); - - /* - * Unregister the upper layer. - */ - list_for_each_entry(lun, &sc->luns, link) { - del_gendisk(lun->disk); - /* - * I wish I could do: - * queue_flag_set(QUEUE_FLAG_DEAD, q); - * As it is, we rely on our internal poisoning and let - * the upper levels to spin furiously failing all the I/O. - */ - } - - /* - * Testing for -EINPROGRESS is always a bug, so we are bending - * the rules a little. - */ - spin_lock_irqsave(sc->lock, flags); - if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */ - printk(KERN_WARNING "%s: " - "URB is active after disconnect\n", sc->name); - } - spin_unlock_irqrestore(sc->lock, flags); - - /* - * There is virtually no chance that other CPU runs a timeout so long - * after ub_urb_complete should have called del_timer, but only if HCD - * didn't forget to deliver a callback on unlink. - */ - del_timer_sync(&sc->work_timer); - - /* - * At this point there must be no commands coming from anyone - * and no URBs left in transit. - */ - - ub_put(sc); -} - -static struct usb_driver ub_driver = { - .name = "ub", - .probe = ub_probe, - .disconnect = ub_disconnect, - .id_table = ub_usb_ids, - .pre_reset = ub_pre_reset, - .post_reset = ub_post_reset, -}; - -static int __init ub_init(void) -{ - int rc; - int i; - - pr_info("'Low Performance USB Block' driver is deprecated. " - "Please switch to usb-storage\n"); - for (i = 0; i < UB_QLOCK_NUM; i++) - spin_lock_init(&ub_qlockv[i]); - - if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) - goto err_regblkdev; - - if ((rc = usb_register(&ub_driver)) != 0) - goto err_register; - - usb_usual_set_present(USB_US_TYPE_UB); - return 0; - -err_register: - unregister_blkdev(UB_MAJOR, DRV_NAME); -err_regblkdev: - return rc; -} - -static void __exit ub_exit(void) -{ - usb_deregister(&ub_driver); - - unregister_blkdev(UB_MAJOR, DRV_NAME); - usb_usual_clear_present(USB_US_TYPE_UB); -} - -module_init(ub_init); -module_exit(ub_exit); - -MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From e5ec69da24803c68f5c035662a68d367359a4132 Mon Sep 17 00:00:00 2001 From: "Hebbar, Gururaja" Date: Mon, 3 Sep 2012 13:40:40 +0530 Subject: ASoC: Davinci: McASP: add support new McASP IP Variant The OMAP2+ variant of McASP is different from Davinci variant w.r.to some register offset. Changes - Add new MCASP_VERSION_3 to identify new variant. New DT compatible "ti,omap2-mcasp-audio" to identify version 3 controller. - The register offsets are handled depending on the version. Note: DMA parameters (dma fifo offset) are not updated and will be done later. Signed-off-by: Hebbar, Gururaja Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 1 + include/linux/platform_data/davinci_asp.h | 1 + sound/soc/davinci/davinci-mcasp.c | 86 ++++++++++++++++++---- 3 files changed, 75 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index e6148eca294..374e145c2ef 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -4,6 +4,7 @@ Required properties: - compatible : "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms + "ti,omap2-mcasp-audio" : for OMAP2 platforms (TI81xx, AM33xx) - reg : Should contain McASP registers offset and length - interrupts : Interrupt number for McASP diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 79c26aa11db..d0c5825876f 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -87,6 +87,7 @@ struct snd_platform_data { enum { MCASP_VERSION_1 = 0, /* DM646x */ MCASP_VERSION_2, /* DA8xx/OMAPL1x */ + MCASP_VERSION_3, /* TI81xx/AM33xx */ }; enum mcbsp_clk_input_pin { diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index c3eae1d8e07..714e51e5be5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -111,6 +111,10 @@ #define DAVINCI_MCASP_WFIFOSTS (0x1014) #define DAVINCI_MCASP_RFIFOCTL (0x1018) #define DAVINCI_MCASP_RFIFOSTS (0x101C) +#define MCASP_VER3_WFIFOCTL (0x1000) +#define MCASP_VER3_WFIFOSTS (0x1004) +#define MCASP_VER3_RFIFOCTL (0x1008) +#define MCASP_VER3_RFIFOSTS (0x100C) /* * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management @@ -384,18 +388,36 @@ static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { if (dev->txnumevt) { /* enable FIFO */ - mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + switch (dev->version) { + case MCASP_VERSION_3: + mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL, FIFO_ENABLE); - mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL, FIFO_ENABLE); + break; + default: + mcasp_clr_bits(dev->base + + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE); + mcasp_set_bits(dev->base + + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE); + } } mcasp_start_tx(dev); } else { if (dev->rxnumevt) { /* enable FIFO */ - mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, + switch (dev->version) { + case MCASP_VERSION_3: + mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL, FIFO_ENABLE); - mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, + mcasp_set_bits(dev->base + MCASP_VER3_RFIFOCTL, FIFO_ENABLE); + break; + default: + mcasp_clr_bits(dev->base + + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE); + mcasp_set_bits(dev->base + + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE); + } } mcasp_start_rx(dev); } @@ -416,14 +438,31 @@ static void mcasp_stop_tx(struct davinci_audio_dev *dev) static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (dev->txnumevt) /* disable FIFO */ - mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + if (dev->txnumevt) { /* disable FIFO */ + switch (dev->version) { + case MCASP_VERSION_3: + mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL, FIFO_ENABLE); + break; + default: + mcasp_clr_bits(dev->base + + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE); + } + } mcasp_stop_tx(dev); } else { - if (dev->rxnumevt) /* disable FIFO */ - mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, + if (dev->rxnumevt) { /* disable FIFO */ + switch (dev->version) { + case MCASP_VERSION_3: + mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL, FIFO_ENABLE); + break; + + default: + mcasp_clr_bits(dev->base + + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE); + } + } mcasp_stop_rx(dev); } } @@ -622,20 +661,37 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) if (dev->txnumevt * tx_ser > 64) dev->txnumevt = 1; - mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, tx_ser, + switch (dev->version) { + case MCASP_VERSION_3: + mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, tx_ser, NUMDMA_MASK); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); + break; + default: + mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + tx_ser, NUMDMA_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); + } } if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) { if (dev->rxnumevt * rx_ser > 64) dev->rxnumevt = 1; - - mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, rx_ser, + switch (dev->version) { + case MCASP_VERSION_3: + mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, rx_ser, NUMDMA_MASK); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, + mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, + ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); + break; + default: + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, + rx_ser, NUMDMA_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); + } } } @@ -874,6 +930,10 @@ static const struct of_device_id mcasp_dt_ids[] = { .compatible = "ti,da830-mcasp-audio", .data = (void *)MCASP_VERSION_2, }, + { + .compatible = "ti,omap2-mcasp-audio", + .data = (void *)MCASP_VERSION_3, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mcasp_dt_ids); -- cgit v1.2.3-70-g09d2 From be84bbcccc757b86449daaf924e72f95c95dc00e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Aug 2012 16:06:43 +0200 Subject: ALSA: Add a documentation for channel mapping API Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Channel-Mapping-API.txt | 144 +++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Documentation/sound/alsa/Channel-Mapping-API.txt (limited to 'Documentation') diff --git a/Documentation/sound/alsa/Channel-Mapping-API.txt b/Documentation/sound/alsa/Channel-Mapping-API.txt new file mode 100644 index 00000000000..df930aa4f4d --- /dev/null +++ b/Documentation/sound/alsa/Channel-Mapping-API.txt @@ -0,0 +1,144 @@ +ALSA PCM channel-mapping API +============================ + Takashi Iwai + +GENERAL +------- + +The channel mapping API allows user to query the possible channel maps +and the current channel map, also optionally to modify the channel map +of the current stream. + +A channel map is an array of position for each PCM channel. +Typically, a stereo PCM stream has a channel map of + { front_left, front_right } +while a 4.0 surround PCM stream has a channel map of + { front left, front right, rear left, rear right }. + +The problem, so far, was that we had no standard channel map +explicitly, and applications had no way to know which channel +corresponds to which (speaker) position. Thus, applications applied +wrong channels for 5.1 outputs, and you hear suddenly strange sound +from rear. Or, some devices secretly assume that center/LFE is the +third/fourth channels while others that C/LFE as 5th/6th channels. + +Also, some devices such as HDMI are configurable for different speaker +positions even with the same number of total channels. However, there +was no way to specify this because of lack of channel map +specification. These are the main motivations for the new channel +mapping API. + + +DESIGN +------ + +Actually, "the channel mapping API" doesn't introduce anything new in +the kernel/user-space ABI perspective. It uses only the existing +control element features. + +As a ground design, each PCM substream may contain a control element +providing the channel mapping information and configuration. This +element is specified by: + iface = SNDRV_CTL_ELEM_IFACE_PCM + name = "Playback Channel Map" or "Capture Channel Map" + device = the same device number for the assigned PCM substream + index = the same index number for the assigned PCM substream + +Note the name is different depending on the PCM substream direction. + +Each control element provides at least the TLV read operation and the +read operation. Optionally, the write operation can be provided to +allow user to change the channel map dynamically. + +* TLV + +The TLV operation gives the list of available channel +maps. A list item of a channel map is usually a TLV of + type data-bytes ch0 ch1 ch2... +where type is the TLV type value, the second argument is the total +bytes (not the numbers) of channel values, and the rest are the +position value for each channel. + +As a TLV type, either SNDRV_CTL_TLVT_CHMAP_FIXED, +SNDRV_CTL_TLV_CHMAP_VAR or SNDRV_CTL_TLVT_CHMAP_PAIRED can be used. +The _FIXED type is for a channel map with the fixed channel position +while the latter two are for flexible channel positions. _VAR type is +for a channel map where all channels are freely swappable and _PAIRED +type is where pair-wise channels are swappable. For example, when you +have {FL/FR/RL/RR} channel map, _PAIRED type would allow you to swap +only {RL/RR/FL/FR} while _VAR type would allow even swapping FL and +RR. + +These new TLV types are defined in sound/tlv.h. + +The available channel position values are defined in sound/asound.h, +here is a cut: + +/* channel positions */ +enum { + SNDRV_CHMAP_UNKNOWN = 0, + SNDRV_CHMAP_FL, /* front left */ + SNDRV_CHMAP_FC, /* front center */ + SNDRV_CHMAP_FR, /* front right */ + SNDRV_CHMAP_FLC, /* front left center */ + SNDRV_CHMAP_FRC, /* front right center */ + SNDRV_CHMAP_RL, /* rear left */ + SNDRV_CHMAP_RC, /* rear center */ + SNDRV_CHMAP_RR, /* rear right */ + SNDRV_CHMAP_RLC, /* rear left center */ + SNDRV_CHMAP_RRC, /* rear right center */ + SNDRV_CHMAP_SL, /* side left */ + SNDRV_CHMAP_SR, /* side right */ + SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_FLW, /* front left wide */ + SNDRV_CHMAP_FRW, /* front right wide */ + SNDRV_CHMAP_FLH, /* front left high */ + SNDRV_CHMAP_FCH, /* front center high */ + SNDRV_CHMAP_FRH, /* front right high */ + SNDRV_CHMAP_TC, /* top center */ + SNDRV_CHMAP_NA, /* N/A, silent */ + SNDRV_CHMAP_LAST = SNDRV_CHMAP_NA, +}; + +When a PCM stream can provide more than one channel map, you can +provide multiple channel maps in a TLV container type. The TLV data +to be returned will contain such as: + SNDRV_CTL_TLVT_CONTAINER 96 + SNDRV_CTL_TLVT_CHMAP_FIXED 4 SNDRV_CHMAP_FC + SNDRV_CTL_TLVT_CHMAP_FIXED 8 SNDRV_CHMAP_FL SNDRV_CHMAP_FR + SNDRV_CTL_TLVT_CHMAP_FIXED 16 NDRV_CHMAP_FL SNDRV_CHMAP_FR \ + SNDRV_CHMAP_RL SNDRV_CHMAP_RR + +The channel position is provided in LSB 16bits. The upper bits are +used for bit flags. + +#define SNDRV_CHMAP_POSITION_MASK 0xffff +#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) +#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) + +SNDRV_CHMAP_PHASE_INVERSE indicates the channel is phase inverted, +(thus summing left and right channels would result in almost silence). +Some digital mic devices have this. + +When SNDRV_CHMAP_DRIVER_SPEC is set, all the channel position values +don't follow the standard definition above but driver-specific. + +* READ OPERATION + +The control read operation is for providing the current channel map of +the given stream. The control element returns an integer array +containing the position of each channel. + +When this is performed before the number of the channel is specified +(i.e. hw_params is set), it should return all channels set to +UNKNOWN. + +* WRITE OPERATION + +The control write operation is optional, and only for devices that can +change the channel configuration on the fly, such as HDMI. User needs +to pass an integer value containing the valid channel positions for +all channels of the assigned PCM substream. + +This operation is allowed only at PCM PREPARED state. When called in +other states, it shall return an error. -- cgit v1.2.3-70-g09d2 From 7185fcc62d73d2a3ea33977007854b03a5a42404 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 21 Aug 2012 12:50:43 -0300 Subject: devicetree: pwm: mxs-pwm.txt: Fix reg field annotation In the reg field we should annotate the register address space in hexadecimal format. Signed-off-by: Fabio Estevam Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/pwm/mxs-pwm.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt index b16f4a57d11..11963e4d6bc 100644 --- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt @@ -11,7 +11,7 @@ Example: pwm: pwm@80064000 { compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; - reg = <0x80064000 2000>; + reg = <0x80064000 0x2000>; #pwm-cells = <2>; fsl,pwm-number = <8>; }; -- cgit v1.2.3-70-g09d2 From 239078da17ee68c275e87cf9a7f849b227706966 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 21 Aug 2012 14:04:59 -0300 Subject: devicetree: serial: Add documentation for imx serial Add documentation for imx serial. Signed-off-by: Fabio Estevam Signed-off-by: Rob Herring --- .../devicetree/bindings/serial/fsl-imx-uart.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/fsl-imx-uart.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt new file mode 100644 index 00000000000..c58573b5b1a --- /dev/null +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt @@ -0,0 +1,35 @@ +* Freescale i.MX UART controller + +Required properties: +- compatible : should be "fsl,imx21-uart" +- reg : Address and length of the register set for the device +- interrupts : Should contain UART interrupt number + +Optional properties: +- fsl,uart-has-rtscts: indicate that RTS/CTS signals are used + +Note: Each uart controller should have an alias correctly numbered +in "aliases" node. + +Example: + +- From imx51.dtsi: +aliases { + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; +}; + +uart1: serial@73fbc000 { + compatible = "fsl,imx51-uart", "fsl,imx21-uart"; + reg = <0x73fbc000 0x4000>; + interrupts = <31>; + status = "disabled"; +} + +- From imx51-babbage.dts: +uart1: serial@73fbc000 { + fsl,uart-has-rtscts; + status = "okay"; +}; + -- cgit v1.2.3-70-g09d2 From 080108c4747c7378c3601b8584237484f977d8a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Aug 2012 14:47:18 +0200 Subject: ALSA: Follow channel position definitions to alsa-lib mixer There is already a set of channel position definitions in alsa-lib mixer.h, and it'd be more practical to keep the same order for the PCM channel map, too. The value is shifted with 1 to keep zero for UNKNOWN. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Channel-Mapping-API.txt | 16 +++++++++------- include/sound/asound.h | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/Channel-Mapping-API.txt b/Documentation/sound/alsa/Channel-Mapping-API.txt index df930aa4f4d..4bbf12d5553 100644 --- a/Documentation/sound/alsa/Channel-Mapping-API.txt +++ b/Documentation/sound/alsa/Channel-Mapping-API.txt @@ -76,20 +76,22 @@ here is a cut: /* channel positions */ enum { + /* this follows the alsa-lib mixer channel value + 1 */ SNDRV_CHMAP_UNKNOWN = 0, SNDRV_CHMAP_FL, /* front left */ - SNDRV_CHMAP_FC, /* front center */ SNDRV_CHMAP_FR, /* front right */ - SNDRV_CHMAP_FLC, /* front left center */ - SNDRV_CHMAP_FRC, /* front right center */ SNDRV_CHMAP_RL, /* rear left */ - SNDRV_CHMAP_RC, /* rear center */ SNDRV_CHMAP_RR, /* rear right */ - SNDRV_CHMAP_RLC, /* rear left center */ - SNDRV_CHMAP_RRC, /* rear right center */ + SNDRV_CHMAP_FC, /* front center */ + SNDRV_CHMAP_LFE, /* LFE */ SNDRV_CHMAP_SL, /* side left */ SNDRV_CHMAP_SR, /* side right */ - SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_RC, /* rear center */ + /* new definitions */ + SNDRV_CHMAP_FLC, /* front left center */ + SNDRV_CHMAP_FRC, /* front right center */ + SNDRV_CHMAP_RLC, /* rear left center */ + SNDRV_CHMAP_RRC, /* rear right center */ SNDRV_CHMAP_FLW, /* front left wide */ SNDRV_CHMAP_FRW, /* front right wide */ SNDRV_CHMAP_FLH, /* front left high */ diff --git a/include/sound/asound.h b/include/sound/asound.h index 376e75632e0..27686da0f65 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -474,20 +474,22 @@ enum { /* channel positions */ enum { + /* this follows the alsa-lib mixer channel value + 1 */ SNDRV_CHMAP_UNKNOWN = 0, SNDRV_CHMAP_FL, /* front left */ - SNDRV_CHMAP_FC, /* front center */ SNDRV_CHMAP_FR, /* front right */ - SNDRV_CHMAP_FLC, /* front left center */ - SNDRV_CHMAP_FRC, /* front right center */ SNDRV_CHMAP_RL, /* rear left */ - SNDRV_CHMAP_RC, /* rear center */ SNDRV_CHMAP_RR, /* rear right */ - SNDRV_CHMAP_RLC, /* rear left center */ - SNDRV_CHMAP_RRC, /* rear right center */ + SNDRV_CHMAP_FC, /* front center */ + SNDRV_CHMAP_LFE, /* LFE */ SNDRV_CHMAP_SL, /* side left */ SNDRV_CHMAP_SR, /* side right */ - SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_RC, /* rear center */ + /* new definitions */ + SNDRV_CHMAP_FLC, /* front left center */ + SNDRV_CHMAP_FRC, /* front right center */ + SNDRV_CHMAP_RLC, /* rear left center */ + SNDRV_CHMAP_RRC, /* rear right center */ SNDRV_CHMAP_FLW, /* front left wide */ SNDRV_CHMAP_FRW, /* front right wide */ SNDRV_CHMAP_FLH, /* front left high */ -- cgit v1.2.3-70-g09d2 From 6915c0e487c822e2436683e14302c0b8a6155cc7 Mon Sep 17 00:00:00 2001 From: Tomas Hlavacek Date: Thu, 6 Sep 2012 03:17:18 +0200 Subject: tty: uartclk value from serial_core exposed to sysfs Added file /sys/devices/.../tty/ttySX/uartclk to allow reading uartclk value in struct uart_port in serial_core via sysfs. tty_register_device() has been generalized and refactored in order to add support for setting drvdata and attribute_group to the device. Signed-off-by: Tomas Hlavacek Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-tty | 9 +++++ drivers/tty/serial/serial_core.c | 34 ++++++++++++++++-- drivers/tty/tty_io.c | 69 +++++++++++++++++++++++++++++++------ include/linux/tty.h | 4 +++ 4 files changed, 104 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index b138b663bf5..0c430150d92 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -17,3 +17,12 @@ Description: device, like 'tty1'. The file supports poll() to detect virtual console switches. + +What: /sys/class/tty/ttyS0/uartclk +Date: Sep 2012 +Contact: Tomas Hlavacek +Description: + Shows the current uartclk value associated with the + UART port in serial_core, that is bound to TTY like ttyS0. + uartclk = 16 * baud_base + diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 19993d89db3..f629bdf2a8c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2309,6 +2309,36 @@ struct tty_driver *uart_console_device(struct console *co, int *index) return p->tty_driver; } +static ssize_t uart_get_attr_uartclk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + mutex_lock(&state->port.mutex); + ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk); + mutex_unlock(&state->port.mutex); + + return ret; +} + +static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); + +static struct attribute *tty_dev_attrs[] = { + &dev_attr_uartclk.attr, + NULL, + }; + +static struct attribute_group tty_dev_attr_group = { + .attrs = tty_dev_attrs, + }; + +static const struct attribute_group *tty_dev_attr_groups[] = { + &tty_dev_attr_group, + NULL + }; + /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2362,8 +2392,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_dev = tty_port_register_device(port, drv->tty_driver, uport->line, - uport->dev); + tty_dev = tty_register_device_attr(drv->tty_driver, uport->line, + uport->dev, port, tty_dev_attr_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d3bf91a2930..dcb30d55d39 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3041,9 +3041,39 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { - struct device *ret; + return tty_register_device_attr(driver, index, device, NULL, NULL); +} +EXPORT_SYMBOL(tty_register_device); + +/** + * tty_register_device_attr - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. + * + * Returns a pointer to the struct device for this tty device + * (or ERR_PTR(-EFOO) on error). + * + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. + * + * Locking: ?? + */ +struct device *tty_register_device_attr(struct tty_driver *driver, + unsigned index, struct device *device, + void *drvdata, + const struct attribute_group **attr_grp) +{ char name[64]; - dev_t dev = MKDEV(driver->major, driver->minor_start) + index; + dev_t devt = MKDEV(driver->major, driver->minor_start) + index; + struct device *dev = NULL; + int retval = -ENODEV; bool cdev = false; if (index >= driver->num) { @@ -3058,19 +3088,38 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, tty_line_name(driver, index, name); if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { - int error = tty_cdev_add(driver, dev, index, 1); - if (error) - return ERR_PTR(error); + retval = tty_cdev_add(driver, devt, index, 1); + if (retval) + goto error; cdev = true; } - ret = device_create(tty_class, device, dev, NULL, name); - if (IS_ERR(ret) && cdev) - cdev_del(&driver->cdevs[index]); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto error; + } - return ret; + dev->devt = devt; + dev->class = tty_class; + dev->parent = device; + dev_set_name(dev, "%s", name); + dev->groups = attr_grp; + dev_set_drvdata(dev, drvdata); + + retval = device_register(dev); + if (retval) + goto error; + + return dev; + +error: + put_device(dev); + if (cdev) + cdev_del(&driver->cdevs[index]); + return ERR_PTR(retval); } -EXPORT_SYMBOL(tty_register_device); +EXPORT_SYMBOL_GPL(tty_register_device_attr); /** * tty_unregister_device - unregister a tty device diff --git a/include/linux/tty.h b/include/linux/tty.h index 9892121354c..599d60347bf 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -412,6 +412,10 @@ extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); extern struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); +extern struct device *tty_register_device_attr(struct tty_driver *driver, + unsigned index, struct device *device, + void *drvdata, + const struct attribute_group **attr_grp); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); -- cgit v1.2.3-70-g09d2 From 27b18dd97ef23b8f4838fdb3a619e6fd369f87e9 Mon Sep 17 00:00:00 2001 From: Ninja Tekkaman Date: Thu, 6 Sep 2012 01:50:15 +0800 Subject: Documentation: Chinese translation of Documentation/arm/Booting This is a Chinese translated version of Documentation/arm/Booting Signed-off-by: Fu Wei Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman --- Documentation/zh_CN/arm/Booting | 175 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 Documentation/zh_CN/arm/Booting (limited to 'Documentation') diff --git a/Documentation/zh_CN/arm/Booting b/Documentation/zh_CN/arm/Booting new file mode 100644 index 00000000000..3014ea89af3 --- /dev/null +++ b/Documentation/zh_CN/arm/Booting @@ -0,0 +1,175 @@ +Chinese translated version of Documentation/arm/Booting + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Russell King +Chinese maintainer: Fu Wei +--------------------------------------------------------------------- +Documentation/arm/Booting 的中文翻译 + +如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 +交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 +译存在问题,请联系中文版维护者。 + +英文版维护者: Russell King +中文版维护者: 傅炜 Fu Wei +中文版翻译者: 傅炜 Fu Wei +中文版校译者: 傅炜 Fu Wei + +以下为正文 +--------------------------------------------------------------------- + + 启动 ARM Linux + ============== + +作者:Russell King +日期:2002年5月18日 + +以下文档适用于 2.4.18-rmk6 及以上版本。 + +为了启动 ARM Linux,你需要一个引导装载程序(boot loader), +它是一个在主内核启动前运行的一个小程序。引导装载程序需要初始化各种 +设备,并最终调用 Linux 内核,将信息传递给内核。 + +从本质上讲,引导装载程序应提供(至少)以下功能: + +1、设置和初始化 RAM。 +2、初始化一个串口。 +3、检测机器的类型(machine type)。 +4、设置内核标签列表(tagged list)。 +5、调用内核映像。 + + +1、设置和初始化 RAM +------------------- + +现有的引导加载程序: 强制 +新开发的引导加载程序: 强制 + +引导装载程序应该找到并初始化系统中所有内核用于保持系统变量数据的 RAM。 +这个操作的执行是设备依赖的。(它可能使用内部算法来自动定位和计算所有 +RAM,或可能使用对这个设备已知的 RAM 信息,还可能使用任何引导装载程序 +设计者想到的匹配方法。) + + +2、初始化一个串口 +----------------------------- + +现有的引导加载程序: 可选、建议 +新开发的引导加载程序: 可选、建议 + +引导加载程序应该初始化并使能一个目标板上的串口。这允许内核串口驱动 +自动检测哪个串口用于内核控制台。(一般用于调试或与目标板通信。) + +作为替代方案,引导加载程序也可以通过标签列表传递相关的'console=' +选项给内核以指定某个串口,而串口数据格式的选项在以下文档中描述: + + Documentation/kernel-parameters.txt。 + + +3、检测机器类型 +-------------------------- + +现有的引导加载程序: 可选 +新开发的引导加载程序: 强制 + +引导加载程序应该通过某些方式检测自身所处的机器类型。这是一个硬件 +代码或通过查看所连接的硬件用某些算法得到,这些超出了本文档的范围。 +引导加载程序最终必须能提供一个 MACH_TYPE_xxx 值给内核。 +(详见 linux/arch/arm/tools/mach-types )。 + +4、设置启动数据 +------------------ + +现有的引导加载程序: 可选、强烈建议 +新开发的引导加载程序: 强制 + +引导加载程序必须提供标签列表或者 dtb 映像以传递配置数据给内核。启动 +数据的物理地址通过寄存器 r2 传递给内核。 + +4a、设置内核标签列表 +-------------------------------- + +bootloader 必须创建和初始化内核标签列表。一个有效的标签列表以 +ATAG_CORE 标签开始,并以 ATAG_NONE 标签结束。ATAG_CORE 标签可以是 +空的,也可以是非空。一个空 ATAG_CORE 标签其 size 域设置为 +‘2’(0x00000002)。ATAG_NONE 标签的 size 域必须设置为零。 + +在列表中可以保存任意数量的标签。对于一个重复的标签是追加到之前标签 +所携带的信息之后,还是会覆盖原来的信息,是未定义的。某些标签的行为 +是前者,其他是后者。 + +bootloader 必须传递一个系统内存的位置和最小值,以及根文件系统位置。 +因此,最小的标签列表如下所示: + + +-----------+ +基地址 -> | ATAG_CORE | | + +-----------+ | + | ATAG_MEM | | 地址增长方向 + +-----------+ | + | ATAG_NONE | | + +-----------+ v + +标签列表应该保存在系统的 RAM 中。 + +标签列表必须置于内核自解压和 initrd'bootp' 程序都不会覆盖的内存区。 +建议放在 RAM 的头 16KiB 中。 + +4b、设置设备树 +------------------------- + +bootloader 必须以 64bit 地址对齐的形式加载一个设备树映像(dtb)到系统 +RAM 中,并用启动数据初始化它。dtb 格式在文档 +Documentation/devicetree/booting-without-of.txt 中。内核将会在 +dtb 物理地址处查找 dtb 魔数值(0xd00dfeed),以确定 dtb 是否已经代替 +标签列表被传递进来。 + +bootloader 必须传递一个系统内存的位置和最小值,以及根文件系统位置。 +dtb 必须置于内核自解压不会覆盖的内存区。建议将其放置于 RAM 的头 16KiB +中。但是不可将其放置于“0”物理地址处,因为内核认为:r2 中为 0,意味着 +没有标签列表和 dtb 传递过来。 + +5、调用内核映像 +--------------------------- + +现有的引导加载程序: 强制 +新开发的引导加载程序: 强制 + +调用内核映像 zImage 有两个选择。如果 zImge 保存在 flash 中,且是为了 +在 flash 中直接运行而被正确链接的。这样引导加载程序就可以在 flash 中 +直接调用 zImage。 + +zImage 也可以被放在系统 RAM(任意位置)中被调用。注意:内核使用映像 +基地址的前 16KB RAM 空间来保存页表。建议将映像置于 RAM 的 32KB 处。 + +对于以上任意一种情况,都必须符合以下启动状态: + +- 停止所有 DMA 设备,这样内存数据就不会因为虚假网络包或磁盘数据而被破坏。 + 这可能可以节省你许多的调试时间。 + +- CPU 寄存器配置 + r0 = 0, + r1 = (在上面 3 中获取的)机器类型码。 + r2 = 标签列表在系统 RAM 中的物理地址,或 + 设备树块(dtb)在系统 RAM 中的物理地址 + +- CPU 模式 + 所有形式的中断必须被禁止 (IRQs 和 FIQs) + CPU 必须处于 SVC 模式。(对于 Angel 调试有特例存在) + +- 缓存,MMUs + MMU 必须关闭。 + 指令缓存开启或关闭都可以。 + 数据缓存必须关闭。 + +- 引导加载程序应该通过直接跳转到内核映像的第一条指令来调用内核映像。 + + 对于支持 ARM 指令集的 CPU,跳入内核入口时必须处在 ARM 状态,即使 + 对于 Thumb-2 内核也是如此。 + + 对于仅支持 Thumb 指令集的 CPU,比如 Cortex-M 系列的 CPU,跳入 + 内核入口时必须处于 Thumb 状态。 -- cgit v1.2.3-70-g09d2 From 657b306a7bdfca4ae1514b533a0e7c3c6d26dbc6 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 6 Sep 2012 20:27:06 +0530 Subject: usb: phy: add a new driver for omap usb2 phy All phy related programming like enabling/disabling the clocks, powering on/off the phy is taken care of by this driver. It is also used for OTG related functionality like srp. This also includes device tree support for usb2 phy driver and the documentation with device tree binding information is updated. Currently writing to control module register is taken care in this driver which will be removed once the control module driver is in place. Cc: Felipe Balbi Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/usb-phy.txt | 17 ++ drivers/usb/phy/Kconfig | 9 + drivers/usb/phy/Makefile | 1 + drivers/usb/phy/omap-usb2.c | 271 ++++++++++++++++++++++ include/linux/usb/omap_usb.h | 46 ++++ include/linux/usb/phy_companion.h | 34 +++ 6 files changed, 378 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/usb-phy.txt create mode 100644 drivers/usb/phy/omap-usb2.c create mode 100644 include/linux/usb/omap_usb.h create mode 100644 include/linux/usb/phy_companion.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt new file mode 100644 index 00000000000..80d4148cb66 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-phy.txt @@ -0,0 +1,17 @@ +USB PHY + +OMAP USB2 PHY + +Required properties: + - compatible: Should be "ti,omap-usb2" + - reg : Address and length of the register set for the device. Also +add the address of control module dev conf register until a driver for +control module is added + +This is usually a subnode of ocp2scp to which it is connected. + +usb2phy@4a0ad080 { + compatible = "ti,omap-usb2"; + reg = <0x4a0ad080 0x58>, + <0x4a002300 0x4>; +}; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 2838adb225e..63c339b3e67 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -4,6 +4,15 @@ comment "USB Physical Layer drivers" depends on USB || USB_GADGET +config OMAP_USB2 + tristate "OMAP USB2 PHY Driver" + select USB_OTG_UTILS + help + Enable this to support the transceiver that is part of SOC. This + driver takes care of all the PHY functionality apart from comparator. + The USB OTG controller communicates with the comparator using this + driver. + config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index bb948fb8654..b069f29f122 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -4,6 +4,7 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG +obj-$(CONFIG_OMAP_USB2) += omap-usb2.o obj-$(CONFIG_USB_ISP1301) += isp1301.o obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c new file mode 100644 index 00000000000..15ab3d6f2e8 --- /dev/null +++ b/drivers/usb/phy/omap-usb2.c @@ -0,0 +1,271 @@ +/* + * omap-usb2.c - USB PHY, talking to musb controller in OMAP. + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * omap_usb2_set_comparator - links the comparator present in the sytem with + * this phy + * @comparator - the companion phy(comparator) for this phy + * + * The phy companion driver should call this API passing the phy_companion + * filled with set_vbus and start_srp to be used by usb phy. + * + * For use by phy companion driver + */ +int omap_usb2_set_comparator(struct phy_companion *comparator) +{ + struct omap_usb *phy; + struct usb_phy *x = usb_get_phy(USB_PHY_TYPE_USB2); + + if (IS_ERR(x)) + return -ENODEV; + + phy = phy_to_omapusb(x); + phy->comparator = comparator; + return 0; +} +EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); + +/** + * omap_usb_phy_power - power on/off the phy using control module reg + * @phy: struct omap_usb * + * @on: 0 or 1, based on powering on or off the PHY + * + * XXX: Remove this function once control module driver gets merged + */ +static void omap_usb_phy_power(struct omap_usb *phy, int on) +{ + u32 val; + + if (on) { + val = readl(phy->control_dev); + if (val & PHY_PD) { + writel(~PHY_PD, phy->control_dev); + /* XXX: add proper documentation for this delay */ + mdelay(200); + } + } else { + writel(PHY_PD, phy->control_dev); + } +} + +static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) +{ + struct omap_usb *phy = phy_to_omapusb(otg->phy); + + if (!phy->comparator) + return -ENODEV; + + return phy->comparator->set_vbus(phy->comparator, enabled); +} + +static int omap_usb_start_srp(struct usb_otg *otg) +{ + struct omap_usb *phy = phy_to_omapusb(otg->phy); + + if (!phy->comparator) + return -ENODEV; + + return phy->comparator->start_srp(phy->comparator); +} + +static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + struct usb_phy *phy = otg->phy; + + otg->host = host; + if (!host) + phy->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int omap_usb_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + struct usb_phy *phy = otg->phy; + + otg->gadget = gadget; + if (!gadget) + phy->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int omap_usb2_suspend(struct usb_phy *x, int suspend) +{ + u32 ret; + struct omap_usb *phy = phy_to_omapusb(x); + + if (suspend && !phy->is_suspended) { + omap_usb_phy_power(phy, 0); + pm_runtime_put_sync(phy->dev); + phy->is_suspended = 1; + } else if (!suspend && phy->is_suspended) { + ret = pm_runtime_get_sync(phy->dev); + if (ret < 0) { + dev_err(phy->dev, "get_sync failed with err %d\n", + ret); + return ret; + } + omap_usb_phy_power(phy, 1); + phy->is_suspended = 0; + } + + return 0; +} + +static int __devinit omap_usb2_probe(struct platform_device *pdev) +{ + struct omap_usb *phy; + struct usb_otg *otg; + struct resource *res; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n"); + return -ENOMEM; + } + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) { + dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n"); + return -ENOMEM; + } + + phy->dev = &pdev->dev; + + phy->phy.dev = phy->dev; + phy->phy.label = "omap-usb2"; + phy->phy.set_suspend = omap_usb2_suspend; + phy->phy.otg = otg; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + phy->control_dev = devm_request_and_ioremap(&pdev->dev, res); + if (phy->control_dev == NULL) { + dev_err(&pdev->dev, "Failed to obtain io memory\n"); + return -ENXIO; + } + + phy->is_suspended = 1; + omap_usb_phy_power(phy, 0); + + otg->set_host = omap_usb_set_host; + otg->set_peripheral = omap_usb_set_peripheral; + otg->set_vbus = omap_usb_set_vbus; + otg->start_srp = omap_usb_start_srp; + otg->phy = &phy->phy; + + phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + if (IS_ERR(phy->wkupclk)) { + dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); + return PTR_ERR(phy->wkupclk); + } + clk_prepare(phy->wkupclk); + + usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2); + + platform_set_drvdata(pdev, phy); + + pm_runtime_enable(phy->dev); + + return 0; +} + +static int __devexit omap_usb2_remove(struct platform_device *pdev) +{ + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_unprepare(phy->wkupclk); + usb_remove_phy(&phy->phy); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static int omap_usb2_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_disable(phy->wkupclk); + + return 0; +} + +static int omap_usb2_runtime_resume(struct device *dev) +{ + u32 ret = 0; + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + ret = clk_enable(phy->wkupclk); + if (ret < 0) + dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); + + return ret; +} + +static const struct dev_pm_ops omap_usb2_pm_ops = { + SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, + NULL) +}; + +#define DEV_PM_OPS (&omap_usb2_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id omap_usb2_id_table[] = { + { .compatible = "ti,omap-usb2" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_usb2_id_table); +#endif + +static struct platform_driver omap_usb2_driver = { + .probe = omap_usb2_probe, + .remove = __devexit_p(omap_usb2_remove), + .driver = { + .name = "omap-usb2", + .owner = THIS_MODULE, + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap_usb2_id_table), + }, +}; + +module_platform_driver(omap_usb2_driver); + +MODULE_ALIAS("platform: omap_usb2"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP USB2 phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h new file mode 100644 index 00000000000..0ea17f8ae82 --- /dev/null +++ b/include/linux/usb/omap_usb.h @@ -0,0 +1,46 @@ +/* + * omap_usb.h -- omap usb2 phy header file + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_OMAP_USB2_H +#define __DRIVERS_OMAP_USB2_H + +#include + +struct omap_usb { + struct usb_phy phy; + struct phy_companion *comparator; + struct device *dev; + u32 __iomem *control_dev; + struct clk *wkupclk; + u8 is_suspended:1; +}; + +#define PHY_PD 0x1 + +#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy) + +#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE) +extern int omap_usb2_set_comparator(struct phy_companion *comparator); +#else +static inline int omap_usb2_set_comparator(struct phy_companion *comparator) +{ + return -ENODEV; +} +#endif + +#endif /* __DRIVERS_OMAP_USB_H */ diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h new file mode 100644 index 00000000000..edd2ec23d28 --- /dev/null +++ b/include/linux/usb/phy_companion.h @@ -0,0 +1,34 @@ +/* + * phy-companion.h -- phy companion to indicate the comparator part of PHY + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_PHY_COMPANION_H +#define __DRIVERS_PHY_COMPANION_H + +#include + +/* phy_companion to take care of VBUS, ID and srp capabilities */ +struct phy_companion { + + /* effective for A-peripheral, ignored for B devices */ + int (*set_vbus)(struct phy_companion *x, bool enabled); + + /* for B devices only: start session with A-Host */ + int (*start_srp)(struct phy_companion *x); +}; + +#endif /* __DRIVERS_PHY_COMPANION_H */ -- cgit v1.2.3-70-g09d2 From ff0a1f39400a8d2c02343bd22d295517d72e58ec Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 6 Sep 2012 20:27:08 +0530 Subject: usb: twl6030: Add dt support for twl6030 usb Add device tree support for twl6030 usb driver. Update the Documentation with device tree binding information. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/twlxxxx-usb.txt | 21 ++++++++++++ drivers/usb/otg/twl6030-usb.c | 39 ++++++++++++++-------- 2 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/twlxxxx-usb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt new file mode 100644 index 00000000000..930f9ff2952 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt @@ -0,0 +1,21 @@ +USB COMPARATOR OF TWL CHIPS + +TWL6030 USB COMPARATOR + - compatible : Should be "ti,twl6030-usb" + - interrupts : Two interrupt numbers to the cpu should be specified. First + interrupt number is the otg interrupt number that raises ID interrupts when + the controller has to act as host and the second interrupt number is the + usb interrupt number that raises VBUS interrupts when the controller has to + act as device + - usb-supply : phandle to the regulator device tree node. It should be vusb + if it is twl6030 or ldousb if it is twl6025 subclass. + +twl6030-usb { + compatible = "ti,twl6030-usb"; + interrupts = < 4 10 >; +}; + +Board specific device node entry +&twl6030-usb { + usb-supply = <&vusb>; +}; diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index 32525bb667e..fcadef7864f 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c @@ -105,7 +105,7 @@ struct twl6030_usb { u8 asleep; bool irq_enabled; bool vbus_enable; - unsigned long features; + const char *regulator; }; #define comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator) @@ -153,13 +153,6 @@ static int twl6030_start_srp(struct phy_companion *comparator) static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { - char *regulator_name; - - if (twl->features & TWL6025_SUBCLASS) - regulator_name = "ldousb"; - else - regulator_name = "vusb"; - /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); @@ -169,7 +162,7 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl) /* Program MISC2 register and set bit VUSB_IN_VBAT */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); - twl->usb3v3 = regulator_get(twl->dev, regulator_name); + twl->usb3v3 = regulator_get(twl->dev, twl->regulator); if (IS_ERR(twl->usb3v3)) return -ENODEV; @@ -322,9 +315,9 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) u32 ret; struct twl6030_usb *twl; int status, err; - struct twl4030_usb_data *pdata; - struct device *dev = &pdev->dev; - pdata = dev->platform_data; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct twl4030_usb_data *pdata = dev->platform_data; twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL); if (!twl) @@ -333,7 +326,6 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) twl->dev = &pdev->dev; twl->irq1 = platform_get_irq(pdev, 0); twl->irq2 = platform_get_irq(pdev, 1); - twl->features = pdata->features; twl->linkstat = OMAP_MUSB_UNKNOWN; twl->comparator.set_vbus = twl6030_set_vbus; @@ -345,6 +337,18 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + if (np) { + twl->regulator = "usb"; + } else if (pdata) { + if (pdata->features & TWL6025_SUBCLASS) + twl->regulator = "ldousb"; + else + twl->regulator = "vusb"; + } else { + dev_err(&pdev->dev, "twl6030 initialized without pdata\n"); + return -EINVAL; + } + /* init spinlock for workqueue */ spin_lock_init(&twl->lock); @@ -406,12 +410,21 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id twl6030_usb_id_table[] = { + { .compatible = "ti,twl6030-usb" }, + {} +}; +MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); +#endif + static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, .remove = __exit_p(twl6030_usb_remove), .driver = { .name = "twl6030_usb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl6030_usb_id_table), }, }; -- cgit v1.2.3-70-g09d2 From f8515f0639c337b6fac2f24073368ae834053a96 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 6 Sep 2012 20:27:09 +0530 Subject: usb: twl4030: Add device tree support for twl4030 usb Add device tree support for twl4030 usb driver. Update the Documentation with device tree binding information. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/twlxxxx-usb.txt | 19 ++++++++++++++++ drivers/usb/otg/twl4030-usb.c | 26 +++++++++++++++++----- 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt index 930f9ff2952..36b9aede3f4 100644 --- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt +++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt @@ -19,3 +19,22 @@ Board specific device node entry &twl6030-usb { usb-supply = <&vusb>; }; + +TWL4030 USB PHY AND COMPARATOR + - compatible : Should be "ti,twl4030-usb" + - interrupts : The interrupt numbers to the cpu should be specified. First + interrupt number is the otg interrupt number that raises ID interrupts + and VBUS interrupts. The second interrupt number is optional. + - -supply : phandle to the regulator device tree node. + should be vusb1v5, vusb1v8 and vusb3v1 + - usb_mode : The mode used by the phy to connect to the controller. "1" + specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode. + +twl4030-usb { + compatible = "ti,twl4030-usb"; + interrupts = < 10 4 >; + usb1v5-supply = <&vusb1v5>; + usb1v8-supply = <&vusb1v8>; + usb3v1-supply = <&vusb3v1>; + usb_mode = <1>; +}; diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 523cad5bfea..f0d2e7530cf 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -585,23 +585,28 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb *twl; int status, err; struct usb_otg *otg; - - if (!pdata) { - dev_dbg(&pdev->dev, "platform_data not available\n"); - return -EINVAL; - } + struct device_node *np = pdev->dev.of_node; twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL); if (!twl) return -ENOMEM; + if (np) + of_property_read_u32(np, "usb_mode", + (enum twl4030_usb_mode *)&twl->usb_mode); + else if (pdata) + twl->usb_mode = pdata->usb_mode; + else { + dev_err(&pdev->dev, "twl4030 initialized without pdata\n"); + return -EINVAL; + } + otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL); if (!otg) return -ENOMEM; twl->dev = &pdev->dev; twl->irq = platform_get_irq(pdev, 0); - twl->usb_mode = pdata->usb_mode; twl->vbus_supplied = false; twl->asleep = 1; twl->linkstat = OMAP_MUSB_UNKNOWN; @@ -690,12 +695,21 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id twl4030_usb_id_table[] = { + { .compatible = "ti,twl4030-usb" }, + {} +}; +MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); +#endif + static struct platform_driver twl4030_usb_driver = { .probe = twl4030_usb_probe, .remove = __exit_p(twl4030_usb_remove), .driver = { .name = "twl4030_usb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl4030_usb_id_table), }, }; -- cgit v1.2.3-70-g09d2 From 620c789263cdcbb507f332b89beda6a40b82daaf Mon Sep 17 00:00:00 2001 From: srinivas pandruvada Date: Wed, 5 Sep 2012 13:56:00 +0100 Subject: HID: sensors: add documentation Added a summary of HID sensor framework. Signed-off-by: srinivas pandruvada Signed-off-by: Jiri Kosina Signed-off-by: Jonathan Cameron --- Documentation/hid/hid-sensor.txt | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100755 Documentation/hid/hid-sensor.txt (limited to 'Documentation') diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.txt new file mode 100755 index 00000000000..948b0989c43 --- /dev/null +++ b/Documentation/hid/hid-sensor.txt @@ -0,0 +1,140 @@ + +HID Sensors Framework +====================== +HID sensor framework provides necessary interfaces to implement sensor drivers, +which are connected to a sensor hub. The sensor hub is a HID device and it provides +a report descriptor conforming to HID 1.12 sensor usage tables. + +Description from the HID 1.12 "HID Sensor Usages" specification: +"Standardization of HID usages for sensors would allow (but not require) sensor +hardware vendors to provide a consistent Plug And Play interface at the USB boundary, +thereby enabling some operating systems to incorporate common device drivers that +could be reused between vendors, alleviating any need for the vendors to provide +the drivers themselves." + +This specification describes many usage IDs, which describe the type of sensor +and also the individual data fields. Each sensor can have variable number of +data fields. The length and order is specified in the report descriptor. For +example a part of report descriptor can look like: + + INPUT(1)[INPUT] + .. + Field(2) + Physical(0020.0073) + Usage(1) + 0020.045f + Logical Minimum(-32767) + Logical Maximum(32767) + Report Size(8) + Report Count(1) + Report Offset(16) + Flags(Variable Absolute) +.. +.. + +The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73). +This accelerometer-3D has some fields. Here for example field 2 is motion intensity +(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The +order of fields and length of each field is important as the input event raw +data will use this format. + + +Implementation +================= + +This specification defines many different types of sensors with different sets of +data fields. It is difficult to have a common input event to user space applications, +for different sensors. For example an accelerometer can send X,Y and Z data, whereas +an ambient light sensor can send illumination data. +So the implementation has two parts: +- Core hid driver +- Individual sensor processing part (sensor drivers) + +Core driver +----------- +The core driver registers (hid-sensor-hub) registers as a HID driver. It parses +report descriptors and identifies all the sensors present. It adds an MFD device +with name HID-SENSOR-xxxx (where xxxx is usage id from the specification). +For example +HID-SENSOR-200073 is registered for an Accelerometer 3D driver. +So if any driver with this name is inserted, then the probe routine for that +function will be called. So an accelerometer processing driver can register +with this name and will be probed if there is an accelerometer-3D detected. + +The core driver provides a set of APIs which can be used by the processing +drivers to register and get events for that usage id. Also it provides parsing +functions, which get and set each input/feature/output report. + +Individual sensor processing part (sensor drivers) +----------- +The processing driver will use an interface provided by the core driver to parse +the report and get the indexes of the fields and also can get events. This driver +can use IIO interface to use the standard ABI defined for a type of sensor. + + +Core driver Interface +===================== + +Callback structure: +Each processing driver can use this structure to set some callbacks. + int (*suspend)(..): Callback when HID suspend is received + int (*resume)(..): Callback when HID resume is received + int (*capture_sample)(..): Capture a sample for one of its data fields + int (*send_event)(..): One complete event is received which can have + multiple data fields. + +Registration functions: +int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_hub_callbacks *usage_callback): + +Registers callbacks for an usage id. The callback functions are not allowed +to sleep. + + +int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id): + +Removes callbacks for an usage id. + + +Parsing function: +int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, + u8 type, + u32 usage_id, u32 attr_usage_id, + struct hid_sensor_hub_attribute_info *info); + +A processing driver can look for some field of interest and check if it exists +in a report descriptor. If it exists it will store necessary information +so that fields can be set or get individually. +These indexes avoid searching every time and getting field index to get or set. + + +Set Feature report +int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 value); + +This interface is used to set a value for a field in feature report. For example +if there is a field report_interval, which is parsed by a call to +sensor_hub_input_get_attribute_info before, then it can directly set that individual +field. + + +int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 *value); + +This interface is used to get a value for a field in input report. For example +if there is a field report_interval, which is parsed by a call to +sensor_hub_input_get_attribute_info before, then it can directly get that individual +field value. + + +int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + u32 attr_usage_id, u32 report_id); + +This is used to get a particular field value through input reports. For example +accelerometer wants to poll X axis value, then it can call this function with +the usage id of X axis. HID sensors can provide events, so this is not necessary +to poll for any field. If there is some new sample, the core driver will call +registered callback function to process the sample. -- cgit v1.2.3-70-g09d2 From 30574f0db1b16fedf705cb792099f8a3171598eb Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Fri, 7 Sep 2012 06:07:19 +0900 Subject: pinctrl: add samsung pinctrl and gpiolib driver Add a new device tree enabled pinctrl and gpiolib driver for Samsung SoC's. This driver provides a common and extensible framework for all Samsung SoC's to interface with the pinctrl and gpiolib subsystems. This driver supports only device tree based instantiation and hence can be used only on those Samsung platforms that have device tree enabled. This driver is split into two parts: the pinctrl interface and the gpiolib interface. The pinctrl interface registers pinctrl devices with the pinctrl subsystem and gpiolib interface registers gpio chips with the gpiolib subsystem. The information about the pins, pin groups, pin functions and gpio chips, which are SoC specific, are parsed from device tree node. Signed-off-by: Thomas Abraham Reviewed-by: Linus Walleij Acked-by: Stephen Warren Signed-off-by: Kukjin Kim --- .../bindings/pinctrl/samsung-pinctrl.txt | 196 +++++ drivers/pinctrl/Kconfig | 5 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-samsung.c | 888 +++++++++++++++++++++ drivers/pinctrl/pinctrl-samsung.h | 239 ++++++ 5 files changed, 1329 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl-samsung.c create mode 100644 drivers/pinctrl/pinctrl-samsung.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt new file mode 100644 index 00000000000..03dee50532f --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt @@ -0,0 +1,196 @@ +Samsung GPIO and Pin Mux/Config controller + +Samsung's ARM based SoC's integrates a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pads/pins +and also provides ability to multiplex and configure the output of various +on-chip controllers onto these pads. + +Required Properties: +- compatible: should be one of the following. + - "samsung,pinctrl-exynos4210": for Exynos4210 compatible pin-controller. + - "samsung,pinctrl-exynos5250": for Exynos5250 compatible pin-controller. + +- reg: Base address of the pin controller hardware module and length of + the address space it occupies. + +- interrupts: interrupt specifier for the controller. The format and value of + the interrupt specifier depends on the interrupt parent for the controller. + +- Pin mux/config groups as child nodes: The pin mux (selecting pin function + mode) and pin config (pull up/down, driver strength) settings are represented + as child nodes of the pin-controller node. There should be atleast one + child node and there is no limit on the count of these child nodes. + + The child node should contain a list of pin(s) on which a particular pin + function selection or pin configuration (or both) have to applied. This + list of pins is specified using the property name "samsung,pins". There + should be atleast one pin specfied for this property and there is no upper + limit on the count of pins that can be specified. The pins are specified + using pin names which are derived from the hardware manual of the SoC. As + an example, the pins in GPA0 bank of the pin controller can be represented + as "gpa0-0", "gpa0-1", "gpa0-2" and so on. The names should be in lower case. + The format of the pin names should be (as per the hardware manual) + "[pin bank name]-[pin number within the bank]". + + The pin function selection that should be applied on the pins listed in the + child node is specified using the "samsung,pin-function" property. The value + of this property that should be applied to each of the pins listed in the + "samsung,pins" property should be picked from the hardware manual of the SoC + for the specified pin group. This property is optional in the child node if + no specific function selection is desired for the pins listed in the child + node. The value of this property is used as-is to program the pin-controller + function selector register of the pin-bank. + + The child node can also optionally specify one or more of the pin + configuration that should be applied on all the pins listed in the + "samsung,pins" property of the child node. The following pin configuration + properties are supported. + + - samsung,pin-pud: Pull up/down configuration. + - samsung,pin-drv: Drive strength configuration. + - samsung,pin-pud-pdn: Pull up/down configuration in power down mode. + - samsung,pin-drv-pdn: Drive strength configuration in power down mode. + + The values specified by these config properties should be derived from the + hardware manual and these values are programmed as-is into the pin + pull up/down and driver strength register of the pin-controller. + + Note: A child should include atleast a pin function selection property or + pin configuration property (one or more) or both. + + The client nodes that require a particular pin function selection and/or + pin configuration should use the bindings listed in the "pinctrl-bindings.txt" + file. + +External GPIO and Wakeup Interrupts: + +The controller supports two types of external interrupts over gpio. The first +is the external gpio interrupt and second is the external wakeup interrupts. +The difference between the two is that the external wakeup interrupts can be +used as system wakeup events. + +A. External GPIO Interrupts: For supporting external gpio interrupts, the + following properties should be specified in the pin-controller device node. + +- interrupt-controller: identifies the controller node as interrupt-parent. +- #interrupt-cells: the value of this property should be 2. + - First Cell: represents the external gpio interrupt number local to the + external gpio interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered + +B. External Wakeup Interrupts: For supporting external wakeup interrupts, a + child node representing the external wakeup interrupt controller should be + included in the pin-controller device node. This child node should include + the following properties. + + - compatible: identifies the type of the external wakeup interrupt controller + The possible values are: + - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller + found on Samsung Exynos4210 SoC. + - interrupt-parent: phandle of the interrupt parent to which the external + wakeup interrupts are forwarded to. + - interrupt-controller: identifies the node as interrupt-parent. + - #interrupt-cells: the value of this property should be 2 + - First Cell: represents the external wakeup interrupt number local to + the external wakeup interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered + +Aliases: + +All the pin controller nodes should be represented in the aliases node using +the following format 'pinctrl{n}' where n is a unique number for the alias. + +Example 1: A pin-controller node with pin groups. + + pinctrl_0: pinctrl@11400000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x11400000 0x1000>; + interrupts = <0 47 0>; + + uart0_data: uart0-data { + samsung,pins = "gpa0-0", "gpa0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart0_fctl: uart0-fctl { + samsung,pins = "gpa0-2", "gpa0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart1_data: uart1-data { + samsung,pins = "gpa0-4", "gpa0-5"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart1_fctl: uart1-fctl { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + i2c2_bus: i2c2-bus { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + }; + +Example 2: A pin-controller node with external wakeup interrupt controller node. + + pinctrl_1: pinctrl@11000000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x11000000 0x1000>; + interrupts = <0 46 0>; + interrupt-controller; + #interrupt-cells = <2>; + + wakup_eint: wakeup-interrupt-controller { + compatible = "samsung,exynos4210-wakeup-eint"; + interrupt-parent = <&gic>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, + <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, + <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, + <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>, + <0 32 0>; + }; + }; + +Example 3: A uart client node that supports 'default' and 'flow-control' states. + + uart@13800000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13800000 0x100>; + interrupts = <0 52 0>; + pinctrl-names = "default", "flow-control; + pinctrl-0 = <&uart0_data>; + pinctrl-1 = <&uart0_data &uart0_fctl>; + }; + +Example 4: Set up the default pin state for uart controller. + + static int s3c24xx_serial_probe(struct platform_device *pdev) { + struct pinctrl *pinctrl; + ... + ... + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + } diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54e3588bef6..ffed467422e 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -145,6 +145,11 @@ config PINCTRL_COH901 COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 ports of 8 GPIO pins each. +config PINCTRL_SAMSUNG + bool "Samsung pinctrl driver" + select PINMUX + select PINCONF + source "drivers/pinctrl/spear/Kconfig" endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f40b1f81ff2..656ed83372c 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o +obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c new file mode 100644 index 00000000000..8a24223d533 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -0,0 +1,888 @@ +/* + * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * Author: Thomas Abraham + * + * 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 driver implements the Samsung pinctrl driver. It supports setting up of + * pinmux and pinconf configurations. The gpiolib interface is also included. + * External interrupt (gpio and wakeup) support are not included in this driver + * but provides extensions to which platform specific implementation of the gpio + * and wakeup interrupts can be hooked to. + */ + +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "pinctrl-samsung.h" + +#define GROUP_SUFFIX "-grp" +#define GSUFFIX_LEN sizeof(GROUP_SUFFIX) +#define FUNCTION_SUFFIX "-mux" +#define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) + +/* list of all possible config options supported */ +struct pin_config { + char *prop_cfg; + unsigned int cfg_type; +} pcfgs[] = { + { "samsung,pin-pud", PINCFG_TYPE_PUD }, + { "samsung,pin-drv", PINCFG_TYPE_DRV }, + { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, + { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, +}; + +/* check if the selector is a valid pin group selector */ +static int samsung_get_group_count(struct pinctrl_dev *pctldev) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->nr_groups; +} + +/* return the name of the group selected by the group selector */ +static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->pin_groups[selector].name; +} + +/* return the pin numbers associated with the specified group */ +static int samsung_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, unsigned *num_pins) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + *pins = drvdata->pin_groups[selector].pins; + *num_pins = drvdata->pin_groups[selector].num_pins; + return 0; +} + +/* create pinctrl_map entries by parsing device tree nodes */ +static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **maps, + unsigned *nmaps) +{ + struct device *dev = pctldev->dev; + struct pinctrl_map *map; + unsigned long *cfg = NULL; + char *gname, *fname; + int cfg_cnt = 0, map_cnt = 0, idx = 0; + + /* count the number of config options specfied in the node */ + for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { + if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) + cfg_cnt++; + } + + /* + * Find out the number of map entries to create. All the config options + * can be accomadated into a single config map entry. + */ + if (cfg_cnt) + map_cnt = 1; + if (of_find_property(np, "samsung,pin-function", NULL)) + map_cnt++; + if (!map_cnt) { + dev_err(dev, "node %s does not have either config or function " + "configurations\n", np->name); + return -EINVAL; + } + + /* Allocate memory for pin-map entries */ + map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); + if (!map) { + dev_err(dev, "could not alloc memory for pin-maps\n"); + return -ENOMEM; + } + *nmaps = 0; + + /* + * Allocate memory for pin group name. The pin group name is derived + * from the node name from which these map entries are be created. + */ + gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); + if (!gname) { + dev_err(dev, "failed to alloc memory for group name\n"); + goto free_map; + } + sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); + + /* + * don't have config options? then skip over to creating function + * map entries. + */ + if (!cfg_cnt) + goto skip_cfgs; + + /* Allocate memory for config entries */ + cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); + if (!cfg) { + dev_err(dev, "failed to alloc memory for configs\n"); + goto free_gname; + } + + /* Prepare a list of config settings */ + for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { + u32 value; + if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) + cfg[cfg_cnt++] = + PINCFG_PACK(pcfgs[idx].cfg_type, value); + } + + /* create the config map entry */ + map[*nmaps].data.configs.group_or_pin = gname; + map[*nmaps].data.configs.configs = cfg; + map[*nmaps].data.configs.num_configs = cfg_cnt; + map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + *nmaps += 1; + +skip_cfgs: + /* create the function map entry */ + if (of_find_property(np, "samsung,pin-function", NULL)) { + fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); + if (!fname) { + dev_err(dev, "failed to alloc memory for func name\n"); + goto free_cfg; + } + sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); + + map[*nmaps].data.mux.group = gname; + map[*nmaps].data.mux.function = fname; + map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + *nmaps += 1; + } + + *maps = map; + return 0; + +free_cfg: + kfree(cfg); +free_gname: + kfree(gname); +free_map: + kfree(map); + return -ENOMEM; +} + +/* free the memory allocated to hold the pin-map table */ +static void samsung_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int idx; + + for (idx = 0; idx < num_maps; idx++) { + if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { + kfree(map[idx].data.mux.function); + if (!idx) + kfree(map[idx].data.mux.group); + } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { + kfree(map[idx].data.configs.configs); + if (!idx) + kfree(map[idx].data.configs.group_or_pin); + } + }; + + kfree(map); +} + +/* list of pinctrl callbacks for the pinctrl core */ +static struct pinctrl_ops samsung_pctrl_ops = { + .get_groups_count = samsung_get_group_count, + .get_group_name = samsung_get_group_name, + .get_group_pins = samsung_get_group_pins, + .dt_node_to_map = samsung_dt_node_to_map, + .dt_free_map = samsung_dt_free_map, +}; + +/* check if the selector is a valid pin function selector */ +static int samsung_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->nr_functions; +} + +/* return the name of the pin function specified */ +static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->pmx_functions[selector].name; +} + +/* return the groups associated for the specified function selector */ +static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, const char * const **groups, + unsigned * const num_groups) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + *groups = drvdata->pmx_functions[selector].groups; + *num_groups = drvdata->pmx_functions[selector].num_groups; + return 0; +} + +/* + * given a pin number that is local to a pin controller, find out the pin bank + * and the register base of the pin bank. + */ +static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, + void __iomem **reg, u32 *offset, + struct samsung_pin_bank **bank) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct samsung_pin_bank *b; + + drvdata = dev_get_drvdata(gc->dev); + b = drvdata->ctrl->pin_banks; + + while ((pin >= b->pin_base) && + ((b->pin_base + b->nr_pins - 1) < pin)) + b++; + + *reg = drvdata->virt_base + b->pctl_offset; + *offset = pin - b->pin_base; + if (bank) + *bank = b; + + /* some banks have two config registers in a single bank */ + if (*offset * b->func_width > BITS_PER_LONG) + *reg += 4; +} + +/* enable or disable a pinmux function */ +static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group, bool enable) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + struct samsung_pin_bank *bank; + void __iomem *reg; + u32 mask, shift, data, pin_offset, cnt; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + + /* + * for each pin in the pin group selected, program the correspoding pin + * pin function number in the config register. + */ + for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { + pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, + ®, &pin_offset, &bank); + mask = (1 << bank->func_width) - 1; + shift = pin_offset * bank->func_width; + + data = readl(reg); + data &= ~(mask << shift); + if (enable) + data |= drvdata->pin_groups[group].func << shift; + writel(data, reg); + } +} + +/* enable a specified pinmux by writing to registers */ +static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + samsung_pinmux_setup(pctldev, selector, group, true); + return 0; +} + +/* disable a specified pinmux by writing to registers */ +static void samsung_pinmux_disable(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + samsung_pinmux_setup(pctldev, selector, group, false); +} + +/* + * The calls to gpio_direction_output() and gpio_direction_input() + * leads to this function call (via the pinctrl_gpio_direction_{input|output}() + * function called from the gpiolib interface). + */ +static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ + struct samsung_pin_bank *bank; + void __iomem *reg; + u32 data, pin_offset, mask, shift; + + pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); + mask = (1 << bank->func_width) - 1; + shift = pin_offset * bank->func_width; + + data = readl(reg); + data &= ~(mask << shift); + if (!input) + data |= FUNC_OUTPUT << shift; + writel(data, reg); + return 0; +} + +/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ +static struct pinmux_ops samsung_pinmux_ops = { + .get_functions_count = samsung_get_functions_count, + .get_function_name = samsung_pinmux_get_fname, + .get_function_groups = samsung_pinmux_get_groups, + .enable = samsung_pinmux_enable, + .disable = samsung_pinmux_disable, + .gpio_set_direction = samsung_pinmux_gpio_set_direction, +}; + +/* set or get the pin config settings for a specified pin */ +static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config, bool set) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct samsung_pin_bank *bank; + void __iomem *reg_base; + enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); + u32 data, width, pin_offset, mask, shift; + u32 cfg_value, cfg_reg; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, + &pin_offset, &bank); + + switch (cfg_type) { + case PINCFG_TYPE_PUD: + width = bank->pud_width; + cfg_reg = PUD_REG; + break; + case PINCFG_TYPE_DRV: + width = bank->drv_width; + cfg_reg = DRV_REG; + break; + case PINCFG_TYPE_CON_PDN: + width = bank->conpdn_width; + cfg_reg = CONPDN_REG; + break; + case PINCFG_TYPE_PUD_PDN: + width = bank->pudpdn_width; + cfg_reg = PUDPDN_REG; + break; + default: + WARN_ON(1); + return -EINVAL; + } + + mask = (1 << width) - 1; + shift = pin_offset * width; + data = readl(reg_base + cfg_reg); + + if (set) { + cfg_value = PINCFG_UNPACK_VALUE(*config); + data &= ~(mask << shift); + data |= (cfg_value << shift); + writel(data, reg_base + cfg_reg); + } else { + data >>= shift; + data &= mask; + *config = PINCFG_PACK(cfg_type, data); + } + return 0; +} + +/* set the pin config settings for a specified pin */ +static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long config) +{ + return samsung_pinconf_rw(pctldev, pin, &config, true); +} + +/* get the pin config settings for a specified pin */ +static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + return samsung_pinconf_rw(pctldev, pin, config, false); +} + +/* set the pin config settings for a specified pin group */ +static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned group, unsigned long config) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + unsigned int cnt; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + + for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) + samsung_pinconf_set(pctldev, pins[cnt], config); + + return 0; +} + +/* get the pin config settings for a specified pin group */ +static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *config) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + samsung_pinconf_get(pctldev, pins[0], config); + return 0; +} + +/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ +static struct pinconf_ops samsung_pinconf_ops = { + .pin_config_get = samsung_pinconf_get, + .pin_config_set = samsung_pinconf_set, + .pin_config_group_get = samsung_pinconf_group_get, + .pin_config_group_set = samsung_pinconf_group_set, +}; + +/* gpiolib gpio_set callback function */ +static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + void __iomem *reg; + u32 pin_offset, data; + + pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); + data = readl(reg + DAT_REG); + data &= ~(1 << pin_offset); + if (value) + data |= 1 << pin_offset; + writel(data, reg + DAT_REG); +} + +/* gpiolib gpio_get callback function */ +static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + void __iomem *reg; + u32 pin_offset, data; + + pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); + data = readl(reg + DAT_REG); + data >>= pin_offset; + data &= 1; + return data; +} + +/* + * gpiolib gpio_direction_input callback function. The setting of the pin + * mux function as 'gpio input' will be handled by the pinctrl susbsystem + * interface. + */ +static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + return pinctrl_gpio_direction_input(gc->base + offset); +} + +/* + * gpiolib gpio_direction_output callback function. The setting of the pin + * mux function as 'gpio output' will be handled by the pinctrl susbsystem + * interface. + */ +static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + samsung_gpio_set(gc, offset, value); + return pinctrl_gpio_direction_output(gc->base + offset); +} + +/* + * Parse the pin names listed in the 'samsung,pins' property and convert it + * into a list of gpio numbers are create a pin group from it. + */ +static int __init samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, + struct device_node *cfg_np, struct pinctrl_desc *pctl, + unsigned int **pin_list, unsigned int *npins) +{ + struct device *dev = &pdev->dev; + struct property *prop; + struct pinctrl_pin_desc const *pdesc = pctl->pins; + unsigned int idx = 0, cnt; + const char *pin_name; + + *npins = of_property_count_strings(cfg_np, "samsung,pins"); + if (*npins < 0) { + dev_err(dev, "invalid pin list in %s node", cfg_np->name); + return -EINVAL; + } + + *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); + if (!*pin_list) { + dev_err(dev, "failed to allocate memory for pin list\n"); + return -ENOMEM; + } + + of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { + for (cnt = 0; cnt < pctl->npins; cnt++) { + if (pdesc[cnt].name) { + if (!strcmp(pin_name, pdesc[cnt].name)) { + (*pin_list)[idx++] = pdesc[cnt].number; + break; + } + } + } + if (cnt == pctl->npins) { + dev_err(dev, "pin %s not valid in %s node\n", + pin_name, cfg_np->name); + devm_kfree(dev, *pin_list); + return -EINVAL; + } + } + + return 0; +} + +/* + * Parse the information about all the available pin groups and pin functions + * from device node of the pin-controller. A pin group is formed with all + * the pins listed in the "samsung,pins" property. + */ +static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + struct device *dev = &pdev->dev; + struct device_node *dev_np = dev->of_node; + struct device_node *cfg_np; + struct samsung_pin_group *groups, *grp; + struct samsung_pmx_func *functions, *func; + unsigned *pin_list; + unsigned int npins, grp_cnt, func_idx = 0; + char *gname, *fname; + int ret; + + grp_cnt = of_get_child_count(dev_np); + if (!grp_cnt) + return -EINVAL; + + groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); + if (!groups) { + dev_err(dev, "failed allocate memory for ping group list\n"); + return -EINVAL; + } + grp = groups; + + functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); + if (!functions) { + dev_err(dev, "failed to allocate memory for function list\n"); + return -EINVAL; + } + func = functions; + + /* + * Iterate over all the child nodes of the pin controller node + * and create pin groups and pin function lists. + */ + for_each_child_of_node(dev_np, cfg_np) { + u32 function; + if (of_find_property(cfg_np, "interrupt-controller", NULL)) + continue; + + ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, + &drvdata->pctl, &pin_list, &npins); + if (ret) + return ret; + + /* derive pin group name from the node name */ + gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, + GFP_KERNEL); + if (!gname) { + dev_err(dev, "failed to alloc memory for group name\n"); + return -ENOMEM; + } + sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); + + grp->name = gname; + grp->pins = pin_list; + grp->num_pins = npins; + of_property_read_u32(cfg_np, "samsung,pin-function", &function); + grp->func = function; + grp++; + + if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) + continue; + + /* derive function name from the node name */ + fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, + GFP_KERNEL); + if (!fname) { + dev_err(dev, "failed to alloc memory for func name\n"); + return -ENOMEM; + } + sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); + + func->name = fname; + func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); + if (!func->groups) { + dev_err(dev, "failed to alloc memory for group list " + "in pin function"); + return -ENOMEM; + } + func->groups[0] = gname; + func->num_groups = 1; + func++; + func_idx++; + } + + drvdata->pin_groups = groups; + drvdata->nr_groups = grp_cnt; + drvdata->pmx_functions = functions; + drvdata->nr_functions = func_idx; + + return 0; +} + +/* register the pinctrl interface with the pinctrl subsystem */ +static int __init samsung_pinctrl_register(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + struct pinctrl_desc *ctrldesc = &drvdata->pctl; + struct pinctrl_pin_desc *pindesc, *pdesc; + struct samsung_pin_bank *pin_bank; + char *pin_names; + int pin, bank, ret; + + ctrldesc->name = "samsung-pinctrl"; + ctrldesc->owner = THIS_MODULE; + ctrldesc->pctlops = &samsung_pctrl_ops; + ctrldesc->pmxops = &samsung_pinmux_ops; + ctrldesc->confops = &samsung_pinconf_ops; + + pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * + drvdata->ctrl->nr_pins, GFP_KERNEL); + if (!pindesc) { + dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + return -ENOMEM; + } + ctrldesc->pins = pindesc; + ctrldesc->npins = drvdata->ctrl->nr_pins; + ctrldesc->npins = drvdata->ctrl->nr_pins; + + /* dynamically populate the pin number and pin name for pindesc */ + for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) + pdesc->number = pin + drvdata->ctrl->base; + + /* + * allocate space for storing the dynamically generated names for all + * the pins which belong to this pin-controller. + */ + pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * + drvdata->ctrl->nr_pins, GFP_KERNEL); + if (!pin_names) { + dev_err(&pdev->dev, "mem alloc for pin names failed\n"); + return -ENOMEM; + } + + /* for each pin, the name of the pin is pin-bank name + pin number */ + for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { + pin_bank = &drvdata->ctrl->pin_banks[bank]; + for (pin = 0; pin < pin_bank->nr_pins; pin++) { + sprintf(pin_names, "%s-%d", pin_bank->name, pin); + pdesc = pindesc + pin_bank->pin_base + pin; + pdesc->name = pin_names; + pin_names += PIN_NAME_LENGTH; + } + } + + drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata); + if (!drvdata->pctl_dev) { + dev_err(&pdev->dev, "could not register pinctrl driver\n"); + return -EINVAL; + } + + drvdata->grange.name = "samsung-pctrl-gpio-range"; + drvdata->grange.id = 0; + drvdata->grange.base = drvdata->ctrl->base; + drvdata->grange.npins = drvdata->ctrl->nr_pins; + drvdata->grange.gc = drvdata->gc; + pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); + + ret = samsung_pinctrl_parse_dt(pdev, drvdata); + if (ret) { + pinctrl_unregister(drvdata->pctl_dev); + return ret; + } + + return 0; +} + +/* register the gpiolib interface with the gpiolib subsystem */ +static int __init samsung_gpiolib_register(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + struct gpio_chip *gc; + int ret; + + gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); + if (!gc) { + dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); + return -ENOMEM; + } + + drvdata->gc = gc; + gc->base = drvdata->ctrl->base; + gc->ngpio = drvdata->ctrl->nr_pins; + gc->dev = &pdev->dev; + gc->set = samsung_gpio_set; + gc->get = samsung_gpio_get; + gc->direction_input = samsung_gpio_direction_input; + gc->direction_output = samsung_gpio_direction_output; + gc->label = drvdata->ctrl->label; + gc->owner = THIS_MODULE; + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error " + "code: %d\n", gc->label, ret); + return ret; + } + + return 0; +} + +/* unregister the gpiolib interface with the gpiolib subsystem */ +static int __init samsung_gpiolib_unregister(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + int ret = gpiochip_remove(drvdata->gc); + if (ret) { + dev_err(&pdev->dev, "gpio chip remove failed\n"); + return ret; + } + return 0; +} + +static const struct of_device_id samsung_pinctrl_dt_match[]; + +/* retrieve the soc specific data */ +static inline struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( + struct platform_device *pdev) +{ + int id; + const struct of_device_id *match; + const struct device_node *node = pdev->dev.of_node; + + id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); + if (id < 0) { + dev_err(&pdev->dev, "failed to get alias id\n"); + return NULL; + } + match = of_match_node(samsung_pinctrl_dt_match, node); + return (struct samsung_pin_ctrl *)match->data + id; +} + +static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct device *dev = &pdev->dev; + struct samsung_pin_ctrl *ctrl; + struct resource *res; + int ret; + + if (!dev->of_node) { + dev_err(dev, "device tree node not found\n"); + return -ENODEV; + } + + ctrl = samsung_pinctrl_get_soc_data(pdev); + if (!ctrl) { + dev_err(&pdev->dev, "driver data not available\n"); + return -EINVAL; + } + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) { + dev_err(dev, "failed to allocate memory for driver's " + "private data\n"); + return -ENOMEM; + } + drvdata->ctrl = ctrl; + drvdata->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot find IO resource\n"); + return -ENOENT; + } + + drvdata->virt_base = devm_request_and_ioremap(&pdev->dev, res); + if (!drvdata->virt_base) { + dev_err(dev, "ioremap failed\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) + drvdata->irq = res->start; + + ret = samsung_gpiolib_register(pdev, drvdata); + if (ret) + return ret; + + ret = samsung_pinctrl_register(pdev, drvdata); + if (ret) { + samsung_gpiolib_unregister(pdev, drvdata); + return ret; + } + + if (ctrl->eint_gpio_init) + ctrl->eint_gpio_init(drvdata); + if (ctrl->eint_wkup_init) + ctrl->eint_wkup_init(drvdata); + + platform_set_drvdata(pdev, drvdata); + return 0; +} + +static const struct of_device_id samsung_pinctrl_dt_match[] = { + { .compatible = "samsung,pinctrl-exynos4210", + .data = (void *)exynos4210_pin_ctrl }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); + +static struct platform_driver samsung_pinctrl_driver = { + .probe = samsung_pinctrl_probe, + .driver = { + .name = "samsung-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), + }, +}; + +static int __init samsung_pinctrl_drv_register(void) +{ + return platform_driver_register(&samsung_pinctrl_driver); +} +postcore_initcall(samsung_pinctrl_drv_register); + +static void __exit samsung_pinctrl_drv_unregister(void) +{ + platform_driver_unregister(&samsung_pinctrl_driver); +} +module_exit(samsung_pinctrl_drv_unregister); + +MODULE_AUTHOR("Thomas Abraham "); +MODULE_DESCRIPTION("Samsung pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h new file mode 100644 index 00000000000..b8956934cda --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -0,0 +1,239 @@ +/* + * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * Author: Thomas Abraham + * + * 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. + */ + +#ifndef __PINCTRL_SAMSUNG_H +#define __PINCTRL_SAMSUNG_H + +#include +#include +#include +#include +#include + +/* register offsets within a pin bank */ +#define DAT_REG 0x4 +#define PUD_REG 0x8 +#define DRV_REG 0xC +#define CONPDN_REG 0x10 +#define PUDPDN_REG 0x14 + +/* pinmux function number for pin as gpio output line */ +#define FUNC_OUTPUT 0x1 + +/** + * enum pincfg_type - possible pin configuration types supported. + * @PINCFG_TYPE_PUD: Pull up/down configuration. + * @PINCFG_TYPE_DRV: Drive strength configuration. + * @PINCFG_TYPE_CON_PDN: Pin function in power down mode. + * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode. + */ +enum pincfg_type { + PINCFG_TYPE_PUD, + PINCFG_TYPE_DRV, + PINCFG_TYPE_CON_PDN, + PINCFG_TYPE_PUD_PDN, +}; + +/* + * pin configuration (pull up/down and drive strength) type and its value are + * packed together into a 16-bits. The upper 8-bits represent the configuration + * type and the lower 8-bits hold the value of the configuration type. + */ +#define PINCFG_TYPE_MASK 0xFF +#define PINCFG_VALUE_SHIFT 8 +#define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) +#define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) +#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) +#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ + PINCFG_VALUE_SHIFT) +/** + * enum eint_type - possible external interrupt types. + * @EINT_TYPE_NONE: bank does not support external interrupts + * @EINT_TYPE_GPIO: bank supportes external gpio interrupts + * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts + * + * Samsung GPIO controller groups all the available pins into banks. The pins + * in a pin bank can support external gpio interrupts or external wakeup + * interrupts or no interrupts at all. From a software perspective, the only + * difference between external gpio and external wakeup interrupts is that + * the wakeup interrupts can additionally wakeup the system if it is in + * suspended state. + */ +enum eint_type { + EINT_TYPE_NONE, + EINT_TYPE_GPIO, + EINT_TYPE_WKUP, +}; + +/* maximum length of a pin in pin descriptor (example: "gpa0-0") */ +#define PIN_NAME_LENGTH 10 + +#define PIN_GROUP(n, p, f) \ + { \ + .name = n, \ + .pins = p, \ + .num_pins = ARRAY_SIZE(p), \ + .func = f \ + } + +#define PMX_FUNC(n, g) \ + { \ + .name = n, \ + .groups = g, \ + .num_groups = ARRAY_SIZE(g), \ + } + +struct samsung_pinctrl_drv_data; + +/** + * struct samsung_pin_bank: represent a controller pin-bank. + * @reg_offset: starting offset of the pin-bank registers. + * @pin_base: starting pin number of the bank. + * @nr_pins: number of pins included in this bank. + * @func_width: width of the function selector bit field. + * @pud_width: width of the pin pull up/down selector bit field. + * @drv_width: width of the pin driver strength selector bit field. + * @conpdn_width: width of the sleep mode function selector bin field. + * @pudpdn_width: width of the sleep mode pull up/down selector bit field. + * @eint_type: type of the external interrupt supported by the bank. + * @irq_base: starting controller local irq number of the bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct samsung_pin_bank { + u32 pctl_offset; + u32 pin_base; + u8 nr_pins; + u8 func_width; + u8 pud_width; + u8 drv_width; + u8 conpdn_width; + u8 pudpdn_width; + enum eint_type eint_type; + u32 irq_base; + char *name; +}; + +/** + * struct samsung_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + * @base: starting system wide pin number. + * @nr_pins: number of pins supported by the controller. + * @nr_gint: number of external gpio interrupts supported. + * @nr_wint: number of external wakeup interrupts supported. + * @geint_con: offset of the ext-gpio controller registers. + * @geint_mask: offset of the ext-gpio interrupt mask registers. + * @geint_pend: offset of the ext-gpio interrupt pending registers. + * @weint_con: offset of the ext-wakeup controller registers. + * @weint_mask: offset of the ext-wakeup interrupt mask registers. + * @weint_pend: offset of the ext-wakeup interrupt pending registers. + * @svc: offset of the interrupt service register. + * @eint_gpio_init: platform specific callback to setup the external gpio + * interrupts for the controller. + * @eint_wkup_init: platform specific callback to setup the external wakeup + * interrupts for the controller. + * @label: for debug information. + */ +struct samsung_pin_ctrl { + struct samsung_pin_bank *pin_banks; + u32 nr_banks; + + u32 base; + u32 nr_pins; + u32 nr_gint; + u32 nr_wint; + + u32 geint_con; + u32 geint_mask; + u32 geint_pend; + + u32 weint_con; + u32 weint_mask; + u32 weint_pend; + + u32 svc; + + int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); + int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); + char *label; +}; + +/** + * struct samsung_pinctrl_drv_data: wrapper for holding driver data together. + * @virt_base: register base address of the controller. + * @dev: device instance representing the controller. + * @irq: interrpt number used by the controller to notify gpio interrupts. + * @ctrl: pin controller instance managed by the driver. + * @pctl: pin controller descriptor registered with the pinctrl subsystem. + * @pctl_dev: cookie representing pinctrl device instance. + * @pin_groups: list of pin groups available to the driver. + * @nr_groups: number of such pin groups. + * @pmx_functions: list of pin functions available to the driver. + * @nr_function: number of such pin functions. + * @gc: gpio_chip instance registered with gpiolib. + * @grange: linux gpio pin range supported by this controller. + */ +struct samsung_pinctrl_drv_data { + void __iomem *virt_base; + struct device *dev; + int irq; + + struct samsung_pin_ctrl *ctrl; + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + + const struct samsung_pin_group *pin_groups; + unsigned int nr_groups; + const struct samsung_pmx_func *pmx_functions; + unsigned int nr_functions; + + struct irq_domain *gpio_irqd; + struct irq_domain *wkup_irqd; + + struct gpio_chip *gc; + struct pinctrl_gpio_range grange; +}; + +/** + * struct samsung_pin_group: represent group of pins of a pinmux function. + * @name: name of the pin group, used to lookup the group. + * @pins: the pins included in this group. + * @num_pins: number of pins included in this group. + * @func: the function number to be programmed when selected. + */ +struct samsung_pin_group { + const char *name; + const unsigned int *pins; + u8 num_pins; + u8 func; +}; + +/** + * struct samsung_pmx_func: represent a pin function. + * @name: name of the pin function, used to lookup the function. + * @groups: one or more names of pin groups that provide this function. + * @num_groups: number of groups included in @groups. + */ +struct samsung_pmx_func { + const char *name; + const char **groups; + u8 num_groups; +}; + +/* list of all exported SoC specific data */ +extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; + +#endif /* __PINCTRL_SAMSUNG_H */ -- cgit v1.2.3-70-g09d2 From 98025c8c754391f5ea962fad788a6f2af02cb886 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 7 Sep 2012 06:40:29 +0900 Subject: gpio: samsung: Update documentation Update Samsung GPIO API documentation to reflect removal of the s3c24xx specific gpio API. While at it, fix some typos. The notes on conversion from s3c2410_* functions to the gpiolib API are left here just in case there is any out of tree code that still needs to be converted. Signed-off-by: Sylwester Nawrocki Acked-by: Linus Walleij Signed-off-by: Kukjin Kim --- Documentation/arm/Samsung-S3C24XX/GPIO.txt | 82 +++++++++--------------------- Documentation/arm/Samsung/GPIO.txt | 8 ++- 2 files changed, 28 insertions(+), 62 deletions(-) (limited to 'Documentation') diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt index 816d6071669..8b46c79679c 100644 --- a/Documentation/arm/Samsung-S3C24XX/GPIO.txt +++ b/Documentation/arm/Samsung-S3C24XX/GPIO.txt @@ -1,4 +1,4 @@ - S3C2410 GPIO Control + S3C24XX GPIO Control ==================== Introduction @@ -12,7 +12,7 @@ Introduction of the s3c2410 GPIO system, please read the Samsung provided data-sheet/users manual to find out the complete list. - See Documentation/arm/Samsung/GPIO.txt for the core implemetation. + See Documentation/arm/Samsung/GPIO.txt for the core implementation. GPIOLIB @@ -41,8 +41,8 @@ GPIOLIB GPIOLIB conversion ------------------ -If you need to convert your board or driver to use gpiolib from the exiting -s3c2410 api, then here are some notes on the process. +If you need to convert your board or driver to use gpiolib from the phased +out s3c2410 API, then here are some notes on the process. 1) If your board is exclusively using an GPIO, say to control peripheral power, then it will require to claim the gpio with gpio_request() before @@ -55,7 +55,7 @@ s3c2410 api, then here are some notes on the process. as they have the same arguments, and can either take the pin specific values, or the more generic special-function-number arguments. -3) s3c2410_gpio_pullup() changs have the problem that whilst the +3) s3c2410_gpio_pullup() changes have the problem that whilst the s3c2410_gpio_pullup(x, 1) can be easily translated to the s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0) are not so easy. @@ -74,7 +74,7 @@ s3c2410 api, then here are some notes on the process. when using gpio_get_value() on an output pin (s3c2410_gpio_getpin would return the value the pin is supposed to be outputting). -6) s3c2410_gpio_getirq() should be directly replacable with the +6) s3c2410_gpio_getirq() should be directly replaceable with the gpio_to_irq() call. The s3c2410_gpio and gpio_ calls have always operated on the same gpio @@ -105,7 +105,7 @@ PIN Numbers ----------- Each pin has an unique number associated with it in regs-gpio.h, - eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell + e.g. S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell the GPIO functions which pin is to be used. With the conversion to gpiolib, there is no longer a direct conversion @@ -120,31 +120,27 @@ Configuring a pin The following function allows the configuration of a given pin to be changed. - void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function); + void s3c_gpio_cfgpin(unsigned int pin, unsigned int function); - Eg: + e.g.: - s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0); - s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); + s3c_gpio_cfgpin(S3C2410_GPA(0), S3C_GPIO_SFN(1)); + s3c_gpio_cfgpin(S3C2410_GPE(8), S3C_GPIO_SFN(2)); which would turn GPA(0) into the lowest Address line A0, and set GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line. - The s3c_gpio_cfgpin() call is a functional replacement for this call. - Reading the current configuration --------------------------------- - The current configuration of a pin can be read by using: + The current configuration of a pin can be read by using standard + gpiolib function: - s3c2410_gpio_getcfg(unsigned int pin); + s3c_gpio_getcfg(unsigned int pin); The return value will be from the same set of values which can be - passed to s3c2410_gpio_cfgpin(). - - The s3c_gpio_getcfg() call should be a functional replacement for - this call. + passed to s3c_gpio_cfgpin(). Configuring a pull-up resistor @@ -154,61 +150,33 @@ Configuring a pull-up resistor pull-up resistors enabled. This can be configured by the following function: - void s3c2410_gpio_pullup(unsigned int pin, unsigned int to); - - Where the to value is zero to set the pull-up off, and 1 to enable - the specified pull-up. Any other values are currently undefined. - - The s3c_gpio_setpull() offers similar functionality, but with the - ability to encode whether the pull is up or down. Currently there - is no 'just on' state, so up or down must be selected. - - -Getting the state of a PIN --------------------------- - - The state of a pin can be read by using the function: - - unsigned int s3c2410_gpio_getpin(unsigned int pin); + void s3c_gpio_setpull(unsigned int pin, unsigned int to); - This will return either zero or non-zero. Do not count on this - function returning 1 if the pin is set. + Where the to value is S3C_GPIO_PULL_NONE to set the pull-up off, + and S3C_GPIO_PULL_UP to enable the specified pull-up. Any other + values are currently undefined. - This call is now implemented by the relevant gpiolib calls, convert - your board or driver to use gpiolib. - - -Setting the state of a PIN --------------------------- - - The value an pin is outputing can be modified by using the following: - void s3c2410_gpio_setpin(unsigned int pin, unsigned int to); +Getting and setting the state of a PIN +-------------------------------------- - Which sets the given pin to the value. Use 0 to write 0, and 1 to - set the output to 1. - - This call is now implemented by the relevant gpiolib calls, convert + These calls are now implemented by the relevant gpiolib calls, convert your board or driver to use gpiolib. Getting the IRQ number associated with a PIN -------------------------------------------- - The following function can map the given pin number to an IRQ + A standard gpiolib function can map the given pin number to an IRQ number to pass to the IRQ system. - int s3c2410_gpio_getirq(unsigned int pin); + int gpio_to_irq(unsigned int pin); Note, not all pins have an IRQ. - This call is now implemented by the relevant gpiolib calls, convert - your board or driver to use gpiolib. - -Authour +Author ------- - Ben Dooks, 03 October 2004 Copyright 2004 Ben Dooks, Simtec Electronics diff --git a/Documentation/arm/Samsung/GPIO.txt b/Documentation/arm/Samsung/GPIO.txt index 513f2562c1a..795adfd8808 100644 --- a/Documentation/arm/Samsung/GPIO.txt +++ b/Documentation/arm/Samsung/GPIO.txt @@ -5,14 +5,14 @@ Introduction ------------ This outlines the Samsung GPIO implementation and the architecture -specific calls provided alongisde the drivers/gpio core. +specific calls provided alongside the drivers/gpio core. S3C24XX (Legacy) ---------------- See Documentation/arm/Samsung-S3C24XX/GPIO.txt for more information -about these devices. Their implementation is being brought into line +about these devices. Their implementation has been brought into line with the core samsung implementation described in this document. @@ -29,7 +29,7 @@ GPIO numbering is synchronised between the Samsung and gpiolib system. PIN configuration ----------------- -Pin configuration is specific to the Samsung architecutre, with each SoC +Pin configuration is specific to the Samsung architecture, with each SoC registering the necessary information for the core gpio configuration implementation to configure pins as necessary. @@ -38,5 +38,3 @@ driver or machine to change gpio configuration. See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information on these functions. - - -- cgit v1.2.3-70-g09d2 From ef4158c5634e3819f93499d598ca617c29307ffd Mon Sep 17 00:00:00 2001 From: liang xie Date: Mon, 27 Aug 2012 00:06:45 +0800 Subject: Document:add Chinese translation of basic_profiling.txt This is a Chinese translated version of Documentation/basic_profiling.txt Signed-off-by: Liang Xie Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman --- Documentation/zh_CN/basic_profiling.txt | 71 +++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Documentation/zh_CN/basic_profiling.txt (limited to 'Documentation') diff --git a/Documentation/zh_CN/basic_profiling.txt b/Documentation/zh_CN/basic_profiling.txt new file mode 100644 index 00000000000..1e6bf0bdf8f --- /dev/null +++ b/Documentation/zh_CN/basic_profiling.txt @@ -0,0 +1,71 @@ +Chinese translated version of Documentation/basic_profiling + +If you have any comment or update to the content, please post to LKML directly. +However, if you have problem communicating in English you can also ask the +Chinese maintainer for help. Contact the Chinese maintainer, if this +translation is outdated or there is problem with translation. + +Chinese maintainer: Liang Xie +--------------------------------------------------------------------- +Documentation/basic_profiling的中文翻译 + +如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可 +以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。 + +中文版维护者: 谢良 Liang Xie +中文版翻译者: 谢良 Liang Xie +中文版校译者: +以下为正文 +--------------------------------------------------------------------- + +下面这些说明指令都是非常基础的,如果你想进一步了解请阅读相关专业文档:) +请不要再在本文档增加新的内容,但可以修复文档中的错误:)(mbligh@aracnet.com) +感谢John Levon,Dave Hansen等在撰写时的帮助 + + 用于表示要测量的目标 +请先确保您已经有正确的System.map / vmlinux配置! + +对于linux系统来说,配置vmlinuz最容易的方法可能就是使用“make install”,然后修改 +/sbin/installkernel将vmlinux拷贝到/boot目录,而System.map通常是默认安装好的 + +Readprofile +----------- +2.6系列内核需要版本相对较新的readprofile,比如util-linux 2.12a中包含的,可以从: + +http://www.kernel.org/pub/linux/utils/util-linux/ 下载 + +大部分linux发行版已经包含了. + +启用readprofile需要在kernel启动命令行增加”profile=2“ + +clear readprofile -r + +dump output readprofile -m /boot/System.map > captured_profile + +Oprofile +-------- + +从http://oprofile.sourceforge.net/获取源代码(请参考Changes以获取匹配的版本) +在kernel启动命令行增加“idle=poll” + +配置CONFIG_PROFILING=y和CONFIG_OPROFILE=y然后重启进入新kernel + +./configure --with-kernel-support +make install + +想得到好的测量结果,请确保启用了本地APIC特性。如果opreport显示有0Hz CPU, +说明APIC特性没有开启。另外注意idle=poll选项可能有损性能。 + +One time setup: + opcontrol --setup --vmlinux=/boot/vmlinux + +clear opcontrol --reset +start opcontrol --start + +stop opcontrol --stop +dump output opreport > output_file + +如果只看kernel相关的报告结果,请运行命令 opreport -l /boot/vmlinux > output_file + +通过reset选项可以清理过期统计数据,相当于重启的效果。 + -- cgit v1.2.3-70-g09d2 From 172c6a13653ac8cd6a231293b87c93821e90c1d6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 7 Sep 2012 06:49:47 +0900 Subject: gpio: samsung: add devicetree init for s3c24xx arches Until now the EXYNOS-SoC was the only Samsung-SoC supporting the GPIOs via the device tree. This patch implements dt-support for the s3c24xx arches. The controllers contain only 3 cells, as the underlying gpio controller does not support controlling the drive strength on a gpio level. Tested with the gpio-keys driver on a s3c2416 based machine. Signed-off-by: Heiko Stuebner Reviewed-by: Thomas Abraham Acked-by: Linus Walleij [kgene.kim@samsung.com: fixed build error] Signed-off-by: Kukjin Kim --- .../devicetree/bindings/gpio/gpio-samsung.txt | 43 +++++++++++++++ drivers/gpio/gpio-samsung.c | 63 ++++++++++++++++++++++ 2 files changed, 106 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt index 5375625e8cd..f1e5dfecf55 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt @@ -39,3 +39,46 @@ Example: #gpio-cells = <4>; gpio-controller; }; + + +Samsung S3C24XX GPIO Controller + +Required properties: +- compatible: Compatible property value should be "samsung,s3c24xx-gpio". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- #gpio-cells: Should be 3. The syntax of the gpio specifier used by client nodes + should be the following with values derived from the SoC user manual. + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [mux function] + [flags and pull up/down] + + Values for gpio specifier: + - Pin number: depending on the controller a number from 0 up to 15. + - Mux function: Depending on the SoC and the gpio bank the gpio can be set + as input, output or a special function + - Flags and Pull Up/Down: the values to use differ for the individual SoCs + example S3C2416/S3C2450: + 0 - Pull Up/Down Disabled. + 1 - Pull Down Enabled. + 2 - Pull Up Enabled. + Bit 16 (0x00010000) - Input is active low. + Consult the user manual for the correct values of Mux and Pull Up/Down. + +- gpio-controller: Specifies that the node is a gpio controller. +- #address-cells: should be 1. +- #size-cells: should be 1. + +Example: + + gpa: gpio-controller@56000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "samsung,s3c24xx-gpio"; + reg = <0x56000000 0x10>; + #gpio-cells = <3>; + gpio-controller; + }; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index ba126cc0407..f4814a889a5 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -938,6 +938,67 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) s3c_gpiolib_track(chip); } +#if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) +static int s3c24xx_gpio_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + unsigned int pin; + + if (WARN_ON(gc->of_gpio_n_cells < 3)) + return -EINVAL; + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + if (gpiospec->args[0] > gc->ngpio) + return -EINVAL; + + pin = gc->base + gpiospec->args[0]; + + if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) + pr_warn("gpio_xlate: failed to set pin function\n"); + if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) + pr_warn("gpio_xlate: failed to set pin pull up/down\n"); + + if (flags) + *flags = gpiospec->args[2] >> 16; + + return gpiospec->args[0]; +} + +static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = { + { .compatible = "samsung,s3c24xx-gpio", }, + {} +}; + +static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + struct gpio_chip *gc = &chip->chip; + u64 address; + + if (!of_have_populated_dt()) + return; + + address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; + gc->of_node = of_find_matching_node_by_address(NULL, + s3c24xx_gpio_dt_match, address); + if (!gc->of_node) { + pr_info("gpio: device tree node not found for gpio controller" + " with base address %08llx\n", address); + return; + } + gc->of_gpio_n_cells = 3; + gc->of_xlate = s3c24xx_gpio_xlate; +} +#else +static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + return; +} +#endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */ + static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, int nr_chips, void __iomem *base) { @@ -962,6 +1023,8 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, gc->direction_output = samsung_gpiolib_2bit_output; samsung_gpiolib_add(chip); + + s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10); } } -- cgit v1.2.3-70-g09d2 From 1128658a0841dbfdc95dc2e3e8d573e4eb1f6a40 Mon Sep 17 00:00:00 2001 From: Shaik Ameer Basha Date: Fri, 7 Sep 2012 14:13:08 +0900 Subject: ARM: EXYNOS: Adds G-Scaler device from Device Tree This patch adds, - 4 G-Scaler devices to the DT device list - G-Scaler specific entries to the machine file - binding documentation for G-Scaler entries Signed-off-by: Abhilash Kesavan Signed-off-by: Leela Krishna Amudala Signed-off-by: Shaik Ameer Basha Signed-off-by: Kukjin Kim --- .../devicetree/bindings/media/exynos5-gsc.txt | 30 ++++++++++++++++++++++ arch/arm/boot/dts/exynos5250.dtsi | 28 ++++++++++++++++++++ arch/arm/mach-exynos/include/mach/map.h | 5 ++++ arch/arm/mach-exynos/mach-exynos5-dt.c | 8 ++++++ 4 files changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/exynos5-gsc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/exynos5-gsc.txt b/Documentation/devicetree/bindings/media/exynos5-gsc.txt new file mode 100644 index 00000000000..0604d42f38d --- /dev/null +++ b/Documentation/devicetree/bindings/media/exynos5-gsc.txt @@ -0,0 +1,30 @@ +* Samsung Exynos5 G-Scaler device + +G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs. + +Required properties: +- compatible: should be "samsung,exynos5-gsc" +- reg: should contain G-Scaler physical address location and length. +- interrupts: should contain G-Scaler interrupt number + +Example: + +gsc_0: gsc@0x13e00000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; +}; + +Aliases: +Each G-Scaler node should have a numbered alias in the aliases node, +in the form of gscN, N = 0...3. G-Scaler driver uses these aliases +to retrieve the device IDs using "of_alias_get_id()" call. + +Example: + +aliases { + gsc0 =&gsc_0; + gsc1 =&gsc_1; + gsc2 =&gsc_2; + gsc3 =&gsc_3; +}; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 004aaa8d123..b55794b494b 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -27,6 +27,10 @@ spi0 = &spi_0; spi1 = &spi_1; spi2 = &spi_2; + gsc0 = &gsc_0; + gsc1 = &gsc_1; + gsc2 = &gsc_2; + gsc3 = &gsc_3; }; gic:interrupt-controller@10481000 { @@ -460,4 +464,28 @@ #gpio-cells = <4>; }; }; + + gsc_0: gsc@0x13e00000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; + }; + + gsc_1: gsc@0x13e10000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e10000 0x1000>; + interrupts = <0 86 0>; + }; + + gsc_2: gsc@0x13e20000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e20000 0x1000>; + interrupts = <0 87 0>; + }; + + gsc_3: gsc@0x13e30000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e30000 0x1000>; + interrupts = <0 88 0>; + }; }; diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index c72b675b3e4..0300d7adc15 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -121,6 +121,11 @@ #define EXYNOS4_PA_SYSMMU_MFC_L 0x13620000 #define EXYNOS4_PA_SYSMMU_MFC_R 0x13630000 +#define EXYNOS5_PA_GSC0 0x13E00000 +#define EXYNOS5_PA_GSC1 0x13E10000 +#define EXYNOS5_PA_GSC2 0x13E20000 +#define EXYNOS5_PA_GSC3 0x13E30000 + #define EXYNOS5_PA_SYSMMU_MDMA1 0x10A40000 #define EXYNOS5_PA_SYSMMU_SSS 0x10A50000 #define EXYNOS5_PA_SYSMMU_2D 0x10A60000 diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index ef770bc2318..e707eb1b1ea 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -56,6 +56,14 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC0, + "exynos-gsc.0", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC1, + "exynos-gsc.1", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC2, + "exynos-gsc.2", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC3, + "exynos-gsc.3", NULL), {}, }; -- cgit v1.2.3-70-g09d2 From 65f8c95e46a1827ae8bbc52a817ea308dd7d65ae Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 17 Jul 2012 14:26:15 -0700 Subject: pstore/ftrace: Convert to its own enable/disable debugfs knob With this patch we no longer reuse function tracer infrastructure, now we register our own tracer back-end via a debugfs knob. It's a bit more code, but that is the only downside. On the bright side we have: - Ability to make persistent_ram module removable (when needed, we can move ftrace_ops struct into a module). Note that persistent_ram is still not removable for other reasons, but with this patch it's just one thing less to worry about; - Pstore part is more isolated from the generic function tracer. We tried it already by registering our own tracer in available_tracers, but that way we're loosing ability to see the traces while we record them to pstore. This solution is somewhere in the middle: we only register "internal ftracer" back-end, but not the "front-end"; - When there is only pstore tracing enabled, the kernel will only write to the pstore buffer, omitting function tracer buffer (which, of course, still can be enabled via 'echo function > current_tracer'). Suggested-by: Steven Rostedt Signed-off-by: Anton Vorontsov --- Documentation/ramoops.txt | 4 +- fs/pstore/Kconfig | 1 + fs/pstore/ftrace.c | 96 +++++++++++++++++++++++++++++++++++++++++- fs/pstore/internal.h | 6 +++ fs/pstore/platform.c | 1 + include/linux/pstore.h | 8 ---- kernel/trace/trace_functions.c | 15 +------ 7 files changed, 105 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt index 197ad59ab9b..69b3cac4749 100644 --- a/Documentation/ramoops.txt +++ b/Documentation/ramoops.txt @@ -102,9 +102,7 @@ related hangs. The functions call chain log is stored in a "ftrace-ramoops" file. Here is an example of usage: # mount -t debugfs debugfs /sys/kernel/debug/ - # cd /sys/kernel/debug/tracing - # echo function > current_tracer - # echo 1 > options/func_pstore + # echo 1 > /sys/kernel/debug/pstore/record_ftrace # reboot -f [...] # mount -t pstore pstore /mnt/ diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index d39bb5cce88..ca71db69da0 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -23,6 +23,7 @@ config PSTORE_FTRACE bool "Persistent function tracer" depends on PSTORE depends on FUNCTION_TRACER + depends on DEBUG_FS help With this option kernel traces function calls into a persistent ram buffer that can be decoded and dumped after reboot through diff --git a/fs/pstore/ftrace.c b/fs/pstore/ftrace.c index a130d484b7d..2d57e1ac011 100644 --- a/fs/pstore/ftrace.c +++ b/fs/pstore/ftrace.c @@ -17,19 +17,113 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include "internal.h" -void notrace pstore_ftrace_call(unsigned long ip, unsigned long parent_ip) +static void notrace pstore_ftrace_call(unsigned long ip, + unsigned long parent_ip) { + unsigned long flags; struct pstore_ftrace_record rec = {}; if (unlikely(oops_in_progress)) return; + local_irq_save(flags); + rec.ip = ip; rec.parent_ip = parent_ip; pstore_ftrace_encode_cpu(&rec, raw_smp_processor_id()); psinfo->write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)&rec, sizeof(rec), psinfo); + + local_irq_restore(flags); +} + +static struct ftrace_ops pstore_ftrace_ops __read_mostly = { + .func = pstore_ftrace_call, +}; + +static DEFINE_MUTEX(pstore_ftrace_lock); +static bool pstore_ftrace_enabled; + +static ssize_t pstore_ftrace_knob_write(struct file *f, const char __user *buf, + size_t count, loff_t *ppos) +{ + u8 on; + ssize_t ret; + + ret = kstrtou8_from_user(buf, count, 2, &on); + if (ret) + return ret; + + mutex_lock(&pstore_ftrace_lock); + + if (!on ^ pstore_ftrace_enabled) + goto out; + + if (on) + ret = register_ftrace_function(&pstore_ftrace_ops); + else + ret = unregister_ftrace_function(&pstore_ftrace_ops); + if (ret) { + pr_err("%s: unable to %sregister ftrace ops: %zd\n", + __func__, on ? "" : "un", ret); + goto err; + } + + pstore_ftrace_enabled = on; +out: + ret = count; +err: + mutex_unlock(&pstore_ftrace_lock); + + return ret; +} + +static ssize_t pstore_ftrace_knob_read(struct file *f, char __user *buf, + size_t count, loff_t *ppos) +{ + char val[] = { '0' + pstore_ftrace_enabled, '\n' }; + + return simple_read_from_buffer(buf, count, ppos, val, sizeof(val)); +} + +static const struct file_operations pstore_knob_fops = { + .open = simple_open, + .read = pstore_ftrace_knob_read, + .write = pstore_ftrace_knob_write, +}; + +void pstore_register_ftrace(void) +{ + struct dentry *dir; + struct dentry *file; + + if (!psinfo->write_buf) + return; + + dir = debugfs_create_dir("pstore", NULL); + if (!dir) { + pr_err("%s: unable to create pstore directory\n", __func__); + return; + } + + file = debugfs_create_file("record_ftrace", 0600, dir, NULL, + &pstore_knob_fops); + if (!file) { + pr_err("%s: unable to create record_ftrace file\n", __func__); + goto err_file; + } + + return; +err_file: + debugfs_remove(dir); } diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 0d0d3b7d5f1..4847f588b7d 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -39,6 +39,12 @@ pstore_ftrace_decode_cpu(struct pstore_ftrace_record *rec) #endif } +#ifdef CONFIG_PSTORE_FTRACE +extern void pstore_register_ftrace(void); +#else +static inline void pstore_register_ftrace(void) {} +#endif + extern struct pstore_info *psinfo; extern void pstore_set_kmsg_bytes(int); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 29996e8793a..6c23eab7f76 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -236,6 +236,7 @@ int pstore_register(struct pstore_info *psi) kmsg_dump_register(&pstore_dumper); pstore_register_console(); + pstore_register_ftrace(); if (pstore_update_ms >= 0) { pstore_timer.expires = jiffies + diff --git a/include/linux/pstore.h b/include/linux/pstore.h index c892587d9b8..ee3034a4088 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -64,14 +64,6 @@ struct pstore_info { void *data; }; - -#ifdef CONFIG_PSTORE_FTRACE -extern void pstore_ftrace_call(unsigned long ip, unsigned long parent_ip); -#else -static inline void pstore_ftrace_call(unsigned long ip, unsigned long parent_ip) -{ } -#endif - #ifdef CONFIG_PSTORE extern int pstore_register(struct pstore_info *); #else diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index a426f410c06..0ad83e3929d 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "trace.h" @@ -75,10 +74,9 @@ function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip) preempt_enable_notrace(); } -/* Our two options */ +/* Our option */ enum { TRACE_FUNC_OPT_STACK = 0x1, - TRACE_FUNC_OPT_PSTORE = 0x2, }; static struct tracer_flags func_flags; @@ -106,12 +104,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip) disabled = atomic_inc_return(&data->disabled); if (likely(disabled == 1)) { - /* - * So far tracing doesn't support multiple buffers, so - * we make an explicit call for now. - */ - if (unlikely(func_flags.val & TRACE_FUNC_OPT_PSTORE)) - pstore_ftrace_call(ip, parent_ip); pc = preempt_count(); trace_function(tr, ip, parent_ip, flags, pc); } @@ -176,9 +168,6 @@ static struct ftrace_ops trace_stack_ops __read_mostly = static struct tracer_opt func_opts[] = { #ifdef CONFIG_STACKTRACE { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) }, -#endif -#ifdef CONFIG_PSTORE_FTRACE - { TRACER_OPT(func_pstore, TRACE_FUNC_OPT_PSTORE) }, #endif { } /* Always set a last empty entry */ }; @@ -231,8 +220,6 @@ static int func_set_flag(u32 old_flags, u32 bit, int set) register_ftrace_function(&trace_ops); } - break; - case TRACE_FUNC_OPT_PSTORE: break; default: return -EINVAL; -- cgit v1.2.3-70-g09d2 From 399264b897bc0efb4fb5c026705805bec9ed93b8 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 25 Jul 2012 10:57:58 +0530 Subject: Documentation: dt: i2c: trivial-devices: Update for tmp102 Add Description for tmp102 temperature sensor. Cc: Felipe Balbi Cc: Santosh Shilimkar Signed-off-by: Sourav Poddar Signed-off-by: Benoit Cousson --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 1a85f986961..2f5322b119e 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -56,3 +56,4 @@ stm,m41t00 Serial Access TIMEKEEPER stm,m41t62 Serial real-time clock (RTC) with alarm stm,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS ti,tsc2003 I2C Touch-Screen Controller +ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface -- cgit v1.2.3-70-g09d2 From 274c27b1f18060db6cc6bedad7812e5a7f97c6a4 Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Thu, 1 Dec 2011 17:47:09 +0530 Subject: Documentation: dt: device tree bindings for LPDDR2 memories device tree bindings for LPDDR2 SDRAM memories compliant to JESD209-2 standard. The 'lpddr2' binding in-turn uses another binding 'lpddr2-timings' for specifying the AC timing parameters of the memory device at different speed-bins. Reviewed-by: Benoit Cousson Reviewed-by: Grant Likely Tested-by: Lokesh Vutla Signed-off-by: Aneesh V [santosh.shilimkar@ti.com: Rebased against 3.6-rc] Signed-off-by: Santosh Shilimkar Signed-off-by: Benoit Cousson --- .../devicetree/bindings/lpddr2/lpddr2-timings.txt | 52 +++++++++++ .../devicetree/bindings/lpddr2/lpddr2.txt | 102 +++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt create mode 100644 Documentation/devicetree/bindings/lpddr2/lpddr2.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt b/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt new file mode 100644 index 00000000000..9ceb19e0c7f --- /dev/null +++ b/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt @@ -0,0 +1,52 @@ +* AC timing parameters of LPDDR2(JESD209-2) memories for a given speed-bin + +Required properties: +- compatible : Should be "jedec,lpddr2-timings" +- min-freq : minimum DDR clock frequency for the speed-bin. Type is +- max-freq : maximum DDR clock frequency for the speed-bin. Type is + +Optional properties: + +The following properties represent AC timing parameters from the memory +data-sheet of the device for a given speed-bin. All these properties are +of type and the default unit is ps (pico seconds). Parameters with +a different unit have a suffix indicating the unit such as 'tRAS-max-ns' +- tRCD +- tWR +- tRAS-min +- tRRD +- tWTR +- tXP +- tRTP +- tDQSCK-max +- tFAW +- tZQCS +- tZQinit +- tRPab +- tZQCL +- tCKESR +- tRAS-max-ns +- tDQSCK-max-derated + +Example: + +timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; +}; diff --git a/Documentation/devicetree/bindings/lpddr2/lpddr2.txt b/Documentation/devicetree/bindings/lpddr2/lpddr2.txt new file mode 100644 index 00000000000..58354a075e1 --- /dev/null +++ b/Documentation/devicetree/bindings/lpddr2/lpddr2.txt @@ -0,0 +1,102 @@ +* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2 + +Required properties: +- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2", + "jedec,lpddr2-s4" + + "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type + + "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type + + "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type + +- density : representing density in Mb (Mega bits) + +- io-width : representing bus width. Possible values are 8, 16, and 32 + +Optional properties: + +The following optional properties represent the minimum value of some AC +timing parameters of the DDR device in terms of number of clock cycles. +These values shall be obtained from the device data-sheet. +- tRRD-min-tck +- tWTR-min-tck +- tXP-min-tck +- tRTP-min-tck +- tCKE-min-tck +- tRPab-min-tck +- tRCD-min-tck +- tWR-min-tck +- tRASmin-min-tck +- tCKESR-min-tck +- tFAW-min-tck + +Child nodes: +- The lpddr2 node may have one or more child nodes of type "lpddr2-timings". + "lpddr2-timings" provides AC timing parameters of the device for + a given speed-bin. The user may provide the timings for as many + speed-bins as is required. Please see Documentation/devicetree/ + bindings/lpddr2/lpddr2-timings.txt for more information on "lpddr2-timings" + +Example: + +elpida_ECB240ABACN : lpddr2 { + compatible = "Elpida,ECB240ABACN","jedec,lpddr2-s4"; + density = <2048>; + io-width = <32>; + + tRPab-min-tck = <3>; + tRCD-min-tck = <3>; + tWR-min-tck = <3>; + tRASmin-min-tck = <3>; + tRRD-min-tck = <2>; + tWTR-min-tck = <2>; + tXP-min-tck = <2>; + tRTP-min-tck = <2>; + tCKE-min-tck = <3>; + tCKESR-min-tck = <3>; + tFAW-min-tck = <8>; + + timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + + timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <200000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <10000>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + +} -- cgit v1.2.3-70-g09d2 From 6bc9c66e5657a33d19559fce730bfa36112cb1cc Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Sat, 17 Dec 2011 17:24:25 +0530 Subject: Documentation: dt: emif: device tree bindings for TI's EMIF sdram controller EMIF - External Memory Interface - is an SDRAM controller used in TI SoCs. EMIF supports, based on the IP revision, one or more of DDR2/DDR3/LPDDR2 protocols. This binding describes a given instance of the EMIF IP and memory parts attached to it. Reviewed-by: Grant Likely Tested-by: Lokesh Vutla Signed-off-by: Aneesh V [santosh.shilimkar@ti.com: Rebased against 3.6-rc] Signed-off-by: Santosh Shilimkar Signed-off-by: Benoit Cousson --- .../bindings/memory-controllers/ti/emif.txt | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti/emif.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt new file mode 100644 index 00000000000..938f8e1ba20 --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt @@ -0,0 +1,55 @@ +* EMIF family of TI SDRAM controllers + +EMIF - External Memory Interface - is an SDRAM controller used in +TI SoCs. EMIF supports, based on the IP revision, one or more of +DDR2/DDR3/LPDDR2 protocols. This binding describes a given instance +of the EMIF IP and memory parts attached to it. + +Required properties: +- compatible : Should be of the form "ti,emif-" where + is the IP revision of the specific EMIF instance. + +- phy-type : indicating the DDR phy type. Following are the + allowed values + <1> : Attila PHY + <2> : Intelli PHY + +- device-handle : phandle to a "lpddr2" node representing the memory part + +- ti,hwmods : For TI hwmods processing and omap device creation + the value shall be "emif" where is the number of the EMIF + instance with base 1. + +Optional properties: +- cs1-used : Have this property if CS1 of this EMIF + instance has a memory part attached to it. If there is a memory + part attached to CS1, it should be the same type as the one on CS0, + so there is no need to give the details of this memory part. + +- cal-resistor-per-cs : Have this property if the board has one + calibration resistor per chip-select. + +- hw-caps-read-idle-ctrl: Have this property if the controller + supports read idle window programming + +- hw-caps-dll-calib-ctrl: Have this property if the controller + supports dll calibration control + +- hw-caps-ll-interface : Have this property if the controller + has a low latency interface and corresponding interrupt events + +- hw-caps-temp-alert : Have this property if the controller + has capability for generating SDRAM temperature alerts + +Example: + +emif1: emif@0x4c000000 { + compatible = "ti,emif-4d"; + ti,hwmods = "emif2"; + phy-type = <1>; + device-handle = <&elpida_ECB240ABACN>; + cs1-used; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; +}; -- cgit v1.2.3-70-g09d2 From f74ce8fb849e9f9c54a494cff5fc30d53ca4e963 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Sep 2012 09:46:25 +0200 Subject: gpio/twl4030: get platform data from device tree Adds a number of missing device tree properties for twl4030/gpio, and update bindings: - "ti,use-leds" -> .use_leds - "ti,debounce" -> .debounce - "ti,mmc-cd" -> .mmc_cd - "ti,pullups" -> .pullups - "ti,pulldowns" -> .pulldowns Signed-off-by: Florian Vaussard Acked-by: Linus Walleij Acked-by: Vaibhav Hiremath [b-cousson@ti.com: Fix some checkpatch CHECK issues] Signed-off-by: Benoit Cousson --- .../devicetree/bindings/gpio/gpio-twl4030.txt | 6 ++ drivers/gpio/gpio-twl4030.c | 82 +++++++++++++++------- 2 files changed, 61 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt index 16695d9cf1e..66788fda1db 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt @@ -11,6 +11,11 @@ Required properties: - interrupt-controller: Mark the device node as an interrupt controller The first cell is the GPIO number. The second cell is not used. +- ti,use-leds : Enables LEDA and LEDB outputs if set +- ti,debounce : if n-th bit is set, debounces GPIO-n +- ti,mmc-cd : if n-th bit is set, GPIO-n controls VMMC(n+1) +- ti,pullups : if n-th bit is set, set a pullup on GPIO-n +- ti,pulldowns : if n-th bit is set, set a pulldown on GPIO-n Example: @@ -20,4 +25,5 @@ twl_gpio: gpio { gpio-controller; #interrupt-cells = <2>; interrupt-controller; + ti,use-leds; }; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 94256fe7bf3..f923252da83 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -395,6 +395,31 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) static int gpio_twl4030_remove(struct platform_device *pdev); +static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) +{ + struct twl4030_gpio_platform_data *omap_twl_info; + + omap_twl_info = devm_kzalloc(dev, sizeof(*omap_twl_info), GFP_KERNEL); + if (!omap_twl_info) + return NULL; + + omap_twl_info->gpio_base = -1; + + omap_twl_info->use_leds = of_property_read_bool(dev->of_node, + "ti,use-leds"); + + of_property_read_u32(dev->of_node, "ti,debounce", + &omap_twl_info->debounce); + of_property_read_u32(dev->of_node, "ti,mmc-cd", + (u32 *)&omap_twl_info->mmc_cd); + of_property_read_u32(dev->of_node, "ti,pullups", + &omap_twl_info->pullups); + of_property_read_u32(dev->of_node, "ti,pulldowns", + &omap_twl_info->pulldowns); + + return omap_twl_info; +} + static int __devinit gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; @@ -423,39 +448,42 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) twl4030_gpio_irq_base = irq_base; no_irqs: - twl_gpiochip.base = -1; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; - if (pdata) { - twl_gpiochip.base = pdata->gpio_base; + if (node) + pdata = of_gpio_twl4030(&pdev->dev); - /* - * NOTE: boards may waste power if they don't set pullups - * and pulldowns correctly ... default for non-ULPI pins is - * pulldown, and some other pins may have external pullups - * or pulldowns. Careful! - */ - ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); - if (ret) - dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", - pdata->pullups, pdata->pulldowns, - ret); - - ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); - if (ret) - dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", - pdata->debounce, pdata->mmc_cd, - ret); - - /* - * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, - * is (still) clear if use_leds is set. - */ - if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data is missing\n"); + return -ENXIO; } + twl_gpiochip.base = pdata->gpio_base; + + /* + * NOTE: boards may waste power if they don't set pullups + * and pulldowns correctly ... default for non-ULPI pins is + * pulldown, and some other pins may have external pullups + * or pulldowns. Careful! + */ + ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); + if (ret) + dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", + pdata->pullups, pdata->pulldowns, ret); + + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, ret); + + /* + * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, + * is (still) clear if use_leds is set. + */ + if (pdata->use_leds) + twl_gpiochip.ngpio += 2; + ret = gpiochip_add(&twl_gpiochip); if (ret < 0) { dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); -- cgit v1.2.3-70-g09d2 From 2fe5d6def1672ae6635dd71867bf36dcfaa7434b Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Mon, 13 Feb 2012 10:15:05 -0500 Subject: ima: integrity appraisal extension IMA currently maintains an integrity measurement list used to assert the integrity of the running system to a third party. The IMA-appraisal extension adds local integrity validation and enforcement of the measurement against a "good" value stored as an extended attribute 'security.ima'. The initial methods for validating 'security.ima' are hashed based, which provides file data integrity, and digital signature based, which in addition to providing file data integrity, provides authenticity. This patch creates and maintains the 'security.ima' xattr, containing the file data hash measurement. Protection of the xattr is provided by EVM, if enabled and configured. Based on policy, IMA calls evm_verifyxattr() to verify a file's metadata integrity and, assuming success, compares the file's current hash value with the one stored as an extended attribute in 'security.ima'. Changelov v4: - changed iint cache flags to hex values Changelog v3: - change appraisal default for filesystems without xattr support to fail Changelog v2: - fix audit msg 'res' value - removed unused 'ima_appraise=' values Changelog v1: - removed unused iint mutex (Dmitry Kasatkin) - setattr hook must not reset appraised (Dmitry Kasatkin) - evm_verifyxattr() now differentiates between no 'security.evm' xattr (INTEGRITY_NOLABEL) and no EVM 'protected' xattrs included in the 'security.evm' (INTEGRITY_NOXATTRS). - replace hash_status with ima_status (Dmitry Kasatkin) - re-initialize slab element ima_status on free (Dmitry Kasatkin) - include 'security.ima' in EVM if CONFIG_IMA_APPRAISE, not CONFIG_IMA - merged half "ima: ima_must_appraise_or_measure API change" (Dmitry Kasatkin) - removed unnecessary error variable in process_measurement() (Dmitry Kasatkin) - use ima_inode_post_setattr() stub function, if IMA_APPRAISE not configured (moved ima_inode_post_setattr() to ima_appraise.c) - make sure ima_collect_measurement() can read file Changelog: - add 'iint' to evm_verifyxattr() call (Dimitry Kasatkin) - fix the race condition between chmod, which takes the i_mutex and then iint->mutex, and ima_file_free() and process_measurement(), which take the locks in the reverse order, by eliminating iint->mutex. (Dmitry Kasatkin) - cleanup of ima_appraise_measurement() (Dmitry Kasatkin) - changes as a result of the iint not allocated for all regular files, but only for those measured/appraised. - don't try to appraise new/empty files - expanded ima_appraisal description in ima/Kconfig - IMA appraise definitions required even if IMA_APPRAISE not enabled - add return value to ima_must_appraise() stub - unconditionally set status = INTEGRITY_PASS *after* testing status, not before. (Found by Joe Perches) Signed-off-by: Mimi Zohar Signed-off-by: Dmitry Kasatkin --- Documentation/kernel-parameters.txt | 4 + include/linux/xattr.h | 3 + security/integrity/evm/evm_main.c | 3 + security/integrity/iint.c | 3 +- security/integrity/ima/Kconfig | 15 +++ security/integrity/ima/Makefile | 1 + security/integrity/ima/ima.h | 37 +++++++- security/integrity/ima/ima_api.c | 50 +++++++--- security/integrity/ima/ima_appraise.c | 168 ++++++++++++++++++++++++++++++++++ security/integrity/ima/ima_crypto.c | 8 +- security/integrity/ima/ima_main.c | 79 +++++++++++----- security/integrity/ima/ima_policy.c | 32 +++++-- security/integrity/integrity.h | 8 +- 13 files changed, 358 insertions(+), 53 deletions(-) create mode 100644 security/integrity/ima/ima_appraise.c (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ad7e2e5088c..fa09e64d987 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1051,6 +1051,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ihash_entries= [KNL] Set number of hash buckets for inode cache. + ima_appraise= [IMA] appraise integrity measurements + Format: { "off" | "enforce" | "fix" } + default: "enforce" + ima_audit= [IMA] Format: { "0" | "1" } 0 -- integrity auditing messages. (Default) diff --git a/include/linux/xattr.h b/include/linux/xattr.h index e5d12203154..77a3e686d56 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -33,6 +33,9 @@ #define XATTR_EVM_SUFFIX "evm" #define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX +#define XATTR_IMA_SUFFIX "ima" +#define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX + #define XATTR_SELINUX_SUFFIX "selinux" #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 8901501425f..eb5484504f5 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -33,6 +33,9 @@ char *evm_config_xattrnames[] = { #endif #ifdef CONFIG_SECURITY_SMACK XATTR_NAME_SMACK, +#endif +#ifdef CONFIG_IMA_APPRAISE + XATTR_NAME_IMA, #endif XATTR_NAME_CAPS, NULL diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 399641c3e84..e600986aa49 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint) { iint->version = 0; iint->flags = 0UL; + iint->ima_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; kmem_cache_free(iint_cache, iint); } @@ -157,7 +158,7 @@ static void init_once(void *foo) memset(iint, 0, sizeof *iint); iint->version = 0; iint->flags = 0UL; - mutex_init(&iint->mutex); + iint->ima_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 809ccf19d09..d232c73647a 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -56,3 +56,18 @@ config IMA_LSM_RULES default y help Disabling this option will disregard LSM based policy rules. + +config IMA_APPRAISE + bool "Appraise integrity measurements" + depends on IMA + default n + help + This option enables local measurement integrity appraisal. + It requires the system to be labeled with a security extended + attribute containing the file hash measurement. To protect + the security extended attributes from offline attack, enable + and configure EVM. + + For more information on integrity appraisal refer to: + + If unsure, say N. diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 5f740f6971e..3f2ca6bdc38 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ ima_policy.o ima-$(CONFIG_IMA_AUDIT) += ima_audit.o +ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e7c99fd0d22..069a4aa63e9 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -40,6 +40,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; extern int ima_initialized; extern int ima_used_chip; extern char *ima_hash; +extern int ima_appraise; /* IMA inode template definition */ struct ima_template_data { @@ -107,6 +108,7 @@ static inline unsigned long ima_hash_key(u8 *digest) } /* LIM API function definitions */ +int ima_must_appraise_or_measure(struct inode *inode, int mask, int function); int ima_must_measure(struct inode *inode, int mask, int function); int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file); @@ -123,14 +125,45 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); struct integrity_iint_cache *integrity_iint_find(struct inode *inode); /* IMA policy related functions */ -enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; +enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; -int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); +int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, + int flags); void ima_init_policy(void); void ima_update_policy(void); ssize_t ima_parse_add_rule(char *); void ima_delete_rules(void); +/* Appraise integrity measurements */ +#define IMA_APPRAISE_ENFORCE 0x01 +#define IMA_APPRAISE_FIX 0x02 + +#ifdef CONFIG_IMA_APPRAISE +int ima_appraise_measurement(struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename); +int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask); +void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); + +#else +static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, + struct file *file, + const unsigned char *filename) +{ + return INTEGRITY_UNKNOWN; +} + +static inline int ima_must_appraise(struct inode *inode, + enum ima_hooks func, int mask) +{ + return 0; +} + +static inline void ima_update_xattr(struct integrity_iint_cache *iint, + struct file *file) +{ +} +#endif + /* LSM based policy rules require audit */ #ifdef CONFIG_IMA_LSM_RULES diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 032ff03ad90..41cce84416c 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -9,13 +9,17 @@ * License. * * File: ima_api.c - * Implements must_measure, collect_measurement, store_measurement, - * and store_template. + * Implements must_appraise_or_measure, collect_measurement, + * appraise_measurement, store_measurement and store_template. */ #include #include - +#include +#include +#include +#include #include "ima.h" + static const char *IMA_TEMPLATE_NAME = "ima"; /* @@ -93,7 +97,7 @@ err_out: } /** - * ima_must_measure - measure decision based on policy. + * ima_must_appraise_or_measure - appraise & measure decision based on policy. * @inode: pointer to inode to measure * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) @@ -105,15 +109,22 @@ err_out: * mask: contains the permission mask * fsmagic: hex value * - * Return 0 to measure. For matching a DONT_MEASURE policy, no policy, - * or other error, return an error code. -*/ -int ima_must_measure(struct inode *inode, int mask, int function) + * Returns IMA_MEASURE, IMA_APPRAISE mask. + * + */ +int ima_must_appraise_or_measure(struct inode *inode, int mask, int function) { - int must_measure; + int flags = IMA_MEASURE | IMA_APPRAISE; + + if (!ima_appraise) + flags &= ~IMA_APPRAISE; + + return ima_match_policy(inode, function, mask, flags); +} - must_measure = ima_match_policy(inode, function, mask); - return must_measure ? 0 : -EACCES; +int ima_must_measure(struct inode *inode, int mask, int function) +{ + return ima_match_policy(inode, function, mask, IMA_MEASURE); } /* @@ -129,16 +140,24 @@ int ima_must_measure(struct inode *inode, int mask, int function) int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file) { - int result = -EEXIST; + struct inode *inode = file->f_dentry->d_inode; + const char *filename = file->f_dentry->d_name.name; + int result = 0; - if (!(iint->flags & IMA_MEASURED)) { + if (!(iint->flags & IMA_COLLECTED)) { u64 i_version = file->f_dentry->d_inode->i_version; memset(iint->digest, 0, IMA_DIGEST_SIZE); result = ima_calc_hash(file, iint->digest); - if (!result) + if (!result) { iint->version = i_version; + iint->flags |= IMA_COLLECTED; + } } + if (result) + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, + filename, "collect_data", "failed", + result, 0); return result; } @@ -167,6 +186,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct ima_template_entry *entry; int violation = 0; + if (iint->flags & IMA_MEASURED) + return; + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c new file mode 100644 index 00000000000..4865f61f904 --- /dev/null +++ b/security/integrity/ima/ima_appraise.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2011 IBM Corporation + * + * Author: + * Mimi Zohar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ima.h" + +static int __init default_appraise_setup(char *str) +{ + if (strncmp(str, "off", 3) == 0) + ima_appraise = 0; + else if (strncmp(str, "fix", 3) == 0) + ima_appraise = IMA_APPRAISE_FIX; + return 1; +} + +__setup("ima_appraise=", default_appraise_setup); + +/* + * ima_must_appraise - set appraise flag + * + * Return 1 to appraise + */ +int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) +{ + return 0; +} + +static void ima_fix_xattr(struct dentry *dentry, + struct integrity_iint_cache *iint) +{ + iint->digest[0] = IMA_XATTR_DIGEST; + __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, + iint->digest, IMA_DIGEST_SIZE + 1, 0); +} + +/* + * ima_appraise_measurement - appraise file measurement + * + * Call evm_verifyxattr() to verify the integrity of 'security.ima'. + * Assuming success, compare the xattr hash with the collected measurement. + * + * Return 0 on success, error code otherwise + */ +int ima_appraise_measurement(struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename) +{ + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + u8 xattr_value[IMA_DIGEST_SIZE]; + enum integrity_status status = INTEGRITY_UNKNOWN; + const char *op = "appraise_data"; + char *cause = "unknown"; + int rc; + + if (!ima_appraise) + return 0; + if (!inode->i_op->getxattr) + return INTEGRITY_UNKNOWN; + + if (iint->flags & IMA_APPRAISED) + return iint->ima_status; + + rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, xattr_value, + IMA_DIGEST_SIZE); + if (rc <= 0) { + if (rc && rc != -ENODATA) + goto out; + + cause = "missing-hash"; + status = + (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL; + goto out; + } + + status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); + if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { + if ((status == INTEGRITY_NOLABEL) + || (status == INTEGRITY_NOXATTRS)) + cause = "missing-HMAC"; + else if (status == INTEGRITY_FAIL) + cause = "invalid-HMAC"; + goto out; + } + + rc = memcmp(xattr_value, iint->digest, IMA_DIGEST_SIZE); + if (rc) { + status = INTEGRITY_FAIL; + cause = "invalid-hash"; + print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE, + xattr_value, IMA_DIGEST_SIZE); + print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE, + iint->digest, IMA_DIGEST_SIZE); + goto out; + } + status = INTEGRITY_PASS; + iint->flags |= IMA_APPRAISED; +out: + if (status != INTEGRITY_PASS) { + if (ima_appraise & IMA_APPRAISE_FIX) { + ima_fix_xattr(dentry, iint); + status = INTEGRITY_PASS; + } + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, + op, cause, rc, 0); + } + iint->ima_status = status; + return status; +} + +/* + * ima_update_xattr - update 'security.ima' hash value + */ +void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) +{ + struct dentry *dentry = file->f_dentry; + int rc = 0; + + rc = ima_collect_measurement(iint, file); + if (rc < 0) + return; + ima_fix_xattr(dentry, iint); +} + +/** + * ima_inode_post_setattr - reflect file metadata changes + * @dentry: pointer to the affected dentry + * + * Changes to a dentry's metadata might result in needing to appraise. + * + * This function is called from notify_change(), which expects the caller + * to lock the inode's i_mutex. + */ +void ima_inode_post_setattr(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct integrity_iint_cache *iint; + int must_appraise, rc; + + if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) + || !inode->i_op->removexattr) + return; + + must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); + iint = integrity_iint_find(inode); + if (iint) { + if (must_appraise) + iint->flags |= IMA_APPRAISE; + else + iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); + } + if (!must_appraise) + rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); + return; +} diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 9b3ade7468b..b21ee5b5495 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -48,7 +48,7 @@ int ima_calc_hash(struct file *file, char *digest) struct scatterlist sg[1]; loff_t i_size, offset = 0; char *rbuf; - int rc; + int rc, read = 0; rc = init_desc(&desc); if (rc != 0) @@ -59,6 +59,10 @@ int ima_calc_hash(struct file *file, char *digest) rc = -ENOMEM; goto out; } + if (!(file->f_mode & FMODE_READ)) { + file->f_mode |= FMODE_READ; + read = 1; + } i_size = i_size_read(file->f_dentry->d_inode); while (offset < i_size) { int rbuf_len; @@ -80,6 +84,8 @@ int ima_calc_hash(struct file *file, char *digest) kfree(rbuf); if (!rc) rc = crypto_hash_final(&desc, digest); + if (read) + file->f_mode &= ~FMODE_READ; out: crypto_free_hash(desc.tfm); return rc; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index be8294915cf..6eb28d47e74 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -22,12 +22,19 @@ #include #include #include +#include #include #include "ima.h" int ima_initialized; +#ifdef CONFIG_IMA_APPRAISE +int ima_appraise = IMA_APPRAISE_ENFORCE; +#else +int ima_appraise; +#endif + char *ima_hash = "sha1"; static int __init hash_setup(char *str) { @@ -52,7 +59,7 @@ static void ima_rdwr_violation_check(struct file *file) struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; fmode_t mode = file->f_mode; - int rc; + int must_measure; bool send_tomtou = false, send_writers = false; unsigned char *pathname = NULL, *pathbuf = NULL; @@ -67,8 +74,8 @@ static void ima_rdwr_violation_check(struct file *file) goto out; } - rc = ima_must_measure(inode, MAY_READ, FILE_CHECK); - if (rc < 0) + must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); + if (!must_measure) goto out; if (atomic_read(&inode->i_writecount) > 0) @@ -100,17 +107,21 @@ out: } static void ima_check_last_writer(struct integrity_iint_cache *iint, - struct inode *inode, - struct file *file) + struct inode *inode, struct file *file) { fmode_t mode = file->f_mode; - mutex_lock(&iint->mutex); - if (mode & FMODE_WRITE && - atomic_read(&inode->i_writecount) == 1 && - iint->version != inode->i_version) - iint->flags &= ~IMA_MEASURED; - mutex_unlock(&iint->mutex); + if (!(mode & FMODE_WRITE)) + return; + + mutex_lock(&inode->i_mutex); + if (atomic_read(&inode->i_writecount) == 1 && + iint->version != inode->i_version) { + iint->flags &= ~(IMA_COLLECTED | IMA_APPRAISED | IMA_MEASURED); + if (iint->flags & IMA_APPRAISE) + ima_update_xattr(iint, file); + } + mutex_unlock(&inode->i_mutex); } /** @@ -140,14 +151,17 @@ static int process_measurement(struct file *file, const unsigned char *filename, struct inode *inode = file->f_dentry->d_inode; struct integrity_iint_cache *iint; unsigned char *pathname = NULL, *pathbuf = NULL; - int rc = 0; + int rc = -ENOMEM, action, must_appraise; if (!ima_initialized || !S_ISREG(inode->i_mode)) return 0; - rc = ima_must_measure(inode, mask, function); - if (rc != 0) - return rc; + /* Determine if in appraise/measurement policy, + * returns IMA_MEASURE, IMA_APPRAISE bitmask. */ + action = ima_must_appraise_or_measure(inode, mask, function); + if (!action) + return 0; + retry: iint = integrity_iint_find(inode); if (!iint) { @@ -157,11 +171,21 @@ retry: return rc; } - mutex_lock(&iint->mutex); + must_appraise = action & IMA_APPRAISE; - rc = iint->flags & IMA_MEASURED ? 1 : 0; - if (rc != 0) + mutex_lock(&inode->i_mutex); + + /* Determine if already appraised/measured based on bitmask + * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED) */ + iint->flags |= action; + action &= ~((iint->flags & (IMA_MEASURED | IMA_APPRAISED)) >> 1); + + /* Nothing to do, just return existing appraised status */ + if (!action) { + if (iint->flags & IMA_APPRAISED) + rc = iint->ima_status; goto out; + } rc = ima_collect_measurement(iint, file); if (rc != 0) @@ -177,11 +201,16 @@ retry: pathname = NULL; } } - ima_store_measurement(iint, file, !pathname ? filename : pathname); + if (action & IMA_MEASURE) + ima_store_measurement(iint, file, + !pathname ? filename : pathname); + if (action & IMA_APPRAISE) + rc = ima_appraise_measurement(iint, file, + !pathname ? filename : pathname); kfree(pathbuf); out: - mutex_unlock(&iint->mutex); - return rc; + mutex_unlock(&inode->i_mutex); + return (rc && must_appraise) ? -EACCES : 0; } /** @@ -197,14 +226,14 @@ out: */ int ima_file_mmap(struct file *file, unsigned long prot) { - int rc; + int rc = 0; if (!file) return 0; if (prot & PROT_EXEC) rc = process_measurement(file, file->f_dentry->d_name.name, MAY_EXEC, FILE_MMAP); - return 0; + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; } /** @@ -228,7 +257,7 @@ int ima_bprm_check(struct linux_binprm *bprm) (strcmp(bprm->filename, bprm->interp) == 0) ? bprm->filename : bprm->interp, MAY_EXEC, BPRM_CHECK); - return 0; + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; } /** @@ -249,7 +278,7 @@ int ima_file_check(struct file *file, int mask) rc = process_measurement(file, file->f_dentry->d_name.name, mask & (MAY_READ | MAY_WRITE | MAY_EXEC), FILE_CHECK); - return 0; + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; } EXPORT_SYMBOL_GPL(ima_file_check); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 1a9583008aa..3e22e17da29 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -25,7 +25,13 @@ #define IMA_FSMAGIC 0x0004 #define IMA_UID 0x0008 -enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; +#define UNKNOWN 0 +#define MEASURE 1 /* same as IMA_MEASURE */ +#define DONT_MEASURE 2 +#define MEASURE_MASK 3 +#define APPRAISE 4 /* same as IMA_APPRAISE */ +#define DONT_APPRAISE 8 +#define APPRAISE_MASK 12 #define MAX_LSM_RULES 6 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, @@ -34,7 +40,7 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, struct ima_measure_rule_entry { struct list_head list; - enum ima_action action; + int action; unsigned int flags; enum ima_hooks func; int mask; @@ -163,18 +169,28 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, * as elements in the list are never deleted, nor does the list * change.) */ -int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) +int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, + int flags) { struct ima_measure_rule_entry *entry; + int action = 0, actmask = flags | (flags << 1); list_for_each_entry(entry, ima_measure, list) { - bool rc; - rc = ima_match_rules(entry, inode, func, mask); - if (rc) - return entry->action; + if (!(entry->action & actmask)) + continue; + + if (!ima_match_rules(entry, inode, func, mask)) + continue; + + action |= (entry->action & (IMA_APPRAISE | IMA_MEASURE)); + actmask &= (entry->action & APPRAISE_MASK) ? + ~APPRAISE_MASK : ~MEASURE_MASK; + if (!actmask) + break; } - return 0; + + return action; } /** diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 7a25ecec5aa..dac6b68e945 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -16,7 +16,11 @@ #include /* iint cache flags */ -#define IMA_MEASURED 0x01 +#define IMA_MEASURE 0x01 +#define IMA_MEASURED 0x02 +#define IMA_APPRAISE 0x04 +#define IMA_APPRAISED 0x08 +#define IMA_COLLECTED 0x10 enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, @@ -36,7 +40,7 @@ struct integrity_iint_cache { u64 version; /* track inode changes */ unsigned char flags; u8 digest[SHA1_DIGEST_SIZE]; - struct mutex mutex; /* protects: version, flags, digest */ + enum integrity_status ima_status; enum integrity_status evm_status; }; -- cgit v1.2.3-70-g09d2 From 07f6a79415d7d502ee0c7d02ace6594a7be7429a Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 9 Mar 2011 22:25:48 -0500 Subject: ima: add appraise action keywords and default rules Unlike the IMA measurement policy, the appraise policy can not be dependent on runtime process information, such as the task uid, as the 'security.ima' xattr is written on file close and must be updated each time the file changes, regardless of the current task uid. This patch extends the policy language with 'fowner', defines an appraise policy, which appraises all files owned by root, and defines 'ima_appraise_tcb', a new boot command line option, to enable the appraise policy. Changelog v3: - separate the measure from the appraise rules in order to support measuring without appraising and appraising without measuring. - change appraisal default for filesystems without xattr support to fail - update default appraise policy for cgroups Changelog v1: - don't appraise RAMFS (Dmitry Kasatkin) - merged rest of "ima: ima_must_appraise_or_measure API change" commit (Dmtiry Kasatkin) ima_must_appraise_or_measure() called ima_match_policy twice, which searched the policy for a matching rule. Once for a matching measurement rule and subsequently for an appraisal rule. Searching the policy twice is unnecessary overhead, which could be noticeable with a large policy. The new version of ima_must_appraise_or_measure() does everything in a single iteration using a new version of ima_match_policy(). It returns IMA_MEASURE, IMA_APPRAISE mask. With the use of action mask only one efficient matching function is enough. Removed other specific versions of matching functions. Changelog: - change 'owner' to 'fowner' to conform to the new LSM conditions posted by Roberto Sassu. - fix calls to ima_log_string() Signed-off-by: Mimi Zohar Signed-off-by: Dmitry Kasatkin --- Documentation/ABI/testing/ima_policy | 25 +++++- Documentation/kernel-parameters.txt | 4 + security/integrity/ima/ima_appraise.c | 5 +- security/integrity/ima/ima_policy.c | 151 +++++++++++++++++++++++++--------- 4 files changed, 141 insertions(+), 44 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 6cd6daefaae..dcff8220547 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -12,11 +12,14 @@ Description: then closing the file. The new policy takes effect after the file ima/policy is closed. + IMA appraisal, if configured, uses these file measurements + for local measurement appraisal. + rule format: action [condition ...] - action: measure | dont_measure + action: measure | dont_measure | appraise | dont_appraise condition:= base | lsm - base: [[func=] [mask=] [fsmagic=] [uid=]] + base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]] lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] @@ -24,36 +27,50 @@ Description: mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] fsmagic:= hex value uid:= decimal value + fowner:=decimal value lsm: are LSM specific default policy: # PROC_SUPER_MAGIC dont_measure fsmagic=0x9fa0 + dont_appraise fsmagic=0x9fa0 # SYSFS_MAGIC dont_measure fsmagic=0x62656572 + dont_appraise fsmagic=0x62656572 # DEBUGFS_MAGIC dont_measure fsmagic=0x64626720 + dont_appraise fsmagic=0x64626720 # TMPFS_MAGIC dont_measure fsmagic=0x01021994 + dont_appraise fsmagic=0x01021994 + # RAMFS_MAGIC + dont_measure fsmagic=0x858458f6 + dont_appraise fsmagic=0x858458f6 # SECURITYFS_MAGIC dont_measure fsmagic=0x73636673 + dont_appraise fsmagic=0x73636673 measure func=BPRM_CHECK measure func=FILE_MMAP mask=MAY_EXEC measure func=FILE_CHECK mask=MAY_READ uid=0 + appraise fowner=0 The default policy measures all executables in bprm_check, all files mmapped executable in file_mmap, and all files - open for read by root in do_filp_open. + open for read by root in do_filp_open. The default appraisal + policy appraises all files owned by root. Examples of LSM specific definitions: SELinux: # SELINUX_MAGIC - dont_measure fsmagic=0xF97CFF8C + dont_measure fsmagic=0xf97cff8c + dont_appraise fsmagic=0xf97cff8c dont_measure obj_type=var_log_t + dont_appraise obj_type=var_log_t dont_measure obj_type=auditd_log_t + dont_appraise obj_type=auditd_log_t measure subj_user=system_u func=FILE_CHECK mask=MAY_READ measure subj_role=system_r func=FILE_CHECK mask=MAY_READ diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fa09e64d987..949dddcfd17 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1055,6 +1055,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Format: { "off" | "enforce" | "fix" } default: "enforce" + ima_appraise_tcb [IMA] + The builtin appraise policy appraises all files + owned by uid=0. + ima_audit= [IMA] Format: { "0" | "1" } 0 -- integrity auditing messages. (Default) diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 4865f61f904..681cb6e7225 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -36,7 +36,10 @@ __setup("ima_appraise=", default_appraise_setup); */ int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) { - return 0; + if (!ima_appraise) + return 0; + + return ima_match_policy(inode, func, mask, IMA_APPRAISE); } static void ima_fix_xattr(struct dentry *dentry, diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 3e22e17da29..0d6d60b4ba6 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -24,6 +24,7 @@ #define IMA_MASK 0x0002 #define IMA_FSMAGIC 0x0004 #define IMA_UID 0x0008 +#define IMA_FOWNER 0x0010 #define UNKNOWN 0 #define MEASURE 1 /* same as IMA_MEASURE */ @@ -38,7 +39,7 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE }; -struct ima_measure_rule_entry { +struct ima_rule_entry { struct list_head list; int action; unsigned int flags; @@ -46,6 +47,7 @@ struct ima_measure_rule_entry { int mask; unsigned long fsmagic; uid_t uid; + uid_t fowner; struct { void *rule; /* LSM file metadata specific */ int type; /* audit type */ @@ -54,7 +56,7 @@ struct ima_measure_rule_entry { /* * Without LSM specific knowledge, the default policy can only be - * written in terms of .action, .func, .mask, .fsmagic, and .uid + * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner */ /* @@ -63,7 +65,7 @@ struct ima_measure_rule_entry { * normal users can easily run the machine out of memory simply building * and running executables. */ -static struct ima_measure_rule_entry default_rules[] = { +static struct ima_rule_entry default_rules[] = { {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, @@ -81,19 +83,41 @@ static struct ima_measure_rule_entry default_rules[] = { .flags = IMA_FUNC | IMA_MASK | IMA_UID}, }; -static LIST_HEAD(measure_default_rules); -static LIST_HEAD(measure_policy_rules); -static struct list_head *ima_measure; +static struct ima_rule_entry default_appraise_rules[] = { + {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC}, + {.action = APPRAISE,.fowner = 0,.flags = IMA_FOWNER}, +}; + +static LIST_HEAD(ima_default_rules); +static LIST_HEAD(ima_policy_rules); +static struct list_head *ima_rules; -static DEFINE_MUTEX(ima_measure_mutex); +static DEFINE_MUTEX(ima_rules_mutex); static bool ima_use_tcb __initdata; -static int __init default_policy_setup(char *str) +static int __init default_measure_policy_setup(char *str) { ima_use_tcb = 1; return 1; } -__setup("ima_tcb", default_policy_setup); +__setup("ima_tcb", default_measure_policy_setup); + +static bool ima_use_appraise_tcb __initdata; +static int __init default_appraise_policy_setup(char *str) +{ + ima_use_appraise_tcb = 1; + return 1; +} +__setup("ima_appraise_tcb", default_appraise_policy_setup); /** * ima_match_rules - determine whether an inode matches the measure rule. @@ -104,7 +128,7 @@ __setup("ima_tcb", default_policy_setup); * * Returns true on rule match, false on failure. */ -static bool ima_match_rules(struct ima_measure_rule_entry *rule, +static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, enum ima_hooks func, int mask) { struct task_struct *tsk = current; @@ -120,6 +144,8 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, return false; if ((rule->flags & IMA_UID) && rule->uid != cred->uid) return false; + if ((rule->flags & IMA_FOWNER) && rule->fowner != inode->i_uid) + return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; u32 osid, sid; @@ -172,10 +198,10 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, int flags) { - struct ima_measure_rule_entry *entry; + struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); - list_for_each_entry(entry, ima_measure, list) { + list_for_each_entry(entry, ima_rules, list) { if (!(entry->action & actmask)) continue; @@ -196,22 +222,31 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, /** * ima_init_policy - initialize the default measure rules. * - * ima_measure points to either the measure_default_rules or the - * the new measure_policy_rules. + * ima_rules points to either the ima_default_rules or the + * the new ima_policy_rules. */ void __init ima_init_policy(void) { - int i, entries; + int i, measure_entries, appraise_entries; /* if !ima_use_tcb set entries = 0 so we load NO default rules */ - if (ima_use_tcb) - entries = ARRAY_SIZE(default_rules); - else - entries = 0; - - for (i = 0; i < entries; i++) - list_add_tail(&default_rules[i].list, &measure_default_rules); - ima_measure = &measure_default_rules; + measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; + appraise_entries = ima_use_appraise_tcb ? + ARRAY_SIZE(default_appraise_rules) : 0; + + for (i = 0; i < measure_entries + appraise_entries; i++) { + if (i < measure_entries) + list_add_tail(&default_rules[i].list, + &ima_default_rules); + else { + int j = i - measure_entries; + + list_add_tail(&default_appraise_rules[j].list, + &ima_default_rules); + } + } + + ima_rules = &ima_default_rules; } /** @@ -228,8 +263,8 @@ void ima_update_policy(void) int result = 1; int audit_info = 0; - if (ima_measure == &measure_default_rules) { - ima_measure = &measure_policy_rules; + if (ima_rules == &ima_default_rules) { + ima_rules = &ima_policy_rules; cause = "complete"; result = 0; } @@ -240,14 +275,17 @@ void ima_update_policy(void) enum { Opt_err = -1, Opt_measure = 1, Opt_dont_measure, + Opt_appraise, Opt_dont_appraise, Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, - Opt_func, Opt_mask, Opt_fsmagic, Opt_uid + Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner }; static match_table_t policy_tokens = { {Opt_measure, "measure"}, {Opt_dont_measure, "dont_measure"}, + {Opt_appraise, "appraise"}, + {Opt_dont_appraise, "dont_appraise"}, {Opt_obj_user, "obj_user=%s"}, {Opt_obj_role, "obj_role=%s"}, {Opt_obj_type, "obj_type=%s"}, @@ -258,10 +296,11 @@ static match_table_t policy_tokens = { {Opt_mask, "mask=%s"}, {Opt_fsmagic, "fsmagic=%s"}, {Opt_uid, "uid=%s"}, + {Opt_fowner, "fowner=%s"}, {Opt_err, NULL} }; -static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, +static int ima_lsm_rule_init(struct ima_rule_entry *entry, char *args, int lsm_rule, int audit_type) { int result; @@ -285,7 +324,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) audit_log_format(ab, " "); } -static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) +static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) { struct audit_buffer *ab; char *p; @@ -294,6 +333,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); entry->uid = -1; + entry->fowner = -1; entry->action = UNKNOWN; while ((p = strsep(&rule, " \t")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -322,11 +362,27 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) entry->action = DONT_MEASURE; break; + case Opt_appraise: + ima_log_string(ab, "action", "appraise"); + + if (entry->action != UNKNOWN) + result = -EINVAL; + + entry->action = APPRAISE; + break; + case Opt_dont_appraise: + ima_log_string(ab, "action", "dont_appraise"); + + if (entry->action != UNKNOWN) + result = -EINVAL; + + entry->action = DONT_APPRAISE; + break; case Opt_func: ima_log_string(ab, "func", args[0].from); if (entry->func) - result = -EINVAL; + result = -EINVAL; if (strcmp(args[0].from, "FILE_CHECK") == 0) entry->func = FILE_CHECK; @@ -391,6 +447,23 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) entry->flags |= IMA_UID; } break; + case Opt_fowner: + ima_log_string(ab, "fowner", args[0].from); + + if (entry->fowner != -1) { + result = -EINVAL; + break; + } + + result = strict_strtoul(args[0].from, 10, &lnum); + if (!result) { + entry->fowner = (uid_t) lnum; + if (entry->fowner != lnum) + result = -EINVAL; + else + entry->flags |= IMA_FOWNER; + } + break; case Opt_obj_user: ima_log_string(ab, "obj_user", args[0].from); result = ima_lsm_rule_init(entry, args[0].from, @@ -442,7 +515,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) } /** - * ima_parse_add_rule - add a rule to measure_policy_rules + * ima_parse_add_rule - add a rule to ima_policy_rules * @rule - ima measurement policy rule * * Uses a mutex to protect the policy list from multiple concurrent writers. @@ -452,12 +525,12 @@ ssize_t ima_parse_add_rule(char *rule) { const char *op = "update_policy"; char *p; - struct ima_measure_rule_entry *entry; + struct ima_rule_entry *entry; ssize_t result, len; int audit_info = 0; /* Prevent installed policy from changing */ - if (ima_measure != &measure_default_rules) { + if (ima_rules != &ima_default_rules) { integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, op, "already exists", -EACCES, audit_info); @@ -490,9 +563,9 @@ ssize_t ima_parse_add_rule(char *rule) return result; } - mutex_lock(&ima_measure_mutex); - list_add_tail(&entry->list, &measure_policy_rules); - mutex_unlock(&ima_measure_mutex); + mutex_lock(&ima_rules_mutex); + list_add_tail(&entry->list, &ima_policy_rules); + mutex_unlock(&ima_rules_mutex); return len; } @@ -500,12 +573,12 @@ ssize_t ima_parse_add_rule(char *rule) /* ima_delete_rules called to cleanup invalid policy */ void ima_delete_rules(void) { - struct ima_measure_rule_entry *entry, *tmp; + struct ima_rule_entry *entry, *tmp; - mutex_lock(&ima_measure_mutex); - list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { + mutex_lock(&ima_rules_mutex); + list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) { list_del(&entry->list); kfree(entry); } - mutex_unlock(&ima_measure_mutex); + mutex_unlock(&ima_rules_mutex); } -- cgit v1.2.3-70-g09d2 From 4254bba17d92d53822a56ebc2a0c1eb7e2a71155 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Thu, 6 Sep 2012 15:35:00 -0700 Subject: block: Kill bi_destructor Now that we've got generic code for freeing bios allocated from bio pools, this isn't needed anymore. This patch also makes bio_free() static, since without bi_destructor there should be no need for it to be called anywhere else. bio_free() is now only called from bio_put, so we can refactor those a bit - move some code from bio_put() to bio_free() and kill the redundant bio->bi_next = NULL. v5: Switch to BIO_KMALLOC_POOL ((void *)~0), per Boaz v6: BIO_KMALLOC_POOL now NULL, drop bio_free's EXPORT_SYMBOL v7: No #define BIO_KMALLOC_POOL anymore Signed-off-by: Kent Overstreet CC: Jens Axboe Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 5 ---- block/blk-core.c | 2 +- fs/bio.c | 64 +++++++++++++++++------------------------- include/linux/bio.h | 1 - include/linux/blk_types.h | 3 -- 5 files changed, 27 insertions(+), 48 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index e418dc0a708..8df5e8e6dce 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -465,7 +465,6 @@ struct bio { bio_end_io_t *bi_end_io; /* bi_end_io (bio) */ atomic_t bi_cnt; /* pin count: free when it hits zero */ void *bi_private; - bio_destructor_t *bi_destructor; /* bi_destructor (bio) */ }; With this multipage bio design: @@ -647,10 +646,6 @@ for a non-clone bio. There are the 6 pools setup for different size biovecs, so bio_alloc(gfp_mask, nr_iovecs) will allocate a vec_list of the given size from these slabs. -The bi_destructor() routine takes into account the possibility of the bio -having originated from a different source (see later discussions on -n/w to block transfers and kvec_cb) - The bio_get() routine may be used to hold an extra reference on a bio prior to i/o submission, if the bio fields are likely to be accessed after the i/o is issued (since the bio may otherwise get freed in case i/o completion diff --git a/block/blk-core.c b/block/blk-core.c index 95c493511be..b776cc90a4e 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2807,7 +2807,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, free_and_out: if (bio) - bio_free(bio, bs); + bio_put(bio); blk_rq_unprep_clone(rq); return -ENOMEM; diff --git a/fs/bio.c b/fs/bio.c index 919ee9aa5c5..736ef12f519 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -233,26 +233,37 @@ fallback: return bvl; } -void bio_free(struct bio *bio, struct bio_set *bs) +static void __bio_free(struct bio *bio) { - void *p; - - if (bio_has_allocated_vec(bio)) - bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); + bio_disassociate_task(bio); if (bio_integrity(bio)) bio_integrity_free(bio); +} - /* - * If we have front padding, adjust the bio pointer before freeing - */ - p = bio; - if (bs->front_pad) +static void bio_free(struct bio *bio) +{ + struct bio_set *bs = bio->bi_pool; + void *p; + + __bio_free(bio); + + if (bs) { + if (bio_has_allocated_vec(bio)) + bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); + + /* + * If we have front padding, adjust the bio pointer before freeing + */ + p = bio; p -= bs->front_pad; - mempool_free(p, bs->bio_pool); + mempool_free(p, bs->bio_pool); + } else { + /* Bio was allocated by bio_kmalloc() */ + kfree(bio); + } } -EXPORT_SYMBOL(bio_free); void bio_init(struct bio *bio) { @@ -276,10 +287,7 @@ void bio_reset(struct bio *bio) { unsigned long flags = bio->bi_flags & (~0UL << BIO_RESET_BITS); - if (bio_integrity(bio)) - bio_integrity_free(bio); - - bio_disassociate_task(bio); + __bio_free(bio); memset(bio, 0, BIO_RESET_BYTES); bio->bi_flags = flags|(1 << BIO_UPTODATE); @@ -362,13 +370,6 @@ struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs) } EXPORT_SYMBOL(bio_alloc); -static void bio_kmalloc_destructor(struct bio *bio) -{ - if (bio_integrity(bio)) - bio_integrity_free(bio); - kfree(bio); -} - /** * bio_kmalloc - allocate a bio for I/O using kmalloc() * @gfp_mask: the GFP_ mask given to the slab allocator @@ -395,7 +396,6 @@ struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs) bio->bi_flags |= BIO_POOL_NONE << BIO_POOL_OFFSET; bio->bi_max_vecs = nr_iovecs; bio->bi_io_vec = bio->bi_inline_vecs; - bio->bi_destructor = bio_kmalloc_destructor; return bio; } @@ -431,20 +431,8 @@ void bio_put(struct bio *bio) /* * last put frees it */ - if (atomic_dec_and_test(&bio->bi_cnt)) { - bio_disassociate_task(bio); - bio->bi_next = NULL; - - /* - * This if statement is temporary - bi_pool is replacing - * bi_destructor, but bi_destructor will be taken out in another - * patch. - */ - if (bio->bi_pool) - bio_free(bio, bio->bi_pool); - else - bio->bi_destructor(bio); - } + if (atomic_dec_and_test(&bio->bi_cnt)) + bio_free(bio); } EXPORT_SYMBOL(bio_put); diff --git a/include/linux/bio.h b/include/linux/bio.h index 76f6c252baf..04944c91fae 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -216,7 +216,6 @@ extern struct bio *bio_alloc(gfp_t, unsigned int); extern struct bio *bio_kmalloc(gfp_t, unsigned int); extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *); extern void bio_put(struct bio *); -extern void bio_free(struct bio *, struct bio_set *); extern void bio_endio(struct bio *, int); struct request_queue; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 1b607c247d7..3eefbb29119 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -84,11 +84,8 @@ struct bio { struct bio_vec *bi_io_vec; /* the actual vec list */ - /* If bi_pool is non NULL, bi_destructor is not called */ struct bio_set *bi_pool; - bio_destructor_t *bi_destructor; /* destructor */ - /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member -- cgit v1.2.3-70-g09d2 From 7efd8fa145c340a68a9cd758012b6e0ae4883c93 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 7 Sep 2012 13:17:47 +0200 Subject: KVM: Improve wording of KVM_SET_USER_MEMORY_REGION documentation Signed-off-by: Jan Kiszka Signed-off-by: Avi Kivity --- Documentation/virtual/kvm/api.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index b91bfd43f00..36befa775fd 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -874,17 +874,17 @@ It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr be identical. This allows large pages in the guest to be backed by large pages in the host. -The flags field supports two flag, KVM_MEM_LOG_DIRTY_PAGES, which -instructs kvm to keep track of writes to memory within the slot. See -the KVM_GET_DIRTY_LOG ioctl. Another flag is KVM_MEM_READONLY when the -KVM_CAP_READONLY_MEM capability, it indicates the guest memory is read-only, -that means, guest is only allowed to read it. Writes will be posted to -userspace as KVM_EXIT_MMIO exits. - -When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory -region are automatically reflected into the guest. For example, an mmap() -that affects the region will be made visible immediately. Another example -is madvise(MADV_DROP). +The flags field supports two flag, KVM_MEM_LOG_DIRTY_PAGES, which instructs +kvm to keep track of writes to memory within the slot. See KVM_GET_DIRTY_LOG +ioctl. The KVM_CAP_READONLY_MEM capability indicates the availability of the +KVM_MEM_READONLY flag. When this flag is set for a memory region, KVM only +allows read accesses. Writes will be posted to userspace as KVM_EXIT_MMIO +exits. + +When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of +the memory region are automatically reflected into the guest. For example, an +mmap() that affects the region will be made visible immediately. Another +example is madvise(MADV_DROP). It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl. The KVM_SET_MEMORY_REGION does not allow fine grained control over memory -- cgit v1.2.3-70-g09d2 From 615b7300717b9ad5c23d1f391843484fe30f6c12 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 4 Sep 2012 08:28:07 +0000 Subject: acpi-cpufreq: Add support for disabling dynamic overclocking One feature present in powernow-k8 that isn't present in acpi-cpufreq is support for enabling or disabling AMD's core performance boost technology. This patch adds support to acpi-cpufreq, but also includes support for Intel's dynamic acceleration. The original boost disabling sysfs file was per CPU, but acted globally. Also the naming (cpb) was at least not intuitive. So lets introduce a single file simply called "boost", which sits once in /sys/devices/system/cpu/cpufreq. This should be the only way of using this feature, so add documentation about the rationale and the usage. A following patch will re-introduce the cpb knob for compatibility reasons on AMD CPUs. Per-CPU boost switching is possible, but not trivial and is thus postponed to a later patch series. Signed-off-by: Andre Przywara Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-devices-system-cpu | 11 ++ Documentation/cpu-freq/boost.txt | 93 +++++++++++ drivers/cpufreq/acpi-cpufreq.c | 177 +++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 Documentation/cpu-freq/boost.txt (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 5dab36448b4..6943133afcb 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -176,3 +176,14 @@ Description: Disable L3 cache indices All AMD processors with L3 caches provide this functionality. For details, see BKDGs at http://developer.amd.com/documentation/guides/Pages/default.aspx + + +What: /sys/devices/system/cpu/cpufreq/boost +Date: August 2012 +Contact: Linux kernel mailing list +Description: Processor frequency boosting control + + This switch controls the boost setting for the whole system. + Boosting allows the CPU and the firmware to run at a frequency + beyound it's nominal limit. + More details can be found in Documentation/cpu-freq/boost.txt diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt new file mode 100644 index 00000000000..9b4edfcf486 --- /dev/null +++ b/Documentation/cpu-freq/boost.txt @@ -0,0 +1,93 @@ +Processor boosting control + + - information for users - + +Quick guide for the impatient: +-------------------- +/sys/devices/system/cpu/cpufreq/boost +controls the boost setting for the whole system. You can read and write +that file with either "0" (boosting disabled) or "1" (boosting allowed). +Reading or writing 1 does not mean that the system is boosting at this +very moment, but only that the CPU _may_ raise the frequency at it's +discretion. +-------------------- + +Introduction +------------- +Some CPUs support a functionality to raise the operating frequency of +some cores in a multi-core package if certain conditions apply, mostly +if the whole chip is not fully utilized and below it's intended thermal +budget. This is done without operating system control by a combination +of hardware and firmware. +On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core", +in technical documentation "Core performance boost". In Linux we use +the term "boost" for convenience. + +Rationale for disable switch +---------------------------- + +Though the idea is to just give better performance without any user +intervention, sometimes the need arises to disable this functionality. +Most systems offer a switch in the (BIOS) firmware to disable the +functionality at all, but a more fine-grained and dynamic control would +be desirable: +1. While running benchmarks, reproducible results are important. Since + the boosting functionality depends on the load of the whole package, + single thread performance can vary. By explicitly disabling the boost + functionality at least for the benchmark's run-time the system will run + at a fixed frequency and results are reproducible again. +2. To examine the impact of the boosting functionality it is helpful + to do tests with and without boosting. +3. Boosting means overclocking the processor, though under controlled + conditions. By raising the frequency and the voltage the processor + will consume more power than without the boosting, which may be + undesirable for instance for mobile users. Disabling boosting may + save power here, though this depends on the workload. + + +User controlled switch +---------------------- + +To allow the user to toggle the boosting functionality, the acpi-cpufreq +driver exports a sysfs knob to disable it. There is a file: +/sys/devices/system/cpu/cpufreq/boost +which can either read "0" (boosting disabled) or "1" (boosting enabled). +Reading the file is always supported, even if the processor does not +support boosting. In this case the file will be read-only and always +reads as "0". Explicitly changing the permissions and writing to that +file anyway will return EINVAL. + +On supported CPUs one can write either a "0" or a "1" into this file. +This will either disable the boost functionality on all cores in the +whole system (0) or will allow the hardware to boost at will (1). + +Writing a "1" does not explicitly boost the system, but just allows the +CPU (and the firmware) to boost at their discretion. Some implementations +take external factors like the chip's temperature into account, so +boosting once does not necessarily mean that it will occur every time +even using the exact same software setup. + + +AMD legacy cpb switch +--------------------- +The AMD powernow-k8 driver used to support a very similar switch to +disable or enable the "Core Performance Boost" feature of some AMD CPUs. +This switch was instantiated in each CPU's cpufreq directory +(/sys/devices/system/cpu[0-9]*/cpufreq) and was called "cpb". +Though the per CPU existence hints at a more fine grained control, the +actual implementation only supported a system-global switch semantics, +which was simply reflected into each CPU's file. Writing a 0 or 1 into it +would pull the other CPUs to the same state. +For compatibility reasons this file and its behavior is still supported +on AMD CPUs, though it is now protected by a config switch +(X86_ACPI_CPUFREQ_CPB). On Intel CPUs this file will never be created, +even with the config option set. +This functionality is considered legacy and will be removed in some future +kernel version. + +More fine grained boosting control +---------------------------------- + +Technically it is possible to switch the boosting functionality at least +on a per package basis, for some CPUs even per core. Currently the driver +does not support it, but this may be implemented in the future. diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 70e717305c2..dffa7af1db7 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -63,6 +63,8 @@ enum { #define INTEL_MSR_RANGE (0xffff) #define AMD_MSR_RANGE (0x7) +#define MSR_K7_HWCR_CPB_DIS (1ULL << 25) + struct acpi_cpufreq_data { struct acpi_processor_performance *acpi_data; struct cpufreq_frequency_table *freq_table; @@ -78,6 +80,96 @@ static struct acpi_processor_performance __percpu *acpi_perf_data; static struct cpufreq_driver acpi_cpufreq_driver; static unsigned int acpi_pstate_strict; +static bool boost_enabled, boost_supported; +static struct msr __percpu *msrs; + +static bool boost_state(unsigned int cpu) +{ + u32 lo, hi; + u64 msr; + + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi); + msr = lo | ((u64)hi << 32); + return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); + case X86_VENDOR_AMD: + rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); + msr = lo | ((u64)hi << 32); + return !(msr & MSR_K7_HWCR_CPB_DIS); + } + return false; +} + +static void boost_set_msrs(bool enable, const struct cpumask *cpumask) +{ + u32 cpu; + u32 msr_addr; + u64 msr_mask; + + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + msr_addr = MSR_IA32_MISC_ENABLE; + msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE; + break; + case X86_VENDOR_AMD: + msr_addr = MSR_K7_HWCR; + msr_mask = MSR_K7_HWCR_CPB_DIS; + break; + default: + return; + } + + rdmsr_on_cpus(cpumask, msr_addr, msrs); + + for_each_cpu(cpu, cpumask) { + struct msr *reg = per_cpu_ptr(msrs, cpu); + if (enable) + reg->q &= ~msr_mask; + else + reg->q |= msr_mask; + } + + wrmsr_on_cpus(cpumask, msr_addr, msrs); +} + +static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long val = 0; + + if (!boost_supported) + return -EINVAL; + + ret = kstrtoul(buf, 10, &val); + if (ret || (val > 1)) + return -EINVAL; + + if ((val && boost_enabled) || (!val && !boost_enabled)) + return count; + + get_online_cpus(); + + boost_set_msrs(val, cpu_online_mask); + + put_online_cpus(); + + boost_enabled = val; + pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis"); + + return count; +} + +static ssize_t show_global_boost(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", boost_enabled); +} + +static struct global_attr global_boost = __ATTR(boost, 0644, + show_global_boost, + store_global_boost); static int check_est_cpu(unsigned int cpuid) { @@ -448,6 +540,44 @@ static void free_acpi_perf_data(void) free_percpu(acpi_perf_data); } +static int boost_notify(struct notifier_block *nb, unsigned long action, + void *hcpu) +{ + unsigned cpu = (long)hcpu; + const struct cpumask *cpumask; + + cpumask = get_cpu_mask(cpu); + + /* + * Clear the boost-disable bit on the CPU_DOWN path so that + * this cpu cannot block the remaining ones from boosting. On + * the CPU_UP path we simply keep the boost-disable flag in + * sync with the current global state. + */ + + switch (action) { + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + boost_set_msrs(boost_enabled, cpumask); + break; + + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + boost_set_msrs(1, cpumask); + break; + + default: + break; + } + + return NOTIFY_OK; +} + + +static struct notifier_block boost_nb = { + .notifier_call = boost_notify, +}; + /* * acpi_cpufreq_early_init - initialize ACPI P-States library * @@ -774,6 +904,49 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .attr = acpi_cpufreq_attr, }; +static void __init acpi_cpufreq_boost_init(void) +{ + if (boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)) { + msrs = msrs_alloc(); + + if (!msrs) + return; + + boost_supported = true; + boost_enabled = boost_state(0); + + get_online_cpus(); + + /* Force all MSRs to the same value */ + boost_set_msrs(boost_enabled, cpu_online_mask); + + register_cpu_notifier(&boost_nb); + + put_online_cpus(); + } else + global_boost.attr.mode = 0444; + + /* We create the boost file in any case, though for systems without + * hardware support it will be read-only and hardwired to return 0. + */ + if (sysfs_create_file(cpufreq_global_kobject, &(global_boost.attr))) + pr_warn(PFX "could not register global boost sysfs file\n"); + else + pr_debug("registered global boost sysfs file\n"); +} + +static void __exit acpi_cpufreq_boost_exit(void) +{ + sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr)); + + if (msrs) { + unregister_cpu_notifier(&boost_nb); + + msrs_free(msrs); + msrs = NULL; + } +} + static int __init acpi_cpufreq_init(void) { int ret; @@ -790,6 +963,8 @@ static int __init acpi_cpufreq_init(void) ret = cpufreq_register_driver(&acpi_cpufreq_driver); if (ret) free_acpi_perf_data(); + else + acpi_cpufreq_boost_init(); return ret; } @@ -798,6 +973,8 @@ static void __exit acpi_cpufreq_exit(void) { pr_debug("acpi_cpufreq_exit\n"); + acpi_cpufreq_boost_exit(); + cpufreq_unregister_driver(&acpi_cpufreq_driver); free_acpi_perf_data(); -- cgit v1.2.3-70-g09d2 From b496dfbc94ab86f970ef0167eaabe51f930aa5fb Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 5 Sep 2012 01:09:12 +0200 Subject: PM / OPP: Initialize OPP table from device tree With a lot of devices booting from device tree nowadays, it requires that OPP table can be initialized from device tree. The patch adds a helper function of_init_opp_table together with a binding doc for that purpose. Signed-off-by: Shawn Guo Acked-by: Rob Herring Signed-off-by: Rafael J. Wysocki --- Documentation/devicetree/bindings/power/opp.txt | 25 +++++++++++++ drivers/base/power/opp.c | 47 +++++++++++++++++++++++++ include/linux/opp.h | 8 +++++ 3 files changed, 80 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/opp.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt new file mode 100644 index 00000000000..74499e5033f --- /dev/null +++ b/Documentation/devicetree/bindings/power/opp.txt @@ -0,0 +1,25 @@ +* Generic OPP Interface + +SoCs have a standard set of tuples consisting of frequency and +voltage pairs that the device will support per voltage domain. These +are called Operating Performance Points or OPPs. + +Properties: +- operating-points: An array of 2-tuples items, and each item consists + of frequency and voltage like . + freq: clock frequency in kHz + vol: voltage in microvolt + +Examples: + +cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 1100000 + 396000 950000 + 198000 850000 + >; +}; diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index ac993eafec8..d9468642fc4 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -22,6 +22,7 @@ #include #include #include +#include /* * Internal data structure organization with the OPP layer library is as @@ -674,3 +675,49 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev) return &dev_opp->head; } + +#ifdef CONFIG_OF +/** + * of_init_opp_table() - Initialize opp table from device tree + * @dev: device pointer used to lookup device OPPs. + * + * Register the initial OPP table with the OPP library for given device. + */ +int of_init_opp_table(struct device *dev) +{ + const struct property *prop; + const __be32 *val; + int nr; + + prop = of_find_property(dev->of_node, "operating-points", NULL); + if (!prop) + return -ENODEV; + if (!prop->value) + return -ENODATA; + + /* + * Each OPP is a set of tuples consisting of frequency and + * voltage like . + */ + nr = prop->length / sizeof(u32); + if (nr % 2) { + dev_err(dev, "%s: Invalid OPP list\n", __func__); + return -EINVAL; + } + + val = prop->value; + while (nr) { + unsigned long freq = be32_to_cpup(val++) * 1000; + unsigned long volt = be32_to_cpup(val++); + + if (opp_add(dev, freq, volt)) { + dev_warn(dev, "%s: Failed to add OPP %ld\n", + __func__, freq); + continue; + } + nr -= 2; + } + + return 0; +} +#endif diff --git a/include/linux/opp.h b/include/linux/opp.h index 2a4e5faee90..214e0ebcb84 100644 --- a/include/linux/opp.h +++ b/include/linux/opp.h @@ -48,6 +48,14 @@ int opp_disable(struct device *dev, unsigned long freq); struct srcu_notifier_head *opp_get_notifier(struct device *dev); +#ifdef CONFIG_OF +int of_init_opp_table(struct device *dev); +#else +static inline int of_init_opp_table(struct device *dev) +{ + return -EINVAL; +} +#endif /* CONFIG_OF */ #else static inline unsigned long opp_get_voltage(struct opp *opp) { -- cgit v1.2.3-70-g09d2 From 95ceafd46359dfd901f9d3b881b33d3036e4b0ce Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 6 Sep 2012 07:09:11 +0000 Subject: cpufreq: Add a generic cpufreq-cpu0 driver It adds a generic cpufreq driver for CPU0 frequency management based on clk, regulator, OPP and device tree support. It can support both uniprocessor (UP) and those symmetric multiprocessor (SMP) systems which share clock and voltage across all CPUs. Signed-off-by: Shawn Guo Acked-by: Santosh Shilimkar Tested-by: AnilKumar Ch Signed-off-by: Rafael J. Wysocki --- .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt | 55 +++++ drivers/cpufreq/Kconfig | 11 + drivers/cpufreq/Makefile | 2 + drivers/cpufreq/cpufreq-cpu0.c | 269 +++++++++++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt create mode 100644 drivers/cpufreq/cpufreq-cpu0.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt new file mode 100644 index 00000000000..4416ccc3347 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@ -0,0 +1,55 @@ +Generic CPU0 cpufreq driver + +It is a generic cpufreq driver for CPU0 frequency management. It +supports both uniprocessor (UP) and symmetric multiprocessor (SMP) +systems which share clock and voltage across all CPUs. + +Both required and optional properties listed below must be defined +under node /cpus/cpu@0. + +Required properties: +- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt + for details + +Optional properties: +- clock-latency: Specify the possible maximum transition latency for clock, + in unit of nanoseconds. +- voltage-tolerance: Specify the CPU voltage tolerance in percentage. + +Examples: + +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 1100000 + 396000 950000 + 198000 850000 + >; + transition-latency = <61036>; /* two CLK32 periods */ + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + reg = <2>; + next-level-cache = <&L2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + reg = <3>; + next-level-cache = <&L2>; + }; +}; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1b666..ea512f47b78 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,17 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config GENERIC_CPUFREQ_CPU0 + bool "Generic CPU0 cpufreq driver" + depends on HAVE_CLK && REGULATOR && PM_OPP && OF + select CPU_FREQ_TABLE + help + This adds a generic cpufreq driver for CPU0 frequency management. + It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) + systems which share clock and voltage across all CPUs. + + If in doubt, say N. + menu "x86 CPU frequency scaling drivers" depends on X86 source "drivers/cpufreq/Kconfig.x86" diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index b99790f400c..1bc90e1306d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o + ################################################################################## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c new file mode 100644 index 00000000000..e9158278c71 --- /dev/null +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * The OPP code in function cpu0_set_target() is reused from + * drivers/cpufreq/omap-cpufreq.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int transition_latency; +static unsigned int voltage_tolerance; /* in percentage */ + +static struct device *cpu_dev; +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *freq_table; + +static int cpu0_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static unsigned int cpu0_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int cpu0_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + struct opp *opp; + unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0; + unsigned int index, cpu; + int ret; + + ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, + relation, &index); + if (ret) { + pr_err("failed to match target freqency %d: %d\n", + target_freq, ret); + return ret; + } + + freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); + if (freq_Hz < 0) + freq_Hz = freq_table[index].frequency * 1000; + freqs.new = freq_Hz / 1000; + freqs.old = clk_get_rate(cpu_clk) / 1000; + + if (freqs.old == freqs.new) + return 0; + + for_each_online_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + if (cpu_reg) { + opp = opp_find_freq_ceil(cpu_dev, &freq_Hz); + if (IS_ERR(opp)) { + pr_err("failed to find OPP for %ld\n", freq_Hz); + return PTR_ERR(opp); + } + volt = opp_get_voltage(opp); + tol = volt * voltage_tolerance / 100; + volt_old = regulator_get_voltage(cpu_reg); + } + + pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", + freqs.old / 1000, volt_old ? volt_old / 1000 : -1, + freqs.new / 1000, volt ? volt / 1000 : -1); + + /* scaling up? scale voltage before frequency */ + if (cpu_reg && freqs.new > freqs.old) { + ret = regulator_set_voltage_tol(cpu_reg, volt, tol); + if (ret) { + pr_err("failed to scale voltage up: %d\n", ret); + freqs.new = freqs.old; + return ret; + } + } + + ret = clk_set_rate(cpu_clk, freqs.new * 1000); + if (ret) { + pr_err("failed to set clock rate: %d\n", ret); + if (cpu_reg) + regulator_set_voltage_tol(cpu_reg, volt_old, tol); + return ret; + } + + /* scaling down? scale voltage after frequency */ + if (cpu_reg && freqs.new < freqs.old) { + ret = regulator_set_voltage_tol(cpu_reg, volt, tol); + if (ret) { + pr_err("failed to scale voltage down: %d\n", ret); + clk_set_rate(cpu_clk, freqs.old * 1000); + freqs.new = freqs.old; + return ret; + } + } + + for_each_online_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + return 0; +} + +static int cpu0_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + + if (policy->cpu != 0) + return -EINVAL; + + ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (ret) { + pr_err("invalid frequency table: %d\n", ret); + return ret; + } + + policy->cpuinfo.transition_latency = transition_latency; + policy->cur = clk_get_rate(cpu_clk) / 1000; + + /* + * The driver only supports the SMP configuartion where all processors + * share the clock and voltage and clock. Use cpufreq affected_cpus + * interface to have all CPUs scaled together. + */ + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_setall(policy->cpus); + + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + + return 0; +} + +static int cpu0_cpufreq_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + + return 0; +} + +static struct freq_attr *cpu0_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver cpu0_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = cpu0_verify_speed, + .target = cpu0_set_target, + .get = cpu0_get_speed, + .init = cpu0_cpufreq_init, + .exit = cpu0_cpufreq_exit, + .name = "generic_cpu0", + .attr = cpu0_cpufreq_attr, +}; + +static int __devinit cpu0_cpufreq_driver_init(void) +{ + struct device_node *np; + int ret; + + np = of_find_node_by_path("/cpus/cpu@0"); + if (!np) { + pr_err("failed to find cpu0 node\n"); + return -ENOENT; + } + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) { + pr_err("failed to get cpu0 device\n"); + ret = -ENODEV; + goto out_put_node; + } + + cpu_dev->of_node = np; + + cpu_clk = clk_get(cpu_dev, NULL); + if (IS_ERR(cpu_clk)) { + ret = PTR_ERR(cpu_clk); + pr_err("failed to get cpu0 clock: %d\n", ret); + goto out_put_node; + } + + cpu_reg = regulator_get(cpu_dev, "cpu0"); + if (IS_ERR(cpu_reg)) { + pr_warn("failed to get cpu0 regulator\n"); + cpu_reg = NULL; + } + + ret = of_init_opp_table(cpu_dev); + if (ret) { + pr_err("failed to init OPP table: %d\n", ret); + goto out_put_node; + } + + ret = opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + pr_err("failed to init cpufreq table: %d\n", ret); + goto out_put_node; + } + + of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance); + + if (of_property_read_u32(np, "clock-latency", &transition_latency)) + transition_latency = CPUFREQ_ETERNAL; + + if (cpu_reg) { + struct opp *opp; + unsigned long min_uV, max_uV; + int i; + + /* + * OPP is maintained in order of increasing frequency, and + * freq_table initialised from OPP is therefore sorted in the + * same order. + */ + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) + ; + opp = opp_find_freq_exact(cpu_dev, + freq_table[0].frequency * 1000, true); + min_uV = opp_get_voltage(opp); + opp = opp_find_freq_exact(cpu_dev, + freq_table[i-1].frequency * 1000, true); + max_uV = opp_get_voltage(opp); + ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); + if (ret > 0) + transition_latency += ret * 1000; + } + + ret = cpufreq_register_driver(&cpu0_cpufreq_driver); + if (ret) { + pr_err("failed register driver: %d\n", ret); + goto out_free_table; + } + + of_node_put(np); + return 0; + +out_free_table: + opp_free_cpufreq_table(cpu_dev, &freq_table); +out_put_node: + of_node_put(np); + return ret; +} +late_initcall(cpu0_cpufreq_driver_init); + +MODULE_AUTHOR("Shawn Guo "); +MODULE_DESCRIPTION("Generic CPU0 cpufreq driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From f59c8f9fe689790248ae7aa7426579982050638c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 31 Aug 2012 10:36:37 -0700 Subject: regulator: core: Support bypass mode Many regulators support a bypass mode where they simply switch their input supply to the output. This is mainly used in low power retention states where power consumption is extremely low so higher voltage or less clean supplies can be used. Support this by providing ops for the drivers and a consumer API which allows the device to be put into bypass mode if all consumers enable it and the machine enables permission for this. This is not supported as a mode since the existing modes are rarely used due to fuzzy definition and mostly redundant with modern hardware which is able to respond promptly to load changes. Signed-off-by: Mark Brown Reviewed-by: Graeme Gregory --- Documentation/ABI/testing/sysfs-class-regulator | 21 ++++++ drivers/regulator/core.c | 85 +++++++++++++++++++++++++ include/linux/regulator/consumer.h | 8 +++ include/linux/regulator/driver.h | 10 +++ include/linux/regulator/machine.h | 2 + 5 files changed, 126 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator index e091fa87379..bc578bc6062 100644 --- a/Documentation/ABI/testing/sysfs-class-regulator +++ b/Documentation/ABI/testing/sysfs-class-regulator @@ -349,3 +349,24 @@ Description: This will be one of the same strings reported by the "state" attribute. + +What: /sys/class/regulator/.../bypass +Date: September 2012 +KernelVersion: 3.7 +Contact: Mark Brown +Description: + Some regulator directories will contain a field called + bypass. This indicates if the device is in bypass mode. + + This will be one of the following strings: + + 'enabled' + 'disabled' + 'unknown' + + 'enabled' means the regulator is in bypass mode. + + 'disabled' means that the regulator is regulating. + + 'unknown' means software cannot determine the state, or + the reported state is invalid. diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 48385318175..64e16053975 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -77,6 +77,7 @@ struct regulator { struct device *dev; struct list_head list; unsigned int always_on:1; + unsigned int bypass:1; int uA_load; int min_uV; int max_uV; @@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev, case REGULATOR_STATUS_STANDBY: label = "standby"; break; + case REGULATOR_STATUS_BYPASS: + label = "bypass"; + break; case REGULATOR_STATUS_UNDEFINED: label = "undefined"; break; @@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev, static DEVICE_ATTR(suspend_standby_state, 0444, regulator_suspend_standby_state_show, NULL); +static ssize_t regulator_bypass_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + const char *report; + bool bypass; + int ret; + + ret = rdev->desc->ops->get_bypass(rdev, &bypass); + + if (ret != 0) + report = "unknown"; + else if (bypass) + report = "enabled"; + else + report = "disabled"; + + return sprintf(buf, "%s\n", report); +} +static DEVICE_ATTR(bypass, 0444, + regulator_bypass_show, NULL); /* * These are the only attributes are present for all regulators. @@ -2673,6 +2698,59 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); +/** + * regulator_allow_bypass - allow the regulator to go into bypass mode + * + * @regulator: Regulator to configure + * @allow: enable or disable bypass mode + * + * Allow the regulator to go into bypass mode if all other consumers + * for the regulator also enable bypass mode and the machine + * constraints allow this. Bypass mode means that the regulator is + * simply passing the input directly to the output with no regulation. + */ +int regulator_allow_bypass(struct regulator *regulator, bool enable) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; + + if (!rdev->desc->ops->set_bypass) + return 0; + + if (rdev->constraints && + !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS)) + return 0; + + mutex_lock(&rdev->mutex); + + if (enable && !regulator->bypass) { + rdev->bypass_count++; + + if (rdev->bypass_count == rdev->open_count) { + ret = rdev->desc->ops->set_bypass(rdev, enable); + if (ret != 0) + rdev->bypass_count--; + } + + } else if (!enable && regulator->bypass) { + rdev->bypass_count--; + + if (rdev->bypass_count != rdev->open_count) { + ret = rdev->desc->ops->set_bypass(rdev, enable); + if (ret != 0) + rdev->bypass_count++; + } + } + + if (ret == 0) + regulator->bypass = enable; + + mutex_unlock(&rdev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_allow_bypass); + /** * regulator_register_notifier - register regulator event notifier * @regulator: regulator source @@ -3036,6 +3114,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev) if (status < 0) return status; } + if (ops->get_bypass) { + status = device_create_file(dev, &dev_attr_bypass); + if (status < 0) + return status; + } /* some attributes are type-specific */ if (rdev->desc->type == REGULATOR_CURRENT) { @@ -3124,6 +3207,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) &rdev->use_count); debugfs_create_u32("open_count", 0444, rdev->debugfs, &rdev->open_count); + debugfs_create_u32("bypass_count", 0444, rdev->debugfs, + &rdev->bypass_count); } /** diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index da339fd8c75..ea3e3581662 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator); int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); +int regulator_allow_bypass(struct regulator *regulator, bool allow); + /* regulator notifier block */ int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb); @@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator, return REGULATOR_MODE_NORMAL; } +static inline int regulator_allow_bypass(struct regulator *regulator, + bool allow) +{ + return 0; +} + static inline int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb) { diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bac4c871f3b..c9869cfbf26 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -32,6 +32,8 @@ enum regulator_status { REGULATOR_STATUS_NORMAL, REGULATOR_STATUS_IDLE, REGULATOR_STATUS_STANDBY, + /* The regulator is enabled but not regulating */ + REGULATOR_STATUS_BYPASS, /* in case that any other status doesn't apply */ REGULATOR_STATUS_UNDEFINED, }; @@ -67,6 +69,9 @@ enum regulator_status { * @get_optimum_mode: Get the most efficient operating mode for the regulator * when running with the specified parameters. * + * @set_bypass: Set the regulator in bypass mode. + * @get_bypass: Get the regulator bypass mode state. + * * @enable_time: Time taken for the regulator voltage output voltage to * stabilise after being enabled, in microseconds. * @set_ramp_delay: Set the ramp delay for the regulator. The driver should @@ -133,6 +138,10 @@ struct regulator_ops { unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, int output_uV, int load_uA); + /* control and report on bypass mode */ + int (*set_bypass)(struct regulator_dev *dev, bool enable); + int (*get_bypass)(struct regulator_dev *dev, bool *enable); + /* the operations below are for configuration of regulator state when * its parent PMIC enters a global STANDBY/HIBERNATE state */ @@ -253,6 +262,7 @@ struct regulator_dev { int exclusive; u32 use_count; u32 open_count; + u32 bypass_count; /* lists we belong to */ struct list_head list; /* list of all regulators */ diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 40dd0a394cf..36adbc82de6 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -32,6 +32,7 @@ struct regulator; * board/machine. * STATUS: Regulator can be enabled and disabled. * DRMS: Dynamic Regulator Mode Switching is enabled for this regulator. + * BYPASS: Regulator can be put into bypass mode */ #define REGULATOR_CHANGE_VOLTAGE 0x1 @@ -39,6 +40,7 @@ struct regulator; #define REGULATOR_CHANGE_MODE 0x4 #define REGULATOR_CHANGE_STATUS 0x8 #define REGULATOR_CHANGE_DRMS 0x10 +#define REGULATOR_CHANGE_BYPASS 0x20 /** * struct regulator_state - regulator state during low power system states -- cgit v1.2.3-70-g09d2 From 4a8f1ddde942e232387e6129ce4f4c412e43802f Mon Sep 17 00:00:00 2001 From: James Ralston Date: Mon, 10 Sep 2012 10:14:02 +0200 Subject: i2c-i801: Add Device IDs for Intel Lynx Point-LP PCH Add the SMBus Device IDs for the Intel Lynx Point-LP PCH. Signed-off-by: James Ralston Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 615142da4ef..157416e78cc 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -21,6 +21,7 @@ Supported adapters: * Intel DH89xxCC (PCH) * Intel Panther Point (PCH) * Intel Lynx Point (PCH) + * Intel Lynx Point-LP (PCH) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index b4aaa1bd672..af8bc83fd85 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -104,6 +104,7 @@ config I2C_I801 DH89xxCC (PCH) Panther Point (PCH) Lynx Point (PCH) + Lynx Point-LP (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 898dcf9c7ad..33e9b0c09af 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -52,6 +52,7 @@ DH89xxCC (PCH) 0x2330 32 hard yes yes yes Panther Point (PCH) 0x1e22 32 hard yes yes yes Lynx Point (PCH) 0x8c22 32 hard yes yes yes + Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -155,6 +156,7 @@ #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 struct i801_priv { struct i2c_adapter adapter; @@ -771,6 +773,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, { 0, } }; -- cgit v1.2.3-70-g09d2 From 807e1b426db755a605f0aa03604c1cd00630e727 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Aug 2012 18:06:12 +0200 Subject: Documentation: dt: Update the OMAP documentation with Overo/Toby Add the Tobi/Overo board to the list of supported platforms. Signed-off-by: Florian Vaussard Signed-off-by: Benoit Cousson --- Documentation/devicetree/bindings/arm/omap/omap.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index ccdd0e53451..d0051a75058 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -36,6 +36,9 @@ Boards: - OMAP3 BeagleBoard : Low cost community board compatible = "ti,omap3-beagle", "ti,omap3" +- OMAP3 Tobi with Overo : Commercial expansion board with daughter board + compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3" + - OMAP4 SDP : Software Developement Board compatible = "ti,omap4-sdp", "ti,omap4430" -- cgit v1.2.3-70-g09d2 From 3a35c00b048ec368978cb497415c7a02f9200415 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 15 Aug 2012 20:28:40 -0300 Subject: [media] DocBook: update ioctl error codes ENOTTY is now returned for unimplemented ioctl by dvb-frontend. Old EOPNOTSUPP & ENOSYS could be still returned by some drivers as well as other "non standard" error codes. EAGAIN is returned in case of device is in state where it cannot perform requested operation. This is for example sleep and statistics are queried. Quick check for few demodulator drivers reveals there is a lot of different error codes used in such case currently, few to mention still: EOPNOTSUPP, ENOSYS, EAGAIN ... Lets try harmonize. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/gen-errors.xml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/gen-errors.xml b/Documentation/DocBook/media/v4l/gen-errors.xml index 5bbf3ce1973..737ecaaa335 100644 --- a/Documentation/DocBook/media/v4l/gen-errors.xml +++ b/Documentation/DocBook/media/v4l/gen-errors.xml @@ -6,6 +6,13 @@ &cs-str; + + EAGAIN + The ioctl can't be handled because the device is in state where + it can't perform it. This could happen for example in case where + device is sleeping and ioctl is performed to query statistics. + + EBADF The file descriptor is not a valid. @@ -50,11 +57,6 @@ that this request would overcommit the usb bandwidth reserved for periodic transfers (up to 80% of the USB bandwidth). - - ENOSYS or EOPNOTSUPP - Function not available for this device (dvb API only. Will likely - be replaced anytime soon by ENOTTY). - EPERM Permission denied. Can be returned if the device needs write -- cgit v1.2.3-70-g09d2 From 6354316dbe5a13b25bea15d7ffc891be025eb267 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Aug 2012 19:20:58 +0900 Subject: pwm: add devm_pwm_get() and devm_pwm_put() Add resource managed variants of pwm_get() and pwm_put() for convenience. Code is largely inspired by the equivalent devm functions of the regulator framework. Signed-off-by: Alexandre Courbot Signed-off-by: Thierry Reding --- Documentation/driver-model/devres.txt | 4 +++ Documentation/pwm.txt | 3 +- drivers/pwm/core.c | 58 +++++++++++++++++++++++++++++++++++ include/linux/pwm.h | 3 ++ 4 files changed, 67 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 950856bd2e3..43cff70465a 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -284,3 +284,7 @@ CLOCK PINCTRL devm_pinctrl_get() devm_pinctrl_put() + +PWM + devm_pwm_get() + devm_pwm_put() diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt index 554290ebab9..7d2b4c9b544 100644 --- a/Documentation/pwm.txt +++ b/Documentation/pwm.txt @@ -36,7 +36,8 @@ Legacy users can request a PWM device using pwm_request() and free it after usage with pwm_free(). New users should use the pwm_get() function and pass to it the consumer -device or a consumer name. pwm_put() is used to free the PWM device. +device or a consumer name. pwm_put() is used to free the PWM device. Managed +variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist. After being requested a PWM has to be configured using: diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 85592e97ef2..92b1782d0d8 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -646,6 +646,64 @@ out: } EXPORT_SYMBOL_GPL(pwm_put); +static void devm_pwm_release(struct device *dev, void *res) +{ + pwm_put(*(struct pwm_device **)res); +} + +/** + * devm_pwm_get() - resource managed pwm_get() + * @dev: device for PWM consumer + * @con_id: consumer name + * + * This function performs like pwm_get() but the acquired PWM device will + * automatically be released on driver detach. + */ +struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) +{ + struct pwm_device **ptr, *pwm; + + ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + pwm = pwm_get(dev, con_id); + if (!IS_ERR(pwm)) { + *ptr = pwm; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return pwm; +} +EXPORT_SYMBOL_GPL(devm_pwm_get); + +static int devm_pwm_match(struct device *dev, void *res, void *data) +{ + struct pwm_device **p = res; + + if (WARN_ON(!p || !*p)) + return 0; + + return *p == data; +} + +/** + * devm_pwm_put() - resource managed pwm_put() + * @dev: device for PWM consumer + * @pwm: PWM device + * + * Release a PWM previously allocated using devm_pwm_get(). Calling this + * function is usually not needed because devm-allocated resources are + * automatically released on driver detach. + */ +void devm_pwm_put(struct device *dev, struct pwm_device *pwm) +{ + WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm)); +} +EXPORT_SYMBOL_GPL(devm_pwm_put); + #ifdef CONFIG_DEBUG_FS static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) { diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 354764cf5f7..40c76431895 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -148,6 +148,9 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, struct pwm_device *pwm_get(struct device *dev, const char *consumer); void pwm_put(struct pwm_device *pwm); +struct pwm_device *devm_pwm_get(struct device *dev, const char *consumer); +void devm_pwm_put(struct device *dev, struct pwm_device *pwm); + struct pwm_lookup { struct list_head list; const char *provider; -- cgit v1.2.3-70-g09d2 From fa2a9566257a3b62c328ea5d621ccf5952079dac Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 5 Sep 2012 13:44:31 +0800 Subject: usb: make usb port a real device This patch turns each USB port on a hub into a new struct device. This new device has the USB hub interface device as its parent. The port devices are stored in a new structure (usb_port), and an array of usb_ports are dynamically allocated once we know how many ports the USB hub has. Move the port_owner variable out of usb_hub and into this new structure. A new file will be created in the hub interface sysfs directory, so add documentation. Acked-by: Alan Stern Signed-off-by: Lan Tianyu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 7 +++ drivers/usb/core/hub.c | 91 +++++++++++++++++++++++++++------ 2 files changed, 82 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 5f75f8f7df3..b6fbe514a86 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -220,3 +220,10 @@ Description: If the device doesn't support LTM, the file will read "no". The file will be present for all speeds of USB devices, and will always read "no" for USB 1.1 and USB 2.0 devices. + +What: /sys/bus/usb/devices/.../(hub interface)/portX +Date: August 2012 +Contact: Lan Tianyu +Description: + The /sys/bus/usb/devices/.../(hub interface)/portX + is usb port device's sysfs directory. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 128a804c42f..87df22eef49 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -39,6 +39,11 @@ #endif #endif +struct usb_port { + struct device dev; + struct dev_state *port_owner; +}; + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -83,7 +88,7 @@ struct usb_hub { u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; struct delayed_work init_work; - struct dev_state **port_owners; + struct usb_port **ports; }; static inline int hub_is_superspeed(struct usb_device *hdev) @@ -156,6 +161,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); #define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STABLE 100 +#define to_usb_port(_dev) \ + container_of(_dev, struct usb_port, dev) static int usb_reset_and_verify_device(struct usb_device *udev); @@ -1222,6 +1229,52 @@ static int hub_post_reset(struct usb_interface *intf) return 0; } +static void usb_port_device_release(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + + kfree(port_dev); +} + +static void usb_hub_remove_port_device(struct usb_hub *hub, + int port1) +{ + device_unregister(&hub->ports[port1 - 1]->dev); +} + +struct device_type usb_port_device_type = { + .name = "usb_port", + .release = usb_port_device_release, +}; + +static int usb_hub_create_port_device(struct usb_hub *hub, + int port1) +{ + struct usb_port *port_dev = NULL; + int retval; + + port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); + if (!port_dev) { + retval = -ENOMEM; + goto exit; + } + + hub->ports[port1 - 1] = port_dev; + port_dev->dev.parent = hub->intfdev; + port_dev->dev.type = &usb_port_device_type; + dev_set_name(&port_dev->dev, "port%d", port1); + + retval = device_register(&port_dev->dev); + if (retval) + goto error_register; + return 0; + +error_register: + put_device(&port_dev->dev); +exit: + return retval; +} + static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { @@ -1231,7 +1284,7 @@ static int hub_configure(struct usb_hub *hub, u16 hubstatus, hubchange; u16 wHubCharacteristics; unsigned int pipe; - int maxp, ret; + int maxp, ret, i; char *message = "out of memory"; hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); @@ -1273,9 +1326,9 @@ static int hub_configure(struct usb_hub *hub, hdev->children = kzalloc(hdev->maxchild * sizeof(struct usb_device *), GFP_KERNEL); - hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *), - GFP_KERNEL); - if (!hdev->children || !hub->port_owners) { + hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *), + GFP_KERNEL); + if (!hdev->children || !hub->ports) { ret = -ENOMEM; goto fail; } @@ -1484,6 +1537,11 @@ static int hub_configure(struct usb_hub *hub, if (hub->has_indicators && blinkenlights) hub->indicator [0] = INDICATOR_CYCLE; + for (i = 0; i < hdev->maxchild; i++) + if (usb_hub_create_port_device(hub, i + 1) < 0) + dev_err(hub->intfdev, + "couldn't create port%d device.\n", i + 1); + hub_activate(hub, HUB_INIT); return 0; @@ -1508,6 +1566,10 @@ static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = interface_to_usbdev(intf); + int i; + + for (i = 0; i < hdev->maxchild; i++) + usb_hub_remove_port_device(hub, i + 1); /* Take the hub off the event list and don't let it be added again */ spin_lock_irq(&hub_event_lock); @@ -1530,7 +1592,7 @@ static void hub_disconnect(struct usb_interface *intf) usb_free_urb(hub->urb); kfree(hdev->children); - kfree(hub->port_owners); + kfree(hub->ports); kfree(hub->descriptor); kfree(hub->status); kfree(hub->buffer); @@ -1662,7 +1724,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1, /* This assumes that devices not managed by the hub driver * will always have maxchild equal to 0. */ - *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]); + *ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1]->port_owner); return 0; } @@ -1699,16 +1761,14 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) { + struct usb_hub *hub = hdev_to_hub(hdev); int n; - struct dev_state **powner; - n = find_port_owner(hdev, 1, &powner); - if (n == 0) { - for (; n < hdev->maxchild; (++n, ++powner)) { - if (*powner == owner) - *powner = NULL; - } + for (n = 0; n < hdev->maxchild; n++) { + if (hub->ports[n]->port_owner == owner) + hub->ports[n]->port_owner = NULL; } + } /* The caller must hold udev's lock */ @@ -1719,10 +1779,9 @@ bool usb_device_is_owned(struct usb_device *udev) if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) return false; hub = hdev_to_hub(udev->parent); - return !!hub->port_owners[udev->portnum - 1]; + return !!hub->ports[udev->portnum - 1]->port_owner; } - static void recursively_mark_NOTATTACHED(struct usb_device *udev) { int i; -- cgit v1.2.3-70-g09d2 From ca9c9d0c922e4f1dac80699ebab1269d6dbaff85 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 5 Sep 2012 13:44:38 +0800 Subject: usb : Add sysfs files to control port power. This patch adds two sysfs files for each usb hub port to allow userspace to control the port power policy. For an upcoming Intel xHCI roothub, this will translate into ACPI calls to completely power off or power on the port. As a reminder, when these ports are completely powered off, the USB host and device will see a physical disconnect. All future USB device connections will be lost, and the device will not be able to signal a remote wakeup. The control sysfs file can be written to with two options: "on" - port power must be on. "off" - port must be off. The state sysfs file reports usb port's power state: "on" - powered on "off" - powered off "error" - can't get power state For now, let userspace dictate the port power off policy. Future patches may add an in-kernel policy. Acked-by: Alan Stern Signed-off-by: Lan Tianyu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 24 ++++++ drivers/usb/core/hub.c | 133 +++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index b6fbe514a86..13f3eeee159 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -227,3 +227,27 @@ Contact: Lan Tianyu Description: The /sys/bus/usb/devices/.../(hub interface)/portX is usb port device's sysfs directory. + +What: /sys/bus/usb/devices/.../(hub interface)/portX/control +Date: August 2012 +Contact: Lan Tianyu +Description: + The /sys/bus/usb/devices/.../(hub interface)/portX/control + attribute allows user space to control the power policy on + the usb port. + + All ports have one of the following two values for control + "on" - port power must be on. + "off" - port power must be off. + +What: /sys/bus/usb/devices/.../(hub interface)/portX/state +Date: August 2012 +Contact: Lan Tianyu +Description: + The /sys/bus/usb/devices/.../(hub interface)/portX/state + attribute allows user space to check hub port's power state. + + All ports have three following states + "on" - port power on + "off" - port power off + "error" - can't get the hub port's power state diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4ffe8371ada..3def91eecaa 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -39,11 +39,17 @@ #endif #endif +enum port_power_policy { + USB_PORT_POWER_ON = 0, + USB_PORT_POWER_OFF, +}; + struct usb_port { struct usb_device *child; struct device dev; struct dev_state *port_owner; enum usb_port_connect_type connect_type; + enum port_power_policy port_power_policy; }; struct usb_hub { @@ -93,6 +99,10 @@ struct usb_hub { struct usb_port **ports; }; +static const char on_string[] = "on"; +static const char off_string[] = "off"; +static const struct attribute_group *port_dev_group[]; + static inline int hub_is_superspeed(struct usb_device *hdev) { return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); @@ -845,7 +855,12 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) dev_dbg(hub->intfdev, "trying to enable port power on " "non-switchable hub\n"); for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) - set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); + if (hub->ports[port1 - 1]->port_power_policy + == USB_PORT_POWER_ON) + set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); + else + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_POWER); /* Wait at least 100 msec for power to become stable */ delay = max(pgood_delay, (unsigned) 100); @@ -1263,6 +1278,7 @@ static int usb_hub_create_port_device(struct usb_hub *hub, hub->ports[port1 - 1] = port_dev; port_dev->dev.parent = hub->intfdev; + port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; dev_set_name(&port_dev->dev, "port%d", port1); @@ -2627,6 +2643,25 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) return ret; } +static int usb_get_hub_port_power_state(struct usb_device *hdev, int port1) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_port_status data; + u16 portstatus; + int ret; + + ret = get_port_status(hub->hdev, port1, &data); + if (ret < 4) { + dev_err(hub->intfdev, + "%s failed (err = %d)\n", __func__, ret); + if (ret >= 0) + ret = -EIO; + return ret; + } else + portstatus = le16_to_cpu(data.wPortStatus); + return port_is_power_on(hub, portstatus); +} + #ifdef CONFIG_PM /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ @@ -4633,6 +4668,102 @@ static int hub_thread(void *__unused) return 0; } +static ssize_t show_port_power_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev->parent->parent); + struct usb_interface *intf = to_usb_interface(dev->parent); + int port1, power_state; + const char *result; + + sscanf(dev_name(dev), "port%d", &port1); + usb_autopm_get_interface(intf); + power_state = usb_get_hub_port_power_state(udev, port1); + usb_autopm_put_interface(intf); + if (power_state == 1) + result = on_string; + else if (!power_state) + result = off_string; + else + result = "error"; + return sprintf(buf, "%s\n", result); +} +static DEVICE_ATTR(state, S_IRUGO, show_port_power_state, NULL); + +static ssize_t show_port_power_control(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_port *hub_port = to_usb_port(dev); + const char *result; + + switch (hub_port->port_power_policy) { + case USB_PORT_POWER_ON: + result = on_string; + break; + case USB_PORT_POWER_OFF: + result = off_string; + break; + default: + return -EINVAL; + } + return sprintf(buf, "%s\n", result); +} + +static ssize_t store_port_power_control(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_interface *intf = to_usb_interface(dev->parent); + struct usb_port *hub_port = to_usb_port(dev); + int port1, ret, len = count; + char *cp; + + sscanf(dev_name(dev), "port%d", &port1); + cp = memchr(buf, '\n', count); + if (cp) + len = cp - buf; + if (len == sizeof(on_string) - 1 + && strncmp(buf, on_string, len) == 0) { + hub_port->port_power_policy = USB_PORT_POWER_ON; + usb_autopm_get_interface(intf); + ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); + usb_autopm_put_interface(intf); + if (ret < 0) + return -EIO; + } else if (len == sizeof(off_string) - 1 + && strncmp(buf, off_string, len) == 0) { + struct usb_hub *hub = hdev_to_hub(hdev); + + hub_port->port_power_policy = USB_PORT_POWER_OFF; + usb_autopm_get_interface(intf); + hub_port_logical_disconnect(hub, port1); + ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); + usb_autopm_put_interface(intf); + if (ret < 0) + return -EIO; + } else + return -EINVAL; + + return count; +} +static DEVICE_ATTR(control, S_IWUSR | S_IRUGO, show_port_power_control, + store_port_power_control); + +static struct attribute *port_dev_attrs[] = { + &dev_attr_control.attr, + &dev_attr_state.attr, + NULL, +}; + +static struct attribute_group port_dev_attr_grp = { + .attrs = port_dev_attrs, +}; + +static const struct attribute_group *port_dev_group[] = { + &port_dev_attr_grp, + NULL, +}; + static const struct usb_device_id hub_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, .bDeviceClass = USB_CLASS_HUB}, -- cgit v1.2.3-70-g09d2 From 4485a12937c936a5973601bb9921d30a0630299d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 11 Sep 2012 08:51:23 +0530 Subject: dt: Fix incorrect reference in gpio-led documentation Path to gpio.txt (dt) document was broken. Signed-off-by: Sachin Kamat Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/led.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/led.txt b/Documentation/devicetree/bindings/gpio/led.txt index 9bb308abd22..edc83c1c0d5 100644 --- a/Documentation/devicetree/bindings/gpio/led.txt +++ b/Documentation/devicetree/bindings/gpio/led.txt @@ -8,7 +8,7 @@ node's name represents the name of the corresponding LED. LED sub-node properties: - gpios : Should specify the LED's GPIO, see "gpios property" in - Documentation/devicetree/gpio.txt. Active low LEDs should be + Documentation/devicetree/bindings/gpio/gpio.txt. Active low LEDs should be indicated using flags in the GPIO specifier. - label : (optional) The label for this LED. If omitted, the label is taken from the node name (excluding the unit address). -- cgit v1.2.3-70-g09d2 From b598b9f311a604ca533033baa5afcf45beb037d9 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 21:36:29 +0800 Subject: clk: mxs: replace imx28 clk_register_clkdev with clock DT lookup It really becomes a maintenance issue that every time a device needs to look up (clk_get) a clock we have to patch kernel clock file to call clk_register_clkdev for that clock. Since clock DT support which is meant to resolve clock lookup in device tree is in place, the patch moves imx28 client devices' clock lookup over to device tree, so that any new lookup to be added at later time can just get done in DT instead of kernel. Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx28-clock.txt | 99 ++++++++++++++++++ arch/arm/boot/dts/imx28.dtsi | 35 ++++++- drivers/clk/mxs/clk-imx28.c | 113 ++------------------- 3 files changed, 142 insertions(+), 105 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx28-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/imx28-clock.txt b/Documentation/devicetree/bindings/clock/imx28-clock.txt new file mode 100644 index 00000000000..aa2af2866fe --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx28-clock.txt @@ -0,0 +1,99 @@ +* Clock bindings for Freescale i.MX28 + +Required properties: +- compatible: Should be "fsl,imx28-clkctrl" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX28 +clocks and IDs. + + Clock ID + ------------------ + ref_xtal 0 + pll0 1 + pll1 2 + pll2 3 + ref_cpu 4 + ref_emi 5 + ref_io0 6 + ref_io1 7 + ref_pix 8 + ref_hsadc 9 + ref_gpmi 10 + saif0_sel 11 + saif1_sel 12 + gpmi_sel 13 + ssp0_sel 14 + ssp1_sel 15 + ssp2_sel 16 + ssp3_sel 17 + emi_sel 18 + etm_sel 19 + lcdif_sel 20 + cpu 21 + ptp_sel 22 + cpu_pll 23 + cpu_xtal 24 + hbus 25 + xbus 26 + ssp0_div 27 + ssp1_div 28 + ssp2_div 29 + ssp3_div 30 + gpmi_div 31 + emi_pll 32 + emi_xtal 33 + lcdif_div 34 + etm_div 35 + ptp 36 + saif0_div 37 + saif1_div 38 + clk32k_div 39 + rtc 40 + lradc 41 + spdif_div 42 + clk32k 43 + pwm 44 + uart 45 + ssp0 46 + ssp1 47 + ssp2 48 + ssp3 49 + gpmi 50 + spdif 51 + emi 52 + saif0 53 + saif1 54 + lcdif 55 + etm 56 + fec 57 + can0 58 + can1 59 + usb0 60 + usb1 61 + usb0_pwr 62 + usb1_pwr 63 + enet_out 64 + +Examples: + +clks: clkctrl@80040000 { + compatible = "fsl,imx28-clkctrl"; + reg = <0x80040000 0x2000>; + #clock-cells = <1>; + clock-output-names = + ... + "uart", /* 45 */ + ... + "end_of_list"; +}; + +auart0: serial@8006a000 { + compatible = "fsl,imx28-auart", "fsl,imx23-auart"; + reg = <0x8006a000 0x2000>; + interrupts = <112 70 71>; + clocks = <&clks 45>; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 96fe74e4935..03e0fef8e7a 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -65,6 +65,7 @@ dma-apbh@80004000 { compatible = "fsl,imx28-dma-apbh"; reg = <0x80004000 0x2000>; + clocks = <&clks 25>; }; perfmon@80006000 { @@ -81,6 +82,7 @@ reg-names = "gpmi-nand", "bch"; interrupts = <88>, <41>; interrupt-names = "gpmi-dma", "bch"; + clocks = <&clks 50>; fsl,gpmi-dma-channel = <4>; status = "disabled"; }; @@ -90,6 +92,7 @@ #size-cells = <0>; reg = <0x80010000 0x2000>; interrupts = <96 82>; + clocks = <&clks 46>; fsl,ssp-dma-channel = <0>; status = "disabled"; }; @@ -99,6 +102,7 @@ #size-cells = <0>; reg = <0x80012000 0x2000>; interrupts = <97 83>; + clocks = <&clks 47>; fsl,ssp-dma-channel = <1>; status = "disabled"; }; @@ -108,6 +112,7 @@ #size-cells = <0>; reg = <0x80014000 0x2000>; interrupts = <98 84>; + clocks = <&clks 48>; fsl,ssp-dma-channel = <2>; status = "disabled"; }; @@ -117,6 +122,7 @@ #size-cells = <0>; reg = <0x80016000 0x2000>; interrupts = <99 85>; + clocks = <&clks 49>; fsl,ssp-dma-channel = <3>; status = "disabled"; }; @@ -606,6 +612,7 @@ dma-apbx@80024000 { compatible = "fsl,imx28-dma-apbx"; reg = <0x80024000 0x2000>; + clocks = <&clks 26>; }; dcp@80028000 { @@ -634,6 +641,7 @@ compatible = "fsl,imx28-lcdif"; reg = <0x80030000 0x2000>; interrupts = <38 86>; + clocks = <&clks 55>; status = "disabled"; }; @@ -641,6 +649,8 @@ compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan"; reg = <0x80032000 0x2000>; interrupts = <8>; + clocks = <&clks 58>, <&clks 58>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -648,6 +658,8 @@ compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan"; reg = <0x80034000 0x2000>; interrupts = <9>; + clocks = <&clks 59>, <&clks 59>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -694,15 +706,17 @@ reg = <0x80040000 0x40000>; ranges; - clkctl@80040000 { + clks: clkctrl@80040000 { + compatible = "fsl,imx28-clkctrl"; reg = <0x80040000 0x2000>; - status = "disabled"; + #clock-cells = <1>; }; saif0: saif@80042000 { compatible = "fsl,imx28-saif"; reg = <0x80042000 0x2000>; interrupts = <59 80>; + clocks = <&clks 53>; fsl,saif-dma-channel = <4>; status = "disabled"; }; @@ -716,6 +730,7 @@ compatible = "fsl,imx28-saif"; reg = <0x80046000 0x2000>; interrupts = <58 81>; + clocks = <&clks 54>; fsl,saif-dma-channel = <5>; status = "disabled"; }; @@ -763,6 +778,7 @@ pwm: pwm@80064000 { compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; reg = <0x80064000 0x2000>; + clocks = <&clks 44>; #pwm-cells = <2>; fsl,pwm-number = <8>; status = "disabled"; @@ -777,6 +793,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x8006a000 0x2000>; interrupts = <112 70 71>; + clocks = <&clks 45>; status = "disabled"; }; @@ -784,6 +801,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x8006c000 0x2000>; interrupts = <113 72 73>; + clocks = <&clks 45>; status = "disabled"; }; @@ -791,6 +809,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x8006e000 0x2000>; interrupts = <114 74 75>; + clocks = <&clks 45>; status = "disabled"; }; @@ -798,6 +817,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x80070000 0x2000>; interrupts = <115 76 77>; + clocks = <&clks 45>; status = "disabled"; }; @@ -805,6 +825,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x80072000 0x2000>; interrupts = <116 78 79>; + clocks = <&clks 45>; status = "disabled"; }; @@ -812,18 +833,22 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0x80074000 0x1000>; interrupts = <47>; + clocks = <&clks 45>, <&clks 26>; + clock-names = "uart", "apb_pclk"; status = "disabled"; }; usbphy0: usbphy@8007c000 { compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy"; reg = <0x8007c000 0x2000>; + clocks = <&clks 62>; status = "disabled"; }; usbphy1: usbphy@8007e000 { compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy"; reg = <0x8007e000 0x2000>; + clocks = <&clks 63>; status = "disabled"; }; }; @@ -840,6 +865,7 @@ compatible = "fsl,imx28-usb", "fsl,imx27-usb"; reg = <0x80080000 0x10000>; interrupts = <93>; + clocks = <&clks 60>; fsl,usbphy = <&usbphy0>; status = "disabled"; }; @@ -848,6 +874,7 @@ compatible = "fsl,imx28-usb", "fsl,imx27-usb"; reg = <0x80090000 0x10000>; interrupts = <92>; + clocks = <&clks 61>; fsl,usbphy = <&usbphy1>; status = "disabled"; }; @@ -861,6 +888,8 @@ compatible = "fsl,imx28-fec"; reg = <0x800f0000 0x4000>; interrupts = <101>; + clocks = <&clks 57>, <&clks 57>; + clock-names = "ipg", "ahb"; status = "disabled"; }; @@ -868,6 +897,8 @@ compatible = "fsl,imx28-fec"; reg = <0x800f4000 0x4000>; interrupts = <102>; + clocks = <&clks 57>, <&clks 57>; + clock-names = "ipg", "ahb"; status = "disabled"; }; diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index e3aab67b3eb..613e76f3758 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "clk.h" @@ -120,90 +121,6 @@ static void __init clk_misc_init(void) writel_relaxed(val, FRAC0); } -static struct clk_lookup uart_lookups[] = { - { .dev_id = "duart", }, - { .dev_id = "mxs-auart.0", }, - { .dev_id = "mxs-auart.1", }, - { .dev_id = "mxs-auart.2", }, - { .dev_id = "mxs-auart.3", }, - { .dev_id = "mxs-auart.4", }, - { .dev_id = "8006a000.serial", }, - { .dev_id = "8006c000.serial", }, - { .dev_id = "8006e000.serial", }, - { .dev_id = "80070000.serial", }, - { .dev_id = "80072000.serial", }, - { .dev_id = "80074000.serial", }, -}; - -static struct clk_lookup hbus_lookups[] = { - { .dev_id = "imx28-dma-apbh", }, - { .dev_id = "80004000.dma-apbh", }, -}; - -static struct clk_lookup xbus_lookups[] = { - { .dev_id = "duart", .con_id = "apb_pclk"}, - { .dev_id = "80074000.serial", .con_id = "apb_pclk"}, - { .dev_id = "imx28-dma-apbx", }, - { .dev_id = "80024000.dma-apbx", }, -}; - -static struct clk_lookup ssp0_lookups[] = { - { .dev_id = "imx28-mmc.0", }, - { .dev_id = "80010000.ssp", }, -}; - -static struct clk_lookup ssp1_lookups[] = { - { .dev_id = "imx28-mmc.1", }, - { .dev_id = "80012000.ssp", }, -}; - -static struct clk_lookup ssp2_lookups[] = { - { .dev_id = "imx28-mmc.2", }, - { .dev_id = "80014000.ssp", }, -}; - -static struct clk_lookup ssp3_lookups[] = { - { .dev_id = "imx28-mmc.3", }, - { .dev_id = "80016000.ssp", }, -}; - -static struct clk_lookup lcdif_lookups[] = { - { .dev_id = "imx28-fb", }, - { .dev_id = "80030000.lcdif", }, -}; - -static struct clk_lookup gpmi_lookups[] = { - { .dev_id = "imx28-gpmi-nand", }, - { .dev_id = "8000c000.gpmi-nand", }, -}; - -static struct clk_lookup fec_lookups[] = { - { .dev_id = "imx28-fec.0", }, - { .dev_id = "imx28-fec.1", }, - { .dev_id = "800f0000.ethernet", }, - { .dev_id = "800f4000.ethernet", }, -}; - -static struct clk_lookup can0_lookups[] = { - { .dev_id = "flexcan.0", }, - { .dev_id = "80032000.can", }, -}; - -static struct clk_lookup can1_lookups[] = { - { .dev_id = "flexcan.1", }, - { .dev_id = "80034000.can", }, -}; - -static struct clk_lookup saif0_lookups[] = { - { .dev_id = "mxs-saif.0", }, - { .dev_id = "80042000.saif", }, -}; - -static struct clk_lookup saif1_lookups[] = { - { .dev_id = "mxs-saif.1", }, - { .dev_id = "80046000.saif", }, -}; - static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", }; static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", }; @@ -228,6 +145,7 @@ enum imx28_clk { }; static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; static enum imx28_clk clks_init_on[] __initdata = { cpu, hbus, xbus, emi, uart, @@ -235,6 +153,7 @@ static enum imx28_clk clks_init_on[] __initdata = { int __init mx28_clocks_init(void) { + struct device_node *np; int i; clk_misc_init(); @@ -312,27 +231,15 @@ int __init mx28_clocks_init(void) return PTR_ERR(clks[i]); } + np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); + if (np) { + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + } + clk_register_clkdev(clks[clk32k], NULL, "timrot"); clk_register_clkdev(clks[enet_out], NULL, "enet_out"); - clk_register_clkdev(clks[pwm], NULL, "80064000.pwm"); - clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); - clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); - clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); - clk_register_clkdevs(clks[ssp0], ssp0_lookups, ARRAY_SIZE(ssp0_lookups)); - clk_register_clkdevs(clks[ssp1], ssp1_lookups, ARRAY_SIZE(ssp1_lookups)); - clk_register_clkdevs(clks[ssp2], ssp2_lookups, ARRAY_SIZE(ssp2_lookups)); - clk_register_clkdevs(clks[ssp3], ssp3_lookups, ARRAY_SIZE(ssp3_lookups)); - clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); - clk_register_clkdevs(clks[saif0], saif0_lookups, ARRAY_SIZE(saif0_lookups)); - clk_register_clkdevs(clks[saif1], saif1_lookups, ARRAY_SIZE(saif1_lookups)); - clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); - clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups)); - clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups)); - clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups)); - clk_register_clkdev(clks[usb0_pwr], NULL, "8007c000.usbphy"); - clk_register_clkdev(clks[usb1_pwr], NULL, "8007e000.usbphy"); - clk_register_clkdev(clks[usb0], NULL, "80080000.usb"); - clk_register_clkdev(clks[usb1], NULL, "80090000.usb"); for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clks[clks_init_on[i]]); -- cgit v1.2.3-70-g09d2 From 53f9443da63db38212e784b0aa205881168757aa Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 21:36:30 +0800 Subject: clk: mxs: replace imx23 clk_register_clkdev with clock DT lookup It really becomes a maintenance issue that every time a device needs to look up (clk_get) a clock we have to patch kernel clock file to call clk_register_clkdev for that clock. Since clock DT support which is meant to resolve clock lookup in device tree is in place, the patch moves imx23 client devices' clock lookup over to device tree, so that any new lookup to be added at later time can just get done in DT instead of kernel. Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx23-clock.txt | 76 ++++++++++++++++++++++ arch/arm/boot/dts/imx23.dtsi | 16 ++++- drivers/clk/mxs/clk-imx23.c | 55 +++------------- 3 files changed, 100 insertions(+), 47 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx23-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/imx23-clock.txt b/Documentation/devicetree/bindings/clock/imx23-clock.txt new file mode 100644 index 00000000000..a0b867ef8d9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx23-clock.txt @@ -0,0 +1,76 @@ +* Clock bindings for Freescale i.MX23 + +Required properties: +- compatible: Should be "fsl,imx23-clkctrl" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX23 +clocks and IDs. + + Clock ID + ------------------ + ref_xtal 0 + pll 1 + ref_cpu 2 + ref_emi 3 + ref_pix 4 + ref_io 5 + saif_sel 6 + lcdif_sel 7 + gpmi_sel 8 + ssp_sel 9 + emi_sel 10 + cpu 11 + etm_sel 12 + cpu_pll 13 + cpu_xtal 14 + hbus 15 + xbus 16 + lcdif_div 17 + ssp_div 18 + gpmi_div 19 + emi_pll 20 + emi_xtal 21 + etm_div 22 + saif_div 23 + clk32k_div 24 + rtc 25 + adc 26 + spdif_div 27 + clk32k 28 + dri 29 + pwm 30 + filt 31 + uart 32 + ssp 33 + gpmi 34 + spdif 35 + emi 36 + saif 37 + lcdif 38 + etm 39 + usb 40 + usb_pwr 41 + +Examples: + +clks: clkctrl@80040000 { + compatible = "fsl,imx23-clkctrl"; + reg = <0x80040000 0x2000>; + #clock-cells = <1>; + clock-output-names = + ... + "uart", /* 32 */ + ... + "end_of_list"; +}; + +auart0: serial@8006c000 { + compatible = "fsl,imx23-auart"; + reg = <0x8006c000 0x2000>; + interrupts = <24 25 23>; + clocks = <&clks 32>; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index b00f3cfb3bf..9d0e803e3ec 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -52,6 +52,7 @@ dma-apbh@80004000 { compatible = "fsl,imx23-dma-apbh"; reg = <0x80004000 0x2000>; + clocks = <&clks 15>; }; ecc@80008000 { @@ -67,6 +68,7 @@ reg-names = "gpmi-nand", "bch"; interrupts = <13>, <56>; interrupt-names = "gpmi-dma", "bch"; + clocks = <&clks 34>; fsl,gpmi-dma-channel = <4>; status = "disabled"; }; @@ -74,6 +76,7 @@ ssp0: ssp@80010000 { reg = <0x80010000 0x2000>; interrupts = <15 14>; + clocks = <&clks 33>; fsl,ssp-dma-channel = <1>; status = "disabled"; }; @@ -290,6 +293,7 @@ dma-apbx@80024000 { compatible = "fsl,imx23-dma-apbx"; reg = <0x80024000 0x2000>; + clocks = <&clks 16>; }; dcp@80028000 { @@ -316,12 +320,14 @@ compatible = "fsl,imx23-lcdif"; reg = <0x80030000 2000>; interrupts = <46 45>; + clocks = <&clks 38>; status = "disabled"; }; ssp1: ssp@80034000 { reg = <0x80034000 0x2000>; interrupts = <2 20>; + clocks = <&clks 33>; fsl,ssp-dma-channel = <2>; status = "disabled"; }; @@ -339,9 +345,10 @@ reg = <0x80040000 0x40000>; ranges; - clkctl@80040000 { + clks: clkctrl@80040000 { + compatible = "fsl,imx23-clkctrl"; reg = <0x80040000 0x2000>; - status = "disabled"; + #clock-cells = <1>; }; saif0: saif@80042000 { @@ -393,6 +400,7 @@ pwm: pwm@80064000 { compatible = "fsl,imx23-pwm"; reg = <0x80064000 0x2000>; + clocks = <&clks 30>; #pwm-cells = <2>; fsl,pwm-number = <5>; status = "disabled"; @@ -407,6 +415,7 @@ compatible = "fsl,imx23-auart"; reg = <0x8006c000 0x2000>; interrupts = <24 25 23>; + clocks = <&clks 32>; status = "disabled"; }; @@ -414,6 +423,7 @@ compatible = "fsl,imx23-auart"; reg = <0x8006e000 0x2000>; interrupts = <59 60 58>; + clocks = <&clks 32>; status = "disabled"; }; @@ -421,6 +431,8 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0x80070000 0x2000>; interrupts = <0>; + clocks = <&clks 32>, <&clks 16>; + clock-names = "uart", "apb_pclk"; status = "disabled"; }; diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c index 844043ad0fe..9f6d15546cb 100644 --- a/drivers/clk/mxs/clk-imx23.c +++ b/drivers/clk/mxs/clk-imx23.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "clk.h" @@ -71,44 +72,6 @@ static void __init clk_misc_init(void) __mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); } -static struct clk_lookup uart_lookups[] = { - { .dev_id = "duart", }, - { .dev_id = "mxs-auart.0", }, - { .dev_id = "mxs-auart.1", }, - { .dev_id = "8006c000.serial", }, - { .dev_id = "8006e000.serial", }, - { .dev_id = "80070000.serial", }, -}; - -static struct clk_lookup hbus_lookups[] = { - { .dev_id = "imx23-dma-apbh", }, - { .dev_id = "80004000.dma-apbh", }, -}; - -static struct clk_lookup xbus_lookups[] = { - { .dev_id = "duart", .con_id = "apb_pclk"}, - { .dev_id = "80070000.serial", .con_id = "apb_pclk"}, - { .dev_id = "imx23-dma-apbx", }, - { .dev_id = "80024000.dma-apbx", }, -}; - -static struct clk_lookup ssp_lookups[] = { - { .dev_id = "imx23-mmc.0", }, - { .dev_id = "imx23-mmc.1", }, - { .dev_id = "80010000.ssp", }, - { .dev_id = "80034000.ssp", }, -}; - -static struct clk_lookup lcdif_lookups[] = { - { .dev_id = "imx23-fb", }, - { .dev_id = "80030000.lcdif", }, -}; - -static struct clk_lookup gpmi_lookups[] = { - { .dev_id = "imx23-gpmi-nand", }, - { .dev_id = "8000c000.gpmi-nand", }, -}; - static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; @@ -127,6 +90,7 @@ enum imx23_clk { }; static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; static enum imx23_clk clks_init_on[] __initdata = { cpu, hbus, xbus, emi, uart, @@ -134,6 +98,7 @@ static enum imx23_clk clks_init_on[] __initdata = { int __init mx23_clocks_init(void) { + struct device_node *np; int i; clk_misc_init(); @@ -188,14 +153,14 @@ int __init mx23_clocks_init(void) return PTR_ERR(clks[i]); } + np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); + if (np) { + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + } + clk_register_clkdev(clks[clk32k], NULL, "timrot"); - clk_register_clkdev(clks[pwm], NULL, "80064000.pwm"); - clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); - clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); - clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); - clk_register_clkdevs(clks[ssp], ssp_lookups, ARRAY_SIZE(ssp_lookups)); - clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); - clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clks[clks_init_on[i]]); -- cgit v1.2.3-70-g09d2 From 00a0b1d58af873d842580dcac55f3b156c3a4077 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 11 Sep 2012 14:39:40 +0530 Subject: usb: musb: omap: Add device tree support for omap musb glue Added device tree support for omap musb driver and updated the Documentation with device tree binding information. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/omap-usb.txt | 33 +++++++++++++ drivers/usb/musb/omap2430.c | 54 ++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/omap-usb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt new file mode 100644 index 00000000000..29a043ecda5 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -0,0 +1,33 @@ +OMAP GLUE + +OMAP MUSB GLUE + - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" + - ti,hwmods : must be "usb_otg_hs" + - multipoint : Should be "1" indicating the musb controller supports + multipoint. This is a MUSB configuration-specific setting. + - num_eps : Specifies the number of endpoints. This is also a + MUSB configuration-specific setting. Should be set to "16" + - ram_bits : Specifies the ram address size. Should be set to "12" + - interface_type : This is a board specific setting to describe the type of + interface between the controller and the phy. It should be "0" or "1" + specifying ULPI and UTMI respectively. + - mode : Should be "3" to represent OTG. "1" signifies HOST and "2" + represents PERIPHERAL. + - power : Should be "50". This signifies the controller can supply upto + 100mA when operating in host mode. + +SOC specific device node entry +usb_otg_hs: usb_otg_hs@4a0ab000 { + compatible = "ti,omap4-musb"; + ti,hwmods = "usb_otg_hs"; + multipoint = <1>; + num_eps = <16>; + ram_bits = <12>; +}; + +Board specific device node entry +&usb_otg_hs { + interface_type = <1>; + mode = <3>; + power = <50>; +}; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index f4d95037db5..d96873ba97c 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -470,8 +471,11 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32); static int __devinit omap2430_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct omap_musb_board_data *data; struct platform_device *musb; struct omap2430_glue *glue; + struct device_node *np = pdev->dev.of_node; + struct musb_hdrc_config *config; struct resource *res; int ret = -ENOMEM; @@ -501,6 +505,42 @@ static int __devinit omap2430_probe(struct platform_device *pdev) if (glue->control_otghs == NULL) dev_dbg(&pdev->dev, "Failed to obtain control memory\n"); + if (np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, + "failed to allocate musb platfrom data\n"); + ret = -ENOMEM; + goto err1; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, + "failed to allocate musb board data\n"); + ret = -ENOMEM; + goto err1; + } + + config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, + "failed to allocate musb hdrc config\n"); + goto err1; + } + + of_property_read_u32(np, "mode", (u32 *)&pdata->mode); + of_property_read_u32(np, "interface_type", + (u32 *)&data->interface_type); + of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps); + of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits); + of_property_read_u32(np, "power", (u32 *)&pdata->power); + config->multipoint = of_property_read_bool(np, "multipoint"); + + pdata->board_data = data; + pdata->config = config; + } + pdata->platform_ops = &omap2430_ops; platform_set_drvdata(pdev, glue); @@ -597,12 +637,26 @@ static struct dev_pm_ops omap2430_pm_ops = { #define DEV_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id omap2430_id_table[] = { + { + .compatible = "ti,omap4-musb" + }, + { + .compatible = "ti,omap3-musb" + }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap2430_id_table); +#endif + static struct platform_driver omap2430_driver = { .probe = omap2430_probe, .remove = __devexit_p(omap2430_remove), .driver = { .name = "musb-omap2430", .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap2430_id_table), }, }; -- cgit v1.2.3-70-g09d2 From 94b43b677104e50b9f8dd75aacb3c69e16089a68 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Wed, 22 Aug 2012 15:32:29 +0800 Subject: leds-lp5523: add channel name in the platform data The name of each led channel is configurable. If the name is NULL, just use the channel id for making the channel name Signed-off-by: Milo(Woogyom) Kim Signed-off-by: Bryan Wu --- Documentation/leds/leds-lp5523.txt | 21 ++++++++++++++++++--- drivers/leds/leds-lp5523.c | 10 +++++++--- include/linux/leds-lp5523.h | 1 + 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt index fad2feb8b7c..c2743f59f9a 100644 --- a/Documentation/leds/leds-lp5523.txt +++ b/Documentation/leds/leds-lp5523.txt @@ -10,8 +10,22 @@ Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) Description ----------- LP5523 can drive up to 9 channels. Leds can be controlled directly via -the led class control interface. Channels have generic names: -lp5523:channelx where x is 0...8 +the led class control interface. +The name of each channel is configurable in the platform data - name and label. +There are three options to make the channel name. + +a) Define the 'name' in the platform data +To make specific channel name, then use 'name' platform data. +/sys/class/leds/R1 (name: 'R1') +/sys/class/leds/B1 (name: 'B1') + +b) Use the 'label' with no 'name' field +For one device name with channel number, then use 'label'. +/sys/class/leds/RGB:channelN (label: 'RGB', N: 0 ~ 8) + +c) Default +If both fields are NULL, 'lp5523' is used by default. +/sys/class/leds/lp5523:channelN (N: 0 ~ 8) The chip provides 3 engines. Each engine can control channels without interaction from the main CPU. Details of the micro engine code can be found @@ -46,12 +60,13 @@ Note - chan_nr can have values between 0 and 8. static struct lp5523_led_config lp5523_led_config[] = { { + .name = "D1", .chan_nr = 0, .led_current = 50, .max_current = 130, }, ... - }, { + { .chan_nr = 8, .led_current = 50, .max_current = 130, diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index fbc12acada9..9fd9a92ed91 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -846,10 +846,14 @@ static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev, return -EINVAL; } - snprintf(name, sizeof(name), "%s:channel%d", - pdata->label ?: "lp5523", chan); + if (pdata->led_config[chan].name) { + led->cdev.name = pdata->led_config[chan].name; + } else { + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: "lp5523", chan); + led->cdev.name = name; + } - led->cdev.name = name; led->cdev.brightness_set = lp5523_set_brightness; res = led_classdev_register(dev, &led->cdev); if (res < 0) { diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h index 2694289babd..727877fb406 100644 --- a/include/linux/leds-lp5523.h +++ b/include/linux/leds-lp5523.h @@ -26,6 +26,7 @@ /* See Documentation/leds/leds-lp5523.txt */ struct lp5523_led_config { + const char *name; u8 chan_nr; u8 led_current; /* mA x10, 0 if led is not connected */ u8 max_current; -- cgit v1.2.3-70-g09d2 From 0e87e0436c0cc3954eb62181a96d7217ca955a4f Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 21:36:28 +0800 Subject: ARM: imx6q: replace clk_register_clkdev with clock DT lookup It really becomes an maintenance issue that every time a device needs to look up (clk_get) a clock we have to patch kernel clock file to call clk_register_clkdev for that clock. Since clock DT support which is meant to resolve clock lookup in device tree is in place, the patch moves imx6q client devices' clock lookup over to device tree, so that any new lookup to be added at later time can just get done in DT instead of kernel. Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx6q-clock.txt | 222 +++++++++++++++++++++ arch/arm/boot/dts/imx6q-sabrelite.dts | 1 + arch/arm/boot/dts/imx6q.dtsi | 73 ++++++- arch/arm/mach-imx/clk-imx6q.c | 44 +--- arch/arm/mach-imx/mach-imx6q.c | 1 - 5 files changed, 291 insertions(+), 50 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx6q-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt new file mode 100644 index 00000000000..492bd991d52 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt @@ -0,0 +1,222 @@ +* Clock bindings for Freescale i.MX6 Quad + +Required properties: +- compatible: Should be "fsl,imx6q-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX6Q +clocks and IDs. + + Clock ID + --------------------------- + dummy 0 + ckil 1 + ckih 2 + osc 3 + pll2_pfd0_352m 4 + pll2_pfd1_594m 5 + pll2_pfd2_396m 6 + pll3_pfd0_720m 7 + pll3_pfd1_540m 8 + pll3_pfd2_508m 9 + pll3_pfd3_454m 10 + pll2_198m 11 + pll3_120m 12 + pll3_80m 13 + pll3_60m 14 + twd 15 + step 16 + pll1_sw 17 + periph_pre 18 + periph2_pre 19 + periph_clk2_sel 20 + periph2_clk2_sel 21 + axi_sel 22 + esai_sel 23 + asrc_sel 24 + spdif_sel 25 + gpu2d_axi 26 + gpu3d_axi 27 + gpu2d_core_sel 28 + gpu3d_core_sel 29 + gpu3d_shader_sel 30 + ipu1_sel 31 + ipu2_sel 32 + ldb_di0_sel 33 + ldb_di1_sel 34 + ipu1_di0_pre_sel 35 + ipu1_di1_pre_sel 36 + ipu2_di0_pre_sel 37 + ipu2_di1_pre_sel 38 + ipu1_di0_sel 39 + ipu1_di1_sel 40 + ipu2_di0_sel 41 + ipu2_di1_sel 42 + hsi_tx_sel 43 + pcie_axi_sel 44 + ssi1_sel 45 + ssi2_sel 46 + ssi3_sel 47 + usdhc1_sel 48 + usdhc2_sel 49 + usdhc3_sel 50 + usdhc4_sel 51 + enfc_sel 52 + emi_sel 53 + emi_slow_sel 54 + vdo_axi_sel 55 + vpu_axi_sel 56 + cko1_sel 57 + periph 58 + periph2 59 + periph_clk2 60 + periph2_clk2 61 + ipg 62 + ipg_per 63 + esai_pred 64 + esai_podf 65 + asrc_pred 66 + asrc_podf 67 + spdif_pred 68 + spdif_podf 69 + can_root 70 + ecspi_root 71 + gpu2d_core_podf 72 + gpu3d_core_podf 73 + gpu3d_shader 74 + ipu1_podf 75 + ipu2_podf 76 + ldb_di0_podf 77 + ldb_di1_podf 78 + ipu1_di0_pre 79 + ipu1_di1_pre 80 + ipu2_di0_pre 81 + ipu2_di1_pre 82 + hsi_tx_podf 83 + ssi1_pred 84 + ssi1_podf 85 + ssi2_pred 86 + ssi2_podf 87 + ssi3_pred 88 + ssi3_podf 89 + uart_serial_podf 90 + usdhc1_podf 91 + usdhc2_podf 92 + usdhc3_podf 93 + usdhc4_podf 94 + enfc_pred 95 + enfc_podf 96 + emi_podf 97 + emi_slow_podf 98 + vpu_axi_podf 99 + cko1_podf 100 + axi 101 + mmdc_ch0_axi_podf 102 + mmdc_ch1_axi_podf 103 + arm 104 + ahb 105 + apbh_dma 106 + asrc 107 + can1_ipg 108 + can1_serial 109 + can2_ipg 110 + can2_serial 111 + ecspi1 112 + ecspi2 113 + ecspi3 114 + ecspi4 115 + ecspi5 116 + enet 117 + esai 118 + gpt_ipg 119 + gpt_ipg_per 120 + gpu2d_core 121 + gpu3d_core 122 + hdmi_iahb 123 + hdmi_isfr 124 + i2c1 125 + i2c2 126 + i2c3 127 + iim 128 + enfc 129 + ipu1 130 + ipu1_di0 131 + ipu1_di1 132 + ipu2 133 + ipu2_di0 134 + ldb_di0 135 + ldb_di1 136 + ipu2_di1 137 + hsi_tx 138 + mlb 139 + mmdc_ch0_axi 140 + mmdc_ch1_axi 141 + ocram 142 + openvg_axi 143 + pcie_axi 144 + pwm1 145 + pwm2 146 + pwm3 147 + pwm4 148 + per1_bch 149 + gpmi_bch_apb 150 + gpmi_bch 151 + gpmi_io 152 + gpmi_apb 153 + sata 154 + sdma 155 + spba 156 + ssi1 157 + ssi2 158 + ssi3 159 + uart_ipg 160 + uart_serial 161 + usboh3 162 + usdhc1 163 + usdhc2 164 + usdhc3 165 + usdhc4 166 + vdo_axi 167 + vpu_axi 168 + cko1 169 + pll1_sys 170 + pll2_bus 171 + pll3_usb_otg 172 + pll4_audio 173 + pll5_video 174 + pll6_mlb 175 + pll7_usb_host 176 + pll8_enet 177 + ssi1_ipg 178 + ssi2_ipg 179 + ssi3_ipg 180 + rom 181 + usbphy1 182 + usbphy2 183 + ldb_di0_div_3_5 184 + ldb_di1_div_3_5 185 + +Examples: + +clks: ccm@020c4000 { + compatible = "fsl,imx6q-ccm"; + reg = <0x020c4000 0x4000>; + interrupts = <0 87 0x04 0 88 0x04>; + #clock-cells = <1>; + clock-output-names = ... + "uart_ipg", + "uart_serial", + ...; +}; + +uart1: serial@02020000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; + interrupts = <0 26 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index 72f30f3e617..cfdbe539c43 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -111,6 +111,7 @@ codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; + clocks = <&clks 169>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_3p3v>; }; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index fd57079f71a..925da33420e 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -97,18 +97,23 @@ dma-apbh@00110000 { compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; reg = <0x00110000 0x2000>; + clocks = <&clks 106>; }; gpmi-nand@00112000 { - compatible = "fsl,imx6q-gpmi-nand"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x00112000 0x2000>, <0x00114000 0x2000>; - reg-names = "gpmi-nand", "bch"; - interrupts = <0 13 0x04>, <0 15 0x04>; - interrupt-names = "gpmi-dma", "bch"; - fsl,gpmi-dma-channel = <0>; - status = "disabled"; + compatible = "fsl,imx6q-gpmi-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x00112000 0x2000>, <0x00114000 0x2000>; + reg-names = "gpmi-nand", "bch"; + interrupts = <0 13 0x04>, <0 15 0x04>; + interrupt-names = "gpmi-dma", "bch"; + clocks = <&clks 152>, <&clks 153>, <&clks 151>, + <&clks 150>, <&clks 149>; + clock-names = "gpmi_io", "gpmi_apb", "gpmi_bch", + "gpmi_bch_apb", "per1_bch"; + fsl,gpmi-dma-channel = <0>; + status = "disabled"; }; timer@00a00600 { @@ -150,6 +155,8 @@ compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02008000 0x4000>; interrupts = <0 31 0x04>; + clocks = <&clks 112>, <&clks 112>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -159,6 +166,8 @@ compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x0200c000 0x4000>; interrupts = <0 32 0x04>; + clocks = <&clks 113>, <&clks 113>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -168,6 +177,8 @@ compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02010000 0x4000>; interrupts = <0 33 0x04>; + clocks = <&clks 114>, <&clks 114>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -177,6 +188,8 @@ compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02014000 0x4000>; interrupts = <0 34 0x04>; + clocks = <&clks 115>, <&clks 115>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -186,6 +199,8 @@ compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; reg = <0x02018000 0x4000>; interrupts = <0 35 0x04>; + clocks = <&clks 116>, <&clks 116>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -193,6 +208,8 @@ compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02020000 0x4000>; interrupts = <0 26 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -205,6 +222,7 @@ compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <0 46 0x04>; + clocks = <&clks 178>; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <38 37>; status = "disabled"; @@ -214,6 +232,7 @@ compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; interrupts = <0 47 0x04>; + clocks = <&clks 179>; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <42 41>; status = "disabled"; @@ -223,6 +242,7 @@ compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x02030000 0x4000>; interrupts = <0 48 0x04>; + clocks = <&clks 180>; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <46 45>; status = "disabled"; @@ -362,6 +382,7 @@ compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; reg = <0x020bc000 0x4000>; interrupts = <0 80 0x04>; + clocks = <&clks 0>; status = "disabled"; }; @@ -369,13 +390,15 @@ compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; reg = <0x020c0000 0x4000>; interrupts = <0 81 0x04>; + clocks = <&clks 0>; status = "disabled"; }; - ccm@020c4000 { + clks: ccm@020c4000 { compatible = "fsl,imx6q-ccm"; reg = <0x020c4000 0x4000>; interrupts = <0 87 0x04 0 88 0x04>; + #clock-cells = <1>; }; anatop@020c8000 { @@ -472,12 +495,14 @@ compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; reg = <0x020c9000 0x1000>; interrupts = <0 44 0x04>; + clocks = <&clks 182>; }; usbphy2: usbphy@020ca000 { compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; reg = <0x020ca000 0x1000>; interrupts = <0 45 0x04>; + clocks = <&clks 183>; }; snvs@020cc000 { @@ -612,6 +637,9 @@ compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma"; reg = <0x020ec000 0x4000>; interrupts = <0 2 0x04>; + clocks = <&clks 155>, <&clks 155>; + clock-names = "ipg", "ahb"; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q-to1.bin"; }; }; @@ -635,6 +663,7 @@ compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184000 0x200>; interrupts = <0 43 0x04>; + clocks = <&clks 162>; fsl,usbphy = <&usbphy1>; status = "disabled"; }; @@ -643,6 +672,7 @@ compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184200 0x200>; interrupts = <0 40 0x04>; + clocks = <&clks 162>; fsl,usbphy = <&usbphy2>; status = "disabled"; }; @@ -651,6 +681,7 @@ compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184400 0x200>; interrupts = <0 41 0x04>; + clocks = <&clks 162>; status = "disabled"; }; @@ -658,6 +689,7 @@ compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; reg = <0x02184600 0x200>; interrupts = <0 42 0x04>; + clocks = <&clks 162>; status = "disabled"; }; @@ -665,6 +697,8 @@ compatible = "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; interrupts = <0 118 0x04 0 119 0x04>; + clocks = <&clks 117>, <&clks 117>; + clock-names = "ipg", "ahb"; status = "disabled"; }; @@ -677,6 +711,8 @@ compatible = "fsl,imx6q-usdhc"; reg = <0x02190000 0x4000>; interrupts = <0 22 0x04>; + clocks = <&clks 163>, <&clks 163>, <&clks 163>; + clock-names = "ipg", "ahb", "per"; status = "disabled"; }; @@ -684,6 +720,8 @@ compatible = "fsl,imx6q-usdhc"; reg = <0x02194000 0x4000>; interrupts = <0 23 0x04>; + clocks = <&clks 164>, <&clks 164>, <&clks 164>; + clock-names = "ipg", "ahb", "per"; status = "disabled"; }; @@ -691,6 +729,8 @@ compatible = "fsl,imx6q-usdhc"; reg = <0x02198000 0x4000>; interrupts = <0 24 0x04>; + clocks = <&clks 165>, <&clks 165>, <&clks 165>; + clock-names = "ipg", "ahb", "per"; status = "disabled"; }; @@ -698,6 +738,8 @@ compatible = "fsl,imx6q-usdhc"; reg = <0x0219c000 0x4000>; interrupts = <0 25 0x04>; + clocks = <&clks 166>, <&clks 166>, <&clks 166>; + clock-names = "ipg", "ahb", "per"; status = "disabled"; }; @@ -707,6 +749,7 @@ compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; reg = <0x021a0000 0x4000>; interrupts = <0 36 0x04>; + clocks = <&clks 125>; status = "disabled"; }; @@ -716,6 +759,7 @@ compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; reg = <0x021a4000 0x4000>; interrupts = <0 37 0x04>; + clocks = <&clks 126>; status = "disabled"; }; @@ -725,6 +769,7 @@ compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; reg = <0x021a8000 0x4000>; interrupts = <0 38 0x04>; + clocks = <&clks 127>; status = "disabled"; }; @@ -788,6 +833,8 @@ compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021e8000 0x4000>; interrupts = <0 27 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -795,6 +842,8 @@ compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021ec000 0x4000>; interrupts = <0 28 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -802,6 +851,8 @@ compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f0000 0x4000>; interrupts = <0 29 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -809,6 +860,8 @@ compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f4000 0x4000>; interrupts = <0 30 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; status = "disabled"; }; }; diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index ea89520b6e2..bbc71f57b92 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -157,6 +157,7 @@ enum mx6q_clks { }; static struct clk *clk[clk_max]; +static struct clk_onecell_data clk_data; static enum mx6q_clks const clks_init_on[] __initconst = { mmdc_ch0_axi, rom, @@ -392,48 +393,13 @@ int __init mx6q_clocks_init(void) pr_err("i.MX6q clk %d: register failed with %ld\n", i, PTR_ERR(clk[i])); + clk_data.clks = clk; + clk_data.clk_num = ARRAY_SIZE(clk); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0"); clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); clk_register_clkdev(clk[twd], NULL, "smp_twd"); - clk_register_clkdev(clk[apbh_dma], NULL, "110000.dma-apbh"); - clk_register_clkdev(clk[per1_bch], "per1_bch", "112000.gpmi-nand"); - clk_register_clkdev(clk[gpmi_bch_apb], "gpmi_bch_apb", "112000.gpmi-nand"); - clk_register_clkdev(clk[gpmi_bch], "gpmi_bch", "112000.gpmi-nand"); - clk_register_clkdev(clk[gpmi_apb], "gpmi_apb", "112000.gpmi-nand"); - clk_register_clkdev(clk[gpmi_io], "gpmi_io", "112000.gpmi-nand"); - clk_register_clkdev(clk[usboh3], NULL, "2184000.usb"); - clk_register_clkdev(clk[usboh3], NULL, "2184200.usb"); - clk_register_clkdev(clk[usboh3], NULL, "2184400.usb"); - clk_register_clkdev(clk[usboh3], NULL, "2184600.usb"); - clk_register_clkdev(clk[usbphy1], NULL, "20c9000.usbphy"); - clk_register_clkdev(clk[usbphy2], NULL, "20ca000.usbphy"); - clk_register_clkdev(clk[uart_serial], "per", "2020000.serial"); - clk_register_clkdev(clk[uart_ipg], "ipg", "2020000.serial"); - clk_register_clkdev(clk[uart_serial], "per", "21e8000.serial"); - clk_register_clkdev(clk[uart_ipg], "ipg", "21e8000.serial"); - clk_register_clkdev(clk[uart_serial], "per", "21ec000.serial"); - clk_register_clkdev(clk[uart_ipg], "ipg", "21ec000.serial"); - clk_register_clkdev(clk[uart_serial], "per", "21f0000.serial"); - clk_register_clkdev(clk[uart_ipg], "ipg", "21f0000.serial"); - clk_register_clkdev(clk[uart_serial], "per", "21f4000.serial"); - clk_register_clkdev(clk[uart_ipg], "ipg", "21f4000.serial"); - clk_register_clkdev(clk[enet], NULL, "2188000.ethernet"); - clk_register_clkdev(clk[usdhc1], NULL, "2190000.usdhc"); - clk_register_clkdev(clk[usdhc2], NULL, "2194000.usdhc"); - clk_register_clkdev(clk[usdhc3], NULL, "2198000.usdhc"); - clk_register_clkdev(clk[usdhc4], NULL, "219c000.usdhc"); - clk_register_clkdev(clk[i2c1], NULL, "21a0000.i2c"); - clk_register_clkdev(clk[i2c2], NULL, "21a4000.i2c"); - clk_register_clkdev(clk[i2c3], NULL, "21a8000.i2c"); - clk_register_clkdev(clk[ecspi1], NULL, "2008000.ecspi"); - clk_register_clkdev(clk[ecspi2], NULL, "200c000.ecspi"); - clk_register_clkdev(clk[ecspi3], NULL, "2010000.ecspi"); - clk_register_clkdev(clk[ecspi4], NULL, "2014000.ecspi"); - clk_register_clkdev(clk[ecspi5], NULL, "2018000.ecspi"); - clk_register_clkdev(clk[sdma], NULL, "20ec000.sdma"); - clk_register_clkdev(clk[dummy], NULL, "20bc000.wdog"); - clk_register_clkdev(clk[dummy], NULL, "20c0000.wdog"); - clk_register_clkdev(clk[ssi1_ipg], NULL, "2028000.ssi"); clk_register_clkdev(clk[cko1_sel], "cko1_sel", NULL); clk_register_clkdev(clk[ahb], "ahb", NULL); clk_register_clkdev(clk[cko1], "cko1", NULL); diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 5ec0608f2a7..0b30aa8799d 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -100,7 +100,6 @@ static void __init imx6q_sabrelite_cko1_setup(void) clk_set_parent(cko1_sel, ahb); rate = clk_round_rate(cko1, 16000000); clk_set_rate(cko1, rate); - clk_register_clkdev(cko1, NULL, "0-000a"); put_clk: if (!IS_ERR(cko1_sel)) clk_put(cko1_sel); -- cgit v1.2.3-70-g09d2 From 65145677a65c31a8fd2704e244801bdb11061f9a Mon Sep 17 00:00:00 2001 From: Ajay Kumar Gupta Date: Fri, 31 Aug 2012 11:09:53 +0000 Subject: usb: musb: dsps: add dt support Added device tree support for dsps musb glue driver and updated the Documentation with device tree binding information. Signed-off-by: Ajay Kumar Gupta Signed-off-by: Santhapuri, Damodar Signed-off-by: Ravi Babu [afzal@ti.com: use '-' instead of '_' for dt properties] Signed-off-by: Afzal Mohammed Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/am33xx-usb.txt | 14 +++++ drivers/usb/musb/musb_dsps.c | 60 ++++++++++++++++++---- 2 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/am33xx-usb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt new file mode 100644 index 00000000000..ca8fa56e9f0 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt @@ -0,0 +1,14 @@ +AM33XX MUSB GLUE + - compatible : Should be "ti,musb-am33xx" + - ti,hwmods : must be "usb_otg_hs" + - multipoint : Should be "1" indicating the musb controller supports + multipoint. This is a MUSB configuration-specific setting. + - num_eps : Specifies the number of endpoints. This is also a + MUSB configuration-specific setting. Should be set to "16" + - ram_bits : Specifies the ram address size. Should be set to "12" + - port0_mode : Should be "3" to represent OTG. "1" signifies HOST and "2" + represents PERIPHERAL. + - port1_mode : Should be "1" to represent HOST. "3" signifies OTG and "2" + represents PERIPHERAL. + - power : Should be "250". This signifies the controller can supply upto + 500mA when operating in host mode. diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 796fc6085fc..b8aecbba740 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -45,6 +46,10 @@ #include "musb_core.h" +#ifdef CONFIG_OF +static const struct of_device_id musb_dsps_of_match[]; +#endif + /** * avoid using musb_readx()/musb_writex() as glue layer should not be * dependent on musb core layer symbols. @@ -448,6 +453,8 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) struct device *dev = glue->dev; struct platform_device *pdev = to_platform_device(dev); struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct device_node *np = pdev->dev.of_node; + struct musb_hdrc_config *config; struct platform_device *musb; struct resource *res; struct resource resources[2]; @@ -499,14 +506,40 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) glue->musb[id] = musb; - pdata->platform_ops = &dsps_ops; - ret = platform_device_add_resources(musb, resources, 2); if (ret) { dev_err(dev, "failed to add resources\n"); goto err2; } + if (np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, + "failed to allocate musb platfrom data\n"); + ret = -ENOMEM; + goto err2; + } + + config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); + if (!config) { + dev_err(&pdev->dev, + "failed to allocate musb hdrc config\n"); + goto err2; + } + + of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); + of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); + sprintf(res_name, "port%d-mode", id); + of_property_read_u32(np, res_name, (u32 *)&pdata->mode); + of_property_read_u32(np, "power", (u32 *)&pdata->power); + config->multipoint = of_property_read_bool(np, "multipoint"); + + pdata->config = config; + } + + pdata->platform_ops = &dsps_ops; + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(dev, "failed to add platform_data\n"); @@ -538,13 +571,21 @@ static void dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id) static int __devinit dsps_probe(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); - const struct dsps_musb_wrapper *wrp = - (struct dsps_musb_wrapper *)id->driver_data; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct dsps_musb_wrapper *wrp; struct dsps_glue *glue; struct resource *iomem; int ret, i; + match = of_match_node(musb_dsps_of_match, np); + if (!match) { + dev_err(&pdev->dev, "fail to get matching of_match struct\n"); + ret = -EINVAL; + goto err0; + } + wrp = match->data; + /* allocate glue */ glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -693,13 +734,14 @@ static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { }; MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); +#ifdef CONFIG_OF static const struct of_device_id musb_dsps_of_match[] __devinitconst = { - { .compatible = "musb-ti81xx", }, - { .compatible = "ti,ti81xx-musb", }, - { .compatible = "ti,am335x-musb", }, + { .compatible = "ti,musb-am33xx", + .data = (void *) &ti81xx_driver_data, }, { }, }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); +#endif static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, @@ -707,7 +749,7 @@ static struct platform_driver dsps_usbss_driver = { .driver = { .name = "musb-dsps", .pm = &dsps_pm_ops, - .of_match_table = musb_dsps_of_match, + .of_match_table = of_match_ptr(musb_dsps_of_match), }, .id_table = musb_dsps_id_table, }; -- cgit v1.2.3-70-g09d2 From a7ff477bb7e5ec9536e8aac02e8856a4bcc595a3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 10 Sep 2012 22:35:40 +0200 Subject: gpio: 74x164: dts: Add documentation for the dt binding Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-74x164.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-74x164.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio-74x164.txt b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt new file mode 100644 index 00000000000..cc2608021f2 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt @@ -0,0 +1,22 @@ +* Generic 8-bits shift register GPIO driver + +Required properties: +- compatible : Should be "fairchild,74hc595" +- reg : chip select number +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- registers-number: Number of daisy-chained shift registers + +Example: + +gpio5: gpio5@0 { + compatible = "fairchild,74hc595"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + registers-number = <4>; + spi-max-frequency = <100000>; +}; -- cgit v1.2.3-70-g09d2 From 5c3d8a46ac9778d117ca26f4fec18d7b8c8831ed Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Mon, 30 Jul 2012 07:21:12 +0000 Subject: i2c: davinci: add OF support add of support for the davinci i2c driver. Signed-off-by: Heiko Schocher Signed-off-by: Sekhar Nori [wsa: fix indentation in the binding description] Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/davinci.txt | 28 +++++++++++++ drivers/i2c/busses/i2c-davinci.c | 48 +++++++++++++++++------ 2 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/davinci.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/davinci.txt b/Documentation/devicetree/bindings/i2c/davinci.txt new file mode 100644 index 00000000000..2dc935b4113 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/davinci.txt @@ -0,0 +1,28 @@ +* Texas Instruments Davinci I2C + +This file provides information, what the device node for the +davinci i2c interface contain. + +Required properties: +- compatible: "ti,davinci-i2c"; +- reg : Offset and length of the register set for the device + +Recommended properties : +- interrupts : standard interrupt property. +- clock-frequency : desired I2C bus clock frequency in Hz. + +Example (enbw_cmc board): + i2c@1c22000 { + compatible = "ti,davinci-i2c"; + reg = <0x22000 0x1000>; + clock-frequency = <100000>; + interrupts = <15>; + interrupt-parent = <&intc>; + #address-cells = <1>; + #size-cells = <0>; + + dtt@48 { + compatible = "national,lm75"; + reg = <0x48>; + }; + }; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 79b4bcb3b85..b6185dccdf4 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -114,6 +116,7 @@ struct davinci_i2c_dev { struct completion xfr_complete; struct notifier_block freq_transition; #endif + struct davinci_i2c_platform_data *pdata; }; /* default platform data to use if not supplied in the platform_device */ @@ -155,7 +158,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin) static void i2c_recover_bus(struct davinci_i2c_dev *dev) { u32 flag = 0; - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; dev_err(dev->dev, "initiating i2c bus recovery\n"); /* Send NACK to the slave */ @@ -163,8 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev) flag |= DAVINCI_I2C_MDR_NACK; /* write the data into mode register */ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); - if (pdata) - generic_i2c_clock_pulse(pdata->scl_pin); + generic_i2c_clock_pulse(pdata->scl_pin); /* Send STOP */ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); flag |= DAVINCI_I2C_MDR_STP; @@ -187,7 +189,7 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; u16 psc; u32 clk; u32 d; @@ -235,10 +237,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) */ static int i2c_davinci_init(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; - - if (!pdata) - pdata = &davinci_i2c_platform_data_default; + struct davinci_i2c_platform_data *pdata = dev->pdata; /* put I2C into reset */ davinci_i2c_reset_ctrl(dev, 0); @@ -260,6 +259,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n", pdata->bus_freq, pdata->bus_delay); + /* Take the I2C module out of reset: */ davinci_i2c_reset_ctrl(dev, 1); @@ -308,13 +308,11 @@ static int i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; u32 flag; u16 w; int r; - if (!pdata) - pdata = &davinci_i2c_platform_data_default; /* Introduce a delay, required for some boards (e.g Davinci EVM) */ if (pdata->bus_delay) udelay(pdata->bus_delay); @@ -635,6 +633,12 @@ static struct i2c_algorithm i2c_davinci_algo = { .functionality = i2c_davinci_func, }; +static const struct of_device_id davinci_i2c_of_match[] = { + {.compatible = "ti,davinci-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, davinci_i2c_of_match); + static int davinci_i2c_probe(struct platform_device *pdev) { struct davinci_i2c_dev *dev; @@ -674,8 +678,27 @@ static int davinci_i2c_probe(struct platform_device *pdev) #endif dev->dev = get_device(&pdev->dev); dev->irq = irq->start; + dev->pdata = dev->dev->platform_data; platform_set_drvdata(pdev, dev); + if (!dev->pdata && pdev->dev.of_node) { + u32 prop; + + dev->pdata = devm_kzalloc(&pdev->dev, + sizeof(struct davinci_i2c_platform_data), GFP_KERNEL); + if (!dev->pdata) { + r = -ENOMEM; + goto err_free_mem; + } + memcpy(dev->pdata, &davinci_i2c_platform_data_default, + sizeof(struct davinci_i2c_platform_data)); + if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &prop)) + dev->pdata->bus_freq = prop / 1000; + } else if (!dev->pdata) { + dev->pdata = &davinci_i2c_platform_data_default; + } + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { r = -ENODEV; @@ -711,6 +734,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->algo = &i2c_davinci_algo; adap->dev.parent = &pdev->dev; adap->timeout = DAVINCI_I2C_TIMEOUT; + adap->dev.of_node = pdev->dev.of_node; adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); @@ -718,6 +742,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failure adding adapter\n"); goto err_free_irq; } + of_i2c_register_devices(adap); return 0; @@ -809,6 +834,7 @@ static struct platform_driver davinci_i2c_driver = { .name = "i2c_davinci", .owner = THIS_MODULE, .pm = davinci_i2c_pm_ops, + .of_match_table = of_match_ptr(davinci_i2c_of_match), }, }; -- cgit v1.2.3-70-g09d2 From 479e2e301c626cc64fb27b6b1938655eaba8b036 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 25 Jun 2012 16:16:25 +0200 Subject: pwm: i.MX: add devicetree support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time remove platform based support. No user for this driver has made it into mainline so far, so all we break is out of tree stuff. Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/imx-pwm.txt | 17 +++++++++ drivers/pwm/pwm-imx.c | 44 ++++++++++++++++++----- 2 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 Documentation/devicetree/bindings/pwm/imx-pwm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt new file mode 100644 index 00000000000..9b9b18514b6 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt @@ -0,0 +1,17 @@ +Freescale i.MX PWM controller + +Required properties: +- compatible: should be "fsl,-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. The first cell specifies the per-chip index + of the PWM to use and the second cell is the duty cycle in nanoseconds. +- interrupts: The interrupt for the pwm controller + +Example: + +pwm1: pwm@53fb4000 { + #pwm-cells = <2>; + compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; + reg = <0x53fb4000 0x4000>; + interrupts = <61>; +}; diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index a1e799ee07d..0f6c436c063 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -16,9 +16,9 @@ #include #include #include +#include #include - /* i.MX1 and i.MX21 share the same PWM function block: */ #define MX1_PWMC 0x00 /* PWM Control Register */ @@ -204,12 +204,41 @@ static struct pwm_ops imx_pwm_ops = { .owner = THIS_MODULE, }; +struct imx_pwm_data { + int (*config)(struct pwm_chip *chip, + struct pwm_device *pwm, int duty_ns, int period_ns); + void (*set_enable)(struct pwm_chip *chip, bool enable); +}; + +static struct imx_pwm_data imx_pwm_data_v1 = { + .config = imx_pwm_config_v1, + .set_enable = imx_pwm_set_enable_v1, +}; + +static struct imx_pwm_data imx_pwm_data_v2 = { + .config = imx_pwm_config_v2, + .set_enable = imx_pwm_set_enable_v2, +}; + +static const struct of_device_id imx_pwm_dt_ids[] = { + { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, }, + { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); + static int __devinit imx_pwm_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(imx_pwm_dt_ids, &pdev->dev); + struct imx_pwm_data *data; struct imx_chip *imx; struct resource *r; int ret = 0; + if (!of_id) + return -ENODEV; + imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); if (imx == NULL) { dev_err(&pdev->dev, "failed to allocate memory\n"); @@ -236,13 +265,9 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) if (imx->mmio_base == NULL) return -EADDRNOTAVAIL; - if (cpu_is_mx1() || cpu_is_mx21()) { - imx->config = imx_pwm_config_v1; - imx->set_enable = imx_pwm_set_enable_v1; - } else { - imx->config = imx_pwm_config_v2; - imx->set_enable = imx_pwm_set_enable_v2; - } + data = of_id->data; + imx->config = data->config; + imx->set_enable = data->set_enable; ret = pwmchip_add(&imx->chip); if (ret < 0) @@ -265,7 +290,8 @@ static int __devexit imx_pwm_remove(struct platform_device *pdev) static struct platform_driver imx_pwm_driver = { .driver = { - .name = "mxc_pwm", + .name = "imx-pwm", + .of_match_table = of_match_ptr(imx_pwm_dt_ids), }, .probe = imx_pwm_probe, .remove = __devexit_p(imx_pwm_remove), -- cgit v1.2.3-70-g09d2 From 70d46a241ed3bb0d1bb2bc15720b6f7c215c37f5 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 12 Sep 2012 08:42:14 +0200 Subject: i2c: at91: add dt support to i2c-at91 Signed-off-by: Ludovic Desroches Acked-by: Nikolaus Voss Acked-by: Nicolas Ferre Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/atmel-i2c.txt | 30 +++++++++++++ drivers/i2c/busses/i2c-at91.c | 49 ++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/atmel-i2c.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt new file mode 100644 index 00000000000..b689a0d9441 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt @@ -0,0 +1,30 @@ +I2C for Atmel platforms + +Required properties : +- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c", + "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c" + or "atmel,at91sam9x5-i2c" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding + +Examples : + +i2c0: i2c@fff84000 { + compatible = "atmel,at91sam9g20-i2c"; + reg = <0xfff84000 0x100>; + interrupts = <12 4 6>; + #address-cells = <1>; + #size-cells = <0>; + + 24c512@50 { + compatible = "24c512"; + reg = <0x50>; + pagesize = <128>; + } +} diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 78bcad031d6..aa59a254be2 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include @@ -347,6 +350,12 @@ static struct at91_twi_pdata at91sam9g10_config = { .has_unre_flag = false, }; +static struct at91_twi_pdata at91sam9x5_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + static const struct platform_device_id at91_twi_devtypes[] = { { .name = "i2c-at91rm9200", @@ -368,6 +377,42 @@ static const struct platform_device_id at91_twi_devtypes[] = { } }; +#if defined(CONFIG_OF) +static const struct of_device_id atmel_twi_dt_ids[] = { + { + .compatible = "atmel,at91sam9260-i2c", + .data = &at91sam9260_config, + } , { + .compatible = "atmel,at91sam9g20-i2c", + .data = &at91sam9g20_config, + } , { + .compatible = "atmel,at91sam9g10-i2c", + .data = &at91sam9g10_config, + }, { + .compatible = "atmel,at91sam9x5-i2c", + .data = &at91sam9x5_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); +#else +#define atmel_twi_dt_ids NULL +#endif + +static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( + struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node); + if (!match) + return NULL; + return match->data; + } + return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data; +} + static int __devinit at91_twi_probe(struct platform_device *pdev) { struct at91_twi_dev *dev; @@ -423,6 +468,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) dev->adapter.dev.parent = dev->dev; dev->adapter.nr = pdev->id; dev->adapter.timeout = AT91_I2C_TIMEOUT; + dev->adapter.dev.of_node = pdev->dev.of_node; rc = i2c_add_numbered_adapter(&dev->adapter); if (rc) { @@ -432,6 +478,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) return rc; } + of_i2c_register_devices(&dev->adapter); + dev_info(dev->dev, "AT91 i2c bus driver.\n"); return 0; } @@ -482,6 +530,7 @@ static struct platform_driver at91_twi_driver = { .driver = { .name = "at91_i2c", .owner = THIS_MODULE, + .of_match_table = atmel_twi_dt_ids, .pm = at91_twi_pm_ops, }, }; -- cgit v1.2.3-70-g09d2 From 7b31d0095e87221dc32c95642a2a714ea08259aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 12 Sep 2012 18:06:54 +0200 Subject: ALSA: Define more channel map positions For following the standard, define more channel map positions and shuffle the items a bit: - As both PulseAudio and gstreamer define MONO channel position explicitly, we should follow that, too. The mono streams point to this channel position unless they are explicitly assigned to certain channel positions. - Top-front-* and Top-rear-* positions are added, carried from PulseAudio's definitions. - Move NA and MONO definitions at the top of table right after UNKNOWN, since these are more abstract in comparison with other practical positions. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Channel-Mapping-API.txt | 13 ++++++++++--- include/sound/asound.h | 13 ++++++++++--- sound/pci/ctxfi/ctpcm.c | 6 +++--- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/Channel-Mapping-API.txt b/Documentation/sound/alsa/Channel-Mapping-API.txt index 4bbf12d5553..3c43d1a4ca0 100644 --- a/Documentation/sound/alsa/Channel-Mapping-API.txt +++ b/Documentation/sound/alsa/Channel-Mapping-API.txt @@ -76,8 +76,10 @@ here is a cut: /* channel positions */ enum { - /* this follows the alsa-lib mixer channel value + 1 */ SNDRV_CHMAP_UNKNOWN = 0, + SNDRV_CHMAP_NA, /* N/A, silent */ + SNDRV_CHMAP_MONO, /* mono stream */ + /* this follows the alsa-lib mixer channel value + 3 */ SNDRV_CHMAP_FL, /* front left */ SNDRV_CHMAP_FR, /* front right */ SNDRV_CHMAP_RL, /* rear left */ @@ -98,8 +100,13 @@ enum { SNDRV_CHMAP_FCH, /* front center high */ SNDRV_CHMAP_FRH, /* front right high */ SNDRV_CHMAP_TC, /* top center */ - SNDRV_CHMAP_NA, /* N/A, silent */ - SNDRV_CHMAP_LAST = SNDRV_CHMAP_NA, + SNDRV_CHMAP_TFL, /* top front left */ + SNDRV_CHMAP_TFR, /* top front right */ + SNDRV_CHMAP_TFC, /* top front center */ + SNDRV_CHMAP_TRL, /* top rear left */ + SNDRV_CHMAP_TRR, /* top rear right */ + SNDRV_CHMAP_TRC, /* top rear center */ + SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC, }; When a PCM stream can provide more than one channel map, you can diff --git a/include/sound/asound.h b/include/sound/asound.h index 27686da0f65..dfe7d441748 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -474,8 +474,10 @@ enum { /* channel positions */ enum { - /* this follows the alsa-lib mixer channel value + 1 */ SNDRV_CHMAP_UNKNOWN = 0, + SNDRV_CHMAP_NA, /* N/A, silent */ + SNDRV_CHMAP_MONO, /* mono stream */ + /* this follows the alsa-lib mixer channel value + 3 */ SNDRV_CHMAP_FL, /* front left */ SNDRV_CHMAP_FR, /* front right */ SNDRV_CHMAP_RL, /* rear left */ @@ -496,8 +498,13 @@ enum { SNDRV_CHMAP_FCH, /* front center high */ SNDRV_CHMAP_FRH, /* front right high */ SNDRV_CHMAP_TC, /* top center */ - SNDRV_CHMAP_NA, /* N/A, silent */ - SNDRV_CHMAP_LAST = SNDRV_CHMAP_NA, + SNDRV_CHMAP_TFL, /* top front left */ + SNDRV_CHMAP_TFR, /* top front right */ + SNDRV_CHMAP_TFC, /* top front center */ + SNDRV_CHMAP_TRL, /* top rear left */ + SNDRV_CHMAP_TRR, /* top rear right */ + SNDRV_CHMAP_TRC, /* top rear center */ + SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC, }; #define SNDRV_CHMAP_POSITION_MASK 0xffff diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index d317107d98c..e8a4feb1ed8 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -397,7 +397,7 @@ static struct snd_pcm_ops ct_pcm_capture_ops = { static const struct snd_pcm_chmap_elem surround_map[] = { { .channels = 1, - .map = { SNDRV_CHMAP_UNKNOWN } }, + .map = { SNDRV_CHMAP_MONO } }, { .channels = 2, .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, { } @@ -405,7 +405,7 @@ static const struct snd_pcm_chmap_elem surround_map[] = { static const struct snd_pcm_chmap_elem clfe_map[] = { { .channels = 1, - .map = { SNDRV_CHMAP_UNKNOWN } }, + .map = { SNDRV_CHMAP_MONO } }, { .channels = 2, .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } }, { } @@ -413,7 +413,7 @@ static const struct snd_pcm_chmap_elem clfe_map[] = { static const struct snd_pcm_chmap_elem side_map[] = { { .channels = 1, - .map = { SNDRV_CHMAP_UNKNOWN } }, + .map = { SNDRV_CHMAP_MONO } }, { .channels = 2, .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } }, { } -- cgit v1.2.3-70-g09d2 From d142d6be231713330f9c0d7ee52f23e1b3f19ee4 Mon Sep 17 00:00:00 2001 From: Richard Zhao Date: Wed, 12 Sep 2012 14:58:05 +0300 Subject: USB: chipidea: add imx usbmisc support i.MX usb controllers share non-core registers, which may include SoC specific controls. We turn it into a usbmisc device and usbmisc driver set operations needed by ci13xxx_imx driver. For example, Sabrelite board has bad over-current design, we can usbmisc to disable over-current detection. Acked-by: Sascha Hauer Signed-off-by: Richard Zhao Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/ci13xxx-imx.txt | 5 + .../devicetree/bindings/usb/usbmisc-imx.txt | 14 ++ drivers/usb/chipidea/Makefile | 2 +- drivers/usb/chipidea/ci13xxx_imx.c | 64 ++++++++ drivers/usb/chipidea/ci13xxx_imx.h | 28 ++++ drivers/usb/chipidea/usbmisc_imx6q.c | 162 +++++++++++++++++++++ 6 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/usb/usbmisc-imx.txt create mode 100644 drivers/usb/chipidea/ci13xxx_imx.h create mode 100644 drivers/usb/chipidea/usbmisc_imx6q.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt index 2c290418bb2..5778b9c83bd 100644 --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt @@ -7,7 +7,10 @@ Required properties: Optional properties: - fsl,usbphy: phandler of usb phy that connects to the only one port +- fsl,usbmisc: phandler of non-core register device, with one argument + that indicate usb controller index - vbus-supply: regulator for vbus +- disable-over-current: disable over current detect Examples: usb@02184000 { /* USB OTG */ @@ -15,4 +18,6 @@ usb@02184000 { /* USB OTG */ reg = <0x02184000 0x200>; interrupts = <0 43 0x04>; fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc 0>; + disable-over-current; }; diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt new file mode 100644 index 00000000000..97ce94e1a6c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt @@ -0,0 +1,14 @@ +* Freescale i.MX non-core registers + +Required properties: +- #index-cells: Cells used to descibe usb controller index. Should be <1> +- compatible: Should be one of below: + "fsl,imx6q-usbmisc" for imx6q +- reg: Should contain registers location and length + +Examples: +usbmisc@02184800 { + #index-cells = <1>; + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; +}; diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 5c66d9c330c..57e510f6c24 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -15,5 +15,5 @@ ifneq ($(CONFIG_PCI),) endif ifneq ($(CONFIG_OF_DEVICE),) - obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o endif diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c index ef60d06835d..96ac67bbd2d 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.c +++ b/drivers/usb/chipidea/ci13xxx_imx.c @@ -22,6 +22,7 @@ #include #include "ci.h" +#include "ci13xxx_imx.h" #define pdev_to_phy(pdev) \ ((struct usb_phy *)platform_get_drvdata(pdev)) @@ -34,6 +35,55 @@ struct ci13xxx_imx_data { struct regulator *reg_vbus; }; +static const struct usbmisc_ops *usbmisc_ops; + +/* Common functions shared by usbmisc drivers */ + +int usbmisc_set_ops(const struct usbmisc_ops *ops) +{ + if (usbmisc_ops) + return -EBUSY; + + usbmisc_ops = ops; + + return 0; +} +EXPORT_SYMBOL_GPL(usbmisc_set_ops); + +void usbmisc_unset_ops(const struct usbmisc_ops *ops) +{ + usbmisc_ops = NULL; +} +EXPORT_SYMBOL_GPL(usbmisc_unset_ops); + +int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) +{ + struct device_node *np = dev->of_node; + struct of_phandle_args args; + int ret; + + usbdev->dev = dev; + + ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", + 0, &args); + if (ret) { + dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", + ret); + memset(usbdev, 0, sizeof(*usbdev)); + return ret; + } + usbdev->index = args.args[0]; + of_node_put(args.np); + + if (of_find_property(np, "disable-over-current", NULL)) + usbdev->disable_oc = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(usbmisc_get_init_data); + +/* End of common functions shared by usbmisc drivers*/ + static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata = { .name = "ci13xxx_imx", .flags = CI13XXX_REQUIRE_TRANSCEIVER | @@ -51,6 +101,10 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev) struct regulator *reg_vbus; int ret; + if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL) + && !usbmisc_ops) + return -EPROBE_DEFER; + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n"); @@ -120,6 +174,16 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev) *pdev->dev.dma_mask = DMA_BIT_MASK(32); dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask); } + + if (usbmisc_ops && usbmisc_ops->init) { + ret = usbmisc_ops->init(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, + "usbmisc init failed, ret=%d\n", ret); + goto err; + } + } + plat_ci = ci13xxx_add_device(&pdev->dev, pdev->resource, pdev->num_resources, &ci13xxx_imx_platdata); diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h new file mode 100644 index 00000000000..2e88accb3d6 --- /dev/null +++ b/drivers/usb/chipidea/ci13xxx_imx.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* Used to set SoC specific callbacks */ +struct usbmisc_ops { + /* It's called once when probe a usb device */ + int (*init)(struct device *dev); +}; + +struct usbmisc_usb_device { + struct device *dev; /* usb controller device */ + int index; + + int disable_oc:1; /* over current detect disabled */ +}; + +int usbmisc_set_ops(const struct usbmisc_ops *ops); +void usbmisc_unset_ops(const struct usbmisc_ops *ops); +int +usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev); diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c new file mode 100644 index 00000000000..416e3fc58fd --- /dev/null +++ b/drivers/usb/chipidea/usbmisc_imx6q.c @@ -0,0 +1,162 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include + +#include "ci13xxx_imx.h" + +#define USB_DEV_MAX 4 + +#define BM_OVER_CUR_DIS BIT(7) + +struct imx6q_usbmisc { + void __iomem *base; + spinlock_t lock; + struct clk *clk; + struct usbmisc_usb_device usbdev[USB_DEV_MAX]; +}; + +static struct imx6q_usbmisc *usbmisc; + +static struct usbmisc_usb_device *get_usbdev(struct device *dev) +{ + int i, ret; + + for (i = 0; i < USB_DEV_MAX; i++) { + if (usbmisc->usbdev[i].dev == dev) + return &usbmisc->usbdev[i]; + else if (!usbmisc->usbdev[i].dev) + break; + } + + if (i >= USB_DEV_MAX) + return ERR_PTR(-EBUSY); + + ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); + if (ret) + return ERR_PTR(ret); + + return &usbmisc->usbdev[i]; +} + +static int usbmisc_imx6q_init(struct device *dev) +{ + + struct usbmisc_usb_device *usbdev; + unsigned long flags; + u32 reg; + + usbdev = get_usbdev(dev); + if (IS_ERR(usbdev)) + return PTR_ERR(usbdev); + + if (usbdev->disable_oc) { + spin_lock_irqsave(&usbmisc->lock, flags); + reg = readl(usbmisc->base + usbdev->index * 4); + writel(reg | BM_OVER_CUR_DIS, + usbmisc->base + usbdev->index * 4); + spin_unlock_irqrestore(&usbmisc->lock, flags); + } + + return 0; +} + +static const struct usbmisc_ops imx6q_usbmisc_ops = { + .init = usbmisc_imx6q_init, +}; + +static const struct of_device_id usbmisc_imx6q_dt_ids[] = { + { .compatible = "fsl,imx6q-usbmisc"}, + { /* sentinel */ } +}; + +static int __devinit usbmisc_imx6q_probe(struct platform_device *pdev) +{ + struct resource *res; + struct imx6q_usbmisc *data; + int ret; + + if (usbmisc) + return -EBUSY; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&data->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_request_and_ioremap(&pdev->dev, res); + if (!data->base) + return -EADDRNOTAVAIL; + + data->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->clk)) { + dev_err(&pdev->dev, + "failed to get clock, err=%ld\n", PTR_ERR(data->clk)); + return PTR_ERR(data->clk); + } + + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed, err=%d\n", ret); + return ret; + } + + ret = usbmisc_set_ops(&imx6q_usbmisc_ops); + if (ret) { + clk_disable_unprepare(data->clk); + return ret; + } + + usbmisc = data; + + return 0; +} + +static int __devexit usbmisc_imx6q_remove(struct platform_device *pdev) +{ + usbmisc_unset_ops(&imx6q_usbmisc_ops); + clk_disable_unprepare(usbmisc->clk); + return 0; +} + +static struct platform_driver usbmisc_imx6q_driver = { + .probe = usbmisc_imx6q_probe, + .remove = __devexit_p(usbmisc_imx6q_remove), + .driver = { + .name = "usbmisc_imx6q", + .owner = THIS_MODULE, + .of_match_table = usbmisc_imx6q_dt_ids, + }, +}; + +int __init usbmisc_imx6q_drv_init(void) +{ + return platform_driver_register(&usbmisc_imx6q_driver); +} +subsys_initcall(usbmisc_imx6q_drv_init); + +void __exit usbmisc_imx6q_drv_exit(void) +{ + platform_driver_unregister(&usbmisc_imx6q_driver); +} +module_exit(usbmisc_imx6q_drv_exit); + +MODULE_ALIAS("platform:usbmisc-imx6q"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("driver for imx6q usb non-core registers"); +MODULE_AUTHOR("Richard Zhao "); -- cgit v1.2.3-70-g09d2 From 19ec2567e0a5fe64f4404ad6df697894aec8c493 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Tue, 11 Sep 2012 16:28:10 -0400 Subject: cgroup: add documentation on extended attributes usage v2: update cgroups.txt instead of creating a new file Cc: Tejun Heo Cc: Hugh Dickins Cc: Hillf Danton Cc: Lennart Poettering Acked-by: Li Zefan Signed-off-by: Aristeu Rozanski Signed-off-by: Tejun Heo --- Documentation/cgroups/cgroups.txt | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index 4a0b64c605f..004fd5a09e1 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -29,7 +29,8 @@ CONTENTS: 3.1 Overview 3.2 Synchronization 3.3 Subsystem API -4. Questions +4. Extended attributes usage +5. Questions 1. Control Groups ================= @@ -650,7 +651,26 @@ and root cgroup. Currently this will only involve movement between the default hierarchy (which never has sub-cgroups) and a hierarchy that is being created/destroyed (and hence has no sub-cgroups). -4. Questions +4. Extended attribute usage +=========================== + +cgroup filesystem supports certain types of extended attributes in its +directories and files. The current supported types are: + - Trusted (XATTR_TRUSTED) + - Security (XATTR_SECURITY) + +Both require CAP_SYS_ADMIN capability to set. + +Like in tmpfs, the extended attributes in cgroup filesystem are stored +using kernel memory and it's advised to keep the usage at minimum. This +is the reason why user defined extended attributes are not supported, since +any user can do it and there's no limit in the value size. + +The current known users for this feature are SELinux to limit cgroup usage +in containers and systemd for assorted meta data like main PID in a cgroup +(systemd creates a cgroup per service). + +5. Questions ============ Q: what's up with this '/bin/echo' ? -- cgit v1.2.3-70-g09d2 From f4dfef75adb12fec7693d0c469e2de6c7d45e975 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Wed, 15 Aug 2012 20:43:52 +0530 Subject: powerpc: Update Integrated Flash controller device tree bindings Freescale's Integrated Flash controller (IFC) may have one or two interrupts. In case of single interrupt line, it will cover all IFC interrupts. Update this information in IFC device tree bindings Signed-off-by: Prabhakar Kushwaha Signed-off-by: Kumar Gala --- Documentation/devicetree/bindings/powerpc/fsl/ifc.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt index 939a26d541f..d5e370450ac 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt @@ -12,9 +12,12 @@ Properties: - #size-cells : Either one or two, depending on how large each chipselect can be. - reg : Offset and length of the register set for the device -- interrupts : IFC has two interrupts. The first one is the "common" - interrupt(CM_EVTER_STAT), and second is the NAND interrupt - (NAND_EVTER_STAT). +- interrupts: IFC may have one or two interrupts. If two interrupt + specifiers are present, the first is the "common" + interrupt (CM_EVTER_STAT), and the second is the NAND + interrupt (NAND_EVTER_STAT). If there is only one, + that interrupt reports both types of event. + - ranges : Each range corresponds to a single chipselect, and covers the entire access window as configured. -- cgit v1.2.3-70-g09d2 From 8996b89d6bc98ae2f6d6e6e624a42a3f89d06949 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Thu, 6 Sep 2012 16:03:30 -0500 Subject: ata: add platform driver for Calxeda AHCI controller Calxeda highbank SATA phy has intermittent problems bringing up a link with Gen3 drives. Retrying the phy hard reset can work-around this issue, but each reset also disables spread spectrum support. The reset function also needs to reprogram the phy to enable spread spectrum support. Create a new driver based on ahci_platform to support the Calxeda Highbank SATA controller. Signed-off-by: Mark Langsdorf Signed-off-by: Rob Herring Signed-off-by: Jeff Garzik --- .../devicetree/bindings/arm/calxeda/combophy.txt | 17 + .../devicetree/bindings/ata/ahci-platform.txt | 8 + arch/arm/boot/dts/highbank.dts | 17 + drivers/ata/Kconfig | 8 + drivers/ata/Makefile | 1 + drivers/ata/ahci_platform.c | 1 - drivers/ata/sata_highbank.c | 450 +++++++++++++++++++++ 7 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/calxeda/combophy.txt create mode 100644 drivers/ata/sata_highbank.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/calxeda/combophy.txt b/Documentation/devicetree/bindings/arm/calxeda/combophy.txt new file mode 100644 index 00000000000..6622bdb2e8b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/calxeda/combophy.txt @@ -0,0 +1,17 @@ +Calxeda Highbank Combination Phys for SATA + +Properties: +- compatible : Should be "calxeda,hb-combophy" +- #phy-cells: Should be 1. +- reg : Address and size for Combination Phy registers. +- phydev: device ID for programming the combophy. + +Example: + + combophy5: combo-phy@fff5d000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff5d000 0x1000>; + phydev = <31>; + }; + diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index 8bb8a76d42e..147c1f6653f 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -8,9 +8,17 @@ Required properties: - interrupts : - reg : +Optional properties: +- calxeda,port-phys: phandle-combophy and lane assignment, which maps each + SATA port to a combophy and a lane within that + combophy + Example: sata@ffe08000 { compatible = "calxeda,hb-ahci"; reg = <0xffe08000 0x1000>; interrupts = <115>; + calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1 + &combophy0 2 &combophy0 3>; + }; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 9fecf1ae777..5204cf73c2d 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -121,6 +121,9 @@ compatible = "calxeda,hb-ahci"; reg = <0xffe08000 0x10000>; interrupts = <0 83 4>; + calxeda,port-phys = <&combophy5 0 &combophy0 0 + &combophy0 1 &combophy0 2 + &combophy0 3>; }; sdhci@ffe0e000 { @@ -306,5 +309,19 @@ reg = <0xfff51000 0x1000>; interrupts = <0 80 4 0 81 4 0 82 4>; }; + + combophy0: combo-phy@fff58000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff58000 0x1000>; + phydev = <5>; + }; + + combophy5: combo-phy@fff5d000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff5d000 0x1000>; + phydev = <31>; + }; }; }; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 27cecd313e7..e08d322d01d 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -214,6 +214,14 @@ config SATA_DWC_VDEBUG help This option enables the taskfile dumping and NCQ debugging. +config SATA_HIGHBANK + tristate "Calxeda Highbank SATA support" + help + This option enables support for the Calxeda Highbank SoC's + onboard SATA. + + If unsure, say N. + config SATA_MV tristate "Marvell SATA support" help diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index a454a139b1d..8b384f1885f 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o +obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 09728e09cb3..dc187c74664 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -277,7 +277,6 @@ static int ahci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); static const struct of_device_id ahci_of_match[] = { - { .compatible = "calxeda,hb-ahci", }, { .compatible = "snps,spear-ahci", }, {}, }; diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c new file mode 100644 index 00000000000..0d7c4c2cd26 --- /dev/null +++ b/drivers/ata/sata_highbank.c @@ -0,0 +1,450 @@ +/* + * Calxeda Highbank AHCI SATA platform driver + * Copyright 2012 Calxeda, Inc. + * + * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f)) +#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2) +#define SERDES_CR_CTL 0x80a0 +#define SERDES_CR_ADDR 0x80a1 +#define SERDES_CR_DATA 0x80a2 +#define CR_BUSY 0x0001 +#define CR_START 0x0001 +#define CR_WR_RDN 0x0002 +#define CPHY_RX_INPUT_STS 0x2002 +#define CPHY_SATA_OVERRIDE 0x4000 +#define CPHY_OVERRIDE 0x2005 +#define SPHY_LANE 0x100 +#define SPHY_HALF_RATE 0x0001 +#define CPHY_SATA_DPLL_MODE 0x0700 +#define CPHY_SATA_DPLL_SHIFT 8 +#define CPHY_SATA_DPLL_RESET (1 << 11) +#define CPHY_PHY_COUNT 6 +#define CPHY_LANE_COUNT 4 +#define CPHY_PORT_COUNT (CPHY_PHY_COUNT * CPHY_LANE_COUNT) + +static DEFINE_SPINLOCK(cphy_lock); +/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based + * sata ports to their phys and then to their lanes within the phys + */ +struct phy_lane_info { + void __iomem *phy_base; + u8 lane_mapping; + u8 phy_devs; +}; +static struct phy_lane_info port_data[CPHY_PORT_COUNT]; + +static u32 __combo_phy_reg_read(u8 sata_port, u32 addr) +{ + u32 data; + u8 dev = port_data[sata_port].phy_devs; + spin_lock(&cphy_lock); + writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800); + data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr)); + spin_unlock(&cphy_lock); + return data; +} + +static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data) +{ + u8 dev = port_data[sata_port].phy_devs; + spin_lock(&cphy_lock); + writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800); + writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr)); + spin_unlock(&cphy_lock); +} + +static void combo_phy_wait_for_ready(u8 sata_port) +{ + while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY) + udelay(5); +} + +static u32 combo_phy_read(u8 sata_port, u32 addr) +{ + combo_phy_wait_for_ready(sata_port); + __combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr); + __combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START); + combo_phy_wait_for_ready(sata_port); + return __combo_phy_reg_read(sata_port, SERDES_CR_DATA); +} + +static void combo_phy_write(u8 sata_port, u32 addr, u32 data) +{ + combo_phy_wait_for_ready(sata_port); + __combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr); + __combo_phy_reg_write(sata_port, SERDES_CR_DATA, data); + __combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START); +} + +static void highbank_cphy_disable_overrides(u8 sata_port) +{ + u8 lane = port_data[sata_port].lane_mapping; + u32 tmp; + if (unlikely(port_data[sata_port].phy_base == NULL)) + return; + tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE); + tmp &= ~CPHY_SATA_OVERRIDE; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); +} + +static void cphy_override_rx_mode(u8 sata_port, u32 val) +{ + u8 lane = port_data[sata_port].lane_mapping; + u32 tmp; + tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE); + tmp &= ~CPHY_SATA_OVERRIDE; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp |= CPHY_SATA_OVERRIDE; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp &= ~CPHY_SATA_DPLL_MODE; + tmp |= val << CPHY_SATA_DPLL_SHIFT; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp |= CPHY_SATA_DPLL_RESET; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp &= ~CPHY_SATA_DPLL_RESET; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + msleep(15); +} + +static void highbank_cphy_override_lane(u8 sata_port) +{ + u8 lane = port_data[sata_port].lane_mapping; + u32 tmp, k = 0; + + if (unlikely(port_data[sata_port].phy_base == NULL)) + return; + do { + tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + + lane * SPHY_LANE); + } while ((tmp & SPHY_HALF_RATE) && (k++ < 1000)); + cphy_override_rx_mode(sata_port, 3); +} + +static int highbank_initialize_phys(struct device *dev, void __iomem *addr) +{ + struct device_node *sata_node = dev->of_node; + int phy_count = 0, phy, port = 0; + void __iomem *cphy_base[CPHY_PHY_COUNT]; + struct device_node *phy_nodes[CPHY_PHY_COUNT]; + memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT); + memset(phy_nodes, 0, sizeof(struct device_node*) * CPHY_PHY_COUNT); + + do { + u32 tmp; + struct of_phandle_args phy_data; + if (of_parse_phandle_with_args(sata_node, + "calxeda,port-phys", "#phy-cells", + port, &phy_data)) + break; + for (phy = 0; phy < phy_count; phy++) { + if (phy_nodes[phy] == phy_data.np) + break; + } + if (phy_nodes[phy] == NULL) { + phy_nodes[phy] = phy_data.np; + cphy_base[phy] = of_iomap(phy_nodes[phy], 0); + if (cphy_base[phy] == NULL) { + return 0; + } + phy_count += 1; + } + port_data[port].lane_mapping = phy_data.args[0]; + of_property_read_u32(phy_nodes[phy], "phydev", &tmp); + port_data[port].phy_devs = tmp; + port_data[port].phy_base = cphy_base[phy]; + of_node_put(phy_data.np); + port += 1; + } while (port < CPHY_PORT_COUNT); + return 0; +} + +static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; + u32 sstatus; + int rc; + int retry = 10; + + ahci_stop_engine(ap); + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = 0x80; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + + do { + highbank_cphy_disable_overrides(link->ap->port_no); + rc = sata_link_hardreset(link, timing, deadline, &online, NULL); + highbank_cphy_override_lane(link->ap->port_no); + + /* If the status is 1, we are connected, but the link did not + * come up. So retry resetting the link again. + */ + if (sata_scr_read(link, SCR_STATUS, &sstatus)) + break; + if (!(sstatus & 0x3)) + break; + } while (!online && retry--); + + ahci_start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + return rc; +} + +static struct ata_port_operations ahci_highbank_ops = { + .inherits = &ahci_ops, + .hardreset = ahci_highbank_hardreset, +}; + +static const struct ata_port_info ahci_highbank_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_highbank_ops, +}; + +static struct scsi_host_template ahci_highbank_platform_sht = { + AHCI_SHT("highbank-ahci"), +}; + +static const struct of_device_id ahci_of_match[] = { + { .compatible = "calxeda,hb-ahci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ahci_of_match); + +static int __init ahci_highbank_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct ata_host *host; + struct resource *mem; + int irq; + int n_ports; + int i; + int rc; + struct ata_port_info pi = ahci_highbank_port_info; + const struct ata_port_info *ppi[] = { &pi, NULL }; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "no mmio space\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "no irq\n"); + return -EINVAL; + } + + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) { + dev_err(dev, "can't alloc ahci_host_priv\n"); + return -ENOMEM; + } + + hpriv->flags |= (unsigned long)pi.private_data; + + hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); + if (!hpriv->mmio) { + dev_err(dev, "can't map %pR\n", mem); + return -ENOMEM; + } + + rc = highbank_initialize_phys(dev, hpriv->mmio); + if (rc) + return rc; + + + ahci_save_initial_config(dev, hpriv, 0, 0); + + /* prepare host */ + if (hpriv->cap & HOST_CAP_NCQ) + pi.flags |= ATA_FLAG_NCQ; + + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + + ahci_set_em_messages(hpriv, &pi); + + /* CAP.NP sometimes indicate the index of the last enabled + * port, at other times, that of the last possible port, so + * determining the maximum port number requires looking at + * both CAP.NP and port_map. + */ + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); + + host = ata_host_alloc_pinfo(dev, ppi, n_ports); + if (!host) { + rc = -ENOMEM; + goto err0; + } + + host->private_data = hpriv; + + if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) + host->flags |= ATA_HOST_PARALLEL_SCAN; + + if (pi.flags & ATA_FLAG_EM) + ahci_reset_em(host); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + ata_port_desc(ap, "mmio %pR", mem); + ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); + + /* set enclosure management message type */ + if (ap->flags & ATA_FLAG_EM) + ap->em_message_type = hpriv->em_msg_type; + + /* disabled/not-implemented port */ + if (!(hpriv->port_map & (1 << i))) + ap->ops = &ata_dummy_port_ops; + } + + rc = ahci_reset_controller(host); + if (rc) + goto err0; + + ahci_init_controller(host); + ahci_print_info(host, "platform"); + + rc = ata_host_activate(host, irq, ahci_interrupt, 0, + &ahci_highbank_platform_sht); + if (rc) + goto err0; + + return 0; +err0: + return rc; +} + +static int __devexit ahci_highbank_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_detach(host); + + return 0; +} + +#ifdef CONFIG_PM +static int ahci_highbank_suspend(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 ctl; + int rc; + + if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { + dev_err(dev, "firmware update required for suspend/resume\n"); + return -EIO; + } + + /* + * AHCI spec rev1.1 section 8.3.3: + * Software must disable interrupts prior to requesting a + * transition of the HBA to D3 state. + */ + ctl = readl(mmio + HOST_CTL); + ctl &= ~HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + + rc = ata_host_suspend(host, PMSG_SUSPEND); + if (rc) + return rc; + + return 0; +} + +static int ahci_highbank_resume(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + int rc; + + if (dev->power.power_state.event == PM_EVENT_SUSPEND) { + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + } + + ata_host_resume(host); + + return 0; +} +#endif + +SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops, + ahci_highbank_suspend, ahci_highbank_resume); + +static struct platform_driver ahci_highbank_driver = { + .remove = __devexit_p(ahci_highbank_remove), + .driver = { + .name = "highbank-ahci", + .owner = THIS_MODULE, + .of_match_table = ahci_of_match, + .pm = &ahci_highbank_pm_ops, + }, + .probe = ahci_highbank_probe, +}; + +module_platform_driver(ahci_highbank_driver); + +MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver"); +MODULE_AUTHOR("Mark Langsdorf "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("sata:highbank"); -- cgit v1.2.3-70-g09d2 From 26fdaa7453db49de80cc216cb696233b23d0b9d1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Aug 2012 10:37:18 +0530 Subject: pata_arasan: add Device Tree probing capability SPEAr platforms now support DT and so must convert all drivers to support DT. This patch adds DT probing support for Arasan Compact Flash controller and updates its documentation too. Signed-off-by: Viresh Kumar Signed-off-by: Jeff Garzik --- Documentation/devicetree/bindings/ata/pata-arasan.txt | 17 +++++++++++++++++ drivers/ata/pata_arasan_cf.c | 10 ++++++++++ 2 files changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/pata-arasan.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/pata-arasan.txt b/Documentation/devicetree/bindings/ata/pata-arasan.txt new file mode 100644 index 00000000000..95ec7f825ed --- /dev/null +++ b/Documentation/devicetree/bindings/ata/pata-arasan.txt @@ -0,0 +1,17 @@ +* ARASAN PATA COMPACT FLASH CONTROLLER + +Required properties: +- compatible: "arasan,cf-spear1340" +- reg: Address range of the CF registers +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupt: Should contain the CF interrupt number + +Example: + + cf@fc000000 { + compatible = "arasan,cf-spear1340"; + reg = <0xfc000000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + }; diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index d82c6dc0c20..26201ebef3c 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -935,6 +936,14 @@ static int arasan_cf_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(arasan_cf_pm_ops, arasan_cf_suspend, arasan_cf_resume); +#ifdef CONFIG_OF +static const struct of_device_id arasan_cf_id_table[] = { + { .compatible = "arasan,cf-spear1340" }, + {} +}; +MODULE_DEVICE_TABLE(of, arasan_cf_id_table); +#endif + static struct platform_driver arasan_cf_driver = { .probe = arasan_cf_probe, .remove = __devexit_p(arasan_cf_remove), @@ -942,6 +951,7 @@ static struct platform_driver arasan_cf_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &arasan_cf_pm_ops, + .of_match_table = of_match_ptr(arasan_cf_id_table), }, }; -- cgit v1.2.3-70-g09d2 From 9e605cb68a21d5704839a192a46ebcf387773704 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Sep 2012 11:54:24 +0300 Subject: pinctrl: pinctrl-single: Add pinctrl-single,bits type of mux With pinctrl-single,bits it is possible to update just part of the register within the pinctrl-single,function-mask area. This is useful when one register configures mmore than one pin's mux. pinctrl-single,bits takes three parameters: Signed-off-by: Peter Ujfalusi Acked-by: Tony Lindgren [Removed a misplaced comment] Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/pinctrl-single.txt | 41 +++++++++++++++++-- drivers/pinctrl/pinctrl-single.c | 46 +++++++++++++++++----- 2 files changed, 74 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt index 5187f0dd8b2..2c81e45f137 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt @@ -14,10 +14,12 @@ Optional properties: - pinctrl-single,function-off : function off mode for disabled state if available and same for all registers; if not specified, disabling of pin functions is ignored +- pinctrl-single,bit-per-mux : boolean to indicate that one register controls + more than one pin -This driver assumes that there is only one register for each pin, -and uses the common pinctrl bindings as specified in the pinctrl-bindings.txt -document in this directory. +This driver assumes that there is only one register for each pin (unless the +pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as +specified in the pinctrl-bindings.txt document in this directory. The pin configuration nodes for pinctrl-single are specified as pinctrl register offset and value pairs using pinctrl-single,pins. Only the bits @@ -31,6 +33,15 @@ device pinctrl register, and 0x118 contains the desired value of the pinctrl register. See the device example and static board pins example below for more information. +In case when one register changes more than one pin's mux the +pinctrl-single,bits need to be used which takes three parameters: + + pinctrl-single,bits = <0xdc 0x18, 0xff>; + +Where 0xdc is the offset from the pinctrl register base address for the +device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to +be used when applying this change to the register. + Example: /* SoC common file */ @@ -55,6 +66,15 @@ pmx_wkup: pinmux@4a31e040 { pinctrl-single,function-mask = <0xffff>; }; +control_devconf0: pinmux@48002274 { + compatible = "pinctrl-single"; + reg = <0x48002274 4>; /* Single register */ + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,bit-per-mux; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x5F>; +}; /* board specific .dts file */ @@ -87,6 +107,21 @@ pmx_wkup: pinmux@4a31e040 { }; }; +&control_devconf0 { + mcbsp1_pins: pinmux_mcbsp1_pins { + pinctrl-single,bits = < + 0x00 0x18 0x18 /* FSR/CLKR signal from FSX/CLKX pin */ + >; + }; + + mcbsp2_clks_pins: pinmux_mcbsp2_clks_pins { + pinctrl-single,bits = < + 0x00 0x40 0x40 /* McBSP2 CLKS from McBSP_CLKS pin */ + >; + }; + +}; + &uart2 { pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 35086310b81..aabecfa507b 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -26,7 +26,8 @@ #include "core.h" #define DRIVER_NAME "pinctrl-single" -#define PCS_MUX_NAME "pinctrl-single,pins" +#define PCS_MUX_PINS_NAME "pinctrl-single,pins" +#define PCS_MUX_BITS_NAME "pinctrl-single,bits" #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) #define PCS_OFF_DISABLED ~0U @@ -54,6 +55,7 @@ struct pcs_pingroup { struct pcs_func_vals { void __iomem *reg; unsigned val; + unsigned mask; }; /** @@ -139,6 +141,7 @@ struct pcs_device { unsigned fshift; unsigned foff; unsigned fmax; + bool bits_per_mux; struct pcs_name *names; struct pcs_data pins; struct radix_tree_root pgtree; @@ -332,12 +335,17 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, for (i = 0; i < func->nvals; i++) { struct pcs_func_vals *vals; - unsigned val; + unsigned val, mask; vals = &func->vals[i]; val = pcs->read(vals->reg); - val &= ~pcs->fmask; - val |= (vals->val & pcs->fmask); + if (!vals->mask) + mask = pcs->fmask; + else + mask = pcs->fmask & vals->mask; + + val &= ~mask; + val |= (vals->val & mask); pcs->write(val, vals->reg); } @@ -657,18 +665,29 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, { struct pcs_func_vals *vals; const __be32 *mux; - int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; + int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM; struct pcs_function *function; - mux = of_get_property(np, PCS_MUX_NAME, &size); - if ((!mux) || (size < sizeof(*mux) * 2)) { - dev_err(pcs->dev, "bad data for mux %s\n", - np->name); + if (pcs->bits_per_mux) { + params = 3; + mux = of_get_property(np, PCS_MUX_BITS_NAME, &size); + } else { + params = 2; + mux = of_get_property(np, PCS_MUX_PINS_NAME, &size); + } + + if (!mux) { + dev_err(pcs->dev, "no valid property for %s\n", np->name); + return -EINVAL; + } + + if (size < (sizeof(*mux) * params)) { + dev_err(pcs->dev, "bad data for %s\n", np->name); return -EINVAL; } size /= sizeof(*mux); /* Number of elements in array */ - rows = size / 2; /* Each row is a key value pair */ + rows = size / params; vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); if (!vals) @@ -686,6 +705,10 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, val = be32_to_cpup(mux + index++); vals[found].reg = pcs->base + offset; vals[found].val = val; + if (params == 3) { + val = be32_to_cpup(mux + index++); + vals[found].mask = val; + } pin = pcs_get_pin_by_offset(pcs, offset); if (pin < 0) { @@ -883,6 +906,9 @@ static int __devinit pcs_probe(struct platform_device *pdev) if (ret) pcs->foff = PCS_OFF_DISABLED; + pcs->bits_per_mux = of_property_read_bool(np, + "pinctrl-single,bit-per-mux"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(pcs->dev, "could not get resource\n"); -- cgit v1.2.3-70-g09d2 From 5c56f76995691cf761f66d6d89a00eea80be660c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 20 Jul 2012 19:01:00 +0200 Subject: Document: devicetree: add OF documents for lantiq xway pinctrl Signed-off-by: John Crispin Acked-by: Linus Walleij Cc: devicetree-discuss@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org --- .../bindings/pinctrl/lantiq,xway-pinumx.txt | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt new file mode 100644 index 00000000000..b5469db1d7a --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt @@ -0,0 +1,97 @@ +Lantiq XWAY pinmux controller + +Required properties: +- compatible: "lantiq,pinctrl-xway" or "lantiq,pinctrl-xr9" +- reg: Should contain the physical address and length of the gpio/pinmux + register range + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Lantiq's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those group(s), and two pin configuration parameters: +pull-up and open-drain + +The name of each subnode is not important as long as it is unique; all subnodes +should be enumerated and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +We support 2 types of nodes. + +Definition of mux function groups: + +Required subnode-properties: +- lantiq,groups : An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. +- lantiq,function: A string containing the name of the function to mux to the + group. Valid values for function names are listed below. + +Valid values for group and function names: + + mux groups: + exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1, + ebu wait, nand ale, nand cs1, nand cle, spi, spi_cs1, spi_cs2, spi_cs3, + spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi , gpt1, gpt2, + gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, req1, req2, + req3 + + additional mux groups (XR9 only): + mdio, nand rdy, nand rd, exin3, exin4, gnt4, req4 + + functions: + spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio + + + +Definition of pin configurations: + +Required subnode-properties: +- lantiq,pins : An array of strings. Each string contains the name of a pin. + Valid values for these names are listed below. + +Optional subnode-properties: +- lantiq,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- lantiq,open-drain: Boolean, enables open-drain on the defined pin. + +Valid values for XWAY pin names: + Pinconf pins can be referenced via the names io0-io31. + +Valid values for XR9 pin names: + Pinconf pins can be referenced via the names io0-io55. + +Example: + gpio: pinmux@E100B10 { + compatible = "lantiq,pinctrl-xway"; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + #gpio-cells = <2>; + gpio-controller; + reg = <0xE100B10 0xA0>; + + state_default: pinmux { + stp { + lantiq,groups = "stp"; + lantiq,function = "stp"; + }; + pci { + lantiq,groups = "gnt1"; + lantiq,function = "pci"; + }; + conf_out { + lantiq,pins = "io4", "io5", "io6"; /* stp */ + lantiq,open-drain; + lantiq,pull = <0>; + }; + }; + }; + -- cgit v1.2.3-70-g09d2 From 8e004b47b7645fe8ebe1bb81f75cd8f16650de68 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 22 Jul 2012 09:23:50 +0200 Subject: Document: devicetree: add OF documents for lantiq falcon pinctrl Signed-off-by: John Crispin Signed-off-by: Thomas Langer Acked-by: Linus Walleij Cc: devicetree-discuss@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org --- .../bindings/pinctrl/lantiq,falcon-pinumx.txt | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt new file mode 100644 index 00000000000..daa76895606 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt @@ -0,0 +1,83 @@ +Lantiq FALCON pinmux controller + +Required properties: +- compatible: "lantiq,pinctrl-falcon" +- reg: Should contain the physical address and length of the gpio/pinmux + register range + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Lantiq's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those group(s), and two pin configuration parameters: +pull-up and open-drain + +The name of each subnode is not important as long as it is unique; all subnodes +should be enumerated and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +We support 2 types of nodes. + +Definition of mux function groups: + +Required subnode-properties: +- lantiq,groups : An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. +- lantiq,function: A string containing the name of the function to mux to the + group. Valid values for function names are listed below. + +Valid values for group and function names: + + mux groups: + por, ntr, ntr8k, hrst, mdio, bootled, asc0, spi, spi cs0, spi cs1, i2c, + jtag, slic, pcm, asc1 + + functions: + rst, ntr, mdio, led, asc, spi, i2c, jtag, slic, pcm + + +Definition of pin configurations: + +Required subnode-properties: +- lantiq,pins : An array of strings. Each string contains the name of a pin. + Valid values for these names are listed below. + +Optional subnode-properties: +- lantiq,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down +- lantiq,drive-current: Boolean, enables drive-current +- lantiq,slew-rate: Boolean, enables slew-rate + +Example: + pinmux0 { + compatible = "lantiq,pinctrl-falcon"; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + asc0 { + lantiq,groups = "asc0"; + lantiq,function = "asc"; + }; + ntr { + lantiq,groups = "ntr8k"; + lantiq,function = "ntr"; + }; + i2c { + lantiq,groups = "i2c"; + lantiq,function = "i2c"; + }; + hrst { + lantiq,groups = "hrst"; + lantiq,function = "rst"; + }; + }; + }; -- cgit v1.2.3-70-g09d2 From 1dac6695c683c66d0cff10a84c6ed10dbbaabc18 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Sep 2012 14:59:47 +0200 Subject: ALSA: hda - Allow to pass position_fix=0 explicitly Set the default value of position_fix -1, and allow user passing position_fix=0 explicitly to set the "auto" position-fix mode. Otherwise the auto mode may be switched to others like COMBO of VIACOMBO when the controller prefers it, thus user can't set the auto mode any longer. Also updated the documentation appropriately, too. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 10 ++++++++-- sound/pci/hda/hda_intel.c | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4e4d0bc9816..d90d8ec2853 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -860,8 +860,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. [Multiple options for each card instance] model - force the model name - position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF, - 3 = VIACOMBO, 4 = COMBO) + position_fix - Fix DMA pointer + -1 = system default: choose appropriate one per controller + hardware + 0 = auto: falls back to LPIB when POSBUF doesn't work + 1 = use LPIB + 2 = POSBUF: use position buffer + 3 = VIACOMBO: VIA-specific workaround for capture + 4 = COMBO: use LPIB for playback, auto for capture stream probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) When the bit 8 (0x100) is set, the lower 8 bits are used as the "fixed" codec slots; i.e. the driver probes the diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e1a12c754de..195d8472618 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -64,7 +64,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; static char *model[SNDRV_CARDS]; -static int position_fix[SNDRV_CARDS]; +static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; @@ -88,7 +88,7 @@ module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "DMA pointer read method." - "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); + "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); @@ -2813,6 +2813,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) const struct snd_pci_quirk *q; switch (fix) { + case POS_FIX_AUTO: case POS_FIX_LPIB: case POS_FIX_POSBUF: case POS_FIX_VIACOMBO: -- cgit v1.2.3-70-g09d2 From f3e947867478af9a12b9956bcd000ac7613a8a95 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 12 Sep 2012 11:22:00 +0200 Subject: sched: Remove __ARCH_WANT_INTERRUPTS_ON_CTXSW Now that the last architecture to use this has stopped doing so (ARM, thanks Catalin!) we can remove this complexity from the scheduler core. Signed-off-by: Peter Zijlstra Cc: Oleg Nesterov Cc: Catalin Marinas Link: http://lkml.kernel.org/n/tip-g9p2a1w81xxbrze25v9zpzbf@git.kernel.org Signed-off-by: Ingo Molnar --- Documentation/scheduler/sched-arch.txt | 10 --------- include/linux/sched.h | 5 ----- kernel/fork.c | 4 ---- kernel/sched/core.c | 40 +--------------------------------- kernel/sched/rt.c | 5 ----- kernel/sched/sched.h | 6 ----- 6 files changed, 1 insertion(+), 69 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scheduler/sched-arch.txt b/Documentation/scheduler/sched-arch.txt index 28aa1075e29..b1b8587b86f 100644 --- a/Documentation/scheduler/sched-arch.txt +++ b/Documentation/scheduler/sched-arch.txt @@ -17,16 +17,6 @@ you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file Unlocked context switches introduce only a very minor performance penalty to the core scheduler implementation in the CONFIG_SMP case. -2. Interrupt status -By default, the switch_to arch function is called with interrupts -disabled. Interrupts may be enabled over the call if it is likely to -introduce a significant interrupt latency by adding the line -`#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for -unlocked context switches. This define also implies -`__ARCH_WANT_UNLOCKED_CTXSW`. See arch/arm/include/asm/system.h for an -example. - - CPU idle ======== Your cpu_idle routines need to obey the following rules: diff --git a/include/linux/sched.h b/include/linux/sched.h index f3eebc121eb..60e5e38eee2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -678,11 +678,6 @@ struct signal_struct { * (notably. ptrace) */ }; -/* Context switch must be unlocked if interrupts are to be enabled */ -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW -# define __ARCH_WANT_UNLOCKED_CTXSW -#endif - /* * Bits in flags field of signal_struct. */ diff --git a/kernel/fork.c b/kernel/fork.c index 2c8857e1285..743d48f4d71 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1280,11 +1280,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, #endif #ifdef CONFIG_TRACE_IRQFLAGS p->irq_events = 0; -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW - p->hardirqs_enabled = 1; -#else p->hardirqs_enabled = 0; -#endif p->hardirq_enable_ip = 0; p->hardirq_enable_event = 0; p->hardirq_disable_ip = _THIS_IP_; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c46a011ce5d..8b51b2d9b1f 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1361,25 +1361,6 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu) smp_send_reschedule(cpu); } -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW -static int ttwu_activate_remote(struct task_struct *p, int wake_flags) -{ - struct rq *rq; - int ret = 0; - - rq = __task_rq_lock(p); - if (p->on_cpu) { - ttwu_activate(rq, p, ENQUEUE_WAKEUP); - ttwu_do_wakeup(rq, p, wake_flags); - ret = 1; - } - __task_rq_unlock(rq); - - return ret; - -} -#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ - bool cpus_share_cache(int this_cpu, int that_cpu) { return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); @@ -1440,21 +1421,8 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) * If the owning (remote) cpu is still in the middle of schedule() with * this task as prev, wait until its done referencing the task. */ - while (p->on_cpu) { -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW - /* - * In case the architecture enables interrupts in - * context_switch(), we cannot busy wait, since that - * would lead to deadlocks when an interrupt hits and - * tries to wake up @prev. So bail and do a complete - * remote wakeup. - */ - if (ttwu_activate_remote(p, wake_flags)) - goto stat; -#else + while (p->on_cpu) cpu_relax(); -#endif - } /* * Pairs with the smp_wmb() in finish_lock_switch(). */ @@ -1798,13 +1766,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) prev_state = prev->state; account_switch_vtime(prev); finish_arch_switch(prev); -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW - local_irq_disable(); -#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ perf_event_task_sched_in(prev, current); -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW - local_irq_enable(); -#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ finish_lock_switch(rq, prev); finish_arch_post_lock_switch(); diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index e0b7ba9c040..418feb01344 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1632,11 +1632,6 @@ static int push_rt_task(struct rq *rq) if (!next_task) return 0; -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW - if (unlikely(task_running(rq, next_task))) - return 0; -#endif - retry: if (unlikely(next_task == rq->curr)) { WARN_ON(1); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 09871698e80..7a7db09cfab 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -737,11 +737,7 @@ static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next) */ next->on_cpu = 1; #endif -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW - raw_spin_unlock_irq(&rq->lock); -#else raw_spin_unlock(&rq->lock); -#endif } static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) @@ -755,9 +751,7 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) smp_wmb(); prev->on_cpu = 0; #endif -#ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW local_irq_enable(); -#endif } #endif /* __ARCH_WANT_UNLOCKED_CTXSW */ -- cgit v1.2.3-70-g09d2 From 83b061fc09489fb1b827f65cdca014c37ed224bb Mon Sep 17 00:00:00 2001 From: Michael Kerrisk Date: Tue, 11 Sep 2012 13:20:20 +0200 Subject: cgroup: trivial fixes for Documentation/cgroups/cgroups.txt While reading through Documentation/cgroups/cgroups.txt, I found a number of minor wordos and typos. The patch below is a conservative handling of some of these: it provides just a number of "obviously correct" fixes to the English that improve the readability of the document somewhat. Obviously some more significant fixes could be made to the document, but some of those may not be in the "obviously correct" category. Signed-off-by: Michael Kerrisk Signed-off-by: Tejun Heo --- Documentation/cgroups/cgroups.txt | 68 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index 004fd5a09e1..9e04196c4d7 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -63,9 +63,9 @@ an instance of the cgroup virtual filesystem associated with it. At any one time there may be multiple active hierarchies of task cgroups. Each hierarchy is a partition of all tasks in the system. -User level code may create and destroy cgroups by name in an +User-level code may create and destroy cgroups by name in an instance of the cgroup virtual file system, specify and query to -which cgroup a task is assigned, and list the task pids assigned to +which cgroup a task is assigned, and list the task PIDs assigned to a cgroup. Those creations and assignments only affect the hierarchy associated with that instance of the cgroup file system. @@ -73,7 +73,7 @@ On their own, the only use for cgroups is for simple job tracking. The intention is that other subsystems hook into the generic cgroup support to provide new attributes for cgroups, such as accounting/limiting the resources which processes in a cgroup can -access. For example, cpusets (see Documentation/cgroups/cpusets.txt) allows +access. For example, cpusets (see Documentation/cgroups/cpusets.txt) allow you to associate a set of CPUs and a set of memory nodes with the tasks in each cgroup. @@ -81,11 +81,11 @@ tasks in each cgroup. ---------------------------- There are multiple efforts to provide process aggregations in the -Linux kernel, mainly for resource tracking purposes. Such efforts +Linux kernel, mainly for resource-tracking purposes. Such efforts include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server namespaces. These all require the basic notion of a grouping/partitioning of processes, with newly forked processes ending -in the same group (cgroup) as their parent process. +up in the same group (cgroup) as their parent process. The kernel cgroup patch provides the minimum essential kernel mechanisms required to efficiently implement such groups. It has @@ -128,14 +128,14 @@ following lines: / \ Professors (15%) students (5%) -Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd go -into NFS network class. +Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd goes +into the NFS network class. At the same time Firefox/Lynx will share an appropriate CPU/Memory class depending on who launched it (prof/student). With the ability to classify tasks differently for different resources -(by putting those resource subsystems in different hierarchies) then +(by putting those resource subsystems in different hierarchies), the admin can easily set up a script which receives exec notifications and depending on who is launching the browser he can @@ -146,19 +146,19 @@ a separate cgroup for every browser launched and associate it with appropriate network and other resource class. This may lead to proliferation of such cgroups. -Also lets say that the administrator would like to give enhanced network +Also let's say that the administrator would like to give enhanced network access temporarily to a student's browser (since it is night and the user -wants to do online gaming :)) OR give one of the students simulation -apps enhanced CPU power, +wants to do online gaming :)) OR give one of the student's simulation +apps enhanced CPU power. -With ability to write pids directly to resource classes, it's just a -matter of : +With ability to write PIDs directly to resource classes, it's just a +matter of: # echo pid > /sys/fs/cgroup/network//tasks (after some time) # echo pid > /sys/fs/cgroup/network//tasks -Without this ability, he would have to split the cgroup into +Without this ability, the administrator would have to split the cgroup into multiple separate ones and then associate the new cgroups with the new resource classes. @@ -185,20 +185,20 @@ Control Groups extends the kernel as follows: field of each task_struct using the css_set, anchored at css_set->tasks. - - A cgroup hierarchy filesystem can be mounted for browsing and + - A cgroup hierarchy filesystem can be mounted for browsing and manipulation from user space. - - You can list all the tasks (by pid) attached to any cgroup. + - You can list all the tasks (by PID) attached to any cgroup. The implementation of cgroups requires a few, simple hooks -into the rest of the kernel, none in performance critical paths: +into the rest of the kernel, none in performance-critical paths: - in init/main.c, to initialize the root cgroups and initial css_set at system boot. - in fork and exit, to attach and detach a task from its css_set. -In addition a new file system, of type "cgroup" may be mounted, to +In addition, a new file system of type "cgroup" may be mounted, to enable browsing and modifying the cgroups presently known to the kernel. When mounting a cgroup hierarchy, you may specify a comma-separated list of subsystems to mount as the filesystem mount @@ -231,13 +231,13 @@ as the path relative to the root of the cgroup file system. Each cgroup is represented by a directory in the cgroup file system containing the following files describing that cgroup: - - tasks: list of tasks (by pid) attached to that cgroup. This list - is not guaranteed to be sorted. Writing a thread id into this file + - tasks: list of tasks (by PID) attached to that cgroup. This list + is not guaranteed to be sorted. Writing a thread ID into this file moves the thread into this cgroup. - - cgroup.procs: list of tgids in the cgroup. This list is not - guaranteed to be sorted or free of duplicate tgids, and userspace + - cgroup.procs: list of thread group IDs in the cgroup. This list is + not guaranteed to be sorted or free of duplicate TGIDs, and userspace should sort/uniquify the list if this property is required. - Writing a thread group id into this file moves all threads in that + Writing a thread group ID into this file moves all threads in that group into this cgroup. - notify_on_release flag: run the release agent on exit? - release_agent: the path to use for release notifications (this file @@ -262,7 +262,7 @@ cgroup file system directories. When a task is moved from one cgroup to another, it gets a new css_set pointer - if there's an already existing css_set with the -desired collection of cgroups then that group is reused, else a new +desired collection of cgroups then that group is reused, otherwise a new css_set is allocated. The appropriate existing css_set is located by looking into a hash table. @@ -293,7 +293,7 @@ file system) of the abandoned cgroup. This enables automatic removal of abandoned cgroups. The default value of notify_on_release in the root cgroup at system boot is disabled (0). The default value of other cgroups at creation is the current -value of their parents notify_on_release setting. The default value of +value of their parents' notify_on_release settings. The default value of a cgroup hierarchy's release_agent path is empty. 1.5 What does clone_children do ? @@ -317,7 +317,7 @@ the "cpuset" cgroup subsystem, the steps are something like: 4) Create the new cgroup by doing mkdir's and write's (or echo's) in the /sys/fs/cgroup virtual file system. 5) Start a task that will be the "founding father" of the new job. - 6) Attach that task to the new cgroup by writing its pid to the + 6) Attach that task to the new cgroup by writing its PID to the /sys/fs/cgroup/cpuset/tasks file for that cgroup. 7) fork, exec or clone the job tasks from this founding father task. @@ -345,7 +345,7 @@ and then start a subshell 'sh' in that cgroup: 2.1 Basic Usage --------------- -Creating, modifying, using the cgroups can be done through the cgroup +Creating, modifying, using cgroups can be done through the cgroup virtual filesystem. To mount a cgroup hierarchy with all available subsystems, type: @@ -442,7 +442,7 @@ You can attach the current shell task by echoing 0: # echo 0 > tasks You can use the cgroup.procs file instead of the tasks file to move all -threads in a threadgroup at once. Echoing the pid of any task in a +threads in a threadgroup at once. Echoing the PID of any task in a threadgroup to cgroup.procs causes all tasks in that threadgroup to be be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks in the writing task's threadgroup. @@ -480,7 +480,7 @@ in /proc/mounts and /proc//cgroups. There is mechanism which allows to get notifications about changing status of a cgroup. -To register new notification handler you need: +To register a new notification handler you need to: - create a file descriptor for event notification using eventfd(2); - open a control file to be monitored (e.g. memory.usage_in_bytes); - write " " to cgroup.event_control. @@ -489,7 +489,7 @@ To register new notification handler you need: eventfd will be woken up by control file implementation or when the cgroup is removed. -To unregister notification handler just close eventfd. +To unregister a notification handler just close eventfd. NOTE: Support of notifications should be implemented for the control file. See documentation for the subsystem. @@ -503,7 +503,7 @@ file. See documentation for the subsystem. Each kernel subsystem that wants to hook into the generic cgroup system needs to create a cgroup_subsys object. This contains various methods, which are callbacks from the cgroup system, along -with a subsystem id which will be assigned by the cgroup system. +with a subsystem ID which will be assigned by the cgroup system. Other fields in the cgroup_subsys object include: @@ -517,7 +517,7 @@ Other fields in the cgroup_subsys object include: at system boot. Each cgroup object created by the system has an array of pointers, -indexed by subsystem id; this pointer is entirely managed by the +indexed by subsystem ID; this pointer is entirely managed by the subsystem; the generic cgroup code will never touch this pointer. 3.2 Synchronization @@ -640,7 +640,7 @@ void post_clone(struct cgroup *cgrp) Called during cgroup_create() to do any parameter initialization which might be required before a task could attach. For -example in cpusets, no task may attach before 'cpus' and 'mems' are set +example, in cpusets, no task may attach before 'cpus' and 'mems' are set up. void bind(struct cgroup *root) @@ -680,5 +680,5 @@ A: bash's builtin 'echo' command does not check calls to write() against Q: When I attach processes, only the first of the line gets really attached ! A: We can only return one error code per call to write(). So you should also - put only ONE pid. + put only ONE PID. -- cgit v1.2.3-70-g09d2 From 6e3321631ac2eca99b3289b83ea1f290b1a8bd92 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 5 Sep 2012 12:28:53 -0700 Subject: ARM: msm: Add DT support to msm_timer Add support to setup the MSM timer via information obtained from the devicetree. Signed-off-by: Stephen Boyd [davidb@codeaurora.org: Remove leading zeros] Signed-off-by: David Brown --- .../devicetree/bindings/arm/msm/timer.txt | 38 ++++++++++ arch/arm/mach-msm/common.h | 1 + arch/arm/mach-msm/timer.c | 87 ++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/timer.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/msm/timer.txt b/Documentation/devicetree/bindings/arm/msm/timer.txt new file mode 100644 index 00000000000..8c5907b9cae --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/timer.txt @@ -0,0 +1,38 @@ +* MSM Timer + +Properties: + +- compatible : Should at least contain "qcom,msm-timer". More specific + properties such as "qcom,msm-gpt" and "qcom,msm-dgt" specify a general + purpose timer and a debug timer respectively. + +- interrupts : Interrupt indicating a match event. + +- reg : Specifies the base address of the timer registers. The second region + specifies an optional register used to configure the clock divider. + +- clock-frequency : The frequency of the timer in Hz. + +Optional: + +- cpu-offset : per-cpu offset used when the timer is accessed without the + CPU remapping facilities. The offset is cpu-offset * cpu-nr. + +Example: + + timer@200a004 { + compatible = "qcom,msm-gpt", "qcom,msm-timer"; + interrupts = <1 2 0x301>; + reg = <0x0200a004 0x10>; + clock-frequency = <32768>; + cpu-offset = <0x40000>; + }; + + timer@200a024 { + compatible = "qcom,msm-dgt", "qcom,msm-timer"; + interrupts = <1 3 0x301>; + reg = <0x0200a024 0x10>, + <0x0200a034 0x4>; + clock-frequency = <6750000>; + cpu-offset = <0x40000>; + }; diff --git a/arch/arm/mach-msm/common.h b/arch/arm/mach-msm/common.h index 4c2dd16e659..7d57fb07619 100644 --- a/arch/arm/mach-msm/common.h +++ b/arch/arm/mach-msm/common.h @@ -16,6 +16,7 @@ extern struct sys_timer msm7x01_timer; extern struct sys_timer msm7x30_timer; extern struct sys_timer msm8x60_timer; extern struct sys_timer msm8960_timer; +extern struct sys_timer msm_dt_timer; extern struct sys_timer qsd8x50_timer; #endif diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index ddb87011765..b17a39db991 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include #include #include @@ -216,6 +219,90 @@ err: setup_sched_clock(msm_sched_clock_read, sched_bits, dgt_hz); } +#ifdef CONFIG_OF +static const struct of_device_id msm_dgt_match[] __initconst = { + { .compatible = "qcom,msm-dgt" }, + { }, +}; + +static const struct of_device_id msm_gpt_match[] __initconst = { + { .compatible = "qcom,msm-gpt" }, + { }, +}; + +static void __init msm_dt_timer_init(void) +{ + struct device_node *np; + u32 freq; + int irq; + struct resource res; + u32 percpu_offset; + void __iomem *dgt_clk_ctl; + + np = of_find_matching_node(NULL, msm_gpt_match); + if (!np) { + pr_err("Can't find GPT DT node\n"); + return; + } + + event_base = of_iomap(np, 0); + if (!event_base) { + pr_err("Failed to map event base\n"); + return; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_err("Can't get irq\n"); + return; + } + of_node_put(np); + + np = of_find_matching_node(NULL, msm_dgt_match); + if (!np) { + pr_err("Can't find DGT DT node\n"); + return; + } + + if (of_property_read_u32(np, "cpu-offset", &percpu_offset)) + percpu_offset = 0; + + if (of_address_to_resource(np, 0, &res)) { + pr_err("Failed to parse DGT resource\n"); + return; + } + + source_base = ioremap(res.start + percpu_offset, resource_size(&res)); + if (!source_base) { + pr_err("Failed to map source base\n"); + return; + } + + if (!of_address_to_resource(np, 1, &res)) { + dgt_clk_ctl = ioremap(res.start + percpu_offset, + resource_size(&res)); + if (!dgt_clk_ctl) { + pr_err("Failed to map DGT control base\n"); + return; + } + writel_relaxed(DGT_CLK_CTL_DIV_4, dgt_clk_ctl); + iounmap(dgt_clk_ctl); + } + + if (of_property_read_u32(np, "clock-frequency", &freq)) { + pr_err("Unknown frequency\n"); + return; + } + of_node_put(np); + + msm_timer_init(freq, 32, irq, !!percpu_offset); +} + +struct sys_timer msm_dt_timer = { + .init = msm_dt_timer_init +}; +#endif + static int __init msm_timer_map(phys_addr_t event, phys_addr_t source) { event_base = ioremap(event, SZ_64); -- cgit v1.2.3-70-g09d2 From e7c568e0fd0cf6d9c8ab8ea537ba8f3a3ae7c3d8 Mon Sep 17 00:00:00 2001 From: Peter Moody Date: Thu, 14 Jun 2012 10:04:36 -0700 Subject: ima: audit log hashes This adds an 'audit' policy action which audit logs file measurements. Changelog v6: - use new action flag handling (Dmitry Kasatkin). - removed whitespace (Mimi) Changelog v5: - use audit_log_untrustedstring. Changelog v4: - cleanup digest -> hash conversion. - use filename rather than d_path in ima_audit_measurement. Changelog v3: - Use newly exported audit_log_task_info for logging pid/ppid/uid/etc. - Update the ima_policy ABI documentation. Changelog v2: - Use 'audit' action rather than 'measure_and_audit' to permit auditing in the absence of measuring.. Changelog v1: - Initial posting. Signed-off-by: Peter Moody Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/ima_policy | 2 +- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_api.c | 32 +++++++++++++++++++++++++++++++- security/integrity/ima/ima_main.c | 9 ++++++--- security/integrity/ima/ima_policy.c | 11 +++++++++++ security/integrity/integrity.h | 7 +++++-- 6 files changed, 56 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index dcff8220547..98694661354 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -17,7 +17,7 @@ Description: rule format: action [condition ...] - action: measure | dont_measure | appraise | dont_appraise + action: measure | dont_measure | appraise | dont_appraise | audit condition:= base | lsm base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]] lsm: [[subj_user=] [subj_role=] [subj_type=] diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 48aa0d46d3e..8180adde10b 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -114,6 +114,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file); void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename); +void ima_audit_measurement(struct integrity_iint_cache *iint, + const unsigned char *filename); int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode); void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index f0d60e754b3..b356884fb3e 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -114,7 +114,7 @@ err_out: */ int ima_get_action(struct inode *inode, int mask, int function) { - int flags = IMA_MEASURE | IMA_APPRAISE; + int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; if (!ima_appraise) flags &= ~IMA_APPRAISE; @@ -207,3 +207,33 @@ void ima_store_measurement(struct integrity_iint_cache *iint, if (result < 0) kfree(entry); } + +void ima_audit_measurement(struct integrity_iint_cache *iint, + const unsigned char *filename) +{ + struct audit_buffer *ab; + char hash[(IMA_DIGEST_SIZE * 2) + 1]; + int i; + + if (iint->flags & IMA_AUDITED) + return; + + for (i = 0; i < IMA_DIGEST_SIZE; i++) + hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); + hash[i * 2] = '\0'; + + ab = audit_log_start(current->audit_context, GFP_KERNEL, + AUDIT_INTEGRITY_RULE); + if (!ab) + return; + + audit_log_format(ab, "file="); + audit_log_untrustedstring(ab, filename); + audit_log_format(ab, " hash="); + audit_log_untrustedstring(ab, hash); + + audit_log_task_info(ab, current); + audit_log_end(ab); + + iint->flags |= IMA_AUDITED; +} diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 5da08b75d36..73c9a268253 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -156,8 +156,8 @@ static int process_measurement(struct file *file, const unsigned char *filename, if (!ima_initialized || !S_ISREG(inode->i_mode)) return 0; - /* Determine if in appraise/measurement policy, - * returns IMA_MEASURE, IMA_APPRAISE bitmask. */ + /* Determine if in appraise/audit/measurement policy, + * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */ action = ima_get_action(inode, mask, function); if (!action) return 0; @@ -171,7 +171,8 @@ static int process_measurement(struct file *file, const unsigned char *filename, goto out; /* Determine if already appraised/measured based on bitmask - * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED) */ + * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, + * IMA_AUDIT, IMA_AUDITED) */ iint->flags |= action; action &= ~((iint->flags & IMA_DONE_MASK) >> 1); @@ -202,6 +203,8 @@ static int process_measurement(struct file *file, const unsigned char *filename, if (action & IMA_APPRAISE) rc = ima_appraise_measurement(iint, file, !pathname ? filename : pathname); + if (action & IMA_AUDIT) + ima_audit_measurement(iint, !pathname ? filename : pathname); kfree(pathbuf); out: mutex_unlock(&inode->i_mutex); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index f46f685a171..cda903131db 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -31,6 +31,7 @@ #define DONT_MEASURE 0x0002 #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ #define DONT_APPRAISE 0x0008 +#define AUDIT 0x0040 #define MAX_LSM_RULES 6 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, @@ -277,6 +278,7 @@ enum { Opt_err = -1, Opt_measure = 1, Opt_dont_measure, Opt_appraise, Opt_dont_appraise, + Opt_audit, Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner @@ -287,6 +289,7 @@ static match_table_t policy_tokens = { {Opt_dont_measure, "dont_measure"}, {Opt_appraise, "appraise"}, {Opt_dont_appraise, "dont_appraise"}, + {Opt_audit, "audit"}, {Opt_obj_user, "obj_user=%s"}, {Opt_obj_role, "obj_role=%s"}, {Opt_obj_type, "obj_type=%s"}, @@ -379,6 +382,14 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->action = DONT_APPRAISE; break; + case Opt_audit: + ima_log_string(ab, "action", "audit"); + + if (entry->action != UNKNOWN) + result = -EINVAL; + + entry->action = AUDIT; + break; case Opt_func: ima_log_string(ab, "func", args[0].from); diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 564ba7db5f6..403ba319a06 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -22,12 +22,15 @@ #define IMA_APPRAISED 0x0008 /*#define IMA_COLLECT 0x0010 do not use this flag */ #define IMA_COLLECTED 0x0020 +#define IMA_AUDIT 0x0040 +#define IMA_AUDITED 0x0080 /* iint cache flags */ #define IMA_DIGSIG 0x0100 -#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE) -#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_COLLECTED) +#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) +#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ + | IMA_COLLECTED) enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, -- cgit v1.2.3-70-g09d2 From 1248c7cb66d734b60efed41be7c7b86909812c0e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 10 Aug 2012 05:45:51 -0300 Subject: [media] V4L2 spec: document the new DV controls and ioctls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/biblio.xml | 40 +++++++ Documentation/DocBook/media/v4l/controls.xml | 161 +++++++++++++++++++++++++++ Documentation/DocBook/media/v4l/v4l2.xml | 1 + 3 files changed, 202 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml index 18b6fc9ff58..d2eb79e41a0 100644 --- a/Documentation/DocBook/media/v4l/biblio.xml +++ b/Documentation/DocBook/media/v4l/biblio.xml @@ -226,4 +226,44 @@ in the frequency range from 87,5 to 108,0 MHz VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT) + + EDID + + Video Electronics Standards Association +(http://www.vesa.org) + + VESA Enhanced Extended Display Identification Data Standard + Release A, Revision 2 + + + + HDCP + + Digital Content Protection LLC +(http://www.digital-cp.com) + + High-bandwidth Digital Content Protection System + Revision 1.3 + + + + HDMI + + HDMI Licensing LLC +(http://www.hdmi.org) + + High-Definition Multimedia Interface + Specification Version 1.4a + + + + DP + + Video Electronics Standards Association +(http://www.vesa.org) + + VESA DisplayPort Standard + Version 1, Revision 2 + + diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 93b9c6872e5..272a5f71850 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4273,4 +4273,165 @@ interface and may change in the future.
+ +
+ Digital Video Control Reference + + + Experimental + + This is an experimental interface and may + change in the future. + + + + The Digital Video control class is intended to control receivers + and transmitters for VGA, + DVI + (Digital Visual Interface), HDMI () and DisplayPort (). + These controls are generally expected to be private to the receiver or transmitter + subdevice that implements them, so they are only exposed on the + /dev/v4l-subdev* device node. + + + Note that these devices can have multiple input or output pads which are + hooked up to e.g. HDMI connectors. Even though the subdevice will receive or + transmit video from/to only one of those pads, the other pads can still be + active when it comes to EDID (Extended Display Identification Data, + ) and HDCP (High-bandwidth Digital Content + Protection System, ) processing, allowing the device + to do the fairly slow EDID/HDCP handling in advance. This allows for quick + switching between connectors. + + These pads appear in several of the controls in this section as + bitmasks, one bit for each pad. Bit 0 corresponds to pad 0, bit 1 to pad 1, + etc. The maximum value of the control is the set of valid pads. + + + Digital Video Control IDs + + + + + + + + + + + ID + Type + Description + + + + + + V4L2_CID_DV_CLASS + class + + + The Digital Video class descriptor. + + + V4L2_CID_DV_TX_HOTPLUG + bitmask + + + Many connectors have a hotplug pin which is high + if EDID information is available from the source. This control shows the + state of the hotplug pin as seen by the transmitter. + Each bit corresponds to an output pad on the transmitter. If an output pad + does not have an associated hotplug pin, then the bit for that pad will be 0. + This read-only control is applicable to DVI-D, HDMI and DisplayPort connectors. + + + + V4L2_CID_DV_TX_RXSENSE + bitmask + + + Rx Sense is the detection of pull-ups on the TMDS + clock lines. This normally means that the sink has left/entered standby (i.e. + the transmitter can sense that the receiver is ready to receive video). + Each bit corresponds to an output pad on the transmitter. If an output pad + does not have an associated Rx Sense, then the bit for that pad will be 0. + This read-only control is applicable to DVI-D and HDMI devices. + + + + V4L2_CID_DV_TX_EDID_PRESENT + bitmask + + + When the transmitter sees the hotplug signal from the + receiver it will attempt to read the EDID. If set, then the transmitter has read + at least the first block (= 128 bytes). + Each bit corresponds to an output pad on the transmitter. If an output pad + does not support EDIDs, then the bit for that pad will be 0. + This read-only control is applicable to VGA, DVI-A/D, HDMI and DisplayPort connectors. + + + + V4L2_CID_DV_TX_MODE + enum v4l2_dv_tx_mode + + + HDMI transmitters can transmit in DVI-D mode (just video) + or in HDMI mode (video + audio + auxiliary data). This control selects which mode + to use: V4L2_DV_TX_MODE_DVI_D or V4L2_DV_TX_MODE_HDMI. + This control is applicable to HDMI connectors. + + + + V4L2_CID_DV_TX_RGB_RANGE + enum v4l2_dv_rgb_range + + + Select the quantization range for RGB output. V4L2_DV_RANGE_AUTO + follows the RGB quantization range specified in the standard for the video interface + (ie. for HDMI). V4L2_DV_RANGE_LIMITED and V4L2_DV_RANGE_FULL override the standard + to be compatible with sinks that have not implemented the standard correctly + (unfortunately quite common for HDMI and DVI-D). Full range allows all possible values to be + used whereas limited range sets the range to (16 << (N-8)) - (235 << (N-8)) + where N is the number of bits per component. + This control is applicable to VGA, DVI-A/D, HDMI and DisplayPort connectors. + + + + V4L2_CID_DV_RX_POWER_PRESENT + bitmask + + + Detects whether the receiver receives power from the source + (e.g. HDMI carries 5V on one of the pins). This is often used to power an eeprom + which contains EDID information, such that the source can read the EDID even if + the sink is in standby/power off. + Each bit corresponds to an input pad on the transmitter. If an input pad + cannot detect whether power is present, then the bit for that pad will be 0. + This read-only control is applicable to DVI-D, HDMI and DisplayPort connectors. + + + + V4L2_CID_DV_RX_RGB_RANGE + enum v4l2_dv_rgb_range + + + Select the quantization range for RGB input. V4L2_DV_RANGE_AUTO + follows the RGB quantization range specified in the standard for the video interface + (ie. for HDMI). V4L2_DV_RANGE_LIMITED and V4L2_DV_RANGE_FULL override the standard + to be compatible with sources that have not implemented the standard correctly + (unfortunately quite common for HDMI and DVI-D). Full range allows all possible values to be + used whereas limited range sets the range to (16 << (N-8)) - (235 << (N-8)) + where N is the number of bits per component. + This control is applicable to VGA, DVI-A/D, HDMI and DisplayPort connectors. + + + + + +
+ +
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 0292ed10688..10ccde9d16d 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -581,6 +581,7 @@ and discussions on the V4L mailing list. &sub-subdev-enum-frame-size; &sub-subdev-enum-mbus-code; &sub-subdev-g-crop; + &sub-subdev-g-edid; &sub-subdev-g-fmt; &sub-subdev-g-frame-interval; &sub-subdev-g-selection; -- cgit v1.2.3-70-g09d2 From 3c8139477bc55166fa4c125209d193bd9851af3c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Sep 2012 17:06:34 -0300 Subject: [media] DocBook: Fix docbook compilation changeset 1248c7cb66d734b60efed41be7c7b86909812c0e broke html compilation: Documentation/DocBook/v4l2.xml:584: parser error : Entity 'sub-subdev-g-edid' not defined Documentation/DocBook/v4l2.xml:626: parser error : chunk is not well balanced Documentation/DocBook/media_api.xml:74: parser error : Failure to process entity sub-v4l2 Documentation/DocBook/media_api.xml:74: parser error : Entity 'sub-v4l2' not defined I suspect that one file was simply missed at the patch. Yet, keeping it broken is a very bad idea, so we should either remove the broken patch or to remove just the invalid include. Let's take the latter approach. Due to that, a warning is now produced: Error: no ID for constraint linkend: v4l2-subdev-edid. Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/v4l2.xml | 1 - 1 file changed, 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 10ccde9d16d..0292ed10688 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -581,7 +581,6 @@ and discussions on the V4L mailing list. &sub-subdev-enum-frame-size; &sub-subdev-enum-mbus-code; &sub-subdev-g-crop; - &sub-subdev-g-edid; &sub-subdev-g-fmt; &sub-subdev-g-frame-interval; &sub-subdev-g-selection; -- cgit v1.2.3-70-g09d2 From 355a4d01bd74bdd7b9dd9adeec683b2e3dd9549b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 18 Aug 2012 12:32:19 -0300 Subject: [media] media-api-docs: Documented V4L2_TUNER_CAP_HWSEEK_PROG_LIM in G_TUNER docs Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-g-tuner.xml | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml index 701138f1209..6cc82010c73 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml @@ -354,6 +354,12 @@ radio tuners. The &VIDIOC-ENUM-FREQ-BANDS; ioctl can be used to enumerate the available frequency bands.
+ + V4L2_TUNER_CAP_HWSEEK_PROG_LIM + 0x0800 + The range to search when using the hardware seek functionality + is programmable, see &VIDIOC-S-HW-FREQ-SEEK; for details. + -- cgit v1.2.3-70-g09d2 From 004c15a68076f5bdc343bed92efed81087cecbfb Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Sun, 19 Aug 2012 18:07:55 -0700 Subject: mfd: dt: tps6586x: Add power off control Add DT property "ti,system-power-controller" telling whether or not this pmic is in charge of controlling the system power, so the power off routine can be hooked up to system call "pm_power_off". Based on the work by: Dan Willemsen Signed-off-by: Bill Huang Tested-by: Stephen Warren Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/regulator/tps6586x.txt | 6 ++++++ drivers/mfd/tps6586x.c | 19 +++++++++++++++++++ include/linux/mfd/tps6586x.h | 1 + 3 files changed, 26 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt index d156e1b5db1..03dfa4e0aa7 100644 --- a/Documentation/devicetree/bindings/regulator/tps6586x.txt +++ b/Documentation/devicetree/bindings/regulator/tps6586x.txt @@ -18,6 +18,10 @@ Required properties: - vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8 - vinldo9-supply: The input supply for the LDO9 +Optional properties: +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. + Each regulator is defined using the standard binding for regulators. Example: @@ -30,6 +34,8 @@ Example: #gpio-cells = <2>; gpio-controller; + ti,system-power-controller; + sm0-supply = <&some_reg>; sm1-supply = <&some_reg>; sm2-supply = <&some_reg>; diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 5f58370ccf5..95ef40754dd 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -29,6 +29,10 @@ #include #include +#define TPS6586X_SUPPLYENE 0x14 +#define EXITSLREQ_BIT BIT(1) +#define SLEEP_MODE_BIT BIT(3) + /* interrupt control registers */ #define TPS6586X_INT_ACK1 0xb5 #define TPS6586X_INT_ACK2 0xb6 @@ -409,6 +413,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien pdata->subdevs = devs; pdata->gpio_base = -1; pdata->irq_base = -1; + pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller"); return pdata; } @@ -441,6 +446,15 @@ static const struct regmap_config tps6586x_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static struct device *tps6586x_dev; +static void tps6586x_power_off(void) +{ + if (tps6586x_clr_bits(tps6586x_dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT)) + return; + + tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); +} + static int __devinit tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -506,6 +520,11 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, goto err_add_devs; } + if (pdata->pm_off && !pm_power_off) { + tps6586x_dev = &client->dev; + pm_power_off = tps6586x_power_off; + } + return 0; err_add_devs: diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index f350fd0ba1d..08f109f0f81 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -77,6 +77,7 @@ struct tps6586x_platform_data { int gpio_base; int irq_base; + bool pm_off; }; /* -- cgit v1.2.3-70-g09d2 From b079fa72069ba7f754ba8bdf737335abdb971b67 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Sun, 19 Aug 2012 18:07:56 -0700 Subject: mfd: dt: tps65910: Add power off control Add DT property "ti,system-power-controller" telling whether or not this pmic is in charge of controlling the system power, so the power off routine can be hooked up to system call "pm_power_off". Based on the work by: Dan Willemsen Signed-off-by: Bill Huang Tested-by: Stephen Warren Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/tps65910.txt | 4 ++++ drivers/mfd/tps65910.c | 22 ++++++++++++++++++++++ include/linux/mfd/tps65910.h | 3 +++ 3 files changed, 29 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/tps65910.txt b/Documentation/devicetree/bindings/mfd/tps65910.txt index db03599ae4d..2e3304888ff 100644 --- a/Documentation/devicetree/bindings/mfd/tps65910.txt +++ b/Documentation/devicetree/bindings/mfd/tps65910.txt @@ -59,6 +59,8 @@ Optional properties: in TPS6591X datasheet) - ti,en-gpio-sleep: enable sleep control for gpios There should be 9 entries here, one for each gpio. +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. Regulator Optional properties: - ti,regulator-ext-sleep-control: enable external sleep @@ -79,6 +81,8 @@ Example: #interrupt-cells = <2>; interrupt-controller; + ti,system-power-controller; + ti,vmbch-threshold = 0; ti,vmbch2-threshold = 0; ti,en-ck32k-xtal; diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index d3ce4d569de..ca902943cfa 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -198,6 +198,8 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, board_info->irq = client->irq; board_info->irq_base = -1; + board_info->pm_off = of_property_read_bool(np, + "ti,system-power-controller"); return board_info; } @@ -210,6 +212,21 @@ struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, } #endif +static struct i2c_client *tps65910_i2c_client; +static void tps65910_power_off(void) +{ + struct tps65910 *tps65910; + + tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev); + + if (tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_PWR_OFF_MASK) < 0) + return; + + tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_ON_MASK); +} + static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -267,6 +284,11 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_ck32k_init(tps65910, pmic_plat_data); tps65910_sleepinit(tps65910, pmic_plat_data); + if (pmic_plat_data->pm_off && !pm_power_off) { + tps65910_i2c_client = i2c; + pm_power_off = tps65910_power_off; + } + return ret; } diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index 9bf8767818b..ac772b36a1b 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -366,6 +366,8 @@ /*Register DEVCTRL (0x80) register.RegisterDescription */ +#define DEVCTRL_PWR_OFF_MASK 0x80 +#define DEVCTRL_PWR_OFF_SHIFT 7 #define DEVCTRL_RTC_PWDN_MASK 0x40 #define DEVCTRL_RTC_PWDN_SHIFT 6 #define DEVCTRL_CK32K_CTRL_MASK 0x20 @@ -809,6 +811,7 @@ struct tps65910_board { int vmbch2_threshold; bool en_ck32k_xtal; bool en_dev_slp; + bool pm_off; struct tps65910_sleep_keepon_data *slp_keepon; bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO]; unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS]; -- cgit v1.2.3-70-g09d2 From 00e4b1975bbcd10445808cec0a3a1442e8deca53 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 24 Aug 2012 05:39:39 +0000 Subject: dt/misc: add bindings documentation for ifm camera sensor interface IFM O2D cameras use special sensor bus interface glue-logic to connect camera sensors to mpc5200 LocalPlus bus. Add device tree bindings documentation for it. Signed-off-by: Anatolij Gustschin --- Documentation/devicetree/bindings/misc/ifm-csi.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/ifm-csi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/misc/ifm-csi.txt b/Documentation/devicetree/bindings/misc/ifm-csi.txt new file mode 100644 index 00000000000..5bdfffb0b9f --- /dev/null +++ b/Documentation/devicetree/bindings/misc/ifm-csi.txt @@ -0,0 +1,41 @@ +IFM camera sensor interface on mpc5200 LocalPlus bus + +Required properties: +- compatible: "ifm,o2d-csi" +- reg: specifies sensor chip select number and associated address range +- interrupts: external interrupt line number and interrupt sense mode + of the interrupt line signaling frame valid events +- gpios: three gpio-specifiers for "capture", "reset" and "master enable" + GPIOs (strictly in this order). +- ifm,csi-clk-handle: the phandle to a node in the DT describing the sensor + clock generator. This node is usually a general purpose timer controller. +- ifm,csi-addr-bus-width: address bus width (valid values are 16, 24, 25) +- ifm,csi-data-bus-width: data bus width (valid values are 8 and 16) +- ifm,csi-wait-cycles: sensor bus wait cycles + +Optional properties: +- ifm,csi-byte-swap: if this property is present, the byte swapping on + the bus will be enabled. + +Example: + + csi@3,0 { + compatible = "ifm,o2d-csi"; + reg = <3 0 0x00100000>; /* CS 3, 1 MiB range */ + interrupts = <1 1 2>; /* IRQ1, edge falling */ + + ifm,csi-clk-handle = <&timer7>; + gpios = <&gpio_simple 23 0 /* image_capture */ + &gpio_simple 26 0 /* image_reset */ + &gpio_simple 29 0>; /* image_master_en */ + + ifm,csi-addr-bus-width = <24>; + ifm,csi-data-bus-width = <8>; + ifm,csi-wait-cycles = <0>; + }; + +The base address of the used chip select is specified in the +ranges property of the parent localbus node, for example: + + ranges = <0 0 0xff000000 0x01000000 + 3 0 0xe3000000 0x00100000>; -- cgit v1.2.3-70-g09d2 From a3b2924547a79cb6dba683d737501c01476f9fb3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 24 Aug 2012 15:12:11 +0200 Subject: ARM: ep93xx: move platform_data definitions Platform data for device drivers should be defined in include/linux/platform_data/*.h, not in the architecture and platform specific directories. This moves such data out of the ep93xx include directories Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Acked-by: Greg Kroah-Hartman Acked-by: Nicolas Pitre Acked-by: Hartley Sweeten Acked-by: Ryan Mallon Acked-by: Vinod Koul Cc: Grant Likely Cc: Jeff Garzik Cc: Dan Williams Cc: Dmitry Torokhov Cc: Florian Tobias Schandinat Cc: Liam Girdwood Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Mika Westerberg Cc: Axel Lin --- Documentation/spi/ep93xx_spi | 2 +- arch/arm/mach-ep93xx/core.c | 6 +- arch/arm/mach-ep93xx/dma.c | 2 +- arch/arm/mach-ep93xx/edb93xx.c | 4 +- arch/arm/mach-ep93xx/include/mach/dma.h | 93 ----------------------- arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h | 35 --------- arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h | 29 ------- arch/arm/mach-ep93xx/include/mach/fb.h | 56 -------------- arch/arm/mach-ep93xx/simone.c | 2 +- arch/arm/mach-ep93xx/snappercl15.c | 2 +- arch/arm/mach-ep93xx/vision_ep9307.c | 4 +- drivers/ata/pata_ep93xx.c | 2 +- drivers/dma/ep93xx_dma.c | 2 +- drivers/input/keyboard/ep93xx_keypad.c | 2 +- drivers/spi/spi-ep93xx.c | 4 +- drivers/video/ep93xx-fb.c | 2 +- include/linux/platform_data/dma-ep93xx.h | 93 +++++++++++++++++++++++ include/linux/platform_data/keypad-ep93xx.h | 35 +++++++++ include/linux/platform_data/spi-ep93xx.h | 29 +++++++ include/linux/platform_data/video-ep93xx.h | 56 ++++++++++++++ sound/soc/ep93xx/ep93xx-ac97.c | 2 +- sound/soc/ep93xx/ep93xx-i2s.c | 2 +- sound/soc/ep93xx/ep93xx-pcm.c | 2 +- 23 files changed, 233 insertions(+), 233 deletions(-) delete mode 100644 arch/arm/mach-ep93xx/include/mach/dma.h delete mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h delete mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h delete mode 100644 arch/arm/mach-ep93xx/include/mach/fb.h create mode 100644 include/linux/platform_data/dma-ep93xx.h create mode 100644 include/linux/platform_data/keypad-ep93xx.h create mode 100644 include/linux/platform_data/spi-ep93xx.h create mode 100644 include/linux/platform_data/video-ep93xx.h (limited to 'Documentation') diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi index d8eb01c15db..832ddce6e5f 100644 --- a/Documentation/spi/ep93xx_spi +++ b/Documentation/spi/ep93xx_spi @@ -26,7 +26,7 @@ arch/arm/mach-ep93xx/ts72xx.c: #include #include -#include +#include /* this is our GPIO line used for chip select */ #define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9 diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 4afe52aaaff..e85bf17f2d2 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -36,9 +36,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/arch/arm/mach-ep93xx/dma.c b/arch/arm/mach-ep93xx/dma.c index 16976d7bdc8..d8bfd02f504 100644 --- a/arch/arm/mach-ep93xx/dma.c +++ b/arch/arm/mach-ep93xx/dma.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include "soc.h" diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index 337ab7cf4c1..b8f53d57a29 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -35,8 +35,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/arch/arm/mach-ep93xx/include/mach/dma.h b/arch/arm/mach-ep93xx/include/mach/dma.h deleted file mode 100644 index e82c642fa53..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/dma.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#include -#include -#include - -/* - * M2P channels. - * - * Note that these values are also directly used for setting the PPALLOC - * register. - */ -#define EP93XX_DMA_I2S1 0 -#define EP93XX_DMA_I2S2 1 -#define EP93XX_DMA_AAC1 2 -#define EP93XX_DMA_AAC2 3 -#define EP93XX_DMA_AAC3 4 -#define EP93XX_DMA_I2S3 5 -#define EP93XX_DMA_UART1 6 -#define EP93XX_DMA_UART2 7 -#define EP93XX_DMA_UART3 8 -#define EP93XX_DMA_IRDA 9 -/* M2M channels */ -#define EP93XX_DMA_SSP 10 -#define EP93XX_DMA_IDE 11 - -/** - * struct ep93xx_dma_data - configuration data for the EP93xx dmaengine - * @port: peripheral which is requesting the channel - * @direction: TX/RX channel - * @name: optional name for the channel, this is displayed in /proc/interrupts - * - * This information is passed as private channel parameter in a filter - * function. Note that this is only needed for slave/cyclic channels. For - * memcpy channels %NULL data should be passed. - */ -struct ep93xx_dma_data { - int port; - enum dma_transfer_direction direction; - const char *name; -}; - -/** - * struct ep93xx_dma_chan_data - platform specific data for a DMA channel - * @name: name of the channel, used for getting the right clock for the channel - * @base: mapped registers - * @irq: interrupt number used by this channel - */ -struct ep93xx_dma_chan_data { - const char *name; - void __iomem *base; - int irq; -}; - -/** - * struct ep93xx_dma_platform_data - platform data for the dmaengine driver - * @channels: array of channels which are passed to the driver - * @num_channels: number of channels in the array - * - * This structure is passed to the DMA engine driver via platform data. For - * M2P channels, contract is that even channels are for TX and odd for RX. - * There is no requirement for the M2M channels. - */ -struct ep93xx_dma_platform_data { - struct ep93xx_dma_chan_data *channels; - size_t num_channels; -}; - -static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan) -{ - return !strcmp(dev_name(chan->device->dev), "ep93xx-dma-m2p"); -} - -/** - * ep93xx_dma_chan_direction - returns direction the channel can be used - * @chan: channel - * - * This function can be used in filter functions to find out whether the - * channel supports given DMA direction. Only M2P channels have such - * limitation, for M2M channels the direction is configurable. - */ -static inline enum dma_transfer_direction -ep93xx_dma_chan_direction(struct dma_chan *chan) -{ - if (!ep93xx_dma_chan_is_m2p(chan)) - return DMA_NONE; - - /* even channels are for TX, odd for RX */ - return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; -} - -#endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h deleted file mode 100644 index 1e2f4e97f42..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h - */ - -#ifndef __ASM_ARCH_EP93XX_KEYPAD_H -#define __ASM_ARCH_EP93XX_KEYPAD_H - -struct matrix_keymap_data; - -/* flags for the ep93xx_keypad driver */ -#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */ -#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */ -#define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */ -#define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */ -#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */ -#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */ - -/** - * struct ep93xx_keypad_platform_data - platform specific device structure - * @keymap_data: pointer to &matrix_keymap_data - * @debounce: debounce start count; terminal count is 0xff - * @prescale: row/column counter pre-scaler load value - * @flags: see above - */ -struct ep93xx_keypad_platform_data { - struct matrix_keymap_data *keymap_data; - unsigned int debounce; - unsigned int prescale; - unsigned int flags; -}; - -#define EP93XX_MATRIX_ROWS (8) -#define EP93XX_MATRIX_COLS (8) - -#endif /* __ASM_ARCH_EP93XX_KEYPAD_H */ diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h deleted file mode 100644 index 9bb63ac13f0..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __ASM_MACH_EP93XX_SPI_H -#define __ASM_MACH_EP93XX_SPI_H - -struct spi_device; - -/** - * struct ep93xx_spi_info - EP93xx specific SPI descriptor - * @num_chipselect: number of chip selects on this board, must be - * at least one - * @use_dma: use DMA for the transfers - */ -struct ep93xx_spi_info { - int num_chipselect; - bool use_dma; -}; - -/** - * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device - * @setup: setup the chip select mechanism - * @cleanup: cleanup the chip select mechanism - * @cs_control: control the device chip select - */ -struct ep93xx_spi_chip_ops { - int (*setup)(struct spi_device *spi); - void (*cleanup)(struct spi_device *spi); - void (*cs_control)(struct spi_device *spi, int value); -}; - -#endif /* __ASM_MACH_EP93XX_SPI_H */ diff --git a/arch/arm/mach-ep93xx/include/mach/fb.h b/arch/arm/mach-ep93xx/include/mach/fb.h deleted file mode 100644 index d5ae11d7c45..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/fb.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/fb.h - */ - -#ifndef __ASM_ARCH_EP93XXFB_H -#define __ASM_ARCH_EP93XXFB_H - -struct platform_device; -struct fb_videomode; -struct fb_info; - -#define EP93XXFB_USE_MODEDB 0 - -/* VideoAttributes flags */ -#define EP93XXFB_STATE_MACHINE_ENABLE (1 << 0) -#define EP93XXFB_PIXEL_CLOCK_ENABLE (1 << 1) -#define EP93XXFB_VSYNC_ENABLE (1 << 2) -#define EP93XXFB_PIXEL_DATA_ENABLE (1 << 3) -#define EP93XXFB_COMPOSITE_SYNC (1 << 4) -#define EP93XXFB_SYNC_VERT_HIGH (1 << 5) -#define EP93XXFB_SYNC_HORIZ_HIGH (1 << 6) -#define EP93XXFB_SYNC_BLANK_HIGH (1 << 7) -#define EP93XXFB_PCLK_FALLING (1 << 8) -#define EP93XXFB_ENABLE_AC (1 << 9) -#define EP93XXFB_ENABLE_LCD (1 << 10) -#define EP93XXFB_ENABLE_CCIR (1 << 12) -#define EP93XXFB_USE_PARALLEL_INTERFACE (1 << 13) -#define EP93XXFB_ENABLE_INTERRUPT (1 << 14) -#define EP93XXFB_USB_INTERLACE (1 << 16) -#define EP93XXFB_USE_EQUALIZATION (1 << 17) -#define EP93XXFB_USE_DOUBLE_HORZ (1 << 18) -#define EP93XXFB_USE_DOUBLE_VERT (1 << 19) -#define EP93XXFB_USE_BLANK_PIXEL (1 << 20) -#define EP93XXFB_USE_SDCSN0 (0 << 21) -#define EP93XXFB_USE_SDCSN1 (1 << 21) -#define EP93XXFB_USE_SDCSN2 (2 << 21) -#define EP93XXFB_USE_SDCSN3 (3 << 21) - -#define EP93XXFB_ENABLE (EP93XXFB_STATE_MACHINE_ENABLE | \ - EP93XXFB_PIXEL_CLOCK_ENABLE | \ - EP93XXFB_VSYNC_ENABLE | \ - EP93XXFB_PIXEL_DATA_ENABLE) - -struct ep93xxfb_mach_info { - unsigned int num_modes; - const struct fb_videomode *modes; - const struct fb_videomode *default_mode; - int bpp; - unsigned int flags; - - int (*setup)(struct platform_device *pdev); - void (*teardown)(struct platform_device *pdev); - void (*blank)(int blank_mode, struct fb_info *info); -}; - -#endif /* __ASM_ARCH_EP93XXFB_H */ diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index 33dc0791741..0eb3f17a6fa 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c index 01abd3516a7..50043eef1cf 100644 --- a/arch/arm/mach-ep93xx/snappercl15.c +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 2905a4929bd..ba92e25e301 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -30,8 +30,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index 6ef2e3741f7..e056406d6a1 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #define DRV_NAME "ep93xx-ide" diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index c64917ec313..4aeaea77f72 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include "dmaengine.h" diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index c46fc818546..7363402de8d 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -29,7 +29,7 @@ #include #include -#include +#include /* * Keypad Interface Register offsets diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index f97f1d24880..3a219599612 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -31,8 +31,8 @@ #include #include -#include -#include +#include +#include #define SSPCR0 0x0000 #define SSPCR0_MODE_SHIFT 6 diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index 345d9623097..f2c092da84b 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -24,7 +24,7 @@ #include #include -#include +#include /* Vertical Frame Timing Registers */ #define EP93XXFB_VLINES_TOTAL 0x0000 /* SW locked */ diff --git a/include/linux/platform_data/dma-ep93xx.h b/include/linux/platform_data/dma-ep93xx.h new file mode 100644 index 00000000000..e82c642fa53 --- /dev/null +++ b/include/linux/platform_data/dma-ep93xx.h @@ -0,0 +1,93 @@ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#include +#include +#include + +/* + * M2P channels. + * + * Note that these values are also directly used for setting the PPALLOC + * register. + */ +#define EP93XX_DMA_I2S1 0 +#define EP93XX_DMA_I2S2 1 +#define EP93XX_DMA_AAC1 2 +#define EP93XX_DMA_AAC2 3 +#define EP93XX_DMA_AAC3 4 +#define EP93XX_DMA_I2S3 5 +#define EP93XX_DMA_UART1 6 +#define EP93XX_DMA_UART2 7 +#define EP93XX_DMA_UART3 8 +#define EP93XX_DMA_IRDA 9 +/* M2M channels */ +#define EP93XX_DMA_SSP 10 +#define EP93XX_DMA_IDE 11 + +/** + * struct ep93xx_dma_data - configuration data for the EP93xx dmaengine + * @port: peripheral which is requesting the channel + * @direction: TX/RX channel + * @name: optional name for the channel, this is displayed in /proc/interrupts + * + * This information is passed as private channel parameter in a filter + * function. Note that this is only needed for slave/cyclic channels. For + * memcpy channels %NULL data should be passed. + */ +struct ep93xx_dma_data { + int port; + enum dma_transfer_direction direction; + const char *name; +}; + +/** + * struct ep93xx_dma_chan_data - platform specific data for a DMA channel + * @name: name of the channel, used for getting the right clock for the channel + * @base: mapped registers + * @irq: interrupt number used by this channel + */ +struct ep93xx_dma_chan_data { + const char *name; + void __iomem *base; + int irq; +}; + +/** + * struct ep93xx_dma_platform_data - platform data for the dmaengine driver + * @channels: array of channels which are passed to the driver + * @num_channels: number of channels in the array + * + * This structure is passed to the DMA engine driver via platform data. For + * M2P channels, contract is that even channels are for TX and odd for RX. + * There is no requirement for the M2M channels. + */ +struct ep93xx_dma_platform_data { + struct ep93xx_dma_chan_data *channels; + size_t num_channels; +}; + +static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan) +{ + return !strcmp(dev_name(chan->device->dev), "ep93xx-dma-m2p"); +} + +/** + * ep93xx_dma_chan_direction - returns direction the channel can be used + * @chan: channel + * + * This function can be used in filter functions to find out whether the + * channel supports given DMA direction. Only M2P channels have such + * limitation, for M2M channels the direction is configurable. + */ +static inline enum dma_transfer_direction +ep93xx_dma_chan_direction(struct dma_chan *chan) +{ + if (!ep93xx_dma_chan_is_m2p(chan)) + return DMA_NONE; + + /* even channels are for TX, odd for RX */ + return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; +} + +#endif /* __ASM_ARCH_DMA_H */ diff --git a/include/linux/platform_data/keypad-ep93xx.h b/include/linux/platform_data/keypad-ep93xx.h new file mode 100644 index 00000000000..1e2f4e97f42 --- /dev/null +++ b/include/linux/platform_data/keypad-ep93xx.h @@ -0,0 +1,35 @@ +/* + * arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h + */ + +#ifndef __ASM_ARCH_EP93XX_KEYPAD_H +#define __ASM_ARCH_EP93XX_KEYPAD_H + +struct matrix_keymap_data; + +/* flags for the ep93xx_keypad driver */ +#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */ +#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */ +#define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */ +#define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */ +#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */ +#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */ + +/** + * struct ep93xx_keypad_platform_data - platform specific device structure + * @keymap_data: pointer to &matrix_keymap_data + * @debounce: debounce start count; terminal count is 0xff + * @prescale: row/column counter pre-scaler load value + * @flags: see above + */ +struct ep93xx_keypad_platform_data { + struct matrix_keymap_data *keymap_data; + unsigned int debounce; + unsigned int prescale; + unsigned int flags; +}; + +#define EP93XX_MATRIX_ROWS (8) +#define EP93XX_MATRIX_COLS (8) + +#endif /* __ASM_ARCH_EP93XX_KEYPAD_H */ diff --git a/include/linux/platform_data/spi-ep93xx.h b/include/linux/platform_data/spi-ep93xx.h new file mode 100644 index 00000000000..9bb63ac13f0 --- /dev/null +++ b/include/linux/platform_data/spi-ep93xx.h @@ -0,0 +1,29 @@ +#ifndef __ASM_MACH_EP93XX_SPI_H +#define __ASM_MACH_EP93XX_SPI_H + +struct spi_device; + +/** + * struct ep93xx_spi_info - EP93xx specific SPI descriptor + * @num_chipselect: number of chip selects on this board, must be + * at least one + * @use_dma: use DMA for the transfers + */ +struct ep93xx_spi_info { + int num_chipselect; + bool use_dma; +}; + +/** + * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device + * @setup: setup the chip select mechanism + * @cleanup: cleanup the chip select mechanism + * @cs_control: control the device chip select + */ +struct ep93xx_spi_chip_ops { + int (*setup)(struct spi_device *spi); + void (*cleanup)(struct spi_device *spi); + void (*cs_control)(struct spi_device *spi, int value); +}; + +#endif /* __ASM_MACH_EP93XX_SPI_H */ diff --git a/include/linux/platform_data/video-ep93xx.h b/include/linux/platform_data/video-ep93xx.h new file mode 100644 index 00000000000..d5ae11d7c45 --- /dev/null +++ b/include/linux/platform_data/video-ep93xx.h @@ -0,0 +1,56 @@ +/* + * arch/arm/mach-ep93xx/include/mach/fb.h + */ + +#ifndef __ASM_ARCH_EP93XXFB_H +#define __ASM_ARCH_EP93XXFB_H + +struct platform_device; +struct fb_videomode; +struct fb_info; + +#define EP93XXFB_USE_MODEDB 0 + +/* VideoAttributes flags */ +#define EP93XXFB_STATE_MACHINE_ENABLE (1 << 0) +#define EP93XXFB_PIXEL_CLOCK_ENABLE (1 << 1) +#define EP93XXFB_VSYNC_ENABLE (1 << 2) +#define EP93XXFB_PIXEL_DATA_ENABLE (1 << 3) +#define EP93XXFB_COMPOSITE_SYNC (1 << 4) +#define EP93XXFB_SYNC_VERT_HIGH (1 << 5) +#define EP93XXFB_SYNC_HORIZ_HIGH (1 << 6) +#define EP93XXFB_SYNC_BLANK_HIGH (1 << 7) +#define EP93XXFB_PCLK_FALLING (1 << 8) +#define EP93XXFB_ENABLE_AC (1 << 9) +#define EP93XXFB_ENABLE_LCD (1 << 10) +#define EP93XXFB_ENABLE_CCIR (1 << 12) +#define EP93XXFB_USE_PARALLEL_INTERFACE (1 << 13) +#define EP93XXFB_ENABLE_INTERRUPT (1 << 14) +#define EP93XXFB_USB_INTERLACE (1 << 16) +#define EP93XXFB_USE_EQUALIZATION (1 << 17) +#define EP93XXFB_USE_DOUBLE_HORZ (1 << 18) +#define EP93XXFB_USE_DOUBLE_VERT (1 << 19) +#define EP93XXFB_USE_BLANK_PIXEL (1 << 20) +#define EP93XXFB_USE_SDCSN0 (0 << 21) +#define EP93XXFB_USE_SDCSN1 (1 << 21) +#define EP93XXFB_USE_SDCSN2 (2 << 21) +#define EP93XXFB_USE_SDCSN3 (3 << 21) + +#define EP93XXFB_ENABLE (EP93XXFB_STATE_MACHINE_ENABLE | \ + EP93XXFB_PIXEL_CLOCK_ENABLE | \ + EP93XXFB_VSYNC_ENABLE | \ + EP93XXFB_PIXEL_DATA_ENABLE) + +struct ep93xxfb_mach_info { + unsigned int num_modes; + const struct fb_videomode *modes; + const struct fb_videomode *default_mode; + int bpp; + unsigned int flags; + + int (*setup)(struct platform_device *pdev); + void (*teardown)(struct platform_device *pdev); + void (*blank)(int blank_mode, struct fb_info *info); +}; + +#endif /* __ASM_ARCH_EP93XXFB_H */ diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c index bdffab33e16..c3521653cfd 100644 --- a/sound/soc/ep93xx/ep93xx-ac97.c +++ b/sound/soc/ep93xx/ep93xx-ac97.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include "ep93xx-pcm.h" /* diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c index 8df8f6dc474..ac4a7515e7b 100644 --- a/sound/soc/ep93xx/ep93xx-i2s.c +++ b/sound/soc/ep93xx/ep93xx-i2s.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "ep93xx-pcm.h" diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index 4eea98b42bc..665d9c94cc1 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include -- cgit v1.2.3-70-g09d2 From 6ed33a4a0b86da42638b5f6a0bb9f9f9aee89f60 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Sat, 18 Aug 2012 15:20:41 -0400 Subject: [SCSI] st: raise device limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device limit of 128 tape drives was established in 2003 as a significant increase from the 8 tape drives allowed previously. We're seeing customer sites that between a large number of drives and multipath are discovering more than 128 devices and running into problems. Now that we're not stuck having to store a pointer in array and aren't limited by kmalloc failing on higher order allocs we can lift the limit to fill the entire minor range based on the number of modes. Based on the current code, that's 2^17 devices. Reviewed-by: Lee Duncan Signed-off-by: Jeff Mahoney Acked-by: Kai Mäkisara Signed-off-by: James Bottomley --- Documentation/scsi/st.txt | 6 ++---- drivers/scsi/st.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt index 685bf3582ab..f346abbdd6f 100644 --- a/Documentation/scsi/st.txt +++ b/Documentation/scsi/st.txt @@ -112,10 +112,8 @@ attempted). MINOR NUMBERS -The tape driver currently supports 128 drives by default. This number -can be increased by editing st.h and recompiling the driver if -necessary. The upper limit is 2^17 drives if 4 modes for each drive -are used. +The tape driver currently supports up to 2^17 drives if 4 modes for +each drive are used. The minor numbers consist of the following bit fields: diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index b7a07c7bf4f..f3eee0f9f40 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -78,7 +78,7 @@ struct st_modedef { #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) #define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT) -#define ST_MAX_TAPES 128 +#define ST_MAX_TAPES (1 << (20 - (ST_NBR_MODE_BITS + 1))) #define ST_MAX_TAPE_ENTRIES (ST_MAX_TAPES << (ST_NBR_MODE_BITS + 1)) /* The status related to each partition */ -- cgit v1.2.3-70-g09d2 From 8ab023812b2b5e81bb1876a925541bceaf62538a Mon Sep 17 00:00:00 2001 From: Shaik Ameer Basha Date: Tue, 31 Jul 2012 10:44:02 -0300 Subject: [media] v4l: Add new YVU420 multi planar fourcc definition This patch adds new 'YM21' fourcc definition for multiplanar YCrCb pixel format - V4L2_PIX_FMT_YVU420M. Signed-off-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/pixfmt-yvu420m.xml | 154 +++++++++++++++++++++ Documentation/DocBook/media/v4l/pixfmt.xml | 1 + include/linux/videodev2.h | 1 + 3 files changed, 156 insertions(+) create mode 100644 Documentation/DocBook/media/v4l/pixfmt-yvu420m.xml (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/pixfmt-yvu420m.xml b/Documentation/DocBook/media/v4l/pixfmt-yvu420m.xml new file mode 100644 index 00000000000..2330667907c --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-yvu420m.xml @@ -0,0 +1,154 @@ + + + V4L2_PIX_FMT_YVU420M ('YM21') + &manvol; + + + V4L2_PIX_FMT_YVU420M + Variation of V4L2_PIX_FMT_YVU420 + with planes non contiguous in memory. + + + + Description + + This is a multi-planar format, as opposed to a packed format. +The three components are separated into three sub-images or planes. + +The Y plane is first. The Y plane has one byte per pixel. The Cr data +constitutes the second plane which is half the width and half +the height of the Y plane (and of the image). Each Cr belongs to four +pixels, a two-by-two square of the image. For example, +Cr0 belongs to Y'00, +Y'01, Y'10, and +Y'11. The Cb data, just like the Cr plane, constitutes +the third plane. + + If the Y plane has pad bytes after each row, then the Cr +and Cb planes have half as many pad bytes after their rows. In other +words, two Cx rows (including padding) is exactly as long as one Y row +(including padding). + + V4L2_PIX_FMT_YVU420M is intended to be +used only in drivers and applications that support the multi-planar API, +described in . + + + <constant>V4L2_PIX_FMT_YVU420M</constant> 4 × 4 +pixel image + + + Byte Order. + Each cell is one byte. + + + + + + start0 + 0: + Y'00 + Y'01 + Y'02 + Y'03 + + + start0 + 4: + Y'10 + Y'11 + Y'12 + Y'13 + + + start0 + 8: + Y'20 + Y'21 + Y'22 + Y'23 + + + start0 + 12: + Y'30 + Y'31 + Y'32 + Y'33 + + + + start1 + 0: + Cr00 + Cr01 + + + start1 + 2: + Cr10 + Cr11 + + + + start2 + 0: + Cb00 + Cb01 + + + start2 + 2: + Cb10 + Cb11 + + + + + + + + + Color Sample Location. + + + + + + + 01 + 23 + + + 0 + YY + YY + + + + C + C + + + 1 + YY + YY + + + + + + 2 + YY + YY + + + + C + C + + + 3 + YY + YY + + + + + + + + + diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index e58934c9289..1ddbfabe319 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -708,6 +708,7 @@ information. &sub-y41p; &sub-yuv420; &sub-yuv420m; + &sub-yvu420m; &sub-yuv410; &sub-yuv422p; &sub-yuv411p; diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 91939a7a896..4862165e195 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -368,6 +368,7 @@ struct v4l2_pix_format { /* three non contiguous planes - Y, Cb, Cr */ #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ +#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'M', '2', '1') /* 12 YVU420 planar */ /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ -- cgit v1.2.3-70-g09d2 From c31a00cd30b176e40e0378664bace6fd5e0417c8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 10 Sep 2012 17:22:00 +0200 Subject: pinctrl: document semantics vs GPIO The semantics of the interactions between GPIO and pinctrl may be unclear, e.g. which one do you request first? This amends the documentation to make this clear. Reported-by: Domenico Andreoli Acked-by: Domenico Andreoli Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 60 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 1479aca2374..3b4ee532886 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -289,6 +289,11 @@ Interaction with the GPIO subsystem The GPIO drivers may want to perform operations of various types on the same physical pins that are also registered as pin controller pins. +First and foremost, the two subsystems can be used as completely orthogonal, +see the section named "pin control requests from drivers" and +"drivers needing both pin control and GPIOs" below for details. But in some +situations a cross-subsystem mapping between pins and GPIOs is needed. + Since the pin controller subsystem have its pinspace local to the pin controller we need a mapping so that the pin control subsystem can figure out which pin controller handles control of a certain GPIO pin. Since a single @@ -359,6 +364,7 @@ will get an pin number into its handled number range. Further it is also passed the range ID value, so that the pin controller knows which range it should deal with. + PINMUX interfaces ================= @@ -960,8 +966,8 @@ all get selected, and they all get enabled and disable simultaneously by the pinmux core. -Pinmux requests from drivers -============================ +Pin control requests from drivers +================================= Generally it is discouraged to let individual drivers get and enable pin control. So if possible, handle the pin control in platform code or some other @@ -969,6 +975,11 @@ place where you have access to all the affected struct device * pointers. In some cases where a driver needs to e.g. switch between different mux mappings at runtime this is not possible. +A typical case is if a driver needs to switch bias of pins from normal +operation and going to sleep, moving from the PINCTRL_STATE_DEFAULT to +PINCTRL_STATE_SLEEP at runtime, re-biasing or even re-muxing pins to save +current in sleep mode. + A driver may request a certain control state to be activated, usually just the default state like this: @@ -1058,6 +1069,51 @@ registered. Thus make sure that the error path in your driver gracefully cleans up and is ready to retry the probing later in the startup process. +Drivers needing both pin control and GPIOs +========================================== + +Again, it is discouraged to let drivers lookup and select pin control states +themselves, but again sometimes this is unavoidable. + +So say that your driver is fetching its resources like this: + +#include +#include + +struct pinctrl *pinctrl; +int gpio; + +pinctrl = devm_pinctrl_get_select_default(&dev); +gpio = devm_gpio_request(&dev, 14, "foo"); + +Here we first request a certain pin state and then request GPIO 14 to be +used. If you're using the subsystems orthogonally like this, you should +nominally always get your pinctrl handle and select the desired pinctrl +state BEFORE requesting the GPIO. This is a semantic convention to avoid +situations that can be electrically unpleasant, you will certainly want to +mux in and bias pins in a certain way before the GPIO subsystems starts to +deal with them. + +The above can be hidden: using pinctrl hogs, the pin control driver may be +setting up the config and muxing for the pins when it is probing, +nevertheless orthogonal to the GPIO subsystem. + +But there are also situations where it makes sense for the GPIO subsystem +to communicate directly with with the pinctrl subsystem, using the latter +as a back-end. This is when the GPIO driver may call out to the functions +described in the section "Pin control interaction with the GPIO subsystem" +above. This only involves per-pin multiplexing, and will be completely +hidden behind the gpio_*() function namespace. In this case, the driver +need not interact with the pin control subsystem at all. + +If a pin control driver and a GPIO driver is dealing with the same pins +and the use cases involve multiplexing, you MUST implement the pin controller +as a back-end for the GPIO driver like this, unless your hardware design +is such that the GPIO controller can override the pin controller's +multiplexing state through hardware without the need to interact with the +pin control system. + + System pin control hogging ========================== -- cgit v1.2.3-70-g09d2 From 9703d9d7f77ce129621f7d80a844822e2daa7008 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 5 Mar 2012 11:49:27 +0000 Subject: arm64: Kernel booting and initialisation The patch adds the kernel booting and the initial setup code. Documentation/arm64/booting.txt describes the booting protocol on the AArch64 Linux kernel. This is subject to change following the work on boot standardisation, ACPI. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Acked-by: Nicolas Pitre Acked-by: Tony Lindgren Acked-by: Olof Johansson Acked-by: Santosh Shilimkar Acked-by: Arnd Bergmann --- Documentation/arm64/booting.txt | 152 ++++++++++++ arch/arm64/include/asm/setup.h | 26 ++ arch/arm64/kernel/head.S | 510 ++++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/setup.c | 347 +++++++++++++++++++++++++++ 4 files changed, 1035 insertions(+) create mode 100644 Documentation/arm64/booting.txt create mode 100644 arch/arm64/include/asm/setup.h create mode 100644 arch/arm64/kernel/head.S create mode 100644 arch/arm64/kernel/setup.c (limited to 'Documentation') diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt new file mode 100644 index 00000000000..9c4d388dadd --- /dev/null +++ b/Documentation/arm64/booting.txt @@ -0,0 +1,152 @@ + Booting AArch64 Linux + ===================== + +Author: Will Deacon +Date : 07 September 2012 + +This document is based on the ARM booting document by Russell King and +is relevant to all public releases of the AArch64 Linux kernel. + +The AArch64 exception model is made up of a number of exception levels +(EL0 - EL3), with EL0 and EL1 having a secure and a non-secure +counterpart. EL2 is the hypervisor level and exists only in non-secure +mode. EL3 is the highest priority level and exists only in secure mode. + +For the purposes of this document, we will use the term `boot loader' +simply to define all software that executes on the CPU(s) before control +is passed to the Linux kernel. This may include secure monitor and +hypervisor code, or it may just be a handful of instructions for +preparing a minimal boot environment. + +Essentially, the boot loader should provide (as a minimum) the +following: + +1. Setup and initialise the RAM +2. Setup the device tree +3. Decompress the kernel image +4. Call the kernel image + + +1. Setup and initialise RAM +--------------------------- + +Requirement: MANDATORY + +The boot loader is expected to find and initialise all RAM that the +kernel will use for volatile data storage in the system. It performs +this in a machine dependent manner. (It may use internal algorithms +to automatically locate and size all RAM, or it may use knowledge of +the RAM in the machine, or any other method the boot loader designer +sees fit.) + + +2. Setup the device tree +------------------------- + +Requirement: MANDATORY + +The device tree blob (dtb) must be no bigger than 2 megabytes in size +and placed at a 2-megabyte boundary within the first 512 megabytes from +the start of the kernel image. This is to allow the kernel to map the +blob using a single section mapping in the initial page tables. + + +3. Decompress the kernel image +------------------------------ + +Requirement: OPTIONAL + +The AArch64 kernel does not currently provide a decompressor and +therefore requires decompression (gzip etc.) to be performed by the boot +loader if a compressed Image target (e.g. Image.gz) is used. For +bootloaders that do not implement this requirement, the uncompressed +Image target is available instead. + + +4. Call the kernel image +------------------------ + +Requirement: MANDATORY + +The decompressed kernel image contains a 32-byte header as follows: + + u32 magic = 0x14000008; /* branch to stext, little-endian */ + u32 res0 = 0; /* reserved */ + u64 text_offset; /* Image load offset */ + u64 res1 = 0; /* reserved */ + u64 res2 = 0; /* reserved */ + +The image must be placed at the specified offset (currently 0x80000) +from the start of the system RAM and called there. The start of the +system RAM must be aligned to 2MB. + +Before jumping into the kernel, the following conditions must be met: + +- Quiesce all DMA capable devices so that memory does not get + corrupted by bogus network packets or disk data. This will save + you many hours of debug. + +- Primary CPU general-purpose register settings + x0 = physical address of device tree blob (dtb) in system RAM. + x1 = 0 (reserved for future use) + x2 = 0 (reserved for future use) + x3 = 0 (reserved for future use) + +- CPU mode + All forms of interrupts must be masked in PSTATE.DAIF (Debug, SError, + IRQ and FIQ). + The CPU must be in either EL2 (RECOMMENDED in order to have access to + the virtualisation extensions) or non-secure EL1. + +- Caches, MMUs + The MMU must be off. + Instruction cache may be on or off. + Data cache must be off and invalidated. + External caches (if present) must be configured and disabled. + +- Architected timers + CNTFRQ must be programmed with the timer frequency. + If entering the kernel at EL1, CNTHCTL_EL2 must have EL1PCTEN (bit 0) + set where available. + +- Coherency + All CPUs to be booted by the kernel must be part of the same coherency + domain on entry to the kernel. This may require IMPLEMENTATION DEFINED + initialisation to enable the receiving of maintenance operations on + each CPU. + +- System registers + All writable architected system registers at the exception level where + the kernel image will be entered must be initialised by software at a + higher exception level to prevent execution in an UNKNOWN state. + +The boot loader is expected to enter the kernel on each CPU in the +following manner: + +- The primary CPU must jump directly to the first instruction of the + kernel image. The device tree blob passed by this CPU must contain + for each CPU node: + + 1. An 'enable-method' property. Currently, the only supported value + for this field is the string "spin-table". + + 2. A 'cpu-release-addr' property identifying a 64-bit, + zero-initialised memory location. + + It is expected that the bootloader will generate these device tree + properties and insert them into the blob prior to kernel entry. + +- Any secondary CPUs must spin outside of the kernel in a reserved area + of memory (communicated to the kernel by a /memreserve/ region in the + device tree) polling their cpu-release-addr location, which must be + contained in the reserved region. A wfe instruction may be inserted + to reduce the overhead of the busy-loop and a sev will be issued by + the primary CPU. When a read of the location pointed to by the + cpu-release-addr returns a non-zero value, the CPU must jump directly + to this value. + +- Secondary CPU general-purpose register settings + x0 = 0 (reserved for future use) + x1 = 0 (reserved for future use) + x2 = 0 (reserved for future use) + x3 = 0 (reserved for future use) diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h new file mode 100644 index 00000000000..9cf2e46fbbd --- /dev/null +++ b/arch/arm64/include/asm/setup.h @@ -0,0 +1,26 @@ +/* + * Based on arch/arm/include/asm/setup.h + * + * Copyright (C) 1997-1999 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_SETUP_H +#define __ASM_SETUP_H + +#include + +#define COMMAND_LINE_SIZE 2048 + +#endif diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S new file mode 100644 index 00000000000..a2f02b63eae --- /dev/null +++ b/arch/arm64/kernel/head.S @@ -0,0 +1,510 @@ +/* + * Low-level CPU initialisation + * Based on arch/arm/kernel/head.S + * + * Copyright (C) 1994-2002 Russell King + * Copyright (C) 2003-2012 ARM Ltd. + * Authors: Catalin Marinas + * Will Deacon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * swapper_pg_dir is the virtual address of the initial page table. We place + * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has + * 2 pages and is placed below swapper_pg_dir. + */ +#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) + +#if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000 +#error KERNEL_RAM_VADDR must start at 0xXXX80000 +#endif + +#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) +#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) + + .globl swapper_pg_dir + .equ swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE + + .globl idmap_pg_dir + .equ idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE + + .macro pgtbl, ttb0, ttb1, phys + add \ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE + sub \ttb0, \ttb1, #IDMAP_DIR_SIZE + .endm + +#ifdef CONFIG_ARM64_64K_PAGES +#define BLOCK_SHIFT PAGE_SHIFT +#define BLOCK_SIZE PAGE_SIZE +#else +#define BLOCK_SHIFT SECTION_SHIFT +#define BLOCK_SIZE SECTION_SIZE +#endif + +#define KERNEL_START KERNEL_RAM_VADDR +#define KERNEL_END _end + +/* + * Initial memory map attributes. + */ +#ifndef CONFIG_SMP +#define PTE_FLAGS PTE_TYPE_PAGE | PTE_AF +#define PMD_FLAGS PMD_TYPE_SECT | PMD_SECT_AF +#else +#define PTE_FLAGS PTE_TYPE_PAGE | PTE_AF | PTE_SHARED +#define PMD_FLAGS PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S +#endif + +#ifdef CONFIG_ARM64_64K_PAGES +#define MM_MMUFLAGS PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS +#define IO_MMUFLAGS PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS +#else +#define MM_MMUFLAGS PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS +#define IO_MMUFLAGS PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS +#endif + +/* + * Kernel startup entry point. + * --------------------------- + * + * The requirements are: + * MMU = off, D-cache = off, I-cache = on or off, + * x0 = physical address to the FDT blob. + * + * This code is mostly position independent so you call this at + * __pa(PAGE_OFFSET + TEXT_OFFSET). + * + * Note that the callee-saved registers are used for storing variables + * that are useful before the MMU is enabled. The allocations are described + * in the entry routines. + */ + __HEAD + + /* + * DO NOT MODIFY. Image header expected by Linux boot-loaders. + */ + b stext // branch to kernel start, magic + .long 0 // reserved + .quad TEXT_OFFSET // Image load offset from start of RAM + .quad 0 // reserved + .quad 0 // reserved + +ENTRY(stext) + mov x21, x0 // x21=FDT + bl el2_setup // Drop to EL1 + mrs x22, midr_el1 // x22=cpuid + mov x0, x22 + bl lookup_processor_type + mov x23, x0 // x23=current cpu_table + cbz x23, __error_p // invalid processor (x23=0)? + bl __calc_phys_offset // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET + bl __vet_fdt + bl __create_page_tables // x25=TTBR0, x26=TTBR1 + /* + * The following calls CPU specific code in a position independent + * manner. See arch/arm64/mm/proc.S for details. x23 = base of + * cpu_info structure selected by lookup_processor_type above. + * On return, the CPU will be ready for the MMU to be turned on and + * the TCR will have been set. + */ + ldr x27, __switch_data // address to jump to after + // MMU has been enabled + adr lr, __enable_mmu // return (PIC) address + ldr x12, [x23, #CPU_INFO_SETUP] + add x12, x12, x28 // __virt_to_phys + br x12 // initialise processor +ENDPROC(stext) + +/* + * If we're fortunate enough to boot at EL2, ensure that the world is + * sane before dropping to EL1. + */ +ENTRY(el2_setup) + mrs x0, CurrentEL + cmp x0, #PSR_MODE_EL2t + ccmp x0, #PSR_MODE_EL2h, #0x4, ne + b.eq 1f + ret + + /* Hyp configuration. */ +1: mov x0, #(1 << 31) // 64-bit EL1 + msr hcr_el2, x0 + + /* Generic timers. */ + mrs x0, cnthctl_el2 + orr x0, x0, #3 // Enable EL1 physical timers + msr cnthctl_el2, x0 + + /* Populate ID registers. */ + mrs x0, midr_el1 + mrs x1, mpidr_el1 + msr vpidr_el2, x0 + msr vmpidr_el2, x1 + + /* sctlr_el1 */ + mov x0, #0x0800 // Set/clear RES{1,0} bits + movk x0, #0x30d0, lsl #16 + msr sctlr_el1, x0 + + /* Coprocessor traps. */ + mov x0, #0x33ff + msr cptr_el2, x0 // Disable copro. traps to EL2 + +#ifdef CONFIG_COMPAT + msr hstr_el2, xzr // Disable CP15 traps to EL2 +#endif + + /* spsr */ + mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ + PSR_MODE_EL1h) + msr spsr_el2, x0 + msr elr_el2, lr + eret +ENDPROC(el2_setup) + + .align 3 +2: .quad . + .quad PAGE_OFFSET + +#ifdef CONFIG_SMP + .pushsection .smp.pen.text, "ax" + .align 3 +1: .quad . + .quad secondary_holding_pen_release + + /* + * This provides a "holding pen" for platforms to hold all secondary + * cores are held until we're ready for them to initialise. + */ +ENTRY(secondary_holding_pen) + bl el2_setup // Drop to EL1 + mrs x0, mpidr_el1 + and x0, x0, #15 // CPU number + adr x1, 1b + ldp x2, x3, [x1] + sub x1, x1, x2 + add x3, x3, x1 +pen: ldr x4, [x3] + cmp x4, x0 + b.eq secondary_startup + wfe + b pen +ENDPROC(secondary_holding_pen) + .popsection + +ENTRY(secondary_startup) + /* + * Common entry point for secondary CPUs. + */ + mrs x22, midr_el1 // x22=cpuid + mov x0, x22 + bl lookup_processor_type + mov x23, x0 // x23=current cpu_table + cbz x23, __error_p // invalid processor (x23=0)? + + bl __calc_phys_offset // x24=phys offset + pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 + ldr x12, [x23, #CPU_INFO_SETUP] + add x12, x12, x28 // __virt_to_phys + blr x12 // initialise processor + + ldr x21, =secondary_data + ldr x27, =__secondary_switched // address to jump to after enabling the MMU + b __enable_mmu +ENDPROC(secondary_startup) + +ENTRY(__secondary_switched) + ldr x0, [x21] // get secondary_data.stack + mov sp, x0 + mov x29, #0 + b secondary_start_kernel +ENDPROC(__secondary_switched) +#endif /* CONFIG_SMP */ + +/* + * Setup common bits before finally enabling the MMU. Essentially this is just + * loading the page table pointer and vector base registers. + * + * On entry to this code, x0 must contain the SCTLR_EL1 value for turning on + * the MMU. + */ +__enable_mmu: + ldr x5, =vectors + msr vbar_el1, x5 + msr ttbr0_el1, x25 // load TTBR0 + msr ttbr1_el1, x26 // load TTBR1 + isb + b __turn_mmu_on +ENDPROC(__enable_mmu) + +/* + * Enable the MMU. This completely changes the structure of the visible memory + * space. You will not be able to trace execution through this. + * + * x0 = system control register + * x27 = *virtual* address to jump to upon completion + * + * other registers depend on the function called upon completion + */ + .align 6 +__turn_mmu_on: + msr sctlr_el1, x0 + isb + br x27 +ENDPROC(__turn_mmu_on) + +/* + * Calculate the start of physical memory. + */ +__calc_phys_offset: + adr x0, 1f + ldp x1, x2, [x0] + sub x28, x0, x1 // x28 = PHYS_OFFSET - PAGE_OFFSET + add x24, x2, x28 // x24 = PHYS_OFFSET + ret +ENDPROC(__calc_phys_offset) + + .align 3 +1: .quad . + .quad PAGE_OFFSET + +/* + * Macro to populate the PGD for the corresponding block entry in the next + * level (tbl) for the given virtual address. + * + * Preserves: pgd, tbl, virt + * Corrupts: tmp1, tmp2 + */ + .macro create_pgd_entry, pgd, tbl, virt, tmp1, tmp2 + lsr \tmp1, \virt, #PGDIR_SHIFT + and \tmp1, \tmp1, #PTRS_PER_PGD - 1 // PGD index + orr \tmp2, \tbl, #3 // PGD entry table type + str \tmp2, [\pgd, \tmp1, lsl #3] + .endm + +/* + * Macro to populate block entries in the page table for the start..end + * virtual range (inclusive). + * + * Preserves: tbl, flags + * Corrupts: phys, start, end, pstate + */ + .macro create_block_map, tbl, flags, phys, start, end, idmap=0 + lsr \phys, \phys, #BLOCK_SHIFT + .if \idmap + and \start, \phys, #PTRS_PER_PTE - 1 // table index + .else + lsr \start, \start, #BLOCK_SHIFT + and \start, \start, #PTRS_PER_PTE - 1 // table index + .endif + orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry + .ifnc \start,\end + lsr \end, \end, #BLOCK_SHIFT + and \end, \end, #PTRS_PER_PTE - 1 // table end index + .endif +9999: str \phys, [\tbl, \start, lsl #3] // store the entry + .ifnc \start,\end + add \start, \start, #1 // next entry + add \phys, \phys, #BLOCK_SIZE // next block + cmp \start, \end + b.ls 9999b + .endif + .endm + +/* + * Setup the initial page tables. We only setup the barest amount which is + * required to get the kernel running. The following sections are required: + * - identity mapping to enable the MMU (low address, TTBR0) + * - first few MB of the kernel linear mapping to jump to once the MMU has + * been enabled, including the FDT blob (TTBR1) + */ +__create_page_tables: + pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses + + /* + * Clear the idmap and swapper page tables. + */ + mov x0, x25 + add x6, x26, #SWAPPER_DIR_SIZE +1: stp xzr, xzr, [x0], #16 + stp xzr, xzr, [x0], #16 + stp xzr, xzr, [x0], #16 + stp xzr, xzr, [x0], #16 + cmp x0, x6 + b.lo 1b + + ldr x7, =MM_MMUFLAGS + + /* + * Create the identity mapping. + */ + add x0, x25, #PAGE_SIZE // section table address + adr x3, __turn_mmu_on // virtual/physical address + create_pgd_entry x25, x0, x3, x5, x6 + create_block_map x0, x7, x3, x5, x5, idmap=1 + + /* + * Map the kernel image (starting with PHYS_OFFSET). + */ + add x0, x26, #PAGE_SIZE // section table address + mov x5, #PAGE_OFFSET + create_pgd_entry x26, x0, x5, x3, x6 + ldr x6, =KERNEL_END - 1 + mov x3, x24 // phys offset + create_block_map x0, x7, x3, x5, x6 + + /* + * Map the FDT blob (maximum 2MB; must be within 512MB of + * PHYS_OFFSET). + */ + mov x3, x21 // FDT phys address + and x3, x3, #~((1 << 21) - 1) // 2MB aligned + mov x6, #PAGE_OFFSET + sub x5, x3, x24 // subtract PHYS_OFFSET + tst x5, #~((1 << 29) - 1) // within 512MB? + csel x21, xzr, x21, ne // zero the FDT pointer + b.ne 1f + add x5, x5, x6 // __va(FDT blob) + add x6, x5, #1 << 21 // 2MB for the FDT blob + sub x6, x6, #1 // inclusive range + create_block_map x0, x7, x3, x5, x6 +1: + ret +ENDPROC(__create_page_tables) + .ltorg + + .align 3 + .type __switch_data, %object +__switch_data: + .quad __mmap_switched + .quad __data_loc // x4 + .quad _data // x5 + .quad __bss_start // x6 + .quad _end // x7 + .quad processor_id // x4 + .quad __fdt_pointer // x5 + .quad memstart_addr // x6 + .quad init_thread_union + THREAD_START_SP // sp + +/* + * The following fragment of code is executed with the MMU on in MMU mode, and + * uses absolute addresses; this is not position independent. + */ +__mmap_switched: + adr x3, __switch_data + 8 + + ldp x4, x5, [x3], #16 + ldp x6, x7, [x3], #16 + cmp x4, x5 // Copy data segment if needed +1: ccmp x5, x6, #4, ne + b.eq 2f + ldr x16, [x4], #8 + str x16, [x5], #8 + b 1b +2: +1: cmp x6, x7 + b.hs 2f + str xzr, [x6], #8 // Clear BSS + b 1b +2: + ldp x4, x5, [x3], #16 + ldr x6, [x3], #8 + ldr x16, [x3] + mov sp, x16 + str x22, [x4] // Save processor ID + str x21, [x5] // Save FDT pointer + str x24, [x6] // Save PHYS_OFFSET + mov x29, #0 + b start_kernel +ENDPROC(__mmap_switched) + +/* + * Exception handling. Something went wrong and we can't proceed. We ought to + * tell the user, but since we don't have any guarantee that we're even + * running on the right architecture, we do virtually nothing. + */ +__error_p: +ENDPROC(__error_p) + +__error: +1: nop + b 1b +ENDPROC(__error) + +/* + * This function gets the processor ID in w0 and searches the cpu_table[] for + * a match. It returns a pointer to the struct cpu_info it found. The + * cpu_table[] must end with an empty (all zeros) structure. + * + * This routine can be called via C code and it needs to work with the MMU + * both disabled and enabled (the offset is calculated automatically). + */ +ENTRY(lookup_processor_type) + adr x1, __lookup_processor_type_data + ldp x2, x3, [x1] + sub x1, x1, x2 // get offset between VA and PA + add x3, x3, x1 // convert VA to PA +1: + ldp w5, w6, [x3] // load cpu_id_val and cpu_id_mask + cbz w5, 2f // end of list? + and w6, w6, w0 + cmp w5, w6 + b.eq 3f + add x3, x3, #CPU_INFO_SZ + b 1b +2: + mov x3, #0 // unknown processor +3: + mov x0, x3 + ret +ENDPROC(lookup_processor_type) + + .align 3 + .type __lookup_processor_type_data, %object +__lookup_processor_type_data: + .quad . + .quad cpu_table + .size __lookup_processor_type_data, . - __lookup_processor_type_data + +/* + * Determine validity of the x21 FDT pointer. + * The dtb must be 8-byte aligned and live in the first 512M of memory. + */ +__vet_fdt: + tst x21, #0x7 + b.ne 1f + cmp x21, x24 + b.lt 1f + mov x0, #(1 << 29) + add x0, x0, x24 + cmp x21, x0 + b.ge 1f + ret +1: + mov x21, #0 + ret +ENDPROC(__vet_fdt) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c new file mode 100644 index 00000000000..48ffb9fb3fe --- /dev/null +++ b/arch/arm64/kernel/setup.c @@ -0,0 +1,347 @@ +/* + * Based on arch/arm/kernel/setup.c + * + * Copyright (C) 1995-2001 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned int processor_id; +EXPORT_SYMBOL(processor_id); + +unsigned int elf_hwcap __read_mostly; +EXPORT_SYMBOL_GPL(elf_hwcap); + +static const char *cpu_name; +static const char *machine_name; +phys_addr_t __fdt_pointer __initdata; + +/* + * Standard memory resources + */ +static struct resource mem_res[] = { + { + .name = "Kernel code", + .start = 0, + .end = 0, + .flags = IORESOURCE_MEM + }, + { + .name = "Kernel data", + .start = 0, + .end = 0, + .flags = IORESOURCE_MEM + } +}; + +#define kernel_code mem_res[0] +#define kernel_data mem_res[1] + +void __init early_print(const char *str, ...) +{ + char buf[256]; + va_list ap; + + va_start(ap, str); + vsnprintf(buf, sizeof(buf), str, ap); + va_end(ap); + + printk("%s", buf); +} + +static void __init setup_processor(void) +{ + struct cpu_info *cpu_info; + + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc.S + */ + cpu_info = lookup_processor_type(read_cpuid_id()); + if (!cpu_info) { + printk("CPU configuration botched (ID %08x), unable to continue.\n", + read_cpuid_id()); + while (1); + } + + cpu_name = cpu_info->cpu_name; + + printk("CPU: %s [%08x] revision %d\n", + cpu_name, read_cpuid_id(), read_cpuid_id() & 15); + + sprintf(init_utsname()->machine, "aarch64"); + elf_hwcap = 0; +} + +static void __init setup_machine_fdt(phys_addr_t dt_phys) +{ + struct boot_param_header *devtree; + unsigned long dt_root; + + /* Check we have a non-NULL DT pointer */ + if (!dt_phys) { + early_print("\n" + "Error: NULL or invalid device tree blob\n" + "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n" + "\nPlease check your bootloader.\n"); + + while (true) + cpu_relax(); + + } + + devtree = phys_to_virt(dt_phys); + + /* Check device tree validity */ + if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) { + early_print("\n" + "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" + "Expected 0x%x, found 0x%x\n" + "\nPlease check your bootloader.\n", + dt_phys, devtree, OF_DT_HEADER, + be32_to_cpu(devtree->magic)); + + while (true) + cpu_relax(); + } + + initial_boot_params = devtree; + dt_root = of_get_flat_dt_root(); + + machine_name = of_get_flat_dt_prop(dt_root, "model", NULL); + if (!machine_name) + machine_name = of_get_flat_dt_prop(dt_root, "compatible", NULL); + if (!machine_name) + machine_name = ""; + pr_info("Machine: %s\n", machine_name); + + /* Retrieve various information from the /chosen node */ + of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); + /* Initialize {size,address}-cells info */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + /* Setup memory, calling early_init_dt_add_memory_arch */ + of_scan_flat_dt(early_init_dt_scan_memory, NULL); +} + +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ + size &= PAGE_MASK; + memblock_add(base, size); +} + +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return __va(memblock_alloc(size, align)); +} + +/* + * Limit the memory size that was specified via FDT. + */ +static int __init early_mem(char *p) +{ + phys_addr_t limit; + + if (!p) + return 1; + + limit = memparse(p, &p) & PAGE_MASK; + pr_notice("Memory limited to %lldMB\n", limit >> 20); + + memblock_enforce_memory_limit(limit); + + return 0; +} +early_param("mem", early_mem); + +static void __init request_standard_resources(void) +{ + struct memblock_region *region; + struct resource *res; + + kernel_code.start = virt_to_phys(_text); + kernel_code.end = virt_to_phys(_etext - 1); + kernel_data.start = virt_to_phys(_sdata); + kernel_data.end = virt_to_phys(_end - 1); + + for_each_memblock(memory, region) { + res = alloc_bootmem_low(sizeof(*res)); + res->name = "System RAM"; + res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); + res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + request_resource(&iomem_resource, res); + + if (kernel_code.start >= res->start && + kernel_code.end <= res->end) + request_resource(res, &kernel_code); + if (kernel_data.start >= res->start && + kernel_data.end <= res->end) + request_resource(res, &kernel_data); + } +} + +void __init setup_arch(char **cmdline_p) +{ + setup_processor(); + + setup_machine_fdt(__fdt_pointer); + + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + *cmdline_p = boot_command_line; + + parse_early_param(); + + arm64_memblock_init(); + + paging_init(); + request_standard_resources(); + + unflatten_device_tree(); + +#ifdef CONFIG_SMP + smp_init_cpus(); +#endif + +#ifdef CONFIG_VT +#if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif +} + +static DEFINE_PER_CPU(struct cpu, cpu_data); + +static int __init topology_init(void) +{ + int i; + + for_each_possible_cpu(i) { + struct cpu *cpu = &per_cpu(cpu_data, i); + cpu->hotpluggable = 1; + register_cpu(cpu, i); + } + + return 0; +} +subsys_initcall(topology_init); + +static const char *hwcap_str[] = { + "fp", + "asimd", + NULL +}; + +static int c_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "Processor\t: %s rev %d (%s)\n", + cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); + + for_each_online_cpu(i) { + /* + * glibc reads /proc/cpuinfo to determine the number of + * online processors, looking for lines beginning with + * "processor". Give glibc what it expects. + */ +#ifdef CONFIG_SMP + seq_printf(m, "processor\t: %d\n", i); +#endif + seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", + loops_per_jiffy / (500000UL/HZ), + loops_per_jiffy / (5000UL/HZ) % 100); + } + + /* dump out the processor features */ + seq_puts(m, "Features\t: "); + + for (i = 0; hwcap_str[i]; i++) + if (elf_hwcap & (1 << i)) + seq_printf(m, "%s ", hwcap_str[i]); + + seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); + seq_printf(m, "CPU architecture: AArch64\n"); + seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15); + seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff); + seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); + + seq_puts(m, "\n"); + + seq_printf(m, "Hardware\t: %s\n", machine_name); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show +}; -- cgit v1.2.3-70-g09d2 From 4f04d8f00545110a0e525ae2fb62ab38cb417236 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 5 Mar 2012 11:49:27 +0000 Subject: arm64: MMU definitions The virtual memory layout is described in Documentation/arm64/memory.txt. This patch adds the MMU definitions for the 4KB and 64KB translation table configurations. The SECTION_SIZE is 2MB with 4KB page and 512MB with 64KB page configuration. PHYS_OFFSET is calculated at run-time and stored in a variable (no run-time code patching at this stage). On the current implementation, both user and kernel address spaces are 512G (39-bit) each with a maximum of 256G for the RAM linear mapping. Linux uses 3 levels of translation tables with the 4K page configuration and 2 levels with the 64K configuration. Extending the memory space beyond 39-bit with the 4K pages or 42-bit with 64K pages requires an additional level of translation tables. The SPARSEMEM configuration is global to all AArch64 platforms and allows for 1GB sections with SPARSEMEM_VMEMMAP enabled by default. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Acked-by: Tony Lindgren Acked-by: Nicolas Pitre Acked-by: Olof Johansson Acked-by: Santosh Shilimkar Acked-by: Arnd Bergmann --- Documentation/arm64/memory.txt | 73 ++++++ arch/arm64/include/asm/memory.h | 144 +++++++++++ arch/arm64/include/asm/mmu.h | 30 +++ arch/arm64/include/asm/pgtable-2level-hwdef.h | 43 ++++ arch/arm64/include/asm/pgtable-2level-types.h | 60 +++++ arch/arm64/include/asm/pgtable-3level-hwdef.h | 50 ++++ arch/arm64/include/asm/pgtable-3level-types.h | 66 ++++++ arch/arm64/include/asm/pgtable-hwdef.h | 94 ++++++++ arch/arm64/include/asm/pgtable.h | 328 ++++++++++++++++++++++++++ arch/arm64/include/asm/sparsemem.h | 24 ++ 10 files changed, 912 insertions(+) create mode 100644 Documentation/arm64/memory.txt create mode 100644 arch/arm64/include/asm/memory.h create mode 100644 arch/arm64/include/asm/mmu.h create mode 100644 arch/arm64/include/asm/pgtable-2level-hwdef.h create mode 100644 arch/arm64/include/asm/pgtable-2level-types.h create mode 100644 arch/arm64/include/asm/pgtable-3level-hwdef.h create mode 100644 arch/arm64/include/asm/pgtable-3level-types.h create mode 100644 arch/arm64/include/asm/pgtable-hwdef.h create mode 100644 arch/arm64/include/asm/pgtable.h create mode 100644 arch/arm64/include/asm/sparsemem.h (limited to 'Documentation') diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt new file mode 100644 index 00000000000..dbbdcbba75a --- /dev/null +++ b/Documentation/arm64/memory.txt @@ -0,0 +1,73 @@ + Memory Layout on AArch64 Linux + ============================== + +Author: Catalin Marinas +Date : 20 February 2012 + +This document describes the virtual memory layout used by the AArch64 +Linux kernel. The architecture allows up to 4 levels of translation +tables with a 4KB page size and up to 3 levels with a 64KB page size. + +AArch64 Linux uses 3 levels of translation tables with the 4KB page +configuration, allowing 39-bit (512GB) virtual addresses for both user +and kernel. With 64KB pages, only 2 levels of translation tables are +used but the memory layout is the same. + +User addresses have bits 63:39 set to 0 while the kernel addresses have +the same bits set to 1. TTBRx selection is given by bit 63 of the +virtual address. The swapper_pg_dir contains only kernel (global) +mappings while the user pgd contains only user (non-global) mappings. +The swapper_pgd_dir address is written to TTBR1 and never written to +TTBR0. + + +AArch64 Linux memory layout: + +Start End Size Use +----------------------------------------------------------------------- +0000000000000000 0000007fffffffff 512GB user + +ffffff8000000000 ffffffbbfffcffff ~240GB vmalloc + +ffffffbbfffd0000 ffffffbcfffdffff 64KB [guard page] + +ffffffbbfffe0000 ffffffbcfffeffff 64KB PCI I/O space + +ffffffbbffff0000 ffffffbcffffffff 64KB [guard page] + +ffffffbc00000000 ffffffbdffffffff 8GB vmemmap + +ffffffbe00000000 ffffffbffbffffff ~8GB [guard, future vmmemap] + +ffffffbffc000000 ffffffbfffffffff 64MB modules + +ffffffc000000000 ffffffffffffffff 256GB memory + + +Translation table lookup with 4KB pages: + ++--------+--------+--------+--------+--------+--------+--------+--------+ +|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| ++--------+--------+--------+--------+--------+--------+--------+--------+ + | | | | | | + | | | | | v + | | | | | [11:0] in-page offset + | | | | +-> [20:12] L3 index + | | | +-----------> [29:21] L2 index + | | +---------------------> [38:30] L1 index + | +-------------------------------> [47:39] L0 index (not used) + +-------------------------------------------------> [63] TTBR0/1 + + +Translation table lookup with 64KB pages: + ++--------+--------+--------+--------+--------+--------+--------+--------+ +|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| ++--------+--------+--------+--------+--------+--------+--------+--------+ + | | | | | + | | | | v + | | | | [15:0] in-page offset + | | | +----------> [28:16] L3 index + | | +--------------------------> [41:29] L2 index (only 38:29 used) + | +-------------------------------> [47:42] L1 index (not used) + +-------------------------------------------------> [63] TTBR0/1 diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h new file mode 100644 index 00000000000..1cac16a001c --- /dev/null +++ b/arch/arm64/include/asm/memory.h @@ -0,0 +1,144 @@ +/* + * Based on arch/arm/include/asm/memory.h + * + * Copyright (C) 2000-2002 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Note: this file should not be included by non-asm/.h files + */ +#ifndef __ASM_MEMORY_H +#define __ASM_MEMORY_H + +#include +#include +#include +#include + +/* + * Allow for constants defined here to be used from assembly code + * by prepending the UL suffix only with actual C code compilation. + */ +#define UL(x) _AC(x, UL) + +/* + * PAGE_OFFSET - the virtual address of the start of the kernel image. + * VA_BITS - the maximum number of bits for virtual addresses. + * TASK_SIZE - the maximum size of a user space task. + * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. + * The module space lives between the addresses given by TASK_SIZE + * and PAGE_OFFSET - it must be within 128MB of the kernel text. + */ +#define PAGE_OFFSET UL(0xffffffc000000000) +#define MODULES_END (PAGE_OFFSET) +#define MODULES_VADDR (MODULES_END - SZ_64M) +#define VA_BITS (39) +#define TASK_SIZE_64 (UL(1) << VA_BITS) + +#ifdef CONFIG_COMPAT +#define TASK_SIZE_32 UL(0x100000000) +#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ + TASK_SIZE_32 : TASK_SIZE_64) +#else +#define TASK_SIZE TASK_SIZE_64 +#endif /* CONFIG_COMPAT */ + +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4)) + +#if TASK_SIZE_64 > MODULES_VADDR +#error Top of 64-bit user space clashes with start of module space +#endif + +/* + * Physical vs virtual RAM address space conversion. These are + * private definitions which should NOT be used outside memory.h + * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. + */ +#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET)) +#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET)) + +/* + * Convert a physical address to a Page Frame Number and back + */ +#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) +#define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT) + +/* + * Convert a page to/from a physical address + */ +#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) +#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) + +/* + * Memory types available. + */ +#define MT_DEVICE_nGnRnE 0 +#define MT_DEVICE_nGnRE 1 +#define MT_DEVICE_GRE 2 +#define MT_NORMAL_NC 3 +#define MT_NORMAL 4 + +#ifndef __ASSEMBLY__ + +extern phys_addr_t memstart_addr; +/* PHYS_OFFSET - the physical address of the start of memory. */ +#define PHYS_OFFSET ({ memstart_addr; }) + +/* + * PFNs are used to describe any physical page; this means + * PFN 0 == physical address 0. + * + * This is the PFN of the first RAM page in the kernel + * direct-mapped view. We assume this is the first page + * of RAM in the mem_map as well. + */ +#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) + +/* + * Note: Drivers should NOT use these. They are the wrong + * translation for translating DMA addresses. Use the driver + * DMA support - see dma-mapping.h. + */ +static inline phys_addr_t virt_to_phys(const volatile void *x) +{ + return __virt_to_phys((unsigned long)(x)); +} + +static inline void *phys_to_virt(phys_addr_t x) +{ + return (void *)(__phys_to_virt(x)); +} + +/* + * Drivers should NOT use these either. + */ +#define __pa(x) __virt_to_phys((unsigned long)(x)) +#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) +#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + +/* + * virt_to_page(k) convert a _valid_ virtual address to struct page * + * virt_addr_valid(k) indicates whether a virtual address is valid + */ +#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET + +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ + ((void *)(kaddr) < (void *)high_memory)) + +#endif + +#include + +#endif diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h new file mode 100644 index 00000000000..d4f7fd5b9e3 --- /dev/null +++ b/arch/arm64/include/asm/mmu.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_MMU_H +#define __ASM_MMU_H + +typedef struct { + unsigned int id; + raw_spinlock_t id_lock; + void *vdso; +} mm_context_t; + +#define ASID(mm) ((mm)->context.id & 0xffff) + +extern void paging_init(void); +extern void setup_mm_for_reboot(void); + +#endif diff --git a/arch/arm64/include/asm/pgtable-2level-hwdef.h b/arch/arm64/include/asm/pgtable-2level-hwdef.h new file mode 100644 index 00000000000..0a8ed3f94e9 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-2level-hwdef.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_PGTABLE_2LEVEL_HWDEF_H +#define __ASM_PGTABLE_2LEVEL_HWDEF_H + +/* + * With LPAE and 64KB pages, there are 2 levels of page tables. Each level has + * 8192 entries of 8 bytes each, occupying a 64KB page. Levels 0 and 1 are not + * used. The 2nd level table (PGD for Linux) can cover a range of 4TB, each + * entry representing 512MB. The user and kernel address spaces are limited to + * 512GB and therefore we only use 1024 entries in the PGD. + */ +#define PTRS_PER_PTE 8192 +#define PTRS_PER_PGD 1024 + +/* + * PGDIR_SHIFT determines the size a top-level page table entry can map. + */ +#define PGDIR_SHIFT 29 +#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * section address mask and size definitions. + */ +#define SECTION_SHIFT 29 +#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) +#define SECTION_MASK (~(SECTION_SIZE-1)) + +#endif diff --git a/arch/arm64/include/asm/pgtable-2level-types.h b/arch/arm64/include/asm/pgtable-2level-types.h new file mode 100644 index 00000000000..3c3ca7d361e --- /dev/null +++ b/arch/arm64/include/asm/pgtable-2level-types.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_PGTABLE_2LEVEL_TYPES_H +#define __ASM_PGTABLE_2LEVEL_TYPES_H + +typedef u64 pteval_t; +typedef u64 pgdval_t; +typedef pgdval_t pmdval_t; + +#undef STRICT_MM_TYPECHECKS + +#ifdef STRICT_MM_TYPECHECKS + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { pteval_t pte; } pte_t; +typedef struct { pgdval_t pgd; } pgd_t; +typedef struct { pteval_t pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +#else /* !STRICT_MM_TYPECHECKS */ + +typedef pteval_t pte_t; +typedef pgdval_t pgd_t; +typedef pteval_t pgprot_t; + +#define pte_val(x) (x) +#define pgd_val(x) (x) +#define pgprot_val(x) (x) + +#define __pte(x) (x) +#define __pgd(x) (x) +#define __pgprot(x) (x) + +#endif /* STRICT_MM_TYPECHECKS */ + +#include + +#endif /* __ASM_PGTABLE_2LEVEL_TYPES_H */ diff --git a/arch/arm64/include/asm/pgtable-3level-hwdef.h b/arch/arm64/include/asm/pgtable-3level-hwdef.h new file mode 100644 index 00000000000..3dbf941d776 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-3level-hwdef.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_PGTABLE_3LEVEL_HWDEF_H +#define __ASM_PGTABLE_3LEVEL_HWDEF_H + +/* + * With LPAE and 4KB pages, there are 3 levels of page tables. Each level has + * 512 entries of 8 bytes each, occupying a 4K page. The first level table + * covers a range of 512GB, each entry representing 1GB. The user and kernel + * address spaces are limited to 512GB each. + */ +#define PTRS_PER_PTE 512 +#define PTRS_PER_PMD 512 +#define PTRS_PER_PGD 512 + +/* + * PGDIR_SHIFT determines the size a top-level page table entry can map. + */ +#define PGDIR_SHIFT 30 +#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * PMD_SHIFT determines the size a middle-level page table entry can map. + */ +#define PMD_SHIFT 21 +#define PMD_SIZE (_AC(1, UL) << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* + * section address mask and size definitions. + */ +#define SECTION_SHIFT 21 +#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) +#define SECTION_MASK (~(SECTION_SIZE-1)) + +#endif diff --git a/arch/arm64/include/asm/pgtable-3level-types.h b/arch/arm64/include/asm/pgtable-3level-types.h new file mode 100644 index 00000000000..4489615f14a --- /dev/null +++ b/arch/arm64/include/asm/pgtable-3level-types.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_PGTABLE_3LEVEL_TYPES_H +#define __ASM_PGTABLE_3LEVEL_TYPES_H + +typedef u64 pteval_t; +typedef u64 pmdval_t; +typedef u64 pgdval_t; + +#undef STRICT_MM_TYPECHECKS + +#ifdef STRICT_MM_TYPECHECKS + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { pteval_t pte; } pte_t; +typedef struct { pmdval_t pmd; } pmd_t; +typedef struct { pgdval_t pgd; } pgd_t; +typedef struct { pteval_t pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((x).pmd) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +#else /* !STRICT_MM_TYPECHECKS */ + +typedef pteval_t pte_t; +typedef pmdval_t pmd_t; +typedef pgdval_t pgd_t; +typedef pteval_t pgprot_t; + +#define pte_val(x) (x) +#define pmd_val(x) (x) +#define pgd_val(x) (x) +#define pgprot_val(x) (x) + +#define __pte(x) (x) +#define __pmd(x) (x) +#define __pgd(x) (x) +#define __pgprot(x) (x) + +#endif /* STRICT_MM_TYPECHECKS */ + +#include + +#endif /* __ASM_PGTABLE_3LEVEL_TYPES_H */ diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h new file mode 100644 index 00000000000..0f3b4581d92 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_PGTABLE_HWDEF_H +#define __ASM_PGTABLE_HWDEF_H + +#ifdef CONFIG_ARM64_64K_PAGES +#include +#else +#include +#endif + +/* + * Hardware page table definitions. + * + * Level 2 descriptor (PMD). + */ +#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0) +#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0) +#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) +#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) + +/* + * Section + */ +#define PMD_SECT_S (_AT(pmdval_t, 3) << 8) +#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) +#define PMD_SECT_NG (_AT(pmdval_t, 1) << 11) +#define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) + +/* + * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). + */ +#define PMD_ATTRINDX(t) (_AT(pmdval_t, (t)) << 2) +#define PMD_ATTRINDX_MASK (_AT(pmdval_t, 7) << 2) + +/* + * Level 3 descriptor (PTE). + */ +#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0) +#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0) +#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) +#define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ +#define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */ +#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ +#define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ +#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */ +#define PTE_XN (_AT(pteval_t, 1) << 54) /* XN */ + +/* + * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). + */ +#define PTE_ATTRINDX(t) (_AT(pteval_t, (t)) << 2) +#define PTE_ATTRINDX_MASK (_AT(pteval_t, 7) << 2) + +/* + * 40-bit physical address supported. + */ +#define PHYS_MASK_SHIFT (40) +#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1) + +/* + * TCR flags. + */ +#define TCR_TxSZ(x) (((UL(64) - (x)) << 16) | ((UL(64) - (x)) << 0)) +#define TCR_IRGN_NC ((UL(0) << 8) | (UL(0) << 24)) +#define TCR_IRGN_WBWA ((UL(1) << 8) | (UL(1) << 24)) +#define TCR_IRGN_WT ((UL(2) << 8) | (UL(2) << 24)) +#define TCR_IRGN_WBnWA ((UL(3) << 8) | (UL(3) << 24)) +#define TCR_IRGN_MASK ((UL(3) << 8) | (UL(3) << 24)) +#define TCR_ORGN_NC ((UL(0) << 10) | (UL(0) << 26)) +#define TCR_ORGN_WBWA ((UL(1) << 10) | (UL(1) << 26)) +#define TCR_ORGN_WT ((UL(2) << 10) | (UL(2) << 26)) +#define TCR_ORGN_WBnWA ((UL(3) << 10) | (UL(3) << 26)) +#define TCR_ORGN_MASK ((UL(3) << 10) | (UL(3) << 26)) +#define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28)) +#define TCR_TG0_64K (UL(1) << 14) +#define TCR_TG1_64K (UL(1) << 30) +#define TCR_IPS_40BIT (UL(2) << 32) +#define TCR_ASID16 (UL(1) << 36) + +#endif diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h new file mode 100644 index 00000000000..8960239be72 --- /dev/null +++ b/arch/arm64/include/asm/pgtable.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_PGTABLE_H +#define __ASM_PGTABLE_H + +#include + +#include +#include + +/* + * Software defined PTE bits definition. + */ +#define PTE_VALID (_AT(pteval_t, 1) << 0) /* pte_present() check */ +#define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ +#define PTE_DIRTY (_AT(pteval_t, 1) << 55) +#define PTE_SPECIAL (_AT(pteval_t, 1) << 56) + +/* + * VMALLOC and SPARSEMEM_VMEMMAP ranges. + */ +#define VMALLOC_START UL(0xffffff8000000000) +#define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K) + +#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) + +#define FIRST_USER_ADDRESS 0 + +#ifndef __ASSEMBLY__ +extern void __pte_error(const char *file, int line, unsigned long val); +extern void __pmd_error(const char *file, int line, unsigned long val); +extern void __pgd_error(const char *file, int line, unsigned long val); + +#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) +#ifndef CONFIG_ARM64_64K_PAGES +#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) +#endif +#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) + +/* + * The pgprot_* and protection_map entries will be fixed up at runtime to + * include the cachable and bufferable bits based on memory policy, as well as + * any architecture dependent bits like global/ASID and SMP shared mapping + * bits. + */ +#define _PAGE_DEFAULT PTE_TYPE_PAGE | PTE_AF + +extern pgprot_t pgprot_default; + +#define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b)) + +#define PAGE_NONE _MOD_PROT(pgprot_default, PTE_NG | PTE_XN | PTE_RDONLY) +#define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN) +#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG) +#define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) +#define PAGE_COPY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY) +#define PAGE_READONLY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) +#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY) +#define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_XN | PTE_DIRTY) +#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_DIRTY) + +#define __PAGE_NONE __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_XN | PTE_RDONLY) +#define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN) +#define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG) +#define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) +#define __PAGE_COPY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY) +#define __PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) +#define __PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY) + +#endif /* __ASSEMBLY__ */ + +#define __P000 __PAGE_NONE +#define __P001 __PAGE_READONLY +#define __P010 __PAGE_COPY +#define __P011 __PAGE_COPY +#define __P100 __PAGE_READONLY_EXEC +#define __P101 __PAGE_READONLY_EXEC +#define __P110 __PAGE_COPY_EXEC +#define __P111 __PAGE_COPY_EXEC + +#define __S000 __PAGE_NONE +#define __S001 __PAGE_READONLY +#define __S010 __PAGE_SHARED +#define __S011 __PAGE_SHARED +#define __S100 __PAGE_READONLY_EXEC +#define __S101 __PAGE_READONLY_EXEC +#define __S110 __PAGE_SHARED_EXEC +#define __S111 __PAGE_SHARED_EXEC + +#ifndef __ASSEMBLY__ +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern struct page *empty_zero_page; +#define ZERO_PAGE(vaddr) (empty_zero_page) + +#define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT) + +#define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) + +#define pte_none(pte) (!pte_val(pte)) +#define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) +#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) +#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr)) + +#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) +#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr)) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) + +/* + * The following only work if pte_present(). Undefined behaviour otherwise. + */ +#define pte_present(pte) (pte_val(pte) & PTE_VALID) +#define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) +#define pte_young(pte) (pte_val(pte) & PTE_AF) +#define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) +#define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) +#define pte_exec(pte) (!(pte_val(pte) & PTE_XN)) + +#define pte_present_exec_user(pte) \ + ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_XN)) == \ + (PTE_VALID | PTE_USER)) + +#define PTE_BIT_FUNC(fn,op) \ +static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } + +PTE_BIT_FUNC(wrprotect, |= PTE_RDONLY); +PTE_BIT_FUNC(mkwrite, &= ~PTE_RDONLY); +PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY); +PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY); +PTE_BIT_FUNC(mkold, &= ~PTE_AF); +PTE_BIT_FUNC(mkyoung, |= PTE_AF); +PTE_BIT_FUNC(mkspecial, |= PTE_SPECIAL); + +static inline void set_pte(pte_t *ptep, pte_t pte) +{ + *ptep = pte; +} + +extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + if (pte_present_exec_user(pte)) + __sync_icache_dcache(pte, addr); + set_pte(ptep, pte); +} + +/* + * Huge pte definitions. + */ +#define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE) +#define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE)) + +#define __pgprot_modify(prot,mask,bits) \ + __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) + +#define __HAVE_ARCH_PTE_SPECIAL + +/* + * Mark the prot value as uncacheable and unbufferable. + */ +#define pgprot_noncached(prot) \ + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE)) +#define pgprot_writecombine(prot) \ + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_GRE)) +#define pgprot_dmacoherent(prot) \ + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC)) +#define __HAVE_PHYS_MEM_ACCESS_PROT +struct file; +extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot); + +#define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_present(pmd) (pmd_val(pmd)) + +#define pmd_bad(pmd) (!(pmd_val(pmd) & 2)) + +static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) +{ + *pmdp = pmd; + dsb(); +} + +static inline void pmd_clear(pmd_t *pmdp) +{ + set_pmd(pmdp, __pmd(0)); +} + +static inline pte_t *pmd_page_vaddr(pmd_t pmd) +{ + return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); +} + +#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) + +#ifndef CONFIG_ARM64_64K_PAGES + +#define pud_none(pud) (!pud_val(pud)) +#define pud_bad(pud) (!(pud_val(pud) & 2)) +#define pud_present(pud) (pud_val(pud)) + +static inline void set_pud(pud_t *pudp, pud_t pud) +{ + *pudp = pud; + dsb(); +} + +static inline void pud_clear(pud_t *pudp) +{ + set_pud(pudp, __pud(0)); +} + +static inline pmd_t *pud_page_vaddr(pud_t pud) +{ + return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); +} + +#endif /* CONFIG_ARM64_64K_PAGES */ + +/* to find an entry in a page-table-directory */ +#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) + +#define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr)) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(addr) pgd_offset(&init_mm, addr) + +/* Find an entry in the second-level page table.. */ +#ifndef CONFIG_ARM64_64K_PAGES +#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) +static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) +{ + return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr); +} +#endif + +/* Find an entry in the third-level page table.. */ +#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + const pteval_t mask = PTE_USER | PTE_XN | PTE_RDONLY; + pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); + return pte; +} + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; + +#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) +#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) + +/* + * Encode and decode a swap entry: + * bits 0-1: present (must be zero) + * bit 2: PTE_FILE + * bits 3-8: swap type + * bits 9-63: swap offset + */ +#define __SWP_TYPE_SHIFT 3 +#define __SWP_TYPE_BITS 6 +#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) +#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) + +#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) +#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT) +#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) }) + +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) + +/* + * Ensure that there are not more swap files than can be encoded in the kernel + * the PTEs. + */ +#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) + +/* + * Encode and decode a file entry: + * bits 0-1: present (must be zero) + * bit 2: PTE_FILE + * bits 3-63: file offset / PAGE_SIZE + */ +#define pte_file(pte) (pte_val(pte) & PTE_FILE) +#define pte_to_pgoff(x) (pte_val(x) >> 3) +#define pgoff_to_pte(x) __pte(((x) << 3) | PTE_FILE) + +#define PTE_FILE_MAX_BITS 61 + +extern int kern_addr_valid(unsigned long addr); + +#include + +/* + * remap a physical page `pfn' of size `size' with page protection `prot' + * into virtual address `from' + */ +#define io_remap_pfn_range(vma,from,pfn,size,prot) \ + remap_pfn_range(vma, from, pfn, size, prot) + +#define pgtable_cache_init() do { } while (0) + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_PGTABLE_H */ diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h new file mode 100644 index 00000000000..1be62bcb9d4 --- /dev/null +++ b/arch/arm64/include/asm/sparsemem.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_SPARSEMEM_H +#define __ASM_SPARSEMEM_H + +#ifdef CONFIG_SPARSEMEM +#define MAX_PHYSMEM_BITS 40 +#define SECTION_SIZE_BITS 30 +#endif + +#endif -- cgit v1.2.3-70-g09d2 From a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6 Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Wed, 15 Aug 2012 10:28:46 -0600 Subject: mfd: Add MAX8907 core driver The MAX8907 is an I2C-based power-management IC containing voltage regulators, a reset controller, a real-time clock, and a touch-screen controller. The original driver was written by: * Gyungoh Yoo Various fixes and enhancements by: * Jin Park * Tom Cherry * Prashant Gaikwad * Dan Willemsen * Laxman Dewangan During upstreaming, I (swarren): * Converted to regmap. * Converted to regmap-irq. * Allowed probing from device tree. * Renamed from max8907c->max8907, since the driver covers at least the C and B revisions. * General cleanup. Signed-off-by: Gyungoh Yoo Signed-off-by: Stephen Warren Reviewed-by: Mark Brown #v3 Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/regulator/max8907.txt | 71 +++++ drivers/mfd/Kconfig | 12 + drivers/mfd/Makefile | 1 + drivers/mfd/max8907.c | 331 +++++++++++++++++++++ include/linux/mfd/max8907.h | 250 ++++++++++++++++ 5 files changed, 665 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/max8907.txt create mode 100644 drivers/mfd/max8907.c create mode 100644 include/linux/mfd/max8907.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/max8907.txt b/Documentation/devicetree/bindings/regulator/max8907.txt new file mode 100644 index 00000000000..4fd847f0afc --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8907.txt @@ -0,0 +1,71 @@ +MAX8907 regulator + +Required properties: +- compatible: "maxim,max8907" +- reg: I2C slave address +- interrupts: The interrupt output of the controller +- mbatt-supply: The input supply for MBATT, BBAT, SDBY, VRTC. +- in-v1-supply: The input supply for SD1. +- in-v2-supply: The input supply for SD2. +- in-v3-supply: The input supply for SD3. +- in1-supply: The input supply for LDO1. +... +- in20-supply: The input supply for LDO20. +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the regulator-compatible + property, with valid values listed below. The content of each sub-node + is defined by the standard binding for regulators; see regulator.txt. + +Valid regulator-compatible values are: + + sd1, sd2, sd3, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, ldo8, ldo9, ldo10, + ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19, ldo20, out5v, + out33v, bbat, sdby, vrtc. + +Example: + + max8907@3c { + compatible = "maxim,max8907"; + reg = <0x3c>; + interrupts = <0 86 0x4>; + + mbatt-supply = <&some_reg>; + in-v1-supply = <&mbatt_reg>; + ... + in1-supply = <&mbatt_reg>; + ... + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + mbatt_reg: regulator@0 { + reg = <0>; + regulator-compatible = "mbatt"; + regulator-name = "vbat_pmu"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + regulator@1 { + reg = <1>; + regulator-compatible = "sd1"; + regulator-name = "nvvdd_sv1,vdd_cpu_pmu"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + regulator@2 { + reg = <2>; + regulator-compatible = "sd2"; + regulator-name = "nvvdd_sv2,vdd_core"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; +... + }; + }; + }; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d1facef28a6..856ec00ab78 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -476,6 +476,18 @@ config MFD_MAX77693 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX8907 + tristate "Maxim Semiconductor MAX8907 PMIC Support" + select MFD_CORE + depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to support for Maxim Semiconductor MAX8907. This is + a Power Management IC. This driver provides common support for + accessing the device; additional drivers must be enabled in order + to use the functionality of the device. + config MFD_MAX8925 bool "Maxim Semiconductor MAX8925 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 79dd22d1dc3..2a4108d9844 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o +obj-$(CONFIG_MFD_MAX8907) += max8907.o max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c new file mode 100644 index 00000000000..6497c98e030 --- /dev/null +++ b/drivers/mfd/max8907.c @@ -0,0 +1,331 @@ +/* + * max8907.c - mfd driver for MAX8907 + * + * Copyright (C) 2010 Gyungoh Yoo + * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mfd_cell max8907_cells[] = { + { .name = "max8907-regulator", }, + { .name = "max8907-rtc", }, +}; + +static bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_ON_OFF_IRQ1: + case MAX8907_REG_ON_OFF_STAT: + case MAX8907_REG_ON_OFF_IRQ2: + case MAX8907_REG_CHG_IRQ1: + case MAX8907_REG_CHG_IRQ2: + case MAX8907_REG_CHG_STAT: + return true; + default: + return false; + } +} + +static bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_ON_OFF_IRQ1: + case MAX8907_REG_ON_OFF_IRQ2: + case MAX8907_REG_CHG_IRQ1: + case MAX8907_REG_CHG_IRQ2: + return true; + default: + return false; + } +} + +static bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return !max8907_gen_is_volatile_reg(dev, reg); +} + +static const struct regmap_config max8907_regmap_gen_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max8907_gen_is_volatile_reg, + .precious_reg = max8907_gen_is_precious_reg, + .writeable_reg = max8907_gen_is_writeable_reg, + .max_register = MAX8907_REG_LDO20VOUT, + .cache_type = REGCACHE_RBTREE, +}; + +static bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg <= MAX8907_REG_RTC_YEAR2) + return true; + + switch (reg) { + case MAX8907_REG_RTC_STATUS: + case MAX8907_REG_RTC_IRQ: + return true; + default: + return false; + } +} + +static bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_RTC_IRQ: + return true; + default: + return false; + } +} + +static bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_RTC_STATUS: + case MAX8907_REG_RTC_IRQ: + return false; + default: + return true; + } +} + +static const struct regmap_config max8907_regmap_rtc_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max8907_rtc_is_volatile_reg, + .precious_reg = max8907_rtc_is_precious_reg, + .writeable_reg = max8907_rtc_is_writeable_reg, + .max_register = MAX8907_REG_MPL_CNTL, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_irq max8907_chg_irqs[] = { + { .reg_offset = 0, .mask = 1 << 0, }, + { .reg_offset = 0, .mask = 1 << 1, }, + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 1, .mask = 1 << 0, }, + { .reg_offset = 1, .mask = 1 << 1, }, + { .reg_offset = 1, .mask = 1 << 2, }, + { .reg_offset = 1, .mask = 1 << 3, }, + { .reg_offset = 1, .mask = 1 << 4, }, + { .reg_offset = 1, .mask = 1 << 5, }, + { .reg_offset = 1, .mask = 1 << 6, }, + { .reg_offset = 1, .mask = 1 << 7, }, +}; + +static const struct regmap_irq_chip max8907_chg_irq_chip = { + .name = "max8907 chg", + .status_base = MAX8907_REG_CHG_IRQ1, + .mask_base = MAX8907_REG_CHG_IRQ1_MASK, + .wake_base = MAX8907_REG_CHG_IRQ1_MASK, + .irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1, + .num_regs = 2, + .irqs = max8907_chg_irqs, + .num_irqs = ARRAY_SIZE(max8907_chg_irqs), +}; + +static const struct regmap_irq max8907_on_off_irqs[] = { + { .reg_offset = 0, .mask = 1 << 0, }, + { .reg_offset = 0, .mask = 1 << 1, }, + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 0, .mask = 1 << 3, }, + { .reg_offset = 0, .mask = 1 << 4, }, + { .reg_offset = 0, .mask = 1 << 5, }, + { .reg_offset = 0, .mask = 1 << 6, }, + { .reg_offset = 0, .mask = 1 << 7, }, + { .reg_offset = 1, .mask = 1 << 0, }, + { .reg_offset = 1, .mask = 1 << 1, }, +}; + +static const struct regmap_irq_chip max8907_on_off_irq_chip = { + .name = "max8907 on_off", + .status_base = MAX8907_REG_ON_OFF_IRQ1, + .mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK, + .irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1, + .num_regs = 2, + .irqs = max8907_on_off_irqs, + .num_irqs = ARRAY_SIZE(max8907_on_off_irqs), +}; + +static const struct regmap_irq max8907_rtc_irqs[] = { + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 0, .mask = 1 << 3, }, +}; + +static const struct regmap_irq_chip max8907_rtc_irq_chip = { + .name = "max8907 rtc", + .status_base = MAX8907_REG_RTC_IRQ, + .mask_base = MAX8907_REG_RTC_IRQ_MASK, + .num_regs = 1, + .irqs = max8907_rtc_irqs, + .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), +}; + +static __devinit int max8907_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max8907 *max8907; + int ret; + + max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL); + if (!max8907) { + ret = -ENOMEM; + goto err_alloc_drvdata; + } + + max8907->dev = &i2c->dev; + dev_set_drvdata(max8907->dev, max8907); + + max8907->i2c_gen = i2c; + i2c_set_clientdata(i2c, max8907); + max8907->regmap_gen = devm_regmap_init_i2c(i2c, + &max8907_regmap_gen_config); + if (IS_ERR(max8907->regmap_gen)) { + ret = PTR_ERR(max8907->regmap_gen); + dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret); + goto err_regmap_gen; + } + + max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR); + if (!max8907->i2c_rtc) { + ret = -ENOMEM; + goto err_dummy_rtc; + } + i2c_set_clientdata(max8907->i2c_rtc, max8907); + max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc, + &max8907_regmap_rtc_config); + if (IS_ERR(max8907->regmap_rtc)) { + ret = PTR_ERR(max8907->regmap_rtc); + dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret); + goto err_regmap_rtc; + } + + irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN); + + ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_chg_irq_chip, + &max8907->irqc_chg); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret); + goto err_irqc_chg; + } + ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_on_off_irq_chip, + &max8907->irqc_on_off); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret); + goto err_irqc_on_off; + } + ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_rtc_irq_chip, + &max8907->irqc_rtc); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret); + goto err_irqc_rtc; + } + + enable_irq(max8907->i2c_gen->irq); + + ret = mfd_add_devices(max8907->dev, -1, max8907_cells, + ARRAY_SIZE(max8907_cells), NULL, 0, NULL); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret); + goto err_add_devices; + } + + return 0; + +err_add_devices: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); +err_irqc_rtc: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); +err_irqc_on_off: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); +err_irqc_chg: +err_regmap_rtc: + i2c_unregister_device(max8907->i2c_rtc); +err_dummy_rtc: +err_regmap_gen: +err_alloc_drvdata: + return ret; +} + +static __devexit int max8907_i2c_remove(struct i2c_client *i2c) +{ + struct max8907 *max8907 = i2c_get_clientdata(i2c); + + mfd_remove_devices(max8907->dev); + + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); + + i2c_unregister_device(max8907->i2c_rtc); + + return 0; +} + +#ifdef CONFIG_OF +static struct of_device_id max8907_of_match[] = { + { .compatible = "maxim,max8907" }, + { }, +}; +MODULE_DEVICE_TABLE(of, max8907_of_match); +#endif + +static const struct i2c_device_id max8907_i2c_id[] = { + {"max8907", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, max8907_i2c_id); + +static struct i2c_driver max8907_i2c_driver = { + .driver = { + .name = "max8907", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max8907_of_match), + }, + .probe = max8907_i2c_probe, + .remove = max8907_i2c_remove, + .id_table = max8907_i2c_id, +}; + +static int __init max8907_i2c_init(void) +{ + int ret = -ENODEV; + + ret = i2c_add_driver(&max8907_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} +subsys_initcall(max8907_i2c_init); + +static void __exit max8907_i2c_exit(void) +{ + i2c_del_driver(&max8907_i2c_driver); +} +module_exit(max8907_i2c_exit); + +MODULE_DESCRIPTION("MAX8907 multi-function core driver"); +MODULE_AUTHOR("Gyungoh Yoo "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/max8907.h b/include/linux/mfd/max8907.h new file mode 100644 index 00000000000..283531fde4e --- /dev/null +++ b/include/linux/mfd/max8907.h @@ -0,0 +1,250 @@ +/* + * Functions to access MAX8907 power management chip. + * + * Copyright (C) 2010 Gyungoh Yoo + * Copyright (C) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MFD_MAX8907_H +#define __LINUX_MFD_MAX8907_H + +#include +#include + +#define MAX8907_GEN_I2C_ADDR (0x78 >> 1) +#define MAX8907_ADC_I2C_ADDR (0x8e >> 1) +#define MAX8907_RTC_I2C_ADDR (0xd0 >> 1) + +/* MAX8907 register map */ +#define MAX8907_REG_SYSENSEL 0x00 +#define MAX8907_REG_ON_OFF_IRQ1 0x01 +#define MAX8907_REG_ON_OFF_IRQ1_MASK 0x02 +#define MAX8907_REG_ON_OFF_STAT 0x03 +#define MAX8907_REG_SDCTL1 0x04 +#define MAX8907_REG_SDSEQCNT1 0x05 +#define MAX8907_REG_SDV1 0x06 +#define MAX8907_REG_SDCTL2 0x07 +#define MAX8907_REG_SDSEQCNT2 0x08 +#define MAX8907_REG_SDV2 0x09 +#define MAX8907_REG_SDCTL3 0x0A +#define MAX8907_REG_SDSEQCNT3 0x0B +#define MAX8907_REG_SDV3 0x0C +#define MAX8907_REG_ON_OFF_IRQ2 0x0D +#define MAX8907_REG_ON_OFF_IRQ2_MASK 0x0E +#define MAX8907_REG_RESET_CNFG 0x0F +#define MAX8907_REG_LDOCTL16 0x10 +#define MAX8907_REG_LDOSEQCNT16 0x11 +#define MAX8907_REG_LDO16VOUT 0x12 +#define MAX8907_REG_SDBYSEQCNT 0x13 +#define MAX8907_REG_LDOCTL17 0x14 +#define MAX8907_REG_LDOSEQCNT17 0x15 +#define MAX8907_REG_LDO17VOUT 0x16 +#define MAX8907_REG_LDOCTL1 0x18 +#define MAX8907_REG_LDOSEQCNT1 0x19 +#define MAX8907_REG_LDO1VOUT 0x1A +#define MAX8907_REG_LDOCTL2 0x1C +#define MAX8907_REG_LDOSEQCNT2 0x1D +#define MAX8907_REG_LDO2VOUT 0x1E +#define MAX8907_REG_LDOCTL3 0x20 +#define MAX8907_REG_LDOSEQCNT3 0x21 +#define MAX8907_REG_LDO3VOUT 0x22 +#define MAX8907_REG_LDOCTL4 0x24 +#define MAX8907_REG_LDOSEQCNT4 0x25 +#define MAX8907_REG_LDO4VOUT 0x26 +#define MAX8907_REG_LDOCTL5 0x28 +#define MAX8907_REG_LDOSEQCNT5 0x29 +#define MAX8907_REG_LDO5VOUT 0x2A +#define MAX8907_REG_LDOCTL6 0x2C +#define MAX8907_REG_LDOSEQCNT6 0x2D +#define MAX8907_REG_LDO6VOUT 0x2E +#define MAX8907_REG_LDOCTL7 0x30 +#define MAX8907_REG_LDOSEQCNT7 0x31 +#define MAX8907_REG_LDO7VOUT 0x32 +#define MAX8907_REG_LDOCTL8 0x34 +#define MAX8907_REG_LDOSEQCNT8 0x35 +#define MAX8907_REG_LDO8VOUT 0x36 +#define MAX8907_REG_LDOCTL9 0x38 +#define MAX8907_REG_LDOSEQCNT9 0x39 +#define MAX8907_REG_LDO9VOUT 0x3A +#define MAX8907_REG_LDOCTL10 0x3C +#define MAX8907_REG_LDOSEQCNT10 0x3D +#define MAX8907_REG_LDO10VOUT 0x3E +#define MAX8907_REG_LDOCTL11 0x40 +#define MAX8907_REG_LDOSEQCNT11 0x41 +#define MAX8907_REG_LDO11VOUT 0x42 +#define MAX8907_REG_LDOCTL12 0x44 +#define MAX8907_REG_LDOSEQCNT12 0x45 +#define MAX8907_REG_LDO12VOUT 0x46 +#define MAX8907_REG_LDOCTL13 0x48 +#define MAX8907_REG_LDOSEQCNT13 0x49 +#define MAX8907_REG_LDO13VOUT 0x4A +#define MAX8907_REG_LDOCTL14 0x4C +#define MAX8907_REG_LDOSEQCNT14 0x4D +#define MAX8907_REG_LDO14VOUT 0x4E +#define MAX8907_REG_LDOCTL15 0x50 +#define MAX8907_REG_LDOSEQCNT15 0x51 +#define MAX8907_REG_LDO15VOUT 0x52 +#define MAX8907_REG_OUT5VEN 0x54 +#define MAX8907_REG_OUT5VSEQ 0x55 +#define MAX8907_REG_OUT33VEN 0x58 +#define MAX8907_REG_OUT33VSEQ 0x59 +#define MAX8907_REG_LDOCTL19 0x5C +#define MAX8907_REG_LDOSEQCNT19 0x5D +#define MAX8907_REG_LDO19VOUT 0x5E +#define MAX8907_REG_LBCNFG 0x60 +#define MAX8907_REG_SEQ1CNFG 0x64 +#define MAX8907_REG_SEQ2CNFG 0x65 +#define MAX8907_REG_SEQ3CNFG 0x66 +#define MAX8907_REG_SEQ4CNFG 0x67 +#define MAX8907_REG_SEQ5CNFG 0x68 +#define MAX8907_REG_SEQ6CNFG 0x69 +#define MAX8907_REG_SEQ7CNFG 0x6A +#define MAX8907_REG_LDOCTL18 0x72 +#define MAX8907_REG_LDOSEQCNT18 0x73 +#define MAX8907_REG_LDO18VOUT 0x74 +#define MAX8907_REG_BBAT_CNFG 0x78 +#define MAX8907_REG_CHG_CNTL1 0x7C +#define MAX8907_REG_CHG_CNTL2 0x7D +#define MAX8907_REG_CHG_IRQ1 0x7E +#define MAX8907_REG_CHG_IRQ2 0x7F +#define MAX8907_REG_CHG_IRQ1_MASK 0x80 +#define MAX8907_REG_CHG_IRQ2_MASK 0x81 +#define MAX8907_REG_CHG_STAT 0x82 +#define MAX8907_REG_WLED_MODE_CNTL 0x84 +#define MAX8907_REG_ILED_CNTL 0x84 +#define MAX8907_REG_II1RR 0x8E +#define MAX8907_REG_II2RR 0x8F +#define MAX8907_REG_LDOCTL20 0x9C +#define MAX8907_REG_LDOSEQCNT20 0x9D +#define MAX8907_REG_LDO20VOUT 0x9E + +/* RTC register map */ +#define MAX8907_REG_RTC_SEC 0x00 +#define MAX8907_REG_RTC_MIN 0x01 +#define MAX8907_REG_RTC_HOURS 0x02 +#define MAX8907_REG_RTC_WEEKDAY 0x03 +#define MAX8907_REG_RTC_DATE 0x04 +#define MAX8907_REG_RTC_MONTH 0x05 +#define MAX8907_REG_RTC_YEAR1 0x06 +#define MAX8907_REG_RTC_YEAR2 0x07 +#define MAX8907_REG_ALARM0_SEC 0x08 +#define MAX8907_REG_ALARM0_MIN 0x09 +#define MAX8907_REG_ALARM0_HOURS 0x0A +#define MAX8907_REG_ALARM0_WEEKDAY 0x0B +#define MAX8907_REG_ALARM0_DATE 0x0C +#define MAX8907_REG_ALARM0_MONTH 0x0D +#define MAX8907_REG_ALARM0_YEAR1 0x0E +#define MAX8907_REG_ALARM0_YEAR2 0x0F +#define MAX8907_REG_ALARM1_SEC 0x10 +#define MAX8907_REG_ALARM1_MIN 0x11 +#define MAX8907_REG_ALARM1_HOURS 0x12 +#define MAX8907_REG_ALARM1_WEEKDAY 0x13 +#define MAX8907_REG_ALARM1_DATE 0x14 +#define MAX8907_REG_ALARM1_MONTH 0x15 +#define MAX8907_REG_ALARM1_YEAR1 0x16 +#define MAX8907_REG_ALARM1_YEAR2 0x17 +#define MAX8907_REG_ALARM0_CNTL 0x18 +#define MAX8907_REG_ALARM1_CNTL 0x19 +#define MAX8907_REG_RTC_STATUS 0x1A +#define MAX8907_REG_RTC_CNTL 0x1B +#define MAX8907_REG_RTC_IRQ 0x1C +#define MAX8907_REG_RTC_IRQ_MASK 0x1D +#define MAX8907_REG_MPL_CNTL 0x1E + +/* ADC and Touch Screen Controller register map */ +#define MAX8907_CTL 0 +#define MAX8907_SEQCNT 1 +#define MAX8907_VOUT 2 + +/* mask bit fields */ +#define MAX8907_MASK_LDO_SEQ 0x1C +#define MAX8907_MASK_LDO_EN 0x01 +#define MAX8907_MASK_VBBATTCV 0x03 +#define MAX8907_MASK_OUT5V_VINEN 0x10 +#define MAX8907_MASK_OUT5V_ENSRC 0x0E +#define MAX8907_MASK_OUT5V_EN 0x01 + +/* Regulator IDs */ +#define MAX8907_MBATT 0 +#define MAX8907_SD1 1 +#define MAX8907_SD2 2 +#define MAX8907_SD3 3 +#define MAX8907_LDO1 4 +#define MAX8907_LDO2 5 +#define MAX8907_LDO3 6 +#define MAX8907_LDO4 7 +#define MAX8907_LDO5 8 +#define MAX8907_LDO6 9 +#define MAX8907_LDO7 10 +#define MAX8907_LDO8 11 +#define MAX8907_LDO9 12 +#define MAX8907_LDO10 13 +#define MAX8907_LDO11 14 +#define MAX8907_LDO12 15 +#define MAX8907_LDO13 16 +#define MAX8907_LDO14 17 +#define MAX8907_LDO15 18 +#define MAX8907_LDO16 19 +#define MAX8907_LDO17 20 +#define MAX8907_LDO18 21 +#define MAX8907_LDO19 22 +#define MAX8907_LDO20 23 +#define MAX8907_OUT5V 24 +#define MAX8907_OUT33V 25 +#define MAX8907_BBAT 26 +#define MAX8907_SDBY 27 +#define MAX8907_VRTC 28 +#define MAX8907_NUM_REGULATORS (MAX8907_VRTC + 1) + +/* IRQ definitions */ +enum { + MAX8907_IRQ_VCHG_DC_OVP = 0, + MAX8907_IRQ_VCHG_DC_F, + MAX8907_IRQ_VCHG_DC_R, + MAX8907_IRQ_VCHG_THM_OK_R, + MAX8907_IRQ_VCHG_THM_OK_F, + MAX8907_IRQ_VCHG_MBATTLOW_F, + MAX8907_IRQ_VCHG_MBATTLOW_R, + MAX8907_IRQ_VCHG_RST, + MAX8907_IRQ_VCHG_DONE, + MAX8907_IRQ_VCHG_TOPOFF, + MAX8907_IRQ_VCHG_TMR_FAULT, + + MAX8907_IRQ_GPM_RSTIN = 0, + MAX8907_IRQ_GPM_MPL, + MAX8907_IRQ_GPM_SW_3SEC, + MAX8907_IRQ_GPM_EXTON_F, + MAX8907_IRQ_GPM_EXTON_R, + MAX8907_IRQ_GPM_SW_1SEC, + MAX8907_IRQ_GPM_SW_F, + MAX8907_IRQ_GPM_SW_R, + MAX8907_IRQ_GPM_SYSCKEN_F, + MAX8907_IRQ_GPM_SYSCKEN_R, + + MAX8907_IRQ_RTC_ALARM1 = 0, + MAX8907_IRQ_RTC_ALARM0, +}; + +struct max8907_platform_data { + struct regulator_init_data *init_data[MAX8907_NUM_REGULATORS]; +}; + +struct regmap_irq_chips_data; + +struct max8907 { + struct device *dev; + struct mutex irq_lock; + struct i2c_client *i2c_gen; + struct i2c_client *i2c_rtc; + struct regmap *regmap_gen; + struct regmap *regmap_rtc; + struct regmap_irq_chip_data *irqc_chg; + struct regmap_irq_chip_data *irqc_on_off; + struct regmap_irq_chip_data *irqc_rtc; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 87d687301f380729ec320619f100f3ba39f3693d Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 5 Sep 2012 10:57:13 +0800 Subject: mfd: Add syscon driver based on regmap Add regmap based syscon driver. This is usually used for access misc bits in registers which does not belong to a specific module, for example, IMX IOMUXC GPR and ANATOP. With this driver, client can use generic regmap API to access registers which are registered into syscon. Reviewed-by: Mark Brown Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/syscon.txt | 20 +++ drivers/mfd/Kconfig | 8 ++ drivers/mfd/Makefile | 1 + drivers/mfd/syscon.c | 176 +++++++++++++++++++++++ include/linux/mfd/syscon.h | 23 +++ 5 files changed, 228 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/syscon.txt create mode 100644 drivers/mfd/syscon.c create mode 100644 include/linux/mfd/syscon.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt new file mode 100644 index 00000000000..fe8150bb324 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/syscon.txt @@ -0,0 +1,20 @@ +* System Controller Registers R/W driver + +System controller node represents a register region containing a set +of miscellaneous registers. The registers are not cohesive enough to +represent as any specific type of device. The typical use-case is for +some other node's driver, or platform-specific code, to acquire a +reference to the syscon node (e.g. by phandle, node path, or search +using a specific compatible value), interrogate the node (or associated +OS driver) to determine the location of the registers, and access the +registers directly. + +Required properties: +- compatible: Should contain "syscon". +- reg: the register region can be accessed from syscon + +Examples: +gpr: iomuxc-gpr@020e0000 { + compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; + reg = <0x020e0000 0x38>; +}; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 856ec00ab78..909d84b1f5c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1004,6 +1004,14 @@ config MFD_ANATOP MFD controller. This controller embeds regulator and thermal devices for Freescale i.MX platforms. +config MFD_SYSCON + bool "System Controller Register R/W Based on Regmap" + depends on OF + select REGMAP_MMIO + help + Select this option to enable accessing system control registers + via regmap. + config MFD_PALMAS bool "Support for the TI Palmas series chips" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2a4108d9844..07b66aff30b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -132,4 +132,5 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o +obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c new file mode 100644 index 00000000000..65fe609026c --- /dev/null +++ b/drivers/mfd/syscon.c @@ -0,0 +1,176 @@ +/* + * System Control Driver + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct platform_driver syscon_driver; + +struct syscon { + struct device *dev; + void __iomem *base; + struct regmap *regmap; +}; + +static int syscon_match(struct device *dev, void *data) +{ + struct syscon *syscon = dev_get_drvdata(dev); + struct device_node *dn = data; + + return (syscon->dev->of_node == dn) ? 1 : 0; +} + +struct regmap *syscon_node_to_regmap(struct device_node *np) +{ + struct syscon *syscon; + struct device *dev; + + dev = driver_find_device(&syscon_driver.driver, NULL, np, + syscon_match); + if (!dev) + return ERR_PTR(-EPROBE_DEFER); + + syscon = dev_get_drvdata(dev); + + return syscon->regmap; +} +EXPORT_SYMBOL_GPL(syscon_node_to_regmap); + +struct regmap *syscon_regmap_lookup_by_compatible(const char *s) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + syscon_np = of_find_compatible_node(NULL, NULL, s); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); + +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + const char *property) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + syscon_np = of_parse_phandle(np, property, 0); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); + +static const struct of_device_id of_syscon_match[] = { + { .compatible = "syscon", }, + { }, +}; + +static struct regmap_config syscon_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int __devinit syscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct syscon *syscon; + struct resource res; + int ret; + + if (!np) + return -ENOENT; + + syscon = devm_kzalloc(dev, sizeof(struct syscon), + GFP_KERNEL); + if (!syscon) + return -ENOMEM; + + syscon->base = of_iomap(np, 0); + if (!syscon->base) + return -EADDRNOTAVAIL; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + syscon_regmap_config.max_register = res.end - res.start - 3; + syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, + &syscon_regmap_config); + if (IS_ERR(syscon->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(syscon->regmap); + } + + syscon->dev = dev; + platform_set_drvdata(pdev, syscon); + + dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", + res.start, res.end); + + return 0; +} + +static int __devexit syscon_remove(struct platform_device *pdev) +{ + struct syscon *syscon; + + syscon = platform_get_drvdata(pdev); + iounmap(syscon->base); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver syscon_driver = { + .driver = { + .name = "syscon", + .owner = THIS_MODULE, + .of_match_table = of_syscon_match, + }, + .probe = syscon_probe, + .remove = __devexit_p(syscon_remove), +}; + +static int __init syscon_init(void) +{ + return platform_driver_register(&syscon_driver); +} +postcore_initcall(syscon_init); + +static void __exit syscon_exit(void) +{ + platform_driver_unregister(&syscon_driver); +} +module_exit(syscon_exit); + +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("System Control driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h new file mode 100644 index 00000000000..6aeb6b8da64 --- /dev/null +++ b/include/linux/mfd/syscon.h @@ -0,0 +1,23 @@ +/* + * System Control Driver + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng + * + * 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. + */ + +#ifndef __LINUX_MFD_SYSCON_H__ +#define __LINUX_MFD_SYSCON_H__ + +extern struct regmap *syscon_node_to_regmap(struct device_node *np); +extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); +extern struct regmap *syscon_regmap_lookup_by_phandle( + struct device_node *np, + const char *property); +#endif /* __LINUX_MFD_SYSCON_H__ */ -- cgit v1.2.3-70-g09d2 From b40c2e665cd552eae5fbdbb878bc29a34357668e Mon Sep 17 00:00:00 2001 From: Tino Reichardt Date: Mon, 17 Sep 2012 11:58:19 -0500 Subject: fs/jfs: TRIM support for JFS Filesystem This patch adds support for the two linux interfaces of the discard/TRIM command for SSD devices and sparse/thinly-provisioned LUNs. JFS will support batched discard via FITRIM ioctl and online discard with the discard mount option. Signed-off-by: Tino Reichardt Signed-off-by: Dave Kleikamp --- Documentation/filesystems/jfs.txt | 19 +++++- fs/jfs/Makefile | 2 +- fs/jfs/ioctl.c | 43 ++++++++++++- fs/jfs/jfs_discard.c | 117 +++++++++++++++++++++++++++++++++++ fs/jfs/jfs_discard.h | 26 ++++++++ fs/jfs/jfs_dmap.c | 125 ++++++++++++++++++++++++++++++++++++-- fs/jfs/jfs_dmap.h | 2 + fs/jfs/jfs_filsys.h | 3 + fs/jfs/jfs_incore.h | 1 + fs/jfs/super.c | 71 +++++++++++++++++----- 10 files changed, 385 insertions(+), 24 deletions(-) create mode 100644 fs/jfs/jfs_discard.c create mode 100644 fs/jfs/jfs_discard.h (limited to 'Documentation') diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt index 26ebde77e82..2f94f9ca179 100644 --- a/Documentation/filesystems/jfs.txt +++ b/Documentation/filesystems/jfs.txt @@ -3,6 +3,7 @@ IBM's Journaled File System (JFS) for Linux JFS Homepage: http://jfs.sourceforge.net/ The following mount options are supported: +(*) == default iocharset=name Character set to use for converting from Unicode to ASCII. The default is to do no conversion. Use @@ -21,12 +22,12 @@ nointegrity Do not write to the journal. The primary use of this option from backup media. The integrity of the volume is not guaranteed if the system abnormally abends. -integrity Default. Commit metadata changes to the journal. Use this - option to remount a volume where the nointegrity option was +integrity(*) Commit metadata changes to the journal. Use this option to + remount a volume where the nointegrity option was previously specified in order to restore normal behavior. errors=continue Keep going on a filesystem error. -errors=remount-ro Default. Remount the filesystem read-only on an error. +errors=remount-ro(*) Remount the filesystem read-only on an error. errors=panic Panic and halt the machine if an error occurs. uid=value Override on-disk uid with specified value @@ -35,6 +36,18 @@ umask=value Override on-disk umask with specified octal value. For directories, the execute bit will be set if the corresponding read bit is set. +discard=minlen This enables/disables the use of discard/TRIM commands. +discard The discard/TRIM commands are sent to the underlying +nodiscard(*) block device when blocks are freed. This is useful for SSD + devices and sparse/thinly-provisioned LUNs. The FITRIM ioctl + command is also available together with the nodiscard option. + The value of minlen specifies the minimum blockcount, when + a TRIM command to the block device is considered usefull. + When no value is given to the discard option, it defaults to + 64 blocks, which means 256KiB in JFS. + The minlen value of discard overrides the minlen value given + on an FITRIM ioctl(). + Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com. The JFS mailing list can be subscribed to by using the link labeled diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile index a58fa72d7e5..d20d4737b3e 100644 --- a/fs/jfs/Makefile +++ b/fs/jfs/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_JFS_FS) += jfs.o jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ - jfs_unicode.o jfs_dtree.o jfs_inode.o \ + jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \ jfs_extent.o symlink.o jfs_metapage.o \ jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ resize.o xattr.o ioctl.o diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index f19d1e04a37..bc555ff417e 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -11,13 +11,17 @@ #include #include #include +#include #include #include +#include "jfs_filsys.h" +#include "jfs_debug.h" #include "jfs_incore.h" #include "jfs_dinode.h" #include "jfs_inode.h" - +#include "jfs_dmap.h" +#include "jfs_discard.h" static struct { long jfs_flag; @@ -123,6 +127,40 @@ setflags_out: mnt_drop_write_file(filp); return err; } + + case FITRIM: + { + struct super_block *sb = inode->i_sb; + struct request_queue *q = bdev_get_queue(sb->s_bdev); + struct fstrim_range range; + s64 ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!blk_queue_discard(q)) { + jfs_warn("FITRIM not supported on device"); + return -EOPNOTSUPP; + } + + if (copy_from_user(&range, (struct fstrim_range __user *)arg, + sizeof(range))) + return -EFAULT; + + range.minlen = max_t(unsigned int, range.minlen, + q->limits.discard_granularity); + + ret = jfs_ioc_trim(inode, &range); + if (ret < 0) + return ret; + + if (copy_to_user((struct fstrim_range __user *)arg, &range, + sizeof(range))) + return -EFAULT; + + return 0; + } + default: return -ENOTTY; } @@ -142,6 +180,9 @@ long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case JFS_IOC_SETFLAGS32: cmd = JFS_IOC_SETFLAGS; break; + case FITRIM: + cmd = FITRIM; + break; } return jfs_ioctl(filp, cmd, arg); } diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c new file mode 100644 index 00000000000..9947563e417 --- /dev/null +++ b/fs/jfs/jfs_discard.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) Tino Reichardt, 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "jfs_incore.h" +#include "jfs_superblock.h" +#include "jfs_discard.h" +#include "jfs_dmap.h" +#include "jfs_debug.h" + + +/* + * NAME: jfs_issue_discard() + * + * FUNCTION: TRIM the specified block range on device, if supported + * + * PARAMETERS: + * ip - pointer to in-core inode + * blkno - starting block number to be trimmed (0..N) + * nblocks - number of blocks to be trimmed + * + * RETURN VALUES: + * none + * + * serialization: IREAD_LOCK(ipbmap) held on entry/exit; + */ +void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks) +{ + struct super_block *sb = ip->i_sb; + int r = 0; + + r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0); + if (unlikely(r != 0)) { + jfs_err("JFS: sb_issue_discard" \ + "(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!\n", + sb, (unsigned long long)blkno, + (unsigned long long)nblocks, r); + } + + jfs_info("JFS: sb_issue_discard" \ + "(%p, %llu, %llu, GFP_NOFS, 0) = %d\n", + sb, (unsigned long long)blkno, + (unsigned long long)nblocks, r); + + return; +} + +/* + * NAME: jfs_ioc_trim() + * + * FUNCTION: attempt to discard (TRIM) all free blocks from the + * filesystem. + * + * PARAMETERS: + * ip - pointer to in-core inode; + * range - the range, given by user space + * + * RETURN VALUES: + * 0 - success + * -EIO - i/o error + */ +int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range) +{ + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; + struct super_block *sb = ipbmap->i_sb; + int agno, agno_end; + s64 start, end, minlen; + u64 trimmed = 0; + + /** + * convert byte values to block size of filesystem: + * start: First Byte to trim + * len: number of Bytes to trim from start + * minlen: minimum extent length in Bytes + */ + start = range->start >> sb->s_blocksize_bits; + if (start < 0) + start = 0; + end = start + (range->len >> sb->s_blocksize_bits) - 1; + if (end >= bmp->db_mapsize) + end = bmp->db_mapsize - 1; + minlen = range->minlen >> sb->s_blocksize_bits; + if (minlen <= 0) + minlen = 1; + + /** + * we trim all ag's within the range + */ + agno = BLKTOAG(start, JFS_SBI(ip->i_sb)); + agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb)); + while (agno <= agno_end) { + trimmed += dbDiscardAG(ip, agno, minlen); + agno++; + } + range->len = trimmed << sb->s_blocksize_bits; + + return 0; +} diff --git a/fs/jfs/jfs_discard.h b/fs/jfs/jfs_discard.h new file mode 100644 index 00000000000..40d1ee6081a --- /dev/null +++ b/fs/jfs/jfs_discard.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) Tino Reichardt, 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _H_JFS_DISCARD +#define _H_JFS_DISCARD + +struct fstrim_range; + +extern void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks); +extern int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range); + +#endif /* _H_JFS_DISCARD */ diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 9cbd11a3f80..174feb6a73c 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -1,5 +1,6 @@ /* * Copyright (C) International Business Machines Corp., 2000-2004 + * Portions Copyright (C) Tino Reichardt, 2012 * * 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 @@ -25,6 +26,7 @@ #include "jfs_lock.h" #include "jfs_metapage.h" #include "jfs_debug.h" +#include "jfs_discard.h" /* * SERIALIZATION of the Block Allocation Map. @@ -104,7 +106,6 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, int nblocks); static int dbMaxBud(u8 * cp); -s64 dbMapFileSizeToMapSize(struct inode *ipbmap); static int blkstol2(s64 nb); static int cntlz(u32 value); @@ -145,7 +146,6 @@ static const s8 budtab[256] = { 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 }; - /* * NAME: dbMount() * @@ -310,7 +310,6 @@ int dbSync(struct inode *ipbmap) return (0); } - /* * NAME: dbFree() * @@ -337,6 +336,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) s64 lblkno, rem; struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; + struct super_block *sb = ipbmap->i_sb; IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); @@ -351,6 +351,13 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) return -EIO; } + /** + * TRIM the blocks, when mounted with discard option + */ + if (JFS_SBI(sb)->flag & JFS_DISCARD) + if (JFS_SBI(sb)->minblks_trim <= nblocks) + jfs_issue_discard(ipbmap, blkno, nblocks); + /* * free the blocks a dmap at a time. */ @@ -1095,7 +1102,6 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) /* we were not successful */ release_metapage(mp); - return (rc); } @@ -1589,6 +1595,117 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results) } +/* + * NAME: dbDiscardAG() + * + * FUNCTION: attempt to discard (TRIM) all free blocks of specific AG + * + * algorithm: + * 1) allocate blocks, as large as possible and save them + * while holding IWRITE_LOCK on ipbmap + * 2) trim all these saved block/length values + * 3) mark the blocks free again + * + * benefit: + * - we work only on one ag at some time, minimizing how long we + * need to lock ipbmap + * - reading / writing the fs is possible most time, even on + * trimming + * + * downside: + * - we write two times to the dmapctl and dmap pages + * - but for me, this seems the best way, better ideas? + * /TR 2012 + * + * PARAMETERS: + * ip - pointer to in-core inode + * agno - ag to trim + * minlen - minimum value of contiguous blocks + * + * RETURN VALUES: + * s64 - actual number of blocks trimmed + */ +s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen) +{ + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; + s64 nblocks, blkno; + u64 trimmed = 0; + int rc, l2nb; + struct super_block *sb = ipbmap->i_sb; + + struct range2trim { + u64 blkno; + u64 nblocks; + } *totrim, *tt; + + /* max blkno / nblocks pairs to trim */ + int count = 0, range_cnt; + + /* prevent others from writing new stuff here, while trimming */ + IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP); + + nblocks = bmp->db_agfree[agno]; + range_cnt = nblocks; + do_div(range_cnt, (int)minlen); + range_cnt = min(range_cnt + 1, 32 * 1024); + totrim = kmalloc(sizeof(struct range2trim) * range_cnt, GFP_NOFS); + if (totrim == NULL) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbDiscardAG: no memory for trim array"); + IWRITE_UNLOCK(ipbmap); + return 0; + } + + tt = totrim; + while (nblocks >= minlen) { + l2nb = BLKSTOL2(nblocks); + + /* 0 = okay, -EIO = fatal, -ENOSPC -> try smaller block */ + rc = dbAllocAG(bmp, agno, nblocks, l2nb, &blkno); + if (rc == 0) { + tt->blkno = blkno; + tt->nblocks = nblocks; + tt++; count++; + + /* the whole ag is free, trim now */ + if (bmp->db_agfree[agno] == 0) + break; + + /* give a hint for the next while */ + nblocks = bmp->db_agfree[agno]; + continue; + } else if (rc == -ENOSPC) { + /* search for next smaller log2 block */ + l2nb = BLKSTOL2(nblocks) - 1; + nblocks = 1 << l2nb; + } else { + /* Trim any already allocated blocks */ + jfs_error(bmp->db_ipbmap->i_sb, + "dbDiscardAG: -EIO"); + break; + } + + /* check, if our trim array is full */ + if (unlikely(count >= range_cnt - 1)) + break; + } + IWRITE_UNLOCK(ipbmap); + + tt->nblocks = 0; /* mark the current end */ + for (tt = totrim; tt->nblocks != 0; tt++) { + /* when mounted with online discard, dbFree() will + * call jfs_issue_discard() itself */ + if (!(JFS_SBI(sb)->flag & JFS_DISCARD)) + jfs_issue_discard(ip, tt->blkno, tt->nblocks); + dbFree(ip, tt->blkno, tt->nblocks); + trimmed += tt->nblocks; + } + kfree(totrim); + + return trimmed; +} + /* * NAME: dbFindCtl() * diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h index 6dcb906c55d..562b9a7e431 100644 --- a/fs/jfs/jfs_dmap.h +++ b/fs/jfs/jfs_dmap.h @@ -311,4 +311,6 @@ extern int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks); extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks); extern void dbFinalizeBmap(struct inode *ipbmap); extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap); +extern s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen); + #endif /* _H_JFS_DMAP */ diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index b3f5463fbe5..b67d64671bb 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h @@ -45,6 +45,9 @@ /* mount time flag to disable journaling to disk */ #define JFS_NOINTEGRITY 0x00000040 +/* mount time flag to enable TRIM to ssd disks */ +#define JFS_DISCARD 0x00000080 + /* commit option */ #define JFS_COMMIT 0x00000f00 /* commit option mask */ #define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */ diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 584a4a1a6e8..4fa958ae198 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -195,6 +195,7 @@ struct jfs_sb_info { uint uid; /* uid to override on-disk uid */ uint gid; /* gid to override on-disk gid */ uint umask; /* umask to override on-disk umask */ + uint minblks_trim; /* minimum blocks, for online trim */ }; /* jfs_sb_info commit_state */ diff --git a/fs/jfs/super.c b/fs/jfs/super.c index c55c7452d28..6f4ac1c070f 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" @@ -100,7 +101,7 @@ void jfs_error(struct super_block *sb, const char * function, ...) vsnprintf(error_buf, sizeof(error_buf), function, args); va_end(args); - printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf); + pr_err("ERROR: (device %s): %s\n", sb->s_id, error_buf); jfs_handle_error(sb); } @@ -197,7 +198,8 @@ static void jfs_put_super(struct super_block *sb) enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask + Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, + Opt_discard, Opt_nodiscard, Opt_discard_minblk }; static const match_table_t tokens = { @@ -214,6 +216,9 @@ static const match_table_t tokens = { {Opt_uid, "uid=%u"}, {Opt_gid, "gid=%u"}, {Opt_umask, "umask=%u"}, + {Opt_discard, "discard"}, + {Opt_nodiscard, "nodiscard"}, + {Opt_discard_minblk, "discard=%u"}, {Opt_err, NULL} }; @@ -255,8 +260,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, else { nls_map = load_nls(args[0].from); if (!nls_map) { - printk(KERN_ERR - "JFS: charset not found\n"); + pr_err("JFS: charset not found\n"); goto cleanup; } } @@ -272,8 +276,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, *newLVSize = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; if (*newLVSize == 0) - printk(KERN_ERR - "JFS: Cannot determine volume size\n"); + pr_err("JFS: Cannot determine volume size\n"); break; } case Opt_errors: @@ -294,8 +297,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, *flag &= ~JFS_ERR_REMOUNT_RO; *flag |= JFS_ERR_PANIC; } else { - printk(KERN_ERR - "JFS: %s is an invalid error handler\n", + pr_err("JFS: %s is an invalid error handler\n", errors); goto cleanup; } @@ -314,8 +316,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, case Opt_usrquota: case Opt_grpquota: case Opt_quota: - printk(KERN_ERR - "JFS: quota operations not supported\n"); + pr_err("JFS: quota operations not supported\n"); break; #endif case Opt_uid: @@ -324,23 +325,61 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, sbi->uid = simple_strtoul(uid, &uid, 0); break; } + case Opt_gid: { char *gid = args[0].from; sbi->gid = simple_strtoul(gid, &gid, 0); break; } + case Opt_umask: { char *umask = args[0].from; sbi->umask = simple_strtoul(umask, &umask, 8); if (sbi->umask & ~0777) { - printk(KERN_ERR - "JFS: Invalid value of umask\n"); + pr_err("JFS: Invalid value of umask\n"); goto cleanup; } break; } + + case Opt_discard: + { + struct request_queue *q = bdev_get_queue(sb->s_bdev); + /* if set to 1, even copying files will cause + * trimming :O + * -> user has more control over the online trimming + */ + sbi->minblks_trim = 64; + if (blk_queue_discard(q)) { + *flag |= JFS_DISCARD; + } else { + pr_err("JFS: discard option " \ + "not supported on device\n"); + } + break; + } + + case Opt_nodiscard: + *flag &= ~JFS_DISCARD; + break; + + case Opt_discard_minblk: + { + struct request_queue *q = bdev_get_queue(sb->s_bdev); + char *minblks_trim = args[0].from; + if (blk_queue_discard(q)) { + *flag |= JFS_DISCARD; + sbi->minblks_trim = simple_strtoull( + minblks_trim, &minblks_trim, 0); + } else { + pr_err("JFS: discard option " \ + "not supported on device\n"); + } + break; + } + default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -374,8 +413,8 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) if (newLVSize) { if (sb->s_flags & MS_RDONLY) { - printk(KERN_ERR - "JFS: resize requires volume to be mounted read-write\n"); + pr_err("JFS: resize requires volume" \ + " to be mounted read-write\n"); return -EROFS; } rc = jfs_extendfs(sb, newLVSize, 0); @@ -457,7 +496,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) #endif if (newLVSize) { - printk(KERN_ERR "resize option for remount only\n"); + pr_err("resize option for remount only\n"); goto out_kfree; } @@ -625,6 +664,8 @@ static int jfs_show_options(struct seq_file *seq, struct dentry *root) seq_printf(seq, ",umask=%03o", sbi->umask); if (sbi->flag & JFS_NOINTEGRITY) seq_puts(seq, ",nointegrity"); + if (sbi->flag & JFS_DISCARD) + seq_printf(seq, ",discard=%u", sbi->minblks_trim); if (sbi->nls_tab) seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset); if (sbi->flag & JFS_ERR_CONTINUE) -- cgit v1.2.3-70-g09d2 From 16221d9071d48841b23256a2ad643a845d5aaf80 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 14 Sep 2012 15:48:35 -0500 Subject: jfs: Remove obsolete email address The MAINTAINERS file suffices. Signed-off-by: Dave Kleikamp --- Documentation/filesystems/jfs.txt | 2 -- 1 file changed, 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt index 2f94f9ca179..f7433355394 100644 --- a/Documentation/filesystems/jfs.txt +++ b/Documentation/filesystems/jfs.txt @@ -48,7 +48,5 @@ nodiscard(*) block device when blocks are freed. This is useful for SSD The minlen value of discard overrides the minlen value given on an FITRIM ioctl(). -Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com. - The JFS mailing list can be subscribed to by using the link labeled "Mail list Subscribe" at our web page http://jfs.sourceforge.net/ -- cgit v1.2.3-70-g09d2 From 879238fecc051d95037ae76332916209a7770709 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Sun, 16 Sep 2012 12:55:40 +0200 Subject: KVM: clarify kvmclock documentation - mention that system time needs to be added to wallclock time - positive tsc_shift means left shift, not right - mention additional 32bit right shift Signed-off-by: Stefan Fritsch Signed-off-by: Marcelo Tosatti --- Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt index 73047104858..6d470ae7b07 100644 --- a/Documentation/virtual/kvm/msr.txt +++ b/Documentation/virtual/kvm/msr.txt @@ -34,9 +34,12 @@ MSR_KVM_WALL_CLOCK_NEW: 0x4b564d00 time information and check that they are both equal and even. An odd version indicates an in-progress update. - sec: number of seconds for wallclock. + sec: number of seconds for wallclock at time of boot. - nsec: number of nanoseconds for wallclock. + nsec: number of nanoseconds for wallclock at time of boot. + + In order to get the current wallclock time, the system_time from + MSR_KVM_SYSTEM_TIME_NEW needs to be added. Note that although MSRs are per-CPU entities, the effect of this particular MSR is global. @@ -82,20 +85,25 @@ MSR_KVM_SYSTEM_TIME_NEW: 0x4b564d01 time at the time this structure was last updated. Unit is nanoseconds. - tsc_to_system_mul: a function of the tsc frequency. One has - to multiply any tsc-related quantity by this value to get - a value in nanoseconds, besides dividing by 2^tsc_shift + tsc_to_system_mul: multiplier to be used when converting + tsc-related quantity to nanoseconds - tsc_shift: cycle to nanosecond divider, as a power of two, to - allow for shift rights. One has to shift right any tsc-related - quantity by this value to get a value in nanoseconds, besides - multiplying by tsc_to_system_mul. + tsc_shift: shift to be used when converting tsc-related + quantity to nanoseconds. This shift will ensure that + multiplication with tsc_to_system_mul does not overflow. + A positive value denotes a left shift, a negative value + a right shift. - With this information, guests can derive per-CPU time by - doing: + The conversion from tsc to nanoseconds involves an additional + right shift by 32 bits. With this information, guests can + derive per-CPU time by doing: time = (current_tsc - tsc_timestamp) - time = (time * tsc_to_system_mul) >> tsc_shift + if (tsc_shift >= 0) + time <<= tsc_shift; + else + time >>= -tsc_shift; + time = (time * tsc_to_system_mul) >> 32 time = time + system_time flags: bits in this field indicate extended capabilities -- cgit v1.2.3-70-g09d2 From 9bc1503185a09930782012fda5601694caeec77a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 6 Sep 2012 09:07:57 +0100 Subject: ARM: 7516/1: plat-versatile: add DT support to FPGA IRQ This adds Device Tree probing support to the Versatile FPGA IRQ controller. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- .../devicetree/bindings/arm/versatile-fpga-irq.txt | 31 ++++++++++ arch/arm/plat-versatile/fpga-irq.c | 72 +++++++++++++++++++--- arch/arm/plat-versatile/include/plat/fpga-irq.h | 2 + 3 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt b/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt new file mode 100644 index 00000000000..9989eda755d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt @@ -0,0 +1,31 @@ +* ARM Versatile FPGA interrupt controller + +One or more FPGA IRQ controllers can be synthesized in an ARM reference board +such as the Integrator or Versatile family. The output of these different +controllers are OR:ed together and fed to the CPU tile's IRQ input. Each +instance can handle up to 32 interrupts. + +Required properties: +- compatible: "arm,versatile-fpga-irq" +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: The number of cells to define the interrupts. Must be 1 + as the FPGA IRQ controller has no configuration options for interrupt + sources. The cell is a u32 and defines the interrupt number. +- reg: The register bank for the FPGA interrupt controller. +- clear-mask: a u32 number representing the mask written to clear all IRQs + on the controller at boot for example. +- valid-mask: a u32 number representing a bit mask determining which of + the interrupts are valid. Unconnected/unused lines are set to 0, and + the system till not make it possible for devices to request these + interrupts. + +Example: + +pic: pic@14000000 { + compatible = "arm,versatile-fpga-irq"; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0x14000000 0x100>; + clear-mask = <0xffffffff>; + valid-mask = <0x003fffff>; +}; diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c index 6e70d03824a..091ae103004 100644 --- a/arch/arm/plat-versatile/fpga-irq.c +++ b/arch/arm/plat-versatile/fpga-irq.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -14,11 +16,17 @@ #define IRQ_RAW_STATUS 0x04 #define IRQ_ENABLE_SET 0x08 #define IRQ_ENABLE_CLEAR 0x0c +#define INT_SOFT_SET 0x10 +#define INT_SOFT_CLEAR 0x14 +#define FIQ_STATUS 0x20 +#define FIQ_RAW_STATUS 0x24 +#define FIQ_ENABLE 0x28 +#define FIQ_ENABLE_SET 0x28 +#define FIQ_ENABLE_CLEAR 0x2C /** * struct fpga_irq_data - irq data container for the FPGA IRQ controller * @base: memory offset in virtual memory - * @irq_start: first IRQ number handled by this instance * @chip: chip container for this instance * @domain: IRQ domain for this instance * @valid: mask for valid IRQs on this controller @@ -26,7 +34,6 @@ */ struct fpga_irq_data { void __iomem *base; - unsigned int irq_start; struct irq_chip chip; u32 valid; struct irq_domain *domain; @@ -125,34 +132,79 @@ static struct irq_domain_ops fpga_irqdomain_ops = { .xlate = irq_domain_xlate_onetwocell, }; -void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, - int parent_irq, u32 valid, struct device_node *node) -{ +static __init struct fpga_irq_data * +fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { struct fpga_irq_data *f; if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { printk(KERN_ERR "%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); - return; + return NULL; } - f = &fpga_irq_devices[fpga_irq_id]; f->base = base; - f->irq_start = irq_start; f->chip.name = name; f->chip.irq_ack = fpga_irq_mask; f->chip.irq_mask = fpga_irq_mask; f->chip.irq_unmask = fpga_irq_unmask; f->valid = valid; + fpga_irq_id++; + + return f; +} + +void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, + int parent_irq, u32 valid, struct device_node *node) +{ + struct fpga_irq_data *f; + + f = fpga_irq_prep_struct(base, name, valid); + if (!f) + return; if (parent_irq != -1) { irq_set_handler_data(parent_irq, f); irq_set_chained_handler(parent_irq, fpga_irq_handle); } - f->domain = irq_domain_add_legacy(node, fls(valid), f->irq_start, 0, + f->domain = irq_domain_add_legacy(node, fls(valid), irq_start, 0, &fpga_irqdomain_ops, f); pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", fpga_irq_id, name, base, f->used_irqs); +} - fpga_irq_id++; +#ifdef CONFIG_OF +int __init fpga_irq_of_init(struct device_node *node, + struct device_node *parent) +{ + struct fpga_irq_data *f; + void __iomem *base; + u32 clear_mask; + u32 valid_mask; + + if (WARN_ON(!node)) + return -ENODEV; + + base = of_iomap(node, 0); + WARN(!base, "unable to map fpga irq registers\n"); + + if (of_property_read_u32(node, "clear-mask", &clear_mask)) + clear_mask = 0; + + if (of_property_read_u32(node, "valid-mask", &valid_mask)) + valid_mask = 0; + + f = fpga_irq_prep_struct(base, node->name, valid_mask); + if (!f) + return -ENOMEM; + + writel(clear_mask, base + IRQ_ENABLE_CLEAR); + writel(clear_mask, base + FIQ_ENABLE_CLEAR); + + f->domain = irq_domain_add_linear(node, fls(valid_mask), &fpga_irqdomain_ops, f); + f->used_irqs = hweight32(valid_mask); + + pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", + fpga_irq_id, node->name, base, f->used_irqs); + return 0; } +#endif diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h index 91bcfb67551..1fac9651d3c 100644 --- a/arch/arm/plat-versatile/include/plat/fpga-irq.h +++ b/arch/arm/plat-versatile/include/plat/fpga-irq.h @@ -7,5 +7,7 @@ struct pt_regs; void fpga_handle_irq(struct pt_regs *regs); void fpga_irq_init(void __iomem *, const char *, int, int, u32, struct device_node *node); +int fpga_irq_of_init(struct device_node *node, + struct device_node *parent); #endif -- cgit v1.2.3-70-g09d2 From 4980f9bc2cec0f8ff0e0f2b021d46c7606ae1849 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 6 Sep 2012 09:08:24 +0100 Subject: ARM: 7517/1: integrator: initial device tree support This is initial device tree support for the ARM Integrator family, we create a very basic device tree, #ifdef out the non-DT machines when compiling for device tree. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- Documentation/devicetree/bindings/arm/arm-boards | 12 ++ arch/arm/boot/dts/integrator.dtsi | 33 +++++ arch/arm/boot/dts/integratorap.dts | 36 ++++++ arch/arm/boot/dts/integratorcp.dts | 54 ++++++++ arch/arm/mach-integrator/integrator_ap.c | 139 ++++++++++++++++---- arch/arm/mach-integrator/integrator_cp.c | 154 ++++++++++++++++------- 6 files changed, 360 insertions(+), 68 deletions(-) create mode 100644 arch/arm/boot/dts/integrator.dtsi create mode 100644 arch/arm/boot/dts/integratorap.dts create mode 100644 arch/arm/boot/dts/integratorcp.dts (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards index 91f26148af7..fc81a7d6b0f 100644 --- a/Documentation/devicetree/bindings/arm/arm-boards +++ b/Documentation/devicetree/bindings/arm/arm-boards @@ -1,3 +1,15 @@ +ARM Integrator/AP (Application Platform) and Integrator/CP (Compact Platform) +----------------------------------------------------------------------------- +ARM's oldest Linux-supported platform with connectors for different core +tiles of ARMv4, ARMv5 and ARMv6 type. + +Required properties (in root node): + compatible = "arm,integrator-ap"; /* Application Platform */ + compatible = "arm,integrator-cp"; /* Compact Platform */ + +FPGA type interrupt controllers, see the versatile-fpga-irq binding doc. + + ARM Versatile Application and Platform Baseboards ------------------------------------------------- ARM's development hardware platform with connectors for customizable diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi new file mode 100644 index 00000000000..b464abadd10 --- /dev/null +++ b/arch/arm/boot/dts/integrator.dtsi @@ -0,0 +1,33 @@ +/* + * SoC core Device Tree for the ARM Integrator platforms + */ + +/include/ "skeleton.dtsi" + +/ { + timer@13000000 { + reg = <0x13000000 0x100>; + interrupt-parent = <&pic>; + interrupts = <5>; + }; + + timer@13000100 { + reg = <0x13000100 0x100>; + interrupt-parent = <&pic>; + interrupts = <6>; + }; + + timer@13000200 { + reg = <0x13000200 0x100>; + interrupt-parent = <&pic>; + interrupts = <7>; + }; + + pic@14000000 { + compatible = "arm,versatile-fpga-irq"; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0x14000000 0x100>; + clear-mask = <0xffffffff>; + }; +}; diff --git a/arch/arm/boot/dts/integratorap.dts b/arch/arm/boot/dts/integratorap.dts new file mode 100644 index 00000000000..083ff395de0 --- /dev/null +++ b/arch/arm/boot/dts/integratorap.dts @@ -0,0 +1,36 @@ +/* + * Device Tree for the ARM Integrator/AP platform + */ + +/dts-v1/; +/include/ "integrator.dtsi" + +/ { + model = "ARM Integrator/AP"; + compatible = "arm,integrator-ap"; + + aliases { + arm,timer-primary = &timer2; + arm,timer-secondary = &timer1; + }; + + chosen { + bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk"; + }; + + timer0: timer@13000000 { + compatible = "arm,integrator-timer"; + }; + + timer1: timer@13000100 { + compatible = "arm,integrator-timer"; + }; + + timer2: timer@13000200 { + compatible = "arm,integrator-timer"; + }; + + pic: pic@14000000 { + valid-mask = <0x003fffff>; + }; +}; diff --git a/arch/arm/boot/dts/integratorcp.dts b/arch/arm/boot/dts/integratorcp.dts new file mode 100644 index 00000000000..63033144442 --- /dev/null +++ b/arch/arm/boot/dts/integratorcp.dts @@ -0,0 +1,54 @@ +/* + * Device Tree for the ARM Integrator/CP platform + */ + +/dts-v1/; +/include/ "integrator.dtsi" + +/ { + model = "ARM Integrator/CP"; + compatible = "arm,integrator-cp"; + + aliases { + arm,timer-primary = &timer2; + arm,timer-secondary = &timer1; + }; + + chosen { + bootargs = "root=/dev/ram0 console=ttyAMA0,38400n8 earlyprintk"; + }; + + timer0: timer@13000000 { + compatible = "arm,sp804", "arm,primecell"; + }; + + timer1: timer@13000100 { + compatible = "arm,sp804", "arm,primecell"; + }; + + timer2: timer@13000200 { + compatible = "arm,sp804", "arm,primecell"; + }; + + pic: pic@14000000 { + valid-mask = <0x1fc003ff>; + }; + + cic: cic@10000040 { + compatible = "arm,versatile-fpga-irq"; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0x10000040 0x100>; + clear-mask = <0xffffffff>; + valid-mask = <0x00000007>; + }; + + sic: sic@ca000000 { + compatible = "arm,versatile-fpga-irq"; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0xca000000 0x100>; + clear-mask = <0x00000fff>; + valid-mask = <0x00000fff>; + }; +}; diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index ff966d83281..57add86c4a6 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include