summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/cx88
diff options
context:
space:
mode:
authorGerd Knorr <devnull@localhost>2004-07-29 21:35:48 +0000
committerGerd Knorr <devnull@localhost>2004-07-29 21:35:48 +0000
commit38ea67b839abf0e8f150106314bc4dff33312e18 (patch)
treedbb14a85e437ad4c2eeec5876f24953c0494aaa6 /linux/drivers/media/video/cx88
parentcd05362dcbcd4554765bd6d811981202533df047 (diff)
downloadmediapointer-dvb-s2-38ea67b839abf0e8f150106314bc4dff33312e18.tar.gz
mediapointer-dvb-s2-38ea67b839abf0e8f150106314bc4dff33312e18.tar.bz2
- cx88: big code reorganization.
- cx88: started merging blackbird patches, not working yet.
Diffstat (limited to 'linux/drivers/media/video/cx88')
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c159
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c598
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c70
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c259
-rw-r--r--linux/drivers/media/video/cx88/cx88-i2c.c85
-rw-r--r--linux/drivers/media/video/cx88/cx88-mpeg.c690
-rw-r--r--linux/drivers/media/video/cx88/cx88-tvaudio.c83
-rw-r--r--linux/drivers/media/video/cx88/cx88-vbi.c11
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c299
-rw-r--r--linux/drivers/media/video/cx88/cx88.h144
10 files changed, 2005 insertions, 393 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
new file mode 100644
index 000000000..e54fd1f23
--- /dev/null
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -0,0 +1,159 @@
+/*
+ * $Id: cx88-alsa.c,v 1.1 2004/07/29 21:35:48 kraxel Exp $
+ *
+ * Support for audio capture
+ * PCI function #1 of the cx2388x.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+
+#include "cx88.h"
+
+/* ------------------------------------------------------------------ */
+
+MODULE_DESCRIPTION("alsa driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static int __devinit cx8801_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx8801_dev *dev;
+ struct cx88_core *core;
+ int err;
+
+ dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+ memset(dev,0,sizeof(*dev));
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto fail_free;
+ }
+ core = cx88_core_get(dev->pci);
+ if (NULL == core) {
+ err = -EINVAL;
+ goto fail_free;
+ }
+ dev->core = core;
+
+ /* print pci info */
+ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/1: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%lx\n", core->name,
+ pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat,pci_resource_start(pci_dev,0));
+
+ pci_set_master(pci_dev);
+ if (!pci_dma_supported(pci_dev,0xffffffff)) {
+ printk("%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+ err = -EIO;
+ goto fail_core;
+ }
+
+ printk("%s/1: alsa dummy module loaded\n",core->name);
+ pci_set_drvdata(pci_dev,dev);
+ return 0;
+
+ fail_core:
+ cx88_core_put(core,dev->pci);
+ fail_free:
+ kfree(dev);
+ return err;
+}
+
+static void __devexit cx8801_finidev(struct pci_dev *pci_dev)
+{
+ struct cx8801_dev *dev = pci_get_drvdata(pci_dev);
+
+ pci_disable_device(pci_dev);
+
+ /* unregister stuff */
+ pci_set_drvdata(pci_dev, NULL);
+
+ /* free memory */
+ cx88_core_put(dev->core,dev->pci);
+ kfree(dev);
+}
+
+struct pci_device_id cx8801_pci_tbl[] = {
+ {
+ .vendor = 0x14f1,
+ .device = 0x8801,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ .vendor = 0x14f1,
+ .device = 0x8811,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, cx8801_pci_tbl);
+
+static struct pci_driver cx8801_pci_driver = {
+ .name = "cx8801",
+ .id_table = cx8801_pci_tbl,
+ .probe = cx8801_initdev,
+ .remove = cx8801_finidev,
+#if 0
+ .suspend = cx8801_suspend,
+ .resume = cx8801_resume,
+#endif
+};
+
+static int cx8801_init(void)
+{
+ printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
+ (CX88_VERSION_CODE >> 16) & 0xff,
+ (CX88_VERSION_CODE >> 8) & 0xff,
+ CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+ return pci_module_init(&cx8801_pci_driver);
+}
+
+static void cx8801_fini(void)
+{
+ pci_unregister_driver(&cx8801_pci_driver);
+}
+
+module_init(cx8801_init);
+module_exit(cx8801_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
new file mode 100644
index 000000000..b0f3a1005
--- /dev/null
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -0,0 +1,598 @@
+/*
+ * $Id: cx88-blackbird.c,v 1.1 2004/07/29 21:35:48 kraxel Exp $
+ *
+ * Support for a cx23416 mpeg encoder via cx2388x host port (PCI function #4).
+ * "blackbird" reference design.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
+#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
+
+/* defines below are from ivtv-driver.h */
+
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/*Firmware API commands*/
+#define IVTV_API_ENC_PING_FW 0x00000080
+#define IVTV_API_ENC_GETVER 0x000000C4
+#define IVTV_API_ENC_HALT_FW 0x000000C3
+#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/
+//#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7
+#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9
+#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb
+#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f
+#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091
+#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099
+#define IVTV_API_ASSIGN_BITRATES 0x00000095
+#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097
+#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1
+#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5
+#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd
+#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b
+#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d
+#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f
+#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1
+#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0
+#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8
+#define IVTV_API_MUTE_VIDEO 0x000000d9
+#define IVTV_API_MUTE_AUDIO 0x000000da
+#define IVTV_API_INITIALIZE_INPUT 0x000000cd
+#define IVTV_API_REFRESH_INPUT 0x000000d3
+#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6
+#define IVTV_API_BEGIN_CAPTURE 0x00000081
+//#define IVTV_API_PAUSE_ENCODER 0x000000d2
+//#define IVTV_API_EVENT_NOTIFICATION 0x000000d5
+#define IVTV_API_END_CAPTURE 0x00000082
+
+/* Registers */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/)
+
+
+/* initialize the dma for the mpegport, called from cx88-video.c:cx8800_initdev */
+int cx8800_mpegport_init_dma(struct cx8800_dev *dev)
+{
+ dprintk(1,"cx88_mpegport_init_dma\n");
+
+ /* toggle reset of the host */
+ cx_write(MO_GPHST_SOFT_RST, 1);
+ udelay(100);
+ cx_write(MO_GPHST_SOFT_RST, 0);
+ udelay(100);
+
+ /* host port setup */
+ cx_write(MO_GPHST_WSC, 0x44444444U);
+ cx_write(MO_GPHST_XFR, 0);
+ cx_write(MO_GPHST_WDTH, 15);
+ cx_write(MO_GPHST_HDSHK, 0);
+ cx_write(MO_GPHST_MUX16, 0x44448888U);
+ cx_write(MO_GPHST_MODE, 0);
+
+ cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
+
+ cx_write(MO_DEV_CNTRL2, 0x20); /* enable the RISC controller */
+ cx_set(MO_PCI_INTMSK, 0x4); /* enable ts_int */
+
+ cx_write(TS_F2_CMD_STAT_MM, 0x2900106); /* F2_CMD_STAT_MM defaults + master + memory space */
+ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
+ cx_write(MO_TS_LNGTH, MD_TS_LNGHT_VAL);
+
+ udelay(100);
+ INIT_LIST_HEAD(&dev->mpegq.active);
+ INIT_LIST_HEAD(&dev->mpegq.queued);
+ dev->mpegq.timeout.function = cx8800_mpegport_timeout;
+ dev->mpegq.timeout.data = (unsigned long)dev;
+ init_timer(&dev->mpegq.timeout);
+ cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
+ MO_TS_DMACNTRL,0x11,0x00);
+ udelay(100);
+
+ cx_write(MO_TS_INTMSK, 0);
+ cx_set(MO_TS_INTSTAT, 0);
+ cx_write(MO_TS_INTMSK, 0x1f1101); /* all except the irq2 bit */
+
+ cx_write(MO_TS_GPCNTRL, 3); /* reset gp counter to 0 */
+ cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */
+ //cx_write(TS_HW_SOP_CNTRL, 0x2F0BC0); /* mpeg start byte ts: 0x2F0BC0 ? */
+ cx_write(TS_VALERR_CNTRL, 0x2000);
+
+ cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
+ udelay(100);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int wait_ready_gpio0_bit1_high(struct cx8800_dev *dev)
+{
+ int timeout = 1000;
+ do { timeout--; udelay(1); } while (!(cx_readb(MO_GP0_IO) & 2) && (timeout >= 0));
+ if (timeout < 0) return -1;
+ return 0;
+}
+
+int wait_ready_gpio0_bit1_low(struct cx8800_dev *dev)
+{
+ int timeout = 1000;
+ do { timeout--; udelay(1); } while ((cx_readb(MO_GP0_IO) & 2) && (timeout >= 0));
+ if (timeout < 0) return -1;
+ return 0;
+}
+
+#define P1_MDATA0 0x390000
+#define P1_MDATA1 0x390001
+#define P1_MDATA2 0x390002
+#define P1_MDATA3 0x390003
+#define P1_MADDR2 0x390004
+#define P1_MADDR1 0x390005
+#define P1_MADDR0 0x390006
+#define P1_RDATA0 0x390008
+#define P1_RDATA1 0x390009
+#define P1_RDATA2 0x39000A
+#define P1_RDATA3 0x39000B
+#define P1_RADDR0 0x39000C
+#define P1_RADDR1 0x39000D
+#define P1_RRDWR 0x39000E
+
+/* Warning: address is dword address (4 bytes) */
+static int memory_write(struct cx8800_dev *dev, int address, int value)
+{
+ int retval;
+
+ //retval = wait_ready_gpio0_bit1_low(dev);
+
+ cx_writeb(P1_MDATA0, (unsigned int)value);
+ cx_writeb(P1_MDATA1, (unsigned int)(value >> 8));
+ cx_writeb(P1_MDATA2, (unsigned int)(value >> 16));
+ cx_writeb(P1_MDATA3, (unsigned int)(value >> 24));
+ cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40);
+ cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));
+ cx_writeb(P1_MADDR0, (unsigned int)address);
+
+ retval = wait_ready_gpio0_bit1_high(dev);
+ return retval;
+}
+
+/* Warning: address is dword address (4 bytes) */
+static int memory_read(struct cx8800_dev *dev, int address, int *value)
+{
+ int retval;
+
+ cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0);
+ cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));
+ cx_writeb(P1_MADDR0, (unsigned int)address);
+
+ retval = wait_ready_gpio0_bit1_high(dev);
+
+ int val;
+ cx_writeb(P1_MDATA3, 0);
+ val = (unsigned char)cx_read(P1_MDATA3) << 24;
+ cx_writeb(P1_MDATA2, 0);
+ val |= (unsigned char)cx_read(P1_MDATA2) << 16;
+ cx_writeb(P1_MDATA1, 0);
+ val |= (unsigned char)cx_read(P1_MDATA1) << 8;
+ cx_writeb(P1_MDATA0, 0);
+ val |= (unsigned char)cx_read(P1_MDATA0);
+ *value = val;
+
+ return retval;
+}
+
+
+static int register_write(struct cx8800_dev *dev, int address, int value)
+{
+ int retval;
+ cx_writeb(P1_RDATA0, (unsigned int)value);
+ cx_writeb(P1_RDATA1, (unsigned int)(value >> 8));
+ cx_writeb(P1_RDATA2, (unsigned int)(value >> 16));
+ cx_writeb(P1_RDATA3, (unsigned int)(value >> 24));
+ cx_writeb(P1_RADDR0, (unsigned int)address);
+ cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));
+ cx_writeb(P1_RRDWR, 1);
+
+ retval = wait_ready_gpio0_bit1_high(dev);
+ udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */
+ /* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */
+ return retval;
+}
+
+
+static int register_read(struct cx8800_dev *dev, int address, int *value)
+{
+ int retval;
+ cx_writeb(P1_RADDR0, (unsigned int)address);
+ cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));
+ cx_writeb(P1_RRDWR, 0);
+
+ retval = wait_ready_gpio0_bit1_high(dev);
+
+ int val;
+ val = (unsigned char)cx_read(P1_RDATA0);
+ val |= (unsigned char)cx_read(P1_RDATA1) << 8;
+ val |= (unsigned char)cx_read(P1_RDATA2) << 16;
+ val |= (unsigned char)cx_read(P1_RDATA3) << 24;
+ *value = val;
+
+ return retval;
+}
+
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+int mpegport_api_cmd(struct cx8800_dev *dev, u32 command, u32 inputcnt, u32 outputcnt, ...)
+{
+ va_list args;
+ va_start(args, outputcnt);
+ int i;
+ u32 value;
+
+ dprintk(1,"API Command 0x%X\n", command);
+
+ /* this may not be 100% safe if we can't read any memory location without side effects */
+ memory_read(dev, dev->mpegport_mailbox - 4, &value);
+ if (value != 0x12345678) {
+ dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n");
+ return -1;
+ }
+
+ u32 flag;
+ memory_read(dev, dev->mpegport_mailbox, &flag);
+ if (flag) {
+ dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag);
+ return -1;
+ }
+
+ flag |= 1; /* tell 'em we're working on it */
+ memory_write(dev, dev->mpegport_mailbox, flag);
+
+ memory_write(dev, dev->mpegport_mailbox + 1, command); /* command code */
+ memory_write(dev, dev->mpegport_mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
+
+ /* write input values */
+ for (i = 0; i < inputcnt ; i++) {
+ u32 value = va_arg(args, int);
+ memory_write(dev, dev->mpegport_mailbox + 4 + i, value);
+ dprintk(1, "API Input %d = %d\n", i, value);
+ }
+
+ /* fill with zeroes (ivtv does it, but is this necessary?) */
+ for (; i < 16 ; i++) {
+ u32 value = 0;
+ memory_write(dev, dev->mpegport_mailbox + 4 + i, value);
+ }
+
+ flag |= 3; /* tell 'em we're done writing */
+ memory_write(dev, dev->mpegport_mailbox, flag);
+
+ /* wait for firmware to handle the API command */
+ int timeoutcnt = 500; /* trial and error plus a margin (longest command I've seen is capture start) */
+ do {
+ udelay(10);
+ timeoutcnt--;
+ memory_read(dev, dev->mpegport_mailbox, &flag);
+ } while (timeoutcnt && ((flag & 4)==0));
+
+ if (!timeoutcnt) {
+ dprintk(0, "ERROR: API Mailbox timeout\n");
+ flag = 0;
+ memory_write(dev, dev->mpegport_mailbox, flag);
+ return -1;
+ }
+
+ /* read output values */
+ for (i = 0; i < outputcnt ; i++) {
+ u32 *value = va_arg(args, int *);
+ memory_read(dev, dev->mpegport_mailbox + 4 + i, value);
+ dprintk(1, "API Output %d = %d\n", i, *value);
+ }
+
+ va_end(args);
+
+ u32 retval;
+ memory_read(dev, dev->mpegport_mailbox + 2, &retval);
+ dprintk(1, "API result = %d (timeoutcnt=%d)\n",retval, timeoutcnt);
+ flag = 0;
+ memory_write(dev, dev->mpegport_mailbox, flag);
+ return retval;
+}
+
+
+int mpegport_find_mailbox(struct cx8800_dev *dev)
+{
+ u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456};
+ int signaturecnt=0;
+ int i;
+ for (i = 0; (i < BLACKBIRD_FIRM_IMAGE_SIZE) && (signaturecnt < 4) ; i++)
+ {
+ u32 value;
+ memory_read(dev, i, &value);
+ if (value == signature[signaturecnt])
+ signaturecnt++;
+ else
+ signaturecnt = 0;
+ }
+ if (signaturecnt == 4)
+ {
+ dprintk(1, "Mailbox signature found\n");
+ return i;
+ }
+ else
+ {
+ dprintk(0, "Mailbox signature values not found!\n");
+ return -1;
+ }
+}
+
+int mpegport_load_firmware(struct cx8800_dev *dev)
+{
+ dprintk(1,"Loading firmware\n");
+ int i, retval = 0;
+ u32 value = 0;
+ const struct firmware *blackbird_firmware;
+
+ retval = register_write(dev, IVTV_REG_VPU, 0xFFFFFFED);
+ //retval = register_write(dev, IVTV_REG_VPU, 0xFFFFFFEF);
+ retval |= register_write(dev, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_write(dev, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+ retval |= register_write(dev, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ udelay(500);
+ retval |= register_write(dev, IVTV_REG_APU, 0);
+
+ if (retval < 0) dprintk(0, "Error with register_write\n");
+
+ /* without this, the encoder chip is just a dead chip */
+
+ /* for this to work, 'apt-get install hotplug' and copy the firmware binary to /usr/lib/hotplug/firmware */
+ retval = request_firmware(&blackbird_firmware, BLACKBIRD_FIRM_ENC_FILENAME, &dev->pci->dev);
+
+ if (retval != 0) {
+ dprintk(0, "ERROR: Hotplug firmware request failed! Fatal for mpegport support!\n");
+ dprintk(0, "********** Perhaps hotplug utilities or the firmware file is not installed?\n");
+ dprintk(0, "********** Or kernel hotplug support of Firmware loading support is not enabled?\n");
+ dprintk(0, "********** - Kernel setup: Your kernel needs the following options:\n");
+ dprintk(0, "********** 1) enable CONFIG_HOTPLUG from \"General Setup\"/\"Support for hot-pluggable devices\"\n");
+ dprintk(0, "********** 2) enable CONFIG_FW_LOADER from \"Device Drivers\"/\"Generic Driver Options\"/\"Hotplug firmware loading support\"\n");
+ dprintk(0, "********** - Hotplug support utilities:\n");
+ dprintk(0, "********** 1) make sure sysfs is mounted on /sys\n");
+ dprintk(0, "********** 2) copy the firmware binary to /usr/lib/hotplug/firmware/" BLACKBIRD_FIRM_ENC_FILENAME "\n");
+ dprintk(0, "********** 3) Debian: 'apt-get install hotplug'\n");
+ dprintk(0, "********** Others: Unknown (ask your vendor) or go here http://linux-hotplug.sourceforge.net/\n");
+ dprintk(0, "********** You will also probably want to have a /etc/hotplug/firmware.agent\n");
+ return -1;
+ }
+
+ if (blackbird_firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+ dprintk(0, "ERROR: Firmware is %d bytes long, which should be %d bytes.\n", blackbird_firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
+ return -1;
+ }
+
+ if ((blackbird_firmware->data[0] != 0xA7) ||
+ (blackbird_firmware->data[1] != 0x0D) ||
+ (blackbird_firmware->data[2] != 0x00) ||
+ (blackbird_firmware->data[3] != 0x00) ||
+ (blackbird_firmware->data[4] != 0x66) ||
+ (blackbird_firmware->data[5] != 0xBB) ||
+ (blackbird_firmware->data[6] != 0x55) ||
+ (blackbird_firmware->data[7] != 0xAA)) {
+ dprintk(0, "ERROR: Firmware is corrupt or not for an encoder chip\n");
+ return -1;
+ }
+
+ /* transfer to the chip */
+ u32 checksum = 0;
+ u32 *dataptr = (u32 *)blackbird_firmware->data;
+ for (i = 0; i < (blackbird_firmware->size >> 2); i++) {
+ value = *dataptr;
+ checksum += ~value;
+ memory_write(dev, i, value);
+ dataptr++;
+ }
+
+ release_firmware(blackbird_firmware);
+
+ /* this takes a whole second, but it ensures the upload worked (maybe some hw needs other RAM timings, etc) */
+ /* read back to verify with the checksum */
+ for (i--; i >= 0; i--) {
+ memory_read(dev, i, &value);
+ checksum -= ~value;
+ }
+
+ if (checksum) {
+ dprintk(0, "ERROR: Firmware Upload Failed (memory checksums don't match).\n");
+ return -1;
+ }
+
+ dprintk(0, "Firmware upload successful.\n");
+
+#if 0
+ for (i = 0; i < 1024; i+=4) {
+ //u32 value;
+ memory_read(dev, (i>>2), &value);
+ if (0 == (i % 16))
+ printk(KERN_INFO "cx88 fw: %02x:",i);
+ printk(" %02x %02x %02x %02x",(value & 0xFF),((value>>8) & 0xFF),((value>>16) & 0xFF),((value>>24) & 0xFF));
+ if (12 == (i % 16))
+ printk("\n");
+ }
+#endif
+
+ retval |= register_write(dev, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_read(dev, IVTV_REG_SPU, &value);
+ retval |= register_write(dev, IVTV_REG_SPU, value & 0xFFFFFFFE);
+
+ udelay(1000);
+
+ retval |= register_read(dev, IVTV_REG_VPU, &value);
+ retval |= register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8UL);
+ //retval |= register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFFB);
+
+ if (retval < 0) dprintk(0, "Error with register_write\n");
+ return 0;
+}
+
+void mpegport_codec_settings(struct cx8800_dev *dev)
+{
+ /* assign stream type */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 0); /* program stream */
+ //mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 2); /* MPEG1 stream */
+ //mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 3); /* PES A/V */
+ //mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 10); /* DVD stream */
+
+ /* assign output port */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_OUTPUT_PORT, 1, 0, 1); /* 1 = Host */
+
+ /* assign framerate */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0);
+
+ /* assign frame size */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720);
+
+ /* assign aspect ratio */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2);
+
+ int bitrate_mode = 1;
+ int bitrate = 7500000;
+ int bitrate_peak = 7500000;
+ /* assign bitrates */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_BITRATES, 5, 0,
+ bitrate_mode, /* mode */
+ bitrate, /* bps */
+ bitrate_peak / 400, /* peak/400 */
+ 0, 0x70); /* encoding buffer, ckennedy */
+
+ /* assign gop properties */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 15, 3);
+ //mpegport_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 2, 1);
+
+ /* assign 3 2 pulldown */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_3_2_PULLDOWN, 1, 0, 0);
+
+ /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
+
+ /* assign gop closure */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_GOP_CLOSURE, 1, 0, 0);
+
+ /* assign audio properties */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4));
+
+ /* assign dnr filter mode */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_MODE, 2, 0, 0, 0);
+
+ /* assign dnr filter props*/
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_PROPS, 2, 0, 0, 0);
+
+ /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_CORING_LEVELS, 4, 0, 0, 255, 0, 255);
+
+ /* assign spatial filter type: luma_t: 1 = horiz_only, chroma_t: 1 = horiz_only */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, 2, 0, 1, 1);
+
+ /* assign frame drop rate */
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0);
+}
+
+int mpegport_initialize_codec(struct cx8800_dev *dev)
+{
+ int retval;
+ dprintk(1,"Initialize codec\n");
+
+ retval = mpegport_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ /* ping was not successful, reset and upload firmware */
+
+ cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
+ udelay(300);
+ cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
+ udelay(100);
+
+ retval = mpegport_load_firmware(dev);
+ if (retval < 0) { dprintk(0, "Error with firmware load!\n"); return retval; }
+
+ dev->mpegport_mailbox = mpegport_find_mailbox(dev);
+ if (dev->mpegport_mailbox < 0) { dprintk(0, "Error with mailbox search!\n"); return dev->mpegport_mailbox; }
+
+ retval = mpegport_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ dprintk(0, "ERROR: Firmware ping failed!\n");
+ return -1;
+ }
+
+ int firmware_version;
+ retval = mpegport_api_cmd(dev, IVTV_API_ENC_GETVER, 0, 1, &firmware_version);
+ if (retval < 0) {
+ dprintk(0, "ERROR: Firmware get encoder version failed!\n");
+ return -1;
+ }
+ dprintk(0, "Encoder revision: 0x%08x\n", firmware_version);
+
+ }
+ else
+ {
+ dprintk(1, "Firmware already present and responding to ping (not reloading)\n");
+ }
+
+ udelay(500);
+
+ cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
+ cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
+ cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */
+
+ cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
+
+ /* this seems to be necessary, because otherwise the picture isn't always correct,
+ even though I think the scaler in the cx23880 should not change the itu656 output.
+ maybe it's a pll or something? */
+ set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED);
+
+ udelay(500);
+
+ mpegport_codec_settings(dev);
+
+ //mpegport_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
+ //mpegport_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180);
+ mpegport_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ mpegport_api_cmd(dev, IVTV_API_INITIALIZE_INPUT, 0, 0); /* initialize the video input */
+
+ udelay(500);
+
+ mpegport_api_cmd(dev, IVTV_API_MUTE_VIDEO, 1, 0, 0);
+ udelay(500);
+ mpegport_api_cmd(dev, IVTV_API_MUTE_AUDIO, 1, 0, 0);
+ udelay(500);
+
+ mpegport_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); /* start capturing to the host interface */
+ //mpegport_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0); /* start capturing to the host interface */
+
+ udelay(500);
+
+ mpegport_api_cmd(dev, IVTV_API_REFRESH_INPUT, 0,0);
+ return retval;
+}
+
+
+/* ------------------------------------------------------------------ */
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index 47ad256d7..84d7a6a29 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -276,6 +276,7 @@ struct cx88_board cx88_boards[] = {
.gpio2 = 0x000000e9,
.gpio3 = 0x00000000,
},
+ .blackbird = 1,
},
[CX88_BOARD_MSI_TVANYWHERE] = {
.name = "MSI TV-@nywhere",
@@ -392,7 +393,7 @@ const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
/* ----------------------------------------------------------------------- */
/* some leadtek specific stuff */
-static void __devinit leadtek_eeprom(struct cx8800_dev *dev, u8 *eeprom_data)
+static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
/* This is just for the Winfast 2000 XP board ATM; I don't have data on
* any others.
@@ -403,16 +404,17 @@ static void __devinit leadtek_eeprom(struct cx8800_dev *dev, u8 *eeprom_data)
if (eeprom_data[4] != 0x7d ||
eeprom_data[5] != 0x10 ||
eeprom_data[7] != 0x66) {
- printk(KERN_WARNING "%s Leadtek eeprom invalid.\n", dev->name);
+ printk(KERN_WARNING "%s: Leadtek eeprom invalid.\n",
+ core->name);
return;
}
- dev->has_radio = 1;
- dev->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
+ core->has_radio = 1;
+ core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: "
"tuner=%d, eeprom[0]=0x%02x\n",
- dev->name, dev->tuner_type, eeprom_data[0]);
+ core->name, core->tuner_type, eeprom_data[0]);
}
@@ -476,13 +478,13 @@ static struct {
{ TUNER_LG_PAL_I, "LG TAPC-I701D"}
};
-static void hauppauge_eeprom(struct cx8800_dev *dev, u8 *eeprom_data)
+static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
unsigned int blk2,tuner,radio,model;
if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) {
printk(KERN_WARNING "%s: Hauppauge eeprom: invalid\n",
- dev->name);
+ core->name);
return;
}
@@ -495,14 +497,14 @@ static void hauppauge_eeprom(struct cx8800_dev *dev, u8 *eeprom_data)
radio = eeprom_data[blk2-1] & 0x01;
if (tuner < ARRAY_SIZE(hauppauge_tuner))
- dev->tuner_type = hauppauge_tuner[tuner].id;
+ core->tuner_type = hauppauge_tuner[tuner].id;
if (radio)
- dev->has_radio = 1;
+ core->has_radio = 1;
printk(KERN_INFO "%s: hauppauge eeprom: model=%d, "
"tuner=%s (%d), radio=%s\n",
- dev->name, model, hauppauge_tuner[tuner].name,
- dev->tuner_type, radio ? "yes" : "no");
+ core->name, model, hauppauge_tuner[tuner].name,
+ core->tuner_type, radio ? "yes" : "no");
}
/* ----------------------------------------------------------------------- */
@@ -543,17 +545,17 @@ static struct {
.name = "PHILIPS_FI1216_MK3" },
};
-static void gdi_eeprom(struct cx8800_dev *dev, u8 *eeprom_data)
+static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
? gdi_tuner[eeprom_data[0x0d]].name : NULL;
- printk(KERN_INFO "%s: GDI: tuner=%s\n", dev->name,
+ printk(KERN_INFO "%s: GDI: tuner=%s\n", core->name,
name ? name : "unknown");
if (NULL == name)
return;
- dev->tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
- dev->has_radio = gdi_tuner[eeprom_data[0x0d]].fm;
+ core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
+ core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm;
}
/* ----------------------------------------------------------------------- */
@@ -588,55 +590,55 @@ i2c_eeprom(struct i2c_client *c, unsigned char *eedata, int len)
return 0;
}
-void cx88_card_list(struct cx8800_dev *dev)
+void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
{
int i;
- if (0 == dev->pci->subsystem_vendor &&
- 0 == dev->pci->subsystem_device) {
+ if (0 == pci->subsystem_vendor &&
+ 0 == pci->subsystem_device) {
printk("%s: Your board has no valid PCI Subsystem ID and thus can't\n"
"%s: be autodetected. Please pass card=<n> insmod option to\n"
"%s: workaround that. Redirect complaints to the vendor of\n"
"%s: the TV card. Best regards,\n"
"%s: -- tux\n",
- dev->name,dev->name,dev->name,dev->name,dev->name);
+ core->name,core->name,core->name,core->name,core->name);
} else {
printk("%s: Your board isn't known (yet) to the driver. You can\n"
"%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);
+ core->name,core->name,core->name,core->name);
}
printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
- dev->name);
+ core->name);
for (i = 0; i < cx88_bcount; i++)
printk("%s: card=%d -> %s\n",
- dev->name, i, cx88_boards[i].name);
+ core->name, i, cx88_boards[i].name);
}
-void cx88_card_setup(struct cx8800_dev *dev)
+void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[128];
- switch (dev->board) {
+ switch (core->board) {
case CX88_BOARD_HAUPPAUGE:
- if (0 == dev->i2c_rc)
- i2c_eeprom(&dev->i2c_client,eeprom,sizeof(eeprom));
- hauppauge_eeprom(dev,eeprom+8);
+ if (0 == core->i2c_rc)
+ i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
+ hauppauge_eeprom(core,eeprom+8);
break;
case CX88_BOARD_GDI:
- if (0 == dev->i2c_rc)
- i2c_eeprom(&dev->i2c_client,eeprom,sizeof(eeprom));
- gdi_eeprom(dev,eeprom);
+ if (0 == core->i2c_rc)
+ i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
+ gdi_eeprom(core,eeprom);
break;
case CX88_BOARD_WINFAST2000XP:
- if (0 == dev->i2c_rc)
- i2c_eeprom(&dev->i2c_client,eeprom,sizeof(eeprom));
- leadtek_eeprom(dev,eeprom);
+ if (0 == core->i2c_rc)
+ i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
+ leadtek_eeprom(core,eeprom);
break;
case CX88_BOARD_ASUS_PVR_416:
case CX88_BOARD_MSI_TVANYWHERE_MASTER:
- dev->has_radio = 1;
+ core->has_radio = 1;
break;
}
}
diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c
index 800556791..31ad10653 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -1,3 +1,4 @@
+
/*
* device driver for Conexant 2388x based TV cards
* driver core
@@ -38,42 +39,28 @@ MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
-#if 0
-static unsigned int gpio_tracking = 0;
-MODULE_PARM(gpio_tracking,"i");
-MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
-
-static unsigned int ts_nr = -1;
-MODULE_PARM(ts_nr,"i");
-MODULE_PARM_DESC(ts_nr,"ts device number");
-
-static unsigned int vbi_nr = -1;
-MODULE_PARM(vbi_nr,"i");
-MODULE_PARM_DESC(vbi_nr,"vbi device number");
-
-static unsigned int radio_nr = -1;
-MODULE_PARM(radio_nr,"i");
-MODULE_PARM_DESC(radio_nr,"radio device number");
-
-static unsigned int oss = 0;
-MODULE_PARM(oss,"i");
-MODULE_PARM_DESC(oss,"register oss devices (default: no)");
-
-static unsigned int dsp_nr = -1;
-MODULE_PARM(dsp_nr,"i");
-MODULE_PARM_DESC(dsp_nr,"oss dsp device number");
-
-static unsigned int mixer_nr = -1;
-MODULE_PARM(mixer_nr,"i");
-MODULE_PARM_DESC(mixer_nr,"oss mixer device number");
-#endif
-
static unsigned int core_debug = 0;
MODULE_PARM(core_debug,"i");
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+static unsigned int latency = UNSET;
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
+
+static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(tuner,"1-" __stringify(CX88_MAXBOARDS) "i");
+MODULE_PARM_DESC(tuner,"tuner type");
+
+static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM(card,"1-" __stringify(CX88_MAXBOARDS) "i");
+MODULE_PARM_DESC(card,"card type");
+
#define dprintk(fmt, arg...) if (core_debug) \
- printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
+ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
+
+static unsigned int cx88_devcount;
+static LIST_HEAD(cx88_devlist);
+static DECLARE_MUTEX(devlist);
/* ------------------------------------------------------------------ */
/* debug help functions */
@@ -259,10 +246,12 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
*
* FIFO space allocations:
* channel 21 (y video) - 10.0k
+ * channel 22 (u video) - 2.0k
+ * channel 23 (v video) - 2.0k
* channel 24 (vbi) - 4.0k
* channels 25+26 (audio) - 0.5k
- * everything else - 2.0k
- * TOTAL = 29.0k
+ * channel 28 (mpeg) - 4.0k
+ * TOTAL = 25.5k
*
* Every channel has 160 bytes control data (64 bytes instruction
* queue and 6 CDT entries), which is close to 2k total.
@@ -346,9 +335,21 @@ struct sram_channel cx88_sram_channels[] = {
.cnt1_reg = MO_DMA26_CNT1,
.cnt2_reg = MO_DMA26_CNT2,
},
+ [SRAM_CH28] = {
+ .name = "mpeg",
+ .cmds_start = 0x180200,
+ .ctrl_start = 0x1807C0,
+ .cdt = 0x1807C0 + 64,
+ .fifo_start = 0x185600,
+ .fifo_size = 0x001000,
+ .ptr1_reg = MO_DMA28_PTR1,
+ .ptr2_reg = MO_DMA28_PTR2,
+ .cnt1_reg = MO_DMA28_CNT1,
+ .cnt2_reg = MO_DMA28_CNT2,
+ },
};
-int cx88_sram_channel_setup(struct cx8800_dev *dev,
+int cx88_sram_channel_setup(struct cx88_core *core,
struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
@@ -378,7 +379,7 @@ int cx88_sram_channel_setup(struct cx8800_dev *dev,
/* fill registers */
cx_write(ch->ptr1_reg, ch->fifo_start);
cx_write(ch->ptr2_reg, cdt);
- cx_write(ch->cnt1_reg, bpl >> 3);
+ cx_write(ch->cnt1_reg, (bpl >> 3) -1);
cx_write(ch->cnt2_reg, (lines*16) >> 3);
dprintk("sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
@@ -426,25 +427,25 @@ int cx88_risc_decode(u32 risc)
return incr[risc >> 28] ? incr[risc >> 28] : 1;
}
-void cx88_risc_disasm(struct cx8800_dev *dev,
+void cx88_risc_disasm(struct cx88_core *core,
struct btcx_riscmem *risc)
{
unsigned int i,j,n;
printk("%s: risc disasm: %p [dma=0x%08lx]\n",
- dev->name, risc->cpu, (unsigned long)risc->dma);
+ core->name, risc->cpu, (unsigned long)risc->dma);
for (i = 0; i < (risc->size >> 2); i += n) {
- printk("%s: %04d: ", dev->name, i);
+ printk("%s: %04d: ", core->name, i);
n = cx88_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);
+ core->name, i+j, risc->cpu[i+j], j);
if (risc->cpu[i] == RISC_JUMP)
break;
}
}
-void cx88_sram_channel_dump(struct cx8800_dev *dev,
+void cx88_sram_channel_dump(struct cx88_core *core,
struct sram_channel *ch)
{
static char *name[] = {
@@ -463,39 +464,40 @@ void cx88_sram_channel_dump(struct cx8800_dev *dev,
u32 risc;
unsigned int i,j,n;
- printk("%s: %s - dma channel status dump\n",dev->name,ch->name);
+ printk("%s: %s - dma channel status dump\n",
+ core->name,ch->name);
for (i = 0; i < ARRAY_SIZE(name); i++)
printk("%s: cmds: %-12s: 0x%08x\n",
- dev->name,name[i],
+ core->name,name[i],
cx_read(ch->cmds_start + 4*i));
for (i = 0; i < 4; i++) {
risc = cx_read(ch->cmds_start + 4 * (i+11));
- printk("%s: risc%d: ", dev->name, i);
+ printk("%s: risc%d: ", core->name, i);
cx88_risc_decode(risc);
}
for (i = 0; i < 16; i += n) {
risc = cx_read(ch->ctrl_start + 4 * i);
- printk("%s: iq %x: ", dev->name, i);
+ printk("%s: iq %x: ", core->name, i);
n = cx88_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);
+ core->name, i+j, risc, j);
}
}
printk("%s: fifo: 0x%08x -> 0x%x\n",
- dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+ core->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);
+ core->name, ch->ctrl_start, ch->ctrl_start+6*16);
printk("%s: ptr1_reg: 0x%08x\n",
- dev->name,cx_read(ch->ptr1_reg));
+ core->name,cx_read(ch->ptr1_reg));
printk("%s: ptr2_reg: 0x%08x\n",
- dev->name,cx_read(ch->ptr2_reg));
+ core->name,cx_read(ch->ptr2_reg));
printk("%s: cnt1_reg: 0x%08x\n",
- dev->name,cx_read(ch->cnt1_reg));
+ core->name,cx_read(ch->cnt1_reg));
printk("%s: cnt2_reg: 0x%08x\n",
- dev->name,cx_read(ch->cnt2_reg));
+ core->name,cx_read(ch->cnt2_reg));
}
char *cx88_pci_irqs[32] = {
@@ -531,14 +533,13 @@ void cx88_print_irqbits(char *name, char *tag, char **strings,
/* ------------------------------------------------------------------ */
-int cx88_pci_quirks(char *name, struct pci_dev *pci, unsigned int *latency)
+static int cx88_pci_quirks(char *name, struct pci_dev *pci)
{
+ unsigned int lat = UNSET;
u8 ctrl = 0;
u8 value;
- if (0 == pci_pci_problems)
- return 0;
-
+ /* check pci quirks */
if (pci_pci_problems & PCIPCI_TRITON) {
printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
name);
@@ -563,19 +564,161 @@ int cx88_pci_quirks(char *name, struct pci_dev *pci, unsigned int *latency)
if (pci_pci_problems & PCIPCI_ALIMAGIK) {
printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
name);
- *latency = 0x0A;
+ lat = 0x0A;
}
#endif
+
+ /* check insmod options */
+ if (UNSET != latency)
+ lat = latency;
+
+ /* apply stuff */
if (ctrl) {
pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
value |= ctrl;
pci_write_config_byte(pci, CX88X_DEVCTRL, value);
}
+ if (UNSET != lat) {
+ printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+ name, latency);
+ pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
+ }
return 0;
}
/* ------------------------------------------------------------------ */
+struct video_device *cx88_vdev_init(struct cx88_core *core,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ vfd->dev = &pci->dev;
+ vfd->release = video_device_release;
+#endif
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+ core->name, type, cx88_boards[core->board].name);
+ return vfd;
+}
+
+static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
+{
+ if (request_mem_region(pci_resource_start(pci,0),
+ pci_resource_len(pci,0),
+ core->name))
+ return 0;
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
+ core->name,pci_resource_start(pci,0));
+ return -EBUSY;
+}
+
+struct cx88_core* cx88_core_get(struct pci_dev *pci)
+{
+ struct cx88_core *core;
+ struct list_head *item;
+ int i;
+
+ down(&devlist);
+ list_for_each(item,&cx88_devlist) {
+ core = list_entry(item, struct cx88_core, devlist);
+ if (pci->bus->number != core->pci_bus)
+ continue;
+ if (PCI_SLOT(pci->devfn) != core->pci_slot)
+ continue;
+
+ if (0 != get_ressources(core,pci))
+ goto fail_unlock;
+ atomic_inc(&core->refcount);
+ up(&devlist);
+ return core;
+ }
+ core = kmalloc(sizeof(*core),GFP_KERNEL);
+ if (NULL == core)
+ goto fail_unlock;
+
+ memset(core,0,sizeof(*core));
+ core->pci_bus = pci->bus->number;
+ core->pci_slot = PCI_SLOT(pci->devfn);
+ atomic_inc(&core->refcount);
+
+ core->nr = cx88_devcount++;
+ sprintf(core->name,"cx88[%d]",core->nr);
+ if (0 != get_ressources(core,pci)) {
+ cx88_devcount--;
+ goto fail_free;
+ }
+ list_add_tail(&core->devlist,&cx88_devlist);
+
+ /* PCI stuff */
+ cx88_pci_quirks(core->name, pci);
+ core->lmmio = ioremap(pci_resource_start(pci,0),
+ pci_resource_len(pci,0));
+ core->bmmio = (u8*)core->lmmio;
+
+ /* board config */
+ core->board = UNSET;
+ if (card[core->nr] < cx88_bcount)
+ core->board = card[core->nr];
+ for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
+ if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
+ pci->subsystem_device == cx88_subids[i].subdevice)
+ core->board = cx88_subids[i].card;
+ if (UNSET == core->board) {
+ core->board = CX88_BOARD_UNKNOWN;
+ cx88_card_list(core,pci);
+ }
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ core->name,pci->subsystem_vendor,
+ pci->subsystem_device,cx88_boards[core->board].name,
+ core->board, card[core->nr] == core->board ?
+ "insmod option" : "autodetected");
+
+ core->tuner_type = tuner[core->nr];
+ if (UNSET == core->tuner_type)
+ core->tuner_type = cx88_boards[core->board].tuner_type;
+ core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
+
+ /* init hardware */
+ cx88_i2c_init(core,pci);
+
+ up(&devlist);
+ return core;
+
+fail_free:
+ kfree(core);
+fail_unlock:
+ up(&devlist);
+ return NULL;
+}
+
+void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
+{
+ release_mem_region(pci_resource_start(pci,0),
+ pci_resource_len(pci,0));
+
+ if (!atomic_dec_and_test(&core->refcount))
+ return;
+
+ down(&devlist);
+ if (0 == core->i2c_rc)
+ i2c_bit_del_bus(&core->i2c_adap);
+ list_del(&core->devlist);
+ iounmap(core->lmmio);
+ cx88_devcount--;
+ up(&devlist);
+ kfree(core);
+}
+
+/* ------------------------------------------------------------------ */
+
EXPORT_SYMBOL(cx88_print_ioctl);
EXPORT_SYMBOL(cx88_pci_irqs);
EXPORT_SYMBOL(cx88_vid_irqs);
@@ -591,7 +734,9 @@ EXPORT_SYMBOL(cx88_sram_channels);
EXPORT_SYMBOL(cx88_sram_channel_setup);
EXPORT_SYMBOL(cx88_sram_channel_dump);
-EXPORT_SYMBOL(cx88_pci_quirks);
+EXPORT_SYMBOL(cx88_vdev_init);
+EXPORT_SYMBOL(cx88_core_get);
+EXPORT_SYMBOL(cx88_core_put);
/*
* Local variables:
diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c
index fcf8b1abd..02595d86c 100644
--- a/linux/drivers/media/video/cx88/cx88-i2c.c
+++ b/linux/drivers/media/video/cx88/cx88-i2c.c
@@ -33,31 +33,31 @@
void cx8800_bit_setscl(void *data, int state)
{
- struct cx8800_dev *dev = data;
+ struct cx88_core *core = data;
if (state)
- dev->i2c_state |= 0x02;
+ core->i2c_state |= 0x02;
else
- dev->i2c_state &= ~0x02;
- cx_write(MO_I2C, dev->i2c_state);
+ core->i2c_state &= ~0x02;
+ cx_write(MO_I2C, core->i2c_state);
cx_read(MO_I2C);
}
void cx8800_bit_setsda(void *data, int state)
{
- struct cx8800_dev *dev = data;
+ struct cx88_core *core = data;
if (state)
- dev->i2c_state |= 0x01;
+ core->i2c_state |= 0x01;
else
- dev->i2c_state &= ~0x01;
- cx_write(MO_I2C, dev->i2c_state);
+ core->i2c_state &= ~0x01;
+ cx_write(MO_I2C, core->i2c_state);
cx_read(MO_I2C);
}
static int cx8800_bit_getscl(void *data)
{
- struct cx8800_dev *dev = data;
+ struct cx88_core *core = data;
u32 state;
state = cx_read(MO_I2C);
@@ -66,7 +66,7 @@ static int cx8800_bit_getscl(void *data)
static int cx8800_bit_getsda(void *data)
{
- struct cx8800_dev *dev = data;
+ struct cx88_core *core = data;
u32 state;
state = cx_read(MO_I2C);
@@ -89,24 +89,24 @@ static void cx8800_dec_use(struct i2c_adapter *adap)
static int attach_inform(struct i2c_client *client)
{
- struct cx8800_dev *dev = i2c_get_adapdata(client->adapter);
+ struct cx88_core *core = i2c_get_adapdata(client->adapter);
- if (dev->tuner_type != UNSET)
- cx8800_call_i2c_clients(dev,TUNER_SET_TYPE,&dev->tuner_type);
- if (dev->tda9887_conf)
- cx8800_call_i2c_clients(dev,TDA9887_SET_CONFIG,&dev->tda9887_conf);
+ if (core->tuner_type != UNSET)
+ cx88_call_i2c_clients(core,TUNER_SET_TYPE,&core->tuner_type);
+ if (core->tda9887_conf)
+ cx88_call_i2c_clients(core,TDA9887_SET_CONFIG,&core->tda9887_conf);
if (1 /* fixme: debug */)
printk("%s: i2c attach [client=%s]\n",
- dev->name, i2c_clientname(client));
+ core->name, i2c_clientname(client));
return 0;
}
-void cx8800_call_i2c_clients(struct cx8800_dev *dev, unsigned int cmd, void *arg)
+void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
{
- if (0 != dev->i2c_rc)
+ if (0 != core->i2c_rc)
return;
- i2c_clients_command(&dev->i2c_adap, cmd, arg);
+ i2c_clients_command(&core->i2c_adap, cmd, arg);
}
static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
@@ -142,33 +142,38 @@ static struct i2c_client cx8800_i2c_client_template = {
};
/* init + register i2c algo-bit adapter */
-int __devinit cx8800_i2c_init(struct cx8800_dev *dev)
+int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
{
- memcpy(&dev->i2c_adap, &cx8800_i2c_adap_template,
- sizeof(dev->i2c_adap));
- memcpy(&dev->i2c_algo, &cx8800_i2c_algo_template,
- sizeof(dev->i2c_algo));
- memcpy(&dev->i2c_client, &cx8800_i2c_client_template,
- sizeof(dev->i2c_client));
+ memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
+ sizeof(core->i2c_adap));
+ memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
+ sizeof(core->i2c_algo));
+ memcpy(&core->i2c_client, &cx8800_i2c_client_template,
+ sizeof(core->i2c_client));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,54)
- dev->i2c_adap.dev.parent = &dev->pci->dev;
+ core->i2c_adap.dev.parent = &pci->dev;
#endif
- strlcpy(dev->i2c_adap.name,dev->name,sizeof(dev->i2c_adap.name));
- dev->i2c_algo.data = dev;
- i2c_set_adapdata(&dev->i2c_adap,dev);
- dev->i2c_adap.algo_data = &dev->i2c_algo;
- dev->i2c_client.adapter = &dev->i2c_adap;
-
- cx8800_bit_setscl(dev,1);
- cx8800_bit_setsda(dev,1);
-
- dev->i2c_rc = i2c_bit_add_bus(&dev->i2c_adap);
- printk("%s: i2c register %s\n", dev->name,
- (0 == dev->i2c_rc) ? "ok" : "FAILED");
- return dev->i2c_rc;
+ strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+ core->i2c_algo.data = core;
+ i2c_set_adapdata(&core->i2c_adap,core);
+ core->i2c_adap.algo_data = &core->i2c_algo;
+ core->i2c_client.adapter = &core->i2c_adap;
+
+ cx8800_bit_setscl(core,1);
+ cx8800_bit_setsda(core,1);
+
+ core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap);
+ printk("%s: i2c register %s\n", core->name,
+ (0 == core->i2c_rc) ? "ok" : "FAILED");
+ return core->i2c_rc;
}
+/* ----------------------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx88_call_i2c_clients);
+EXPORT_SYMBOL(cx88_i2c_init);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c
new file mode 100644
index 000000000..f5fb18ee8
--- /dev/null
+++ b/linux/drivers/media/video/cx88/cx88-mpeg.c
@@ -0,0 +1,690 @@
+/*
+ * $Id: cx88-mpeg.c,v 1.1 2004/07/29 21:35:48 kraxel Exp $
+ *
+ * Support for the mpeg transport stream transfers
+ * PCI function #2 of the cx2388x.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+
+#include "cx88.h"
+
+#define PACKET_SIZE 512 // smaller ones seem not to work
+#define PACKETS_PER_BUFFER 1024
+#define BUFFER_SIZE (PACKET_SIZE * PACKETS_PER_BUFFER)
+
+/* ------------------------------------------------------------------ */
+
+MODULE_DESCRIPTION("mpeg driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int mpegbufs = 8;
+MODULE_PARM(mpegbufs,"i");
+MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
+
+static unsigned int mpeg_debug = 0;
+MODULE_PARM(mpeg_debug,"i");
+MODULE_PARM_DESC(mpeg_debug,"enable debug messages [mpeg]");
+
+#define dprintk(level,fmt, arg...) if (mpeg_debug >= level) \
+ printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg)
+
+static LIST_HEAD(cx8802_devlist);
+
+/* ------------------------------------------------------------------ */
+
+int cx8802_start_dma(struct cx8802_dev *dev,
+ struct cx88_dmaqueue *q,
+ struct cx88_buffer *buf)
+{
+ struct cx88_core *core = dev->core;
+
+ dprintk(0, "cx8802_start_mpegport_dma %d\n", buf->vb.width);
+
+ /* setup fifo + format */
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
+ PACKET_SIZE, buf->risc.dma);
+
+ //cx_set(VID_CAPTURE_CONTROL,0x0); /* should this??? */
+ /* enable capture */
+
+ /* reset counter */
+ cx_write(MO_TS_GPCNTRL,0x3); /* general purpose counter for risc program (?) */
+ q->count = 1;
+
+ /* enable irqs */
+ cx_set(MO_PCI_INTMSK, 0x4); /* enable ts_int */
+ cx_set(MO_TS_INTMSK, 0x1f1101); /* all except the irq2 bit */
+
+ /* start dma */
+ cx_set(MO_DEV_CNTRL2, (1<<5)); /* enable the risc controller */
+ cx_set(MO_TS_DMACNTRL, 0x11); /* enable TS RISC and FIFO */
+
+ return 0;
+}
+
+int cx8802_restart_queue(struct cx8802_dev *dev,
+ struct cx88_dmaqueue *q)
+{
+ struct cx88_buffer *buf;
+ struct list_head *item;
+
+ if (list_empty(&q->active))
+ return 0;
+
+ buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+ buf, buf->vb.i);
+ cx8802_start_dma(dev, q, buf);
+ list_for_each(item,&q->active) {
+ buf = list_entry(item, struct cx88_buffer, vb.queue);
+ buf->count = q->count++;
+ }
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int
+mpeg_buf_setup(struct file *file, unsigned int *count, unsigned int *size)
+{
+ *size = BUFFER_SIZE;
+ if (0 == *count)
+ *count = mpegbufs;
+ if (*count < 2)
+ *count = 2;
+ if (*count > 32)
+ *count = 32;
+ return 0;
+}
+
+static int
+mpeg_buf_prepare(struct file *file, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx8802_fh *fh = file->private_data;
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_buffer *buf = (struct cx88_buffer*)vb;
+ int rc;
+
+ dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ if (0 != buf->vb.baddr && buf->vb.bsize < BUFFER_SIZE)
+ return -EINVAL;
+
+ if (STATE_NEEDS_INIT == buf->vb.state) {
+ buf->vb.width = PACKET_SIZE;
+ buf->vb.height = PACKETS_PER_BUFFER;
+ buf->vb.size = BUFFER_SIZE;
+ buf->vb.field = field;
+
+ if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+ goto fail;
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ buf->vb.dma.sglist,
+ 0, UNSET,
+ buf->vb.width, 0,
+ buf->vb.height);
+ }
+ buf->vb.state = STATE_PREPARED;
+ return 0;
+
+ fail:
+ cx88_free_buffer(dev->pci,buf);
+ return rc;
+}
+
+static void
+mpeg_buf_queue(struct file *file, struct videobuf_buffer *vb)
+{
+ struct cx88_buffer *buf = (struct cx88_buffer*)vb;
+ struct cx88_buffer *prev;
+ struct cx8802_fh *fh = file->private_data;
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_dmaqueue *q = &dev->mpegq;
+
+ /* add jump to stopper */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | 0x10000);
+ buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+
+ if (list_empty(&q->active)) {
+ list_add_tail(&buf->vb.queue,&q->active);
+ cx8802_start_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2,"[%p/%d] %s - first active\n",
+ buf, buf->vb.i, __FUNCTION__);
+
+ } else {
+ prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(2,"[%p/%d] %s - append to active\n",
+ buf, buf->vb.i, __FUNCTION__);
+ }
+}
+
+static void mpeg_buf_release(struct file *file, struct videobuf_buffer *vb)
+{
+ struct cx88_buffer *buf = (struct cx88_buffer*)vb;
+ struct cx8802_fh *fh = file->private_data;
+ struct cx8802_dev *dev = fh->dev;
+
+ dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+
+#if 0
+ /* FIXME: probably wrong place */
+ mpegport_api_cmd(fh->dev, IVTV_API_END_CAPTURE, 3, 0, 1, 0, 0x13);
+#endif
+ cx88_free_buffer(fh->dev->pci, buf);
+}
+
+struct videobuf_queue_ops cx8802_mpeg_qops = {
+ .buf_setup = mpeg_buf_setup,
+ .buf_prepare = mpeg_buf_prepare,
+ .buf_queue = mpeg_buf_queue,
+ .buf_release = mpeg_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int mpeg_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct cx8802_fh *fh = file->private_data;
+ struct cx8802_dev *dev = fh->dev;
+
+ if (mpeg_debug > 1)
+ cx88_print_ioctl(dev->core->name,cmd);
+
+ switch (cmd) {
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ int index;
+
+ index = f->index;
+ if (index != 0)
+ return -EINVAL;
+
+ memset(f,0,sizeof(*f));
+ f->index = index;
+ strlcpy(f->description, "MPEG TS", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+ }
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ {
+ /* FIXME -- quick'n'dirty for exactly one size ... */
+ struct v4l2_format *f = arg;
+
+ memset(f,0,sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.width = 720;
+ f->fmt.pix.height = 576;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = BUFFER_SIZE;
+ }
+
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOC_REQBUFS:
+ return videobuf_reqbufs(file, &fh->mpegq, arg);
+
+ case VIDIOC_QUERYBUF:
+ return videobuf_querybuf(&fh->mpegq, arg);
+
+ case VIDIOC_QBUF:
+ return videobuf_qbuf(file, &fh->mpegq, arg);
+
+ case VIDIOC_DQBUF:
+ return videobuf_dqbuf(file, &fh->mpegq, arg);
+
+ case VIDIOC_STREAMON:
+ return videobuf_streamon(file, &fh->mpegq);
+
+ case VIDIOC_STREAMOFF:
+ return videobuf_streamoff(file, &fh->mpegq);
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mpeg_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+}
+
+static int mpeg_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct cx8802_dev *h,*dev = NULL;
+ struct cx8802_fh *fh;
+ struct list_head *list;
+
+ list_for_each(list,&cx8802_devlist) {
+ h = list_entry(list, struct cx8802_dev, devlist);
+ if (h->mpeg_dev->minor == minor)
+ dev = h;
+ }
+ if (NULL == dev)
+ return -ENODEV;
+
+#if 0 /* FIXME */
+ if (mpegport_initialize_codec(dev) < 0)
+ return -EINVAL;
+#endif
+
+ dprintk(1,"open minor=%d\n",minor);
+
+ /* allocate + initialize per filehandle data */
+ fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+ memset(fh,0,sizeof(*fh));
+ file->private_data = fh;
+ fh->dev = dev;
+
+ videobuf_queue_init(&fh->mpegq, &cx8802_mpeg_qops,
+ dev->pci, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_TOP,
+ sizeof(struct cx88_buffer));
+ init_MUTEX(&fh->mpegq.lock);
+
+ return 0;
+}
+
+static int mpeg_release(struct inode *inode, struct file *file)
+{
+ struct cx8802_fh *fh = file->private_data;
+
+#if 0 /* FIXME */
+ mpegport_api_cmd(fh->dev, IVTV_API_END_CAPTURE, 3, 0, 1, 0, 0x13);
+#endif
+
+ /* stop mpeg capture */
+ if (fh->mpegq.streaming)
+ videobuf_streamoff(file,&fh->mpegq);
+ if (fh->mpegq.reading)
+ videobuf_read_stop(file,&fh->mpegq);
+
+ file->private_data = NULL;
+ kfree(fh);
+ return 0;
+}
+
+static ssize_t
+mpeg_read(struct file *file, char *data, size_t count, loff_t *ppos)
+{
+ struct cx8802_fh *fh = file->private_data;
+
+ return videobuf_read_stream(file, &fh->mpegq, data, count, ppos, 0);
+}
+
+static unsigned int
+mpeg_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct cx8802_fh *fh = file->private_data;
+
+ return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int
+mpeg_mmap(struct file *file, struct vm_area_struct * vma)
+{
+ struct cx8802_fh *fh = file->private_data;
+
+ return videobuf_mmap_mapper(vma, &fh->mpegq);
+}
+
+static struct file_operations mpeg_fops =
+{
+ .owner = THIS_MODULE,
+ .open = mpeg_open,
+ .release = mpeg_release,
+ .read = mpeg_read,
+ .poll = mpeg_poll,
+ .mmap = mpeg_mmap,
+ .ioctl = mpeg_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct video_device cx8802_mpeg_template =
+{
+ .name = "cx8802",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
+ .hardware = 0,
+ .fops = &mpeg_fops,
+ .minor = -1,
+};
+
+/* ----------------------------------------------------------- */
+/* exported stuff */
+
+static void cx8802_timeout(unsigned long data)
+{
+ struct cx8802_dev *dev = (struct cx8802_dev*)data;
+ struct cx88_core *core = dev->core;
+ struct cx88_dmaqueue *q = &dev->mpegq;
+ struct cx88_buffer *buf;
+ unsigned long flags;
+
+ dprintk(0, "cx8802_mpegport_timeout\n");
+
+#if 0 /* FIXME */
+ mpegport_api_cmd(dev, IVTV_API_END_CAPTURE, 3, 0, 1, 0, 0x13);
+#endif
+
+ cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
+
+ cx_clear(MO_TS_DMACNTRL, 0x11); /* disable TS RISC and FIFO */
+
+ spin_lock_irqsave(&dev->slock,flags);
+ while (!list_empty(&q->active)) {
+ buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = STATE_ERROR;
+ wake_up(&buf->vb.done);
+ printk("%s: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
+ buf, buf->vb.i, (unsigned long)buf->risc.dma);
+ }
+ cx8802_restart_queue(dev,q);
+ spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+#if 0
+static void cx8802_mpeg_irq(struct cx8802_dev *dev)
+{
+ u32 status, mask, count;
+
+ status = cx_read(MO_TS_INTSTAT);
+ mask = cx_read(MO_TS_INTMSK);
+ if (0 == (status & mask))
+ return;
+
+ cx_write(MO_TS_INTSTAT, status);
+ //if (irq_debug || (status & mask & ~0xff))
+ cx88_print_irqbits(dev->name, "irq mpegport ",
+ cx88_vid_irqs, status, mask);
+
+ /* risc op code error */
+ if (status & (1 << 16)) {
+ printk(KERN_WARNING "%s: mpegport risc op code error\n",dev->name);
+ cx_clear(MO_TS_DMACNTRL, 0x11);
+ //cx_clear(VID_CAPTURE_CONTROL, 0x06);
+ cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH28]);
+ }
+
+ /* risc1 y */
+ if (status & 0x01) {
+ spin_lock(&dev->slock);
+ count = cx_read(MO_TS_GPCNT);
+ cx8802_wakeup(dev, &dev->mpegq, count);
+ spin_unlock(&dev->slock);
+ }
+
+ /* risc2 y */
+ if (status & 0x10) { /* I don't know what this does/when it's needed */
+ spin_lock(&dev->slock);
+ cx8802_restart_mpegport_queue(dev,&dev->mpegq);
+ spin_unlock(&dev->slock);
+ }
+}
+#endif
+
+static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct cx8802_dev *dev = dev_id;
+ struct cx88_core *core = dev->core;
+ u32 status, mask;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < 10; loop++) {
+ status = cx_read(MO_PCI_INTSTAT);
+ mask = cx_read(MO_PCI_INTMSK);
+ if (0 == (status & mask))
+ goto out;
+ handled = 1;
+ cx_write(MO_PCI_INTSTAT, status);
+
+#if 0 /* FIXME */
+ if (status & 1)
+ cx8800_mpeg_irq(dev);
+#endif
+ };
+ if (10 == loop) {
+ printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
+ core->name);
+ cx_write(MO_PCI_INTMSK,0);
+ }
+
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+/* ----------------------------------------------------------- */
+
+static void cx8802_unregister_video(struct cx8802_dev *dev)
+{
+ if (dev->mpeg_dev) {
+ if (-1 != dev->mpeg_dev->minor)
+ video_unregister_device(dev->mpeg_dev);
+ else
+ video_device_release(dev->mpeg_dev);
+ dev->mpeg_dev = NULL;
+ }
+}
+
+static int __devinit cx8802_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx8802_dev *dev;
+ struct cx88_core *core;
+ int err;
+
+ dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+ memset(dev,0,sizeof(*dev));
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto fail_free;
+ }
+ core = cx88_core_get(dev->pci);
+ if (NULL == core) {
+ err = -EINVAL;
+ goto fail_free;
+ }
+ dev->core = core;
+
+ /* look what exactly we have ... */
+ if (cx88_boards[core->board].blackbird) {
+ printk("%s/2: cx23416 based mpeg encoder (blackbird design)\n",
+ core->name);
+ /* todo */
+ } else {
+ printk("%s/2: don't what the mpeg port on this card is used for\n"
+ "%s/2: going to ignore it, sorry\n",
+ core->name, core->name);
+ err = -EINVAL;
+ goto fail_core;
+ }
+
+ /* print pci info */
+ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%lx\n", core->name,
+ pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat,pci_resource_start(pci_dev,0));
+
+ pci_set_master(pci_dev);
+ if (!pci_dma_supported(pci_dev,0xffffffff)) {
+ printk("%s/2: Oops: no 32bit PCI DMA ???\n",core->name);
+ err = -EIO;
+ goto fail_core;
+ }
+
+ /* initialize driver struct */
+ init_MUTEX(&dev->lock);
+ dev->slock = SPIN_LOCK_UNLOCKED;
+
+ /* init dma queue */
+ INIT_LIST_HEAD(&dev->mpegq.active);
+ INIT_LIST_HEAD(&dev->mpegq.queued);
+ dev->mpegq.timeout.function = cx8802_timeout;
+ dev->mpegq.timeout.data = (unsigned long)dev;
+ init_timer(&dev->mpegq.timeout);
+ cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
+ MO_TS_DMACNTRL,0x11,0x00);
+
+#if 0 /* FIXME */
+ /* initialize hardware */
+ cx8802_reset(dev);
+#endif
+
+ /* get irq */
+ err = request_irq(pci_dev->irq, cx8802_irq,
+ SA_SHIRQ | SA_INTERRUPT, core->name, dev);
+ if (err < 0) {
+ printk(KERN_ERR "%s: can't get IRQ %d\n",
+ core->name,pci_dev->irq);
+ goto fail_core;
+ }
+
+#if 0 /* FIXME */
+ /* register i2c bus + load i2c helpers */
+ cx88_card_setup(dev);
+#endif
+
+ /* register v4l devices */
+ dev->mpeg_dev = cx88_vdev_init(core,dev->pci,&cx8802_mpeg_template,"mpeg");
+ err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1);
+ if (err < 0) {
+ printk(KERN_INFO "%s/2: can't register mpeg device\n",
+ core->name);
+ return err;
+ }
+ printk(KERN_INFO "%s/2: registered device video%d [mpeg]\n",
+ core->name,dev->mpeg_dev->minor & 0x1f);
+
+ /* everything worked */
+ list_add_tail(&dev->devlist,&cx8802_devlist);
+ pci_set_drvdata(pci_dev,dev);
+ return 0;
+
+ fail_core:
+ cx88_core_put(core,dev->pci);
+ fail_free:
+ kfree(dev);
+ return err;
+}
+
+static void __devexit cx8802_finidev(struct pci_dev *pci_dev)
+{
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+
+#if 0
+ cx8802_shutdown(dev);
+#endif
+ pci_disable_device(pci_dev);
+
+ /* unregister stuff */
+ free_irq(pci_dev->irq, dev);
+ cx8802_unregister_video(dev);
+ pci_set_drvdata(pci_dev, NULL);
+
+ /* free memory */
+ btcx_riscmem_free(dev->pci,&dev->mpegq.stopper);
+ list_del(&dev->devlist);
+ cx88_core_put(dev->core,dev->pci);
+ kfree(dev);
+}
+
+struct pci_device_id cx8802_pci_tbl[] = {
+ {
+ .vendor = 0x14f1,
+ .device = 0x8802,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
+
+static struct pci_driver cx8802_pci_driver = {
+ .name = "cx8802",
+ .id_table = cx8802_pci_tbl,
+ .probe = cx8802_initdev,
+ .remove = cx8802_finidev,
+#if 0
+ .suspend = cx8802_suspend,
+ .resume = cx8802_resume,
+#endif
+};
+
+static int cx8802_init(void)
+{
+ printk(KERN_INFO "cx2388x mpeg driver version %d.%d.%d loaded\n",
+ (CX88_VERSION_CODE >> 16) & 0xff,
+ (CX88_VERSION_CODE >> 8) & 0xff,
+ CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+ return pci_module_init(&cx8802_pci_driver);
+}
+
+static void cx8802_fini(void)
+{
+ pci_unregister_driver(&cx8802_pci_driver);
+}
+
+module_init(cx8802_init);
+module_exit(cx8802_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/linux/drivers/media/video/cx88/cx88-tvaudio.c b/linux/drivers/media/video/cx88/cx88-tvaudio.c
index 06faebd3a..0810b9ede 100644
--- a/linux/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/linux/drivers/media/video/cx88/cx88-tvaudio.c
@@ -57,7 +57,7 @@ MODULE_PARM(audio_debug,"i");
MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
#define dprintk(fmt, arg...) if (audio_debug) \
- printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+ printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
/* ----------------------------------------------------------- */
@@ -93,7 +93,7 @@ struct rlist {
u32 val;
};
-static void set_audio_registers(struct cx8800_dev *dev,
+static void set_audio_registers(struct cx88_core *core,
const struct rlist *l)
{
int i;
@@ -115,7 +115,7 @@ static void set_audio_registers(struct cx8800_dev *dev,
}
}
-static void set_audio_start(struct cx8800_dev *dev,
+static void set_audio_start(struct cx88_core *core,
u32 mode, u32 ctl)
{
// mute
@@ -133,7 +133,7 @@ static void set_audio_start(struct cx8800_dev *dev,
cx_write(AUD_CTL, ctl);
}
-static void set_audio_finish(struct cx8800_dev *dev)
+static void set_audio_finish(struct cx88_core *core)
{
u32 volume;
@@ -150,7 +150,7 @@ static void set_audio_finish(struct cx8800_dev *dev)
/* ----------------------------------------------------------- */
-static void set_audio_standard_BTSC(struct cx8800_dev *dev, unsigned int sap)
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap)
{
static const struct rlist btsc[] = {
/* from dscaler */
@@ -247,20 +247,22 @@ static void set_audio_standard_BTSC(struct cx8800_dev *dev, unsigned int sap)
// dscaler: don't know why to set EN_FMRADIO_EN_RDS
if (sap) {
dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
- set_audio_start(dev, 0x0001,
+ set_audio_start(core, 0x0001,
EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP);
- set_audio_registers(dev, btsc_sap);
+ set_audio_registers(core, btsc_sap);
} else {
dprintk("%s (status: known-good)\n",__FUNCTION__);
- set_audio_start(dev, 0x0001,
+ set_audio_start(core, 0x0001,
EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO);
- set_audio_registers(dev, btsc);
+ set_audio_registers(core, btsc);
}
- set_audio_finish(dev);
+ set_audio_finish(core);
}
static void set_audio_standard_NICAM(struct cx8800_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
static const struct rlist nicam_common[] = {
/* from dscaler */
{ AUD_RATE_ADJ1, 0x00000010 },
@@ -316,22 +318,22 @@ static void set_audio_standard_NICAM(struct cx8800_dev *dev)
{ /* end of list */ },
};
- set_audio_start(dev, 0x0010,
+ set_audio_start(core, 0x0010,
EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
- set_audio_registers(dev, nicam_common);
+ set_audio_registers(core, nicam_common);
switch (dev->tvaudio) {
case WW_NICAM_I:
dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
- set_audio_registers(dev, nicam_pal_i);
+ set_audio_registers(core, nicam_pal_i);
case WW_NICAM_BGDKL:
dprintk("%s PAL NICAM (status: unknown)\n",__FUNCTION__);
- set_audio_registers(dev, nicam_default);
+ set_audio_registers(core, nicam_default);
break;
};
- set_audio_finish(dev);
+ set_audio_finish(core);
}
-static void set_audio_standard_NICAM_L(struct cx8800_dev *dev)
+static void set_audio_standard_NICAM_L(struct cx88_core *core)
{
/* This is officially wierd.. register dumps indicate windows
* uses audio mode 4.. A2. Let's operate and find out. */
@@ -449,14 +451,16 @@ static void set_audio_standard_NICAM_L(struct cx8800_dev *dev)
};
dprintk("%s (status: unknown)\n",__FUNCTION__);
- set_audio_start(dev, 0x0004,
+ set_audio_start(core, 0x0004,
0 /* FIXME */);
- set_audio_registers(dev, nicam_l);
- set_audio_finish(dev);
+ set_audio_registers(core, nicam_l);
+ set_audio_finish(core);
}
static void set_audio_standard_A2(struct cx8800_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
/* from dscaler cvs */
static const struct rlist a2_common[] = {
{ AUD_PDF_DDS_CNST_BYTE2, 0x06 },
@@ -545,26 +549,26 @@ static void set_audio_standard_A2(struct cx8800_dev *dev)
{ /* end of list */ },
};
- set_audio_start(dev, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
- set_audio_registers(dev, a2_common);
+ set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
+ set_audio_registers(core, a2_common);
switch (dev->tvaudio) {
case WW_A2_BG:
dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
- set_audio_registers(dev, a2_table1);
+ set_audio_registers(core, a2_table1);
break;
case WW_A2_DK:
dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
- set_audio_registers(dev, a2_table2);
+ set_audio_registers(core, a2_table2);
break;
case WW_A2_M:
dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
- set_audio_registers(dev, a2_table3);
+ set_audio_registers(core, a2_table3);
break;
};
- set_audio_finish(dev);
+ set_audio_finish(core);
}
-static void set_audio_standard_EIAJ(struct cx8800_dev *dev)
+static void set_audio_standard_EIAJ(struct cx88_core *core)
{
static const struct rlist eiaj[] = {
/* TODO: eiaj register settings are not there yet ... */
@@ -573,12 +577,12 @@ static void set_audio_standard_EIAJ(struct cx8800_dev *dev)
};
dprintk("%s (status: unknown)\n",__FUNCTION__);
- set_audio_start(dev, 0x0002, EN_EIAJ_AUTO_STEREO);
- set_audio_registers(dev, eiaj);
- set_audio_finish(dev);
+ set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO);
+ set_audio_registers(core, eiaj);
+ set_audio_finish(core);
}
-static void set_audio_standard_FM(struct cx8800_dev *dev)
+static void set_audio_standard_FM(struct cx88_core *core)
{
#if 0 /* FIXME */
switch (dev->audio_properties.FM_deemphasis)
@@ -618,12 +622,12 @@ static void set_audio_standard_FM(struct cx8800_dev *dev)
#endif
dprintk("%s (status: unknown)\n",__FUNCTION__);
- set_audio_start(dev, 0x0020, EN_FMRADIO_AUTO_STEREO);
+ set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
// AB: 10/2/01: this register is not being reset appropriately on occasion.
cx_write(AUD_POLYPH80SCALEFAC,3);
- set_audio_finish(dev);
+ set_audio_finish(core);
}
/* ----------------------------------------------------------- */
@@ -632,7 +636,7 @@ void cx88_set_tvaudio(struct cx8800_dev *dev)
{
switch (dev->tvaudio) {
case WW_BTSC:
- set_audio_standard_BTSC(dev,0);
+ set_audio_standard_BTSC(dev->core,0);
break;
case WW_NICAM_I:
case WW_NICAM_BGDKL:
@@ -644,18 +648,18 @@ void cx88_set_tvaudio(struct cx8800_dev *dev)
set_audio_standard_A2(dev);
break;
case WW_EIAJ:
- set_audio_standard_EIAJ(dev);
+ set_audio_standard_EIAJ(dev->core);
break;
case WW_FM:
- set_audio_standard_FM(dev);
+ set_audio_standard_FM(dev->core);
break;
case WW_SYSTEM_L_AM:
- set_audio_standard_NICAM_L(dev);
+ set_audio_standard_NICAM_L(dev->core);
break;
case WW_NONE:
default:
- printk("%s: unknown tv audio mode [%d]\n",
- dev->name, dev->tvaudio);
+ printk("%s/0: unknown tv audio mode [%d]\n",
+ dev->core->name, dev->tvaudio);
break;
}
return;
@@ -665,6 +669,7 @@ void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
{
static char *m[] = {"stereo", "dual mono", "mono", "sap"};
static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
+ struct cx88_core *core = dev->core;
u32 reg,mode,pilot;
reg = cx_read(AUD_STATUS);
@@ -712,6 +717,7 @@ void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
{
+ struct cx88_core *core = dev->core;
u32 ctl = UNSET;
u32 mask = UNSET;
@@ -781,6 +787,7 @@ void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
int cx88_audio_thread(void *data)
{
struct cx8800_dev *dev = data;
+ struct cx88_core *core = dev->core;
struct v4l2_tuner t;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
diff --git a/linux/drivers/media/video/cx88/cx88-vbi.c b/linux/drivers/media/video/cx88/cx88-vbi.c
index 068955ec8..cdd6953fb 100644
--- a/linux/drivers/media/video/cx88/cx88-vbi.c
+++ b/linux/drivers/media/video/cx88/cx88-vbi.c
@@ -14,7 +14,7 @@ MODULE_PARM(vbi_debug,"i");
MODULE_PARM_DESC(vbi_debug,"enable debug messages [video]");
#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \
- printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+ printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
/* ------------------------------------------------------------------ */
@@ -46,8 +46,10 @@ int cx8800_start_vbi_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
struct cx88_buffer *buf)
{
+ struct cx88_core *core = dev->core;
+
/* setup fifo + format */
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH24],
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24],
buf->vb.width, buf->risc.dma);
cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup
@@ -96,11 +98,12 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
void cx8800_vbi_timeout(unsigned long data)
{
struct cx8800_dev *dev = (struct cx8800_dev*)data;
+ struct cx88_core *core = dev->core;
struct cx88_dmaqueue *q = &dev->vbiq;
struct cx88_buffer *buf;
unsigned long flags;
- cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH24]);
+ cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]);
cx_clear(MO_VID_DMACNTRL, 0x88);
cx_clear(VID_CAPTURE_CONTROL, 0x18);
@@ -111,7 +114,7 @@ void cx8800_vbi_timeout(unsigned long data)
list_del(&buf->vb.queue);
buf->vb.state = STATE_ERROR;
wake_up(&buf->vb.done);
- printk("%s: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
+ printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
buf, buf->vb.i, (unsigned long)buf->risc.dma);
}
cx8800_restart_vbi_queue(dev,q);
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index 910ef7c82..79ccb4989 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -1,4 +1,6 @@
/*
+ * $Id: cx88-video.c,v 1.29 2004/07/29 21:35:48 kraxel Exp $
+ *
* device driver for Conexant 2388x based TV cards
* video4linux video interface
*
@@ -50,10 +52,6 @@ static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
MODULE_PARM(radio_nr,"1-" __stringify(CX88_MAXBOARDS) "i");
MODULE_PARM_DESC(radio_nr,"radio device numbers");
-static unsigned int latency = UNSET;
-MODULE_PARM(latency,"i");
-MODULE_PARM_DESC(latency,"pci latency timer");
-
static unsigned int video_debug = 0;
MODULE_PARM(video_debug,"i");
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
@@ -66,25 +64,16 @@ static unsigned int vid_limit = 16;
MODULE_PARM(vid_limit,"i");
MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
-static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-MODULE_PARM(tuner,"1-" __stringify(CX88_MAXBOARDS) "i");
-MODULE_PARM_DESC(tuner,"tuner type");
-
-static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-MODULE_PARM(card,"1-" __stringify(CX88_MAXBOARDS) "i");
-MODULE_PARM_DESC(card,"card type");
-
static unsigned int nicam = 0;
MODULE_PARM(nicam,"i");
MODULE_PARM_DESC(nicam,"tv audio is nicam");
#define dprintk(level,fmt, arg...) if (video_debug >= level) \
- printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+ printk(KERN_DEBUG "%s/0: " fmt, dev->core->name , ## arg)
/* ------------------------------------------------------------------ */
-static struct list_head cx8800_devlist;
-static unsigned int cx8800_devcount;
+static LIST_HEAD(cx8800_devlist);
/* ------------------------------------------------------------------- */
/* static data */
@@ -448,6 +437,7 @@ static const u32 xtal = 28636363;
static int set_pll(struct cx8800_dev *dev, int prescale, u32 ofreq)
{
static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+ struct cx88_core *core = dev->core;
u64 pll;
u32 reg;
int i;
@@ -461,7 +451,7 @@ static int set_pll(struct cx8800_dev *dev, int prescale, u32 ofreq)
do_div(pll,xtal);
reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
if (((reg >> 20) & 0x3f) < 14) {
- printk("%s: pll out of range\n",dev->name);
+ printk("%s/0: pll out of range\n",core->name);
return -1;
}
@@ -485,6 +475,8 @@ static int set_pll(struct cx8800_dev *dev, int prescale, u32 ofreq)
static int set_tvaudio(struct cx8800_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
if (CX88_VMUX_TELEVISION != INPUT(dev->input)->type)
return 0;
@@ -511,8 +503,8 @@ static int set_tvaudio(struct cx8800_dev *dev)
dev->tvaudio = WW_EIAJ;
} else {
- printk("%s: tvaudio support needs work for this tv norm [%s], sorry\n",
- dev->name, dev->tvnorm->name);
+ printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
+ core->name, dev->tvnorm->name);
dev->tvaudio = 0;
return 0;
}
@@ -529,6 +521,7 @@ static int set_tvaudio(struct cx8800_dev *dev)
static int set_tvnorm(struct cx8800_dev *dev, struct cx8800_tvnorm *norm)
{
+ struct cx88_core *core = dev->core;
u32 fsc8;
u32 adc_clock;
u32 vdec_clock;
@@ -608,7 +601,7 @@ static int set_tvnorm(struct cx8800_dev *dev, struct cx8800_tvnorm *norm)
// tell i2c chips
#ifdef V4L2_I2C_CLIENTS
- cx8800_call_i2c_clients(dev,VIDIOC_S_STD,&norm->id);
+ cx88_call_i2c_clients(dev->core,VIDIOC_S_STD,&norm->id);
#else
{
struct video_channel c;
@@ -619,7 +612,7 @@ static int set_tvnorm(struct cx8800_dev *dev, struct cx8800_tvnorm *norm)
c.norm = VIDEO_MODE_NTSC;
if (norm->id & V4L2_STD_SECAM)
c.norm = VIDEO_MODE_SECAM;
- cx8800_call_i2c_clients(dev,VIDIOCSCHAN,&c);
+ cx88_call_i2c_clients(dev->core,VIDIOCSCHAN,&c);
}
#endif
@@ -630,6 +623,7 @@ static int set_tvnorm(struct cx8800_dev *dev, struct cx8800_tvnorm *norm)
static int set_scale(struct cx8800_dev *dev, unsigned int width, unsigned int height,
enum v4l2_field field)
{
+ struct cx88_core *core = dev->core;
unsigned int swidth = norm_swidth(dev->tvnorm);
unsigned int sheight = norm_maxh(dev->tvnorm);
u32 value;
@@ -696,6 +690,8 @@ static int set_scale(struct cx8800_dev *dev, unsigned int width, unsigned int he
static int video_mux(struct cx8800_dev *dev, unsigned int input)
{
+ struct cx88_core *core = dev->core;
+
dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",
input, INPUT(input)->vmux,
INPUT(input)->gpio0,INPUT(input)->gpio1,
@@ -730,8 +726,10 @@ static int start_video_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
struct cx88_buffer *buf)
{
+ struct cx88_core *core = dev->core;
+
/* setup fifo + format */
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH21],
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH21],
buf->bpl, buf->risc.dma);
set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma);
@@ -1282,15 +1280,17 @@ static int video_open(struct inode *inode, struct file *file)
init_MUTEX(&fh->vbiq.lock);
if (fh->radio) {
+ struct cx88_core *core = dev->core;
+ int board = core->board;
dprintk(1,"video_open: setting radio device\n");
- cx_write(MO_GP0_IO, cx88_boards[dev->board].radio.gpio0);
- cx_write(MO_GP1_IO, cx88_boards[dev->board].radio.gpio1);
- cx_write(MO_GP2_IO, cx88_boards[dev->board].radio.gpio2);
- cx_write(MO_GP3_IO, cx88_boards[dev->board].radio.gpio3);
+ cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0);
+ cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1);
+ cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2);
+ cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
dev->tvaudio = WW_FM;
cx88_set_tvaudio(dev);
cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
- cx8800_call_i2c_clients(dev,AUDC_SET_RADIO,NULL);
+ cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL);
}
return 0;
@@ -1375,6 +1375,7 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl)
{
+ struct cx88_core *core = dev->core;
struct cx88_ctrl *c = NULL;
u32 value;
int i;
@@ -1402,6 +1403,7 @@ static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl)
static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl)
{
+ struct cx88_core *core = dev->core;
struct cx88_ctrl *c = NULL;
u32 v_sat_value;
u32 value;
@@ -1579,15 +1581,16 @@ static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
static int video_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_fh *fh = file->private_data;
+ struct cx8800_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
#if 0
unsigned long flags;
#endif
int err;
if (video_debug > 1)
- cx88_print_ioctl(dev->name,cmd);
+ cx88_print_ioctl(core->name,cmd);
switch (cmd) {
case VIDIOC_QUERYCAP:
{
@@ -1595,7 +1598,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
memset(cap,0,sizeof(*cap));
strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[dev->board].name,
+ strlcpy(cap->card, cx88_boards[core->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
@@ -1608,7 +1611,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_VIDEO_OVERLAY |
#endif
0;
- if (UNSET != dev->tuner_type)
+ if (UNSET != core->tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
@@ -1774,7 +1777,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_tuner *t = arg;
u32 reg;
- if (UNSET == dev->tuner_type)
+ if (UNSET == core->tuner_type)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1794,7 +1797,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_tuner *t = arg;
- if (UNSET == dev->tuner_type)
+ if (UNSET == core->tuner_type)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1805,7 +1808,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *f = arg;
- if (UNSET == dev->tuner_type)
+ if (UNSET == core->tuner_type)
return -EINVAL;
if (f->tuner != 0)
return -EINVAL;
@@ -1818,7 +1821,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *f = arg;
- if (UNSET == dev->tuner_type)
+ if (UNSET == core->tuner_type)
return -EINVAL;
if (f->tuner != 0)
return -EINVAL;
@@ -1829,9 +1832,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
down(&dev->lock);
dev->freq = f->frequency;
#ifdef V4L2_I2C_CLIENTS
- cx8800_call_i2c_clients(dev,VIDIOC_S_FREQUENCY,f);
+ cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f);
#else
- cx8800_call_i2c_clients(dev,VIDIOCSFREQ,&dev->freq);
+ cx88_call_i2c_clients(dev->core,VIDIOCSFREQ,&dev->freq);
#endif
up(&dev->lock);
return 0;
@@ -1911,11 +1914,12 @@ static int video_ioctl(struct inode *inode, struct file *file,
static int radio_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_fh *fh = file->private_data;
+ struct cx8800_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
if (video_debug > 1)
- cx88_print_ioctl(dev->name,cmd);
+ cx88_print_ioctl(core->name,cmd);
switch (cmd) {
case VIDIOC_QUERYCAP:
@@ -1924,7 +1928,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(cap,0,sizeof(*cap));
strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[dev->board].name,
+ strlcpy(cap->card, cx88_boards[core->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
@@ -1944,7 +1948,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
t->rangehigh = (int)(108*16);
#ifdef V4L2_I2C_CLIENTS
- cx8800_call_i2c_clients(dev,VIDIOC_G_TUNER,t);
+ cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t);
#else
{
struct video_tuner vt;
@@ -2034,12 +2038,12 @@ static int radio_ioctl(struct inode *inode, struct file *file,
static void cx8800_vid_timeout(unsigned long data)
{
struct cx8800_dev *dev = (struct cx8800_dev*)data;
+ struct cx88_core *core = dev->core;
struct cx88_dmaqueue *q = &dev->vidq;
struct cx88_buffer *buf;
unsigned long flags;
- cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH21]);
- //cx88_risc_disasm(dev,&dev->vidq.stopper);
+ cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH21]);
cx_clear(MO_VID_DMACNTRL, 0x11);
cx_clear(VID_CAPTURE_CONTROL, 0x06);
@@ -2050,7 +2054,7 @@ static void cx8800_vid_timeout(unsigned long data)
list_del(&buf->vb.queue);
buf->vb.state = STATE_ERROR;
wake_up(&buf->vb.done);
- printk("%s: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
+ printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
buf, buf->vb.i, (unsigned long)buf->risc.dma);
}
restart_video_queue(dev,q);
@@ -2085,6 +2089,7 @@ static void cx8800_wakeup(struct cx8800_dev *dev,
static void cx8800_vid_irq(struct cx8800_dev *dev)
{
+ struct cx88_core *core = dev->core;
u32 status, mask, count;
status = cx_read(MO_VID_INTSTAT);
@@ -2093,15 +2098,15 @@ static void cx8800_vid_irq(struct cx8800_dev *dev)
return;
cx_write(MO_VID_INTSTAT, status);
if (irq_debug || (status & mask & ~0xff))
- cx88_print_irqbits(dev->name, "irq vid",
+ cx88_print_irqbits(core->name, "irq vid",
cx88_vid_irqs, status, mask);
/* risc op code error */
if (status & (1 << 16)) {
- printk(KERN_WARNING "%s: video risc op code error\n",dev->name);
+ printk(KERN_WARNING "%s/0: video risc op code error\n",core->name);
cx_clear(MO_VID_DMACNTRL, 0x11);
cx_clear(VID_CAPTURE_CONTROL, 0x06);
- cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH21]);
+ cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH21]);
}
/* risc1 y */
@@ -2140,6 +2145,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev)
static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct cx8800_dev *dev = dev_id;
+ struct cx88_core *core = dev->core;
u32 status, mask;
int loop, handled = 0;
@@ -2151,15 +2157,15 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs)
handled = 1;
cx_write(MO_PCI_INTSTAT, status);
if (irq_debug || (status & mask & ~0x1f))
- cx88_print_irqbits(dev->name, "irq pci",
+ cx88_print_irqbits(core->name, "irq pci",
cx88_pci_irqs, status, mask);
if (status & 1)
cx8800_vid_irq(dev);
};
if (10 == loop) {
- printk(KERN_WARNING "%s: irq loop -- clearing mask\n",
- dev->name);
+ printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
+ core->name);
cx_write(MO_PCI_INTMSK,0);
}
@@ -2222,6 +2228,8 @@ struct video_device cx8800_radio_template =
static void cx8800_shutdown(struct cx8800_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
/* disable RISC controller + IRQs */
cx_write(MO_DEV_CNTRL2, 0);
@@ -2246,6 +2254,8 @@ static void cx8800_shutdown(struct cx8800_dev *dev)
static int cx8800_reset(struct cx8800_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
dprintk(1,"cx8800_reset\n");
cx8800_shutdown(dev);
@@ -2260,12 +2270,13 @@ static int cx8800_reset(struct cx8800_dev *dev)
schedule_timeout(HZ/10);
/* init sram */
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH22], 128, 0);
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH23], 128, 0);
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH24], 128, 0);
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH25], 128, 0);
- cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH26], 128, 0);
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH22], 128, 0);
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH23], 128, 0);
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24], 128, 0);
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH25], 128, 0);
+ cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH26], 128, 0);
+ // cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH28], 512, 0);
/* misc init ... */
cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
@@ -2293,26 +2304,6 @@ static int cx8800_reset(struct cx8800_dev *dev)
return 0;
}
-static struct video_device *vdev_init(struct cx8800_dev *dev,
- struct video_device *template,
- char *type)
-{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
- *vfd = *template;
- vfd->minor = -1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
- vfd->dev = &dev->pci->dev;
- vfd->release = video_device_release;
-#endif
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- dev->name, type, cx88_boards[dev->board].name);
- return vfd;
-}
-
static void cx8800_unregister_video(struct cx8800_dev *dev)
{
if (dev->radio_dev) {
@@ -2342,7 +2333,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct cx8800_dev *dev;
- unsigned int i;
+ struct cx88_core *core;
int err;
dev = kmalloc(sizeof(*dev),GFP_KERNEL);
@@ -2354,68 +2345,29 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
dev->pci = pci_dev;
if (pci_enable_device(pci_dev)) {
err = -EIO;
- goto fail1;
+ goto fail_free;
}
- sprintf(dev->name,"cx%x[%d]",pci_dev->device,cx8800_devcount);
-
- /* pci quirks */
- cx88_pci_quirks(dev->name, dev->pci, &latency);
- if (UNSET != latency) {
- printk(KERN_INFO "%s: setting pci latency timer to %d\n",
- dev->name,latency);
- pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+ core = cx88_core_get(dev->pci);
+ if (NULL == core) {
+ err = -EINVAL;
+ goto fail_free;
}
+ dev->core = core;
/* print pci info */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
- "latency: %d, mmio: 0x%lx\n", dev->name,
+ printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%lx\n", core->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,pci_resource_start(pci_dev,0));
pci_set_master(pci_dev);
if (!pci_dma_supported(pci_dev,0xffffffff)) {
- printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
+ printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name);
err = -EIO;
- goto fail1;
- }
-
- /* board config */
- dev->board = UNSET;
- if (card[cx8800_devcount] < cx88_bcount)
- dev->board = card[cx8800_devcount];
- for (i = 0; UNSET == dev->board && i < cx88_idcount; i++)
- if (pci_dev->subsystem_vendor == cx88_subids[i].subvendor &&
- pci_dev->subsystem_device == cx88_subids[i].subdevice)
- dev->board = cx88_subids[i].card;
- if (UNSET == dev->board) {
- dev->board = CX88_BOARD_UNKNOWN;
- cx88_card_list(dev);
- }
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- dev->name,pci_dev->subsystem_vendor,
- pci_dev->subsystem_device,cx88_boards[dev->board].name,
- dev->board, card[cx8800_devcount] == dev->board ?
- "insmod option" : "autodetected");
-
- dev->tuner_type = tuner[cx8800_devcount];
- if (UNSET == dev->tuner_type)
- dev->tuner_type = cx88_boards[dev->board].tuner_type;
- dev->tda9887_conf = cx88_boards[dev->board].tda9887_conf;
-
- /* get mmio */
- if (!request_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0),
- dev->name)) {
- err = -EBUSY;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
- dev->name,pci_resource_start(pci_dev,0));
- goto fail1;
- }
- dev->lmmio = ioremap(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
- dev->bmmio = (u8*)dev->lmmio;
+ goto fail_core;
+ }
/* initialize driver struct */
init_MUTEX(&dev->lock);
@@ -2445,67 +2397,67 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* get irq */
err = request_irq(pci_dev->irq, cx8800_irq,
- SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
+ SA_SHIRQ | SA_INTERRUPT, core->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
- dev->name,pci_dev->irq);
- goto fail2;
+ core->name,pci_dev->irq);
+ goto fail_core;
}
/* register i2c bus + load i2c helpers */
- cx8800_i2c_init(dev);
- cx88_card_setup(dev);
+ cx88_card_setup(dev->core);
/* load and configure helper modules */
- if (TUNER_ABSENT != dev->tuner_type)
+ if (TUNER_ABSENT != core->tuner_type)
request_module("tuner");
- if (dev->tda9887_conf)
+ if (core->tda9887_conf)
request_module("tda9887");
- if (dev->tuner_type != UNSET)
- cx8800_call_i2c_clients(dev,TUNER_SET_TYPE,&dev->tuner_type);
- if (dev->tda9887_conf)
- cx8800_call_i2c_clients(dev,TDA9887_SET_CONFIG,&dev->tda9887_conf);
+ if (core->tuner_type != UNSET)
+ cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE,&core->tuner_type);
+ if (core->tda9887_conf)
+ cx88_call_i2c_clients(dev->core,TDA9887_SET_CONFIG,&core->tda9887_conf);
/* register v4l devices */
- dev->video_dev = vdev_init(dev,&cx8800_video_template,"video");
+ dev->video_dev = cx88_vdev_init(core,dev->pci,
+ &cx8800_video_template,"video");
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
- video_nr[cx8800_devcount]);
+ video_nr[core->nr]);
if (err < 0) {
printk(KERN_INFO "%s: can't register video device\n",
- dev->name);
- goto fail3;
+ core->name);
+ goto fail_unreg;
}
- printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
- dev->name,dev->video_dev->minor & 0x1f);
+ printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
+ core->name,dev->video_dev->minor & 0x1f);
- dev->vbi_dev = vdev_init(dev,&cx8800_vbi_template,"vbi");
+ dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi");
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
- vbi_nr[cx8800_devcount]);
+ vbi_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s: can't register vbi device\n",
- dev->name);
- goto fail3;
+ printk(KERN_INFO "%s/0: can't register vbi device\n",
+ core->name);
+ goto fail_unreg;
}
- printk(KERN_INFO "%s: registered device vbi%d\n",
- dev->name,dev->vbi_dev->minor & 0x1f);
+ printk(KERN_INFO "%s/0: registered device vbi%d\n",
+ core->name,dev->vbi_dev->minor & 0x1f);
- if (dev->has_radio) {
- dev->radio_dev = vdev_init(dev,&cx8800_radio_template,"radio");
+ if (core->has_radio) {
+ dev->radio_dev = cx88_vdev_init(core,dev->pci,
+ &cx8800_radio_template,"radio");
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
- radio_nr[cx8800_devcount]);
+ radio_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s: can't register radio device\n",
- dev->name);
- goto fail3;
+ printk(KERN_INFO "%s/0: can't register radio device\n",
+ core->name);
+ goto fail_unreg;
}
- printk(KERN_INFO "%s: registered device radio%d\n",
- dev->name,dev->radio_dev->minor & 0x1f);
+ printk(KERN_INFO "%s/0: registered device radio%d\n",
+ core->name,dev->radio_dev->minor & 0x1f);
}
/* everything worked */
list_add_tail(&dev->devlist,&cx8800_devlist);
pci_set_drvdata(pci_dev,dev);
- cx8800_devcount++;
/* initial device configuration */
down(&dev->lock);
@@ -2519,15 +2471,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
dev->tpid = kernel_thread(cx88_audio_thread, dev, 0);
return 0;
- fail3:
+fail_unreg:
cx8800_unregister_video(dev);
- if (0 == dev->i2c_rc)
- i2c_bit_del_bus(&dev->i2c_adap);
free_irq(pci_dev->irq, dev);
- fail2:
- release_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
- fail1:
+fail_core:
+ cx88_core_put(core,dev->pci);
+fail_free:
kfree(dev);
return err;
}
@@ -2545,28 +2494,24 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
pci_disable_device(pci_dev);
/* unregister stuff */
- if (0 == dev->i2c_rc)
- i2c_bit_del_bus(&dev->i2c_adap);
free_irq(pci_dev->irq, dev);
- release_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
-
cx8800_unregister_video(dev);
pci_set_drvdata(pci_dev, NULL);
/* free memory */
btcx_riscmem_free(dev->pci,&dev->vidq.stopper);
list_del(&dev->devlist);
- cx8800_devcount--;
+ cx88_core_put(dev->core,dev->pci);
kfree(dev);
}
static int cx8800_suspend(struct pci_dev *pci_dev, u32 state)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx88_core *core = dev->core;
- printk("%s: suspend %d\n", dev->name, state);
+ printk("%s: suspend %d\n", core->name, state);
cx8800_shutdown(dev);
del_timer(&dev->vidq.timeout);
@@ -2582,8 +2527,9 @@ static int cx8800_suspend(struct pci_dev *pci_dev, u32 state)
static int cx8800_resume(struct pci_dev *pci_dev)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx88_core *core = dev->core;
- printk("%s: resume\n", dev->name);
+ printk("%s: resume\n", core->name);
if (dev->state.disabled) {
pci_enable_device(pci_dev);
@@ -2629,7 +2575,6 @@ static struct pci_driver cx8800_pci_driver = {
static int cx8800_init(void)
{
- INIT_LIST_HEAD(&cx8800_devlist);
printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index 715cdf520..a4b508ffa 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -1,4 +1,6 @@
/*
+ * $Id: cx88.h,v 1.21 2004/07/29 21:35:48 kraxel Exp $
+ *
* v4l2 device driver for cx2388x based TV cards
*
* (c) 2003,04 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
@@ -111,6 +113,7 @@ struct cx88_ctrl {
#define SRAM_CH24 3 /* vbi */
#define SRAM_CH25 4 /* audio */
#define SRAM_CH26 5
+#define SRAM_CH28 6 /* mpeg */
/* more */
struct sram_channel {
@@ -171,6 +174,7 @@ struct cx88_board {
int tda9887_conf;
struct cx88_input input[8];
struct cx88_input radio;
+ int blackbird:1;
};
struct cx88_subid {
@@ -179,7 +183,7 @@ struct cx88_subid {
u32 card;
};
-#define INPUT(nr) (&cx88_boards[dev->board].input[nr])
+#define INPUT(nr) (&cx88_boards[dev->core->board].input[nr])
/* ----------------------------------------------------------- */
/* device / file handle status */
@@ -191,8 +195,6 @@ struct cx88_subid {
//#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
#define BUFFER_TIMEOUT (HZ*2)
-struct cx8800_dev;
-
/* buffer for one video frame */
struct cx88_buffer {
/* common v4l buffer stuff -- must be first */
@@ -213,7 +215,40 @@ struct cx88_dmaqueue {
u32 count;
};
-/* video filehandle status */
+struct cx88_core {
+ struct list_head devlist;
+ atomic_t refcount;
+
+ /* board name */
+ int nr;
+ char name[32];
+
+ /* pci stuff */
+ int pci_bus;
+ int pci_slot;
+ u32 *lmmio;
+ u8 *bmmio;
+ u32 shadow[SHADOW_MAX];
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_state, i2c_rc;
+
+ /* config info */
+ unsigned int board;
+ unsigned int tuner_type;
+ unsigned int tda9887_conf;
+ unsigned int has_radio;
+};
+
+struct cx8800_dev;
+struct cx8802_dev;
+
+/* ----------------------------------------------------------- */
+/* function 0: video stuff */
+
struct cx8800_fh {
struct cx8800_dev *dev;
enum v4l2_buf_type type;
@@ -239,8 +274,8 @@ struct cx8800_suspend_state {
int disabled;
};
-/* global device status */
struct cx8800_dev {
+ struct cx88_core *core;
struct list_head devlist;
struct semaphore lock;
spinlock_t slock;
@@ -252,23 +287,8 @@ struct cx8800_dev {
struct video_device *radio_dev;
/* pci i/o */
- char name[32];
struct pci_dev *pci;
unsigned char pci_rev,pci_lat;
- u32 *lmmio;
- u8 *bmmio;
-
- /* config info */
- unsigned int board;
- unsigned int tuner_type;
- unsigned int tda9887_conf;
- unsigned int has_radio;
-
- /* i2c i/o */
- struct i2c_adapter i2c_adap;
- struct i2c_algo_bit_data i2c_algo;
- struct i2c_client i2c_client;
- u32 i2c_state, i2c_rc;
/* video overlay */
struct v4l2_framebuffer fbuf;
@@ -285,7 +305,6 @@ struct cx8800_dev {
u32 freq;
/* other global state info */
- u32 shadow[SHADOW_MAX];
int shutdown;
pid_t tpid;
struct completion texit;
@@ -294,27 +313,63 @@ struct cx8800_dev {
};
/* ----------------------------------------------------------- */
+/* function 1: audio/alsa stuff */
+
+struct cx8801_dev {
+ struct cx88_core *core;
-#define cx_read(reg) readl(dev->lmmio + ((reg)>>2))
-#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2));
-#define cx_writeb(reg,value) writeb((value), dev->bmmio + (reg));
+ /* pci i/o */
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+};
+
+/* ----------------------------------------------------------- */
+/* function 2: mpeg stuff */
+
+struct cx8802_fh {
+ struct cx8802_dev *dev;
+ struct videobuf_queue mpegq;
+};
+
+struct cx8802_dev {
+ struct cx88_core *core;
+ struct list_head devlist;
+ struct semaphore lock;
+ spinlock_t slock;
+
+ /* misc */
+ struct video_device *mpeg_dev;
+
+ /* pci i/o */
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+
+ /* dma queues */
+ struct cx88_dmaqueue mpegq;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg) readl(core->lmmio + ((reg)>>2))
+#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2));
+#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg));
#define cx_andor(reg,mask,value) \
- writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
- ((value) & (mask)), dev->lmmio+((reg)>>2))
+ writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), core->lmmio+((reg)>>2))
#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); }
/* shadow registers */
-#define cx_sread(sreg) (dev->shadow[sreg])
+#define cx_sread(sreg) (core->shadow[sreg])
#define cx_swrite(sreg,reg,value) \
- (dev->shadow[sreg] = value, \
- writel(dev->shadow[sreg], dev->lmmio + ((reg)>>2)))
+ (core->shadow[sreg] = value, \
+ writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
#define cx_sandor(sreg,reg,mask,value) \
- (dev->shadow[sreg] = (dev->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
- writel(dev->shadow[sreg], dev->lmmio + ((reg)>>2)))
+ (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
+ writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
/* ----------------------------------------------------------- */
/* cx88-core.c */
@@ -336,17 +391,20 @@ cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
extern void
cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf);
-extern void cx88_risc_disasm(struct cx8800_dev *dev,
+extern void cx88_risc_disasm(struct cx88_core *core,
struct btcx_riscmem *risc);
-
-extern int cx88_sram_channel_setup(struct cx8800_dev *dev,
+extern int cx88_sram_channel_setup(struct cx88_core *core,
struct sram_channel *ch,
unsigned int bpl, u32 risc);
-extern void cx88_sram_channel_dump(struct cx8800_dev *dev,
+extern void cx88_sram_channel_dump(struct cx88_core *core,
struct sram_channel *ch);
-
-extern int cx88_pci_quirks(char *name, struct pci_dev *pci,
- unsigned int *latency);
+extern struct video_device *cx88_vdev_init(struct cx88_core *core,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type);
+extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
+extern void cx88_core_put(struct cx88_core *core,
+ struct pci_dev *pci);
/* ----------------------------------------------------------- */
/* cx88-vbi.c */
@@ -364,9 +422,9 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
/* ----------------------------------------------------------- */
/* cx88-i2c.c */
-extern int cx8800_i2c_init(struct cx8800_dev *dev);
-extern void cx8800_call_i2c_clients(struct cx8800_dev *dev,
- unsigned int cmd, void *arg);
+extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+extern void cx88_call_i2c_clients(struct cx88_core *core,
+ unsigned int cmd, void *arg);
/* ----------------------------------------------------------- */
@@ -378,8 +436,8 @@ extern const unsigned int cx88_bcount;
extern struct cx88_subid cx88_subids[];
extern const unsigned int cx88_idcount;
-extern void cx88_card_list(struct cx8800_dev *dev);
-extern void cx88_card_setup(struct cx8800_dev *dev);
+extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
+extern void cx88_card_setup(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-tvaudio.c */