aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/cx23885/Kconfig17
-rw-r--r--drivers/media/video/cx23885/Makefile9
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c198
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c1601
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c199
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c375
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h429
-rw-r--r--drivers/media/video/cx23885/cx23885.h295
9 files changed, 3124 insertions, 0 deletions
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 00699c36ec1..9e99d2e1c1b 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -124,5 +124,6 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
new file mode 100644
index 00000000000..ea53466dacb
--- /dev/null
+++ b/drivers/media/video/cx23885/Kconfig
@@ -0,0 +1,17 @@
+config VIDEO_CX23885
+ tristate "Conexant cx23885 (2388x successor) support"
+ depends on VIDEO_DEV && PCI && I2C
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_BTCX
+ select VIDEO_BUF
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ ---help---
+ This is a video4linux driver for Conexant 23885 based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx23885
+
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
new file mode 100644
index 00000000000..665067022d2
--- /dev/null
+++ b/drivers/media/video/cx23885/Makefile
@@ -0,0 +1,9 @@
+cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+
+obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
new file mode 100644
index 00000000000..9344fb5d95f
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -0,0 +1,198 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "cx23885.h"
+
+/* ------------------------------------------------------------------ */
+/* board config info */
+
+struct cx23885_board cx23885_boards[] = {
+ [CX23885_BOARD_UNKNOWN] = {
+ .name = "UNKNOWN/GENERIC",
+ .bridge = CX23885_BRIDGE_UNDEFINED,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 0,
+ },{
+ .type = CX23885_VMUX_COMPOSITE2,
+ .vmux = 1,
+ },{
+ .type = CX23885_VMUX_COMPOSITE3,
+ .vmux = 2,
+ },{
+ .type = CX23885_VMUX_COMPOSITE4,
+ .vmux = 3,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
+ .name = "Hauppauge WinTV-HVR1800lp",
+ .bridge = CX23885_BRIDGE_885,
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+ .name = "Hauppauge WinTV-HVR1800",
+ .bridge = CX23885_BRIDGE_887,
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+};
+const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs */
+
+struct cx23885_subid cx23885_subids[] = {
+ {
+ .subvendor = 0x0070,
+ .subdevice = 0x3400,
+ .card = CX23885_BOARD_UNKNOWN,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7600,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7800,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7801,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ },
+};
+const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+void cx23885_card_list(struct cx23885_dev *dev)
+{
+ int i;
+
+ if (0 == dev->pci->subsystem_vendor &&
+ 0 == dev->pci->subsystem_device) {
+ printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name, dev->name, dev->name, dev->name, dev->name);
+ } else {
+ printk("%s: Your board isn't known (yet) to the driver. You can\n"
+ "%s: try to pick one of the existing card configs via\n"
+ "%s: card=<n> insmod option. Updating to the latest\n"
+ "%s: version might help as well.\n",
+ dev->name, dev->name, dev->name, dev->name);
+ }
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < cx23885_bcount; i++)
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, cx23885_boards[i].name);
+}
+
+static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data);
+
+
+ /* Make sure we support the board model */
+ switch (tv.model)
+ {
+ case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
+ case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+ case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+ case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+ break;
+ default:
+ printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ dev->name, tv.model);
+}
+
+void cx23885_card_setup(struct cx23885_dev *dev)
+{
+ static u8 eeprom[256];
+
+ if (dev->i2c_bus[0].i2c_rc == 0) {
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0x80);
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(cx23885_boards);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
new file mode 100644
index 00000000000..876d396fb7a
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -0,0 +1,1601 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+
+MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
+
+static unsigned int cx23885_devcount;
+
+static DEFINE_MUTEX(devlist);
+static LIST_HEAD(cx23885_devlist);
+
+#define NO_SYNC_LINE (-1U)
+
+/*
+ * CX23885 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ * 15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23885_sram_channels[] = {
+ [SRAM_CH01] = {
+ .name = "test ch1",
+ .cmds_start = 0x10000,
+ .ctrl_start = 0x10500,
+ .cdt = 0x10900,
+ .fifo_start = 0x3000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA1_PTR1,
+ .ptr2_reg = DMA1_PTR2,
+ .cnt1_reg = DMA1_CNT1,
+ .cnt2_reg = DMA1_CNT2,
+ .jumponly = 1,
+ },
+ [SRAM_CH02] = {
+ .name = "ch2",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA2_PTR1,
+ .ptr2_reg = DMA2_PTR2,
+ .cnt1_reg = DMA2_CNT1,
+ .cnt2_reg = DMA2_CNT2,
+ },
+ [SRAM_CH03] = {
+ .name = "ch3",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA3_PTR1,
+ .ptr2_reg = DMA3_PTR2,
+ .cnt1_reg = DMA3_CNT1,
+ .cnt2_reg = DMA3_CNT2,
+ },
+ [SRAM_CH04] = {
+ .name = "ch4",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA4_PTR1,
+ .ptr2_reg = DMA4_PTR2,
+ .cnt1_reg = DMA4_CNT1,
+ .cnt2_reg = DMA4_CNT2,
+ },
+ [SRAM_CH05] = {
+ .name = "ch5",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH06] = {
+ .name = "TS2 C",
+ .cmds_start = 0x10140,
+ .ctrl_start = 0x10680,
+ .cdt = 0x10480,
+ .fifo_start = 0x6000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH07] = {
+ .name = "ch7",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA6_PTR1,
+ .ptr2_reg = DMA6_PTR2,
+ .cnt1_reg = DMA6_CNT1,
+ .cnt2_reg = DMA6_CNT2,
+ },
+ [SRAM_CH08] = {
+ .name = "ch8",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA7_PTR1,
+ .ptr2_reg = DMA7_PTR2,
+ .cnt1_reg = DMA7_CNT1,
+ .cnt2_reg = DMA7_CNT2,
+ },
+ [SRAM_CH09] = {
+ .name = "ch9",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA8_PTR1,
+ .ptr2_reg = DMA8_PTR2,
+ .cnt1_reg = DMA8_CNT1,
+ .cnt2_reg = DMA8_CNT2,
+ },
+};
+
+/* FIXME, these allocations will change when
+ * analog arrives. The be reviewed.
+ * CX23887 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ * 15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23887_sram_channels[] = {
+ [SRAM_CH01] = {
+ .name = "test ch1",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA1_PTR1,
+ .ptr2_reg = DMA1_PTR2,
+ .cnt1_reg = DMA1_CNT1,
+ .cnt2_reg = DMA1_CNT2,
+ },
+ [SRAM_CH02] = {
+ .name = "ch2",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA2_PTR1,
+ .ptr2_reg = DMA2_PTR2,
+ .cnt1_reg = DMA2_CNT1,
+ .cnt2_reg = DMA2_CNT2,
+ },
+ [SRAM_CH03] = {
+ .name = "ch3",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA3_PTR1,
+ .ptr2_reg = DMA3_PTR2,
+ .cnt1_reg = DMA3_CNT1,
+ .cnt2_reg = DMA3_CNT2,
+ },
+ [SRAM_CH04] = {
+ .name = "ch4",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA4_PTR1,
+ .ptr2_reg = DMA4_PTR2,
+ .cnt1_reg = DMA4_CNT1,
+ .cnt2_reg = DMA4_CNT2,
+ },
+ [SRAM_CH05] = {
+ .name = "ch5",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH06] = {
+ .name = "TS2 C",
+ .cmds_start = 0x10140,
+ .ctrl_start = 0x10680,
+ .cdt = 0x10480,
+ .fifo_start = 0x6000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH07] = {
+ .name = "ch7",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA6_PTR1,
+ .ptr2_reg = DMA6_PTR2,
+ .cnt1_reg = DMA6_CNT1,
+ .cnt2_reg = DMA6_CNT2,
+ },
+ [SRAM_CH08] = {
+ .name = "ch8",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA7_PTR1,
+ .ptr2_reg = DMA7_PTR2,
+ .cnt1_reg = DMA7_CNT1,
+ .cnt2_reg = DMA7_CNT2,
+ },
+ [SRAM_CH09] = {
+ .name = "ch9",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA8_PTR1,
+ .ptr2_reg = DMA8_PTR2,
+ .cnt1_reg = DMA8_CNT1,
+ .cnt2_reg = DMA8_CNT2,
+ },
+};
+
+static int cx23885_risc_decode(u32 risc)
+{
+ static char *instr[16] = {
+ [ RISC_SYNC >> 28 ] = "sync",
+ [ RISC_WRITE >> 28 ] = "write",
+ [ RISC_WRITEC >> 28 ] = "writec",
+ [ RISC_READ >> 28 ] = "read",
+ [ RISC_READC >> 28 ] = "readc",
+ [ RISC_JUMP >> 28 ] = "jump",
+ [ RISC_SKIP >> 28 ] = "skip",
+ [ RISC_WRITERM >> 28 ] = "writerm",
+ [ RISC_WRITECM >> 28 ] = "writecm",
+ [ RISC_WRITECR >> 28 ] = "writecr",
+ };
+ static int incr[16] = {
+ [ RISC_WRITE >> 28 ] = 3, // 2
+ [ RISC_JUMP >> 28 ] = 3, // 2
+ [ RISC_SKIP >> 28 ] = 1,
+ [ RISC_SYNC >> 28 ] = 1,
+ [ RISC_WRITERM >> 28 ] = 3,
+ [ RISC_WRITECM >> 28 ] = 3,
+ [ RISC_WRITECR >> 28 ] = 4,
+ };
+ static char *bits[] = {
+ "12", "13", "14", "resync",
+ "cnt0", "cnt1", "18", "19",
+ "20", "21", "22", "23",
+ "irq1", "irq2", "eol", "sol",
+ };
+ int i;
+
+ printk("0x%08x [ %s", risc,
+ instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+ for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+ if (risc & (1 << (i + 12)))
+ printk(" %s",bits[i]);
+ printk(" count=%d ]\n", risc & 0xfff);
+ return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+void cx23885_wakeup(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q, u32 count)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_buffer *buf;
+ int bc;
+
+ for (bc = 0;; bc++) {
+ if (list_empty(&q->active))
+ break;
+ buf = list_entry(q->active.next,
+ struct cx23885_buffer, vb.queue);
+ /* count comes from the hw and is is 16bit wide --
+ * this trick handles wrap-arounds correctly for
+ * up to 32767 buffers in flight... */
+ if ((s16) (count - buf->count) < 0)
+ break;
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
+ count, buf->count);
+ buf->vb.state = STATE_DONE;
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ }
+ if (list_empty(&q->active)) {
+ del_timer(&q->timeout);
+ } else {
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ }
+ if (bc != 1)
+ printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+}
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ struct sram_channel *ch);
+
+int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ struct sram_channel *ch,
+ unsigned int bpl, u32 risc)
+{
+ unsigned int i,lines;
+ u32 cdt;
+
+ if (ch->cmds_start == 0)
+ {
+ dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name);
+ cx_write(ch->ptr1_reg, 0);
+ cx_write(ch->ptr2_reg, 0);
+ cx_write(ch->cnt2_reg, 0);
+ cx_write(ch->cnt1_reg, 0);
+ return 0;
+ } else {
+ dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name);
+ }
+
+ bpl = (bpl + 7) & ~7; /* alignment */
+ cdt = ch->cdt;
+ lines = ch->fifo_size / bpl;
+ if (lines > 6)
+ lines = 6;
+ BUG_ON(lines < 2);
+
+ cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) );
+ cx_write(8+4, cpu_to_le32(8) );
+ cx_write(8+8, cpu_to_le32(0) );
+
+ /* write CDT */
+ for (i = 0; i < lines; i++) {
+ dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i);
+ cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+ cx_write(cdt + 16*i + 4, 0);
+ cx_write(cdt + 16*i + 8, 0);
+ cx_write(cdt + 16*i + 12, 0);
+ }
+
+ /* write CMDS */
+ if (ch->jumponly)
+ cx_write(ch->cmds_start + 0, 8);
+ else
+ cx_write(ch->cmds_start + 0, risc);
+ cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
+ cx_write(ch->cmds_start + 8, cdt);
+ cx_write(ch->cmds_start + 12, (lines*16) >> 3);
+ cx_write(ch->cmds_start + 16, ch->ctrl_start);
+ if (ch->jumponly)
+ cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) );
+ else
+ cx_write(ch->cmds_start + 20, 64 >> 2);
+ for (i = 24; i < 80; i += 4)
+ cx_write(ch->cmds_start + i, 0);
+
+ /* fill registers */
+ cx_write(ch->ptr1_reg, ch->fifo_start);
+ cx_write(ch->ptr2_reg, cdt);
+ cx_write(ch->cnt2_reg, (lines*16) >> 3);
+ cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+
+ dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n",
+ cx23885_boards[dev->board].bridge,
+ ch->name,
+ bpl,
+ lines);
+
+ return 0;
+}
+
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ struct sram_channel *ch)
+{
+ static char *name[] = {
+ "init risc lo",
+ "init risc hi",
+ "cdt base",
+ "cdt size",
+ "iq base",
+ "iq size",
+ "risc pc lo",
+ "risc pc hi",
+ "iq wr ptr",
+ "iq rd ptr",
+ "cdt current",
+ "pci target lo",
+ "pci target hi",
+ "line / byte",
+ };
+ u32 risc;
+ unsigned int i,j,n;
+
+ printk("%s: %s - dma channel status dump\n",
+ dev->name, ch->name);
+ for (i = 0; i < ARRAY_SIZE(name); i++)
+ printk("%s: cmds: %-15s: 0x%08x\n",
+ dev->name, name[i],
+ cx_read(ch->cmds_start + 4*i));
+
+ for (i = 0; i < 4; i++) {
+ risc = cx_read(ch->cmds_start + 4 * (i+14));
+ printk("%s: risc%d: ", dev->name, i);
+ cx23885_risc_decode(risc);
+ }
+ for (i = 0; i < (64 >> 2); i += n) {
+ risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */
+ printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i);
+ n = cx23885_risc_decode(risc);
+ for (j = 1; j < n; j++) {
+ risc = cx_read(ch->ctrl_start + 4 * (i+j));
+ printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
+ dev->name, i+j, risc, j);
+ }
+ }
+
+ printk("%s: fifo: 0x%08x -> 0x%x\n",
+ dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+ printk("%s: ctrl: 0x%08x -> 0x%x\n",
+ dev->name, ch->ctrl_start, ch->ctrl_start+6*16);
+ printk("%s: ptr1_reg: 0x%08x\n",
+ dev->name, cx_read(ch->ptr1_reg));
+ printk("%s: ptr2_reg: 0x%08x\n",
+ dev->name, cx_read(ch->ptr2_reg));
+ printk("%s: cnt1_reg: 0x%08x\n",
+ dev->name, cx_read(ch->cnt1_reg));
+ printk("%s: cnt2_reg: 0x%08x\n",
+ dev->name, cx_read(ch->cnt2_reg));
+}
+
+void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc)
+{
+ struct cx23885_dev *dev = port->dev;
+ unsigned int i,j,n;
+
+ printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+ dev->name, risc->cpu, (unsigned long)risc->dma);
+ for (i = 0; i < (risc->size >> 2); i += n) {
+ printk("%s: %04d: ", dev->name, i);
+ n = cx23885_risc_decode(risc->cpu[i]);
+ for (j = 1; j < n; j++)
+ printk("%s: %04d: 0x%08x [ arg #%d ]\n",
+ dev->name, i+j, risc->cpu[i+j], j);
+ if (risc->cpu[i] == RISC_JUMP)
+ break;
+ }
+}
+
+void cx23885_shutdown(struct cx23885_dev *dev)
+{
+ /* disable RISC controller */
+ cx_write(DEV_CNTRL2, 0);
+
+ /* Disable all IR activity */
+ cx_write(IR_CNTRL_REG, 0);
+
+ /* Disable Video A/B activity */
+ cx_write(VID_A_DMA_CTL, 0);
+ cx_write(VID_B_DMA_CTL, 0);
+ cx_write(VID_C_DMA_CTL, 0);
+
+ /* Disable Audio activity */
+ cx_write(AUD_INT_DMA_CTL, 0);
+ cx_write(AUD_EXT_DMA_CTL, 0);
+
+ /* Disable Serial port */
+ cx_write(UART_CTL, 0);
+
+ /* Disable Interrupts */
+ cx_write(PCI_INT_MSK, 0);
+ cx_write(VID_A_INT_MSK, 0);
+ cx_write(VID_B_INT_MSK, 0);
+ cx_write(VID_C_INT_MSK, 0);
+ cx_write(AUDIO_INT_INT_MSK, 0);
+ cx_write(AUDIO_EXT_INT_MSK, 0);
+
+}
+
+void cx23885_reset(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ cx23885_shutdown(dev);
+
+ cx_write(PCI_INT_STAT, 0xffffffff);
+ cx_write(VID_A_INT_STAT, 0xffffffff);
+ cx_write(VID_B_INT_STAT, 0xffffffff);
+ cx_write(VID_C_INT_STAT, 0xffffffff);
+ cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
+ cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
+ cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
+
+ mdelay(100);
+
+#if SRAM
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
+
+#else
+ // FIXME: Put a pointer to the sram_channel table in cx23885_dev
+ // and stop all this ugly switch/if code
+ switch(cx23885_boards[dev->board].bridge) {
+ case CX23885_BRIDGE_885:
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0);
+ break;
+ case CX23885_BRIDGE_887:
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0);
+ break;
+ default:
+ printk(KERN_ERR "%s() error, default case", __FUNCTION__ );
+ }
+#endif
+
+ switch(dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+ dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__);
+ // FIXME: Analog requires the tuner is brought out of reset
+ break;
+ }
+}
+
+
+static int cx23885_pci_quirks(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ switch(dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ cx_clear(RDR_TLCTL0, 1 << 4);
+ break;
+ }
+ return 0;
+}
+
+static int get_resources(struct cx23885_dev *dev)
+{
+ if (request_mem_region(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0),
+ dev->name))
+ return 0;
+
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ dev->name, (unsigned long long)pci_resource_start(dev->pci,0));
+
+ return -EBUSY;
+}
+
+static void cx23885_timeout(unsigned long data);
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value);
+
+static int cx23885_ir_init(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__);
+ break;
+ }
+
+ return 0;
+}
+
+static int cx23885_dev_setup(struct cx23885_dev *dev)
+{
+ int i;
+
+ mutex_init(&dev->lock);
+
+ atomic_inc(&dev->refcount);
+
+ dev->nr = cx23885_devcount++;
+ dev->pci_bus = dev->pci->bus->number;
+ dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+ dev->pci_irqmask = 0x001f00;
+
+ /* External Master 1 Bus */
+ dev->i2c_bus[0].nr = 0;
+ dev->i2c_bus[0].dev = dev;
+ dev->i2c_bus[0].reg_stat = I2C1_STAT;
+ dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
+ dev->i2c_bus[0].reg_addr = I2C1_ADDR;
+ dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
+ dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
+ dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
+
+ /* External Master 2 Bus */
+ dev->i2c_bus[1].nr = 1;
+ dev->i2c_bus[1].dev = dev;
+ dev->i2c_bus[1].reg_stat = I2C2_STAT;
+ dev->i2c_bus[1].reg_ctrl = I2C2_CTRL;
+ dev->i2c_bus[1].reg_addr = I2C2_ADDR;
+ dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
+ dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
+ dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
+
+ /* Internal Master 3 Bus */
+ dev->i2c_bus[2].nr = 2;
+ dev->i2c_bus[2].dev = dev;
+ dev->i2c_bus[2].reg_stat = I2C3_STAT;
+ dev->i2c_bus[2].reg_ctrl = I2C3_CTRL;
+ dev->i2c_bus[2].reg_addr = I2C2_ADDR;
+ dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
+ dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
+ dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
+
+ /* Transport bus init dma queue */
+ spin_lock_init(&dev->ts2.slock);
+ dev->ts2.dev = dev;
+ dev->ts2.nr = 2;
+ dev->ts2.sram_chno = SRAM_CH06;
+ INIT_LIST_HEAD(&dev->ts2.mpegq.active);
+ INIT_LIST_HEAD(&dev->ts2.mpegq.queued);
+ dev->ts2.mpegq.timeout.function = cx23885_timeout;
+ dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2;
+ init_timer(&dev->ts2.mpegq.timeout);
+
+ dev->ts2.reg_gpcnt = VID_C_GPCNT;
+ dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL;
+ dev->ts2.reg_dma_ctl = VID_C_DMA_CTL;
+ dev->ts2.reg_lngth = VID_C_LNGTH;
+ dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL;
+ dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL;
+ dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS;
+ dev->ts2.reg_sop_status = VID_C_SOP_STATUS;
+ dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
+ dev->ts2.reg_vld_misc = VID_C_VLD_MISC;
+ dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN;
+ dev->ts2.reg_ts_int_msk = VID_C_INT_MSK;
+
+ // FIXME: Make this board specific
+ dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */
+ dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */
+ dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */
+ dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */
+
+ cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00);
+
+ sprintf(dev->name,"cx23885[%d]", dev->nr);
+
+ if (get_resources(dev) < 0) {
+ printk(KERN_ERR "CORE %s No more PCIe resources for "
+ "subsystem: %04x:%04x\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device);
+
+ cx23885_devcount--;
+ goto fail_free;
+ }
+
+ mutex_lock(&devlist);
+ list_add_tail(&dev->devlist, &cx23885_devlist);
+ mutex_unlock(&devlist);
+
+ /* PCIe stuff */
+ dev->lmmio = ioremap(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0));
+
+ dev->bmmio = (u8 __iomem *)dev->lmmio;
+
+ cx23885_pci_quirks(dev);
+
+ /* board config */
+ dev->board = UNSET;
+ if (card[dev->nr] < cx23885_bcount)
+ dev->board = card[dev->nr];
+ for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++)
+ if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
+ dev->pci->subsystem_device == cx23885_subids[i].subdevice)
+ dev->board = cx23885_subids[i].card;
+ if (UNSET == dev->board) {
+ dev->board = CX23885_BOARD_UNKNOWN;
+ cx23885_card_list(dev);
+ }
+ printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, cx23885_boards[dev->board].name,
+ dev->board, card[dev->nr] == dev->board ?
+ "insmod option" : "autodetected");
+
+ /* Configure the hardware internal memory for fifos */
+ switch(cx23885_boards[dev->board].bridge) {
+ case CX23885_BRIDGE_UNDEFINED:
+ case CX23885_BRIDGE_885:
+ dev->sram_channels = cx23885_sram_channels;
+ break;
+ case CX23885_BRIDGE_887:
+ dev->sram_channels = cx23887_sram_channels;
+ break;
+ default:
+ printk(KERN_ERR "%s() error, default case", __FUNCTION__ );
+ }
+
+ /* init hardware */
+ cx23885_reset(dev);
+