summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorGerd Knorr <devnull@localhost>2004-08-25 14:47:53 +0000
committerGerd Knorr <devnull@localhost>2004-08-25 14:47:53 +0000
commit6550ed72a57b714bfb1a718538d1fb5c542aa470 (patch)
tree7e7eb707f80203ecdb680cfd8b3d7ac4f2d3af11 /linux
parentf680c1f3f262eae1802d080db3eccee4f9da3f43 (diff)
downloadmediapointer-dvb-s2-6550ed72a57b714bfb1a718538d1fb5c542aa470.tar.gz
mediapointer-dvb-s2-6550ed72a57b714bfb1a718538d1fb5c542aa470.tar.bz2
- cx88: plenty of mpeg work. blackbird might even work with
some luck. dvb needs more work.
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c539
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c44
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c301
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c521
-rw-r--r--linux/drivers/media/video/cx88/cx88-mpeg.c270
-rw-r--r--linux/drivers/media/video/cx88/cx88-tvaudio.c79
-rw-r--r--linux/drivers/media/video/cx88/cx88-vbi.c4
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c364
-rw-r--r--linux/drivers/media/video/cx88/cx88.h86
-rw-r--r--linux/include/media/tuner.h1
10 files changed, 1110 insertions, 1099 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
index 5d1b83107..51f4b1e9a 100644
--- a/linux/drivers/media/video/cx88/cx88-blackbird.c
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-blackbird.c,v 1.4 2004/08/23 10:38:54 kraxel Exp $
+ * $Id: cx88-blackbird.c,v 1.5 2004/08/25 14:47:53 kraxel Exp $
*
* Support for a cx23416 mpeg encoder via cx2388x host port.
* "blackbird" reference design.
@@ -34,9 +34,23 @@
#include "cx88.h"
MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
-MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+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 debug = 0;
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg)
+
+static struct list_head cx8802_devlist;
+
/* ------------------------------------------------------------------ */
#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
@@ -222,364 +236,357 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
/* ------------------------------------------------------------------ */
-#if 0
-
/* We don't need to call the API often, so using just one mailbox will probably suffice */
-int blackbird_cmd(struct cx8802_dev *dev, u32 command, u32 inputcnt, u32 outputcnt, ...)
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+ u32 inputcnt, u32 outputcnt, ...)
{
va_list args;
va_start(args, outputcnt);
+ unsigned long timeout;
+ u32 value, flag, retval;
int i;
- u32 value;
- u32 flag;
dprintk(1,"%s: 0x%X\n", __FUNCTION__, 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);
+ memory_read(dev->core, dev->mailbox - 4, &value);
if (value != 0x12345678) {
dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n");
return -1;
}
- memory_read(dev, dev->mpegport_mailbox, &flag);
+ memory_read(dev->core, dev->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->core, dev->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 */
+ /* write command + args + fill remaining with zeros */
+ memory_write(dev->core, dev->mailbox + 1, command); /* command code */
+ memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
for (i = 0; i < inputcnt ; i++) {
- u32 value = va_arg(args, int);
- memory_write(dev, dev->mpegport_mailbox + 4 + i, value);
+ value = va_arg(args, int);
+ memory_write(dev->core, dev->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);
- }
+ for (; i < 16 ; i++)
+ memory_write(dev->core, dev->mailbox + 4 + i, 0);
flag |= 3; /* tell 'em we're done writing */
- memory_write(dev, dev->mpegport_mailbox, flag);
+ memory_write(dev->core, dev->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 {
+ timeout = jiffies + msecs_to_jiffies(10);
+ for (;;) {
+ memory_read(dev->core, dev->mailbox, &flag);
+ if (0 == (flag & 4))
+ break;
+ if (time_after(jiffies,timeout)) {
+ dprintk(0, "ERROR: API Mailbox timeout\n");
+ return -1;
+ }
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);
+ int *vptr = va_arg(args, int *);
+ memory_read(dev->core, dev->mailbox + 4 + i, vptr);
+ dprintk(1, "API Output %d = %d\n", i, *vptr);
}
-
va_end(args);
- u32 retval;
- memory_read(dev, dev->mpegport_mailbox + 2, &retval);
- dprintk(1, "API result = %d (timeoutcnt=%d)\n",retval, timeoutcnt);
+ memory_read(dev->core, dev->mailbox + 2, &retval);
+ dprintk(1, "API result = %d\n",retval);
+
flag = 0;
- memory_write(dev, dev->mpegport_mailbox, flag);
+ memory_write(dev->core, dev->mailbox, flag);
return retval;
}
-int mpegport_find_mailbox(struct cx8800_dev *dev)
+static int blackbird_find_mailbox(struct cx8802_dev *dev)
{
u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456};
int signaturecnt=0;
+ u32 value;
int i;
- for (i = 0; (i < BLACKBIRD_FIRM_IMAGE_SIZE) && (signaturecnt < 4) ; i++)
- {
- u32 value;
- memory_read(dev, i, &value);
+
+ for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
+ memory_read(dev->core, i, &value);
if (value == signature[signaturecnt])
signaturecnt++;
else
signaturecnt = 0;
+ if (4 == signaturecnt) {
+ dprintk(1, "Mailbox signature found\n");
+ return i;
+ }
}
- if (signaturecnt == 4)
- {
- dprintk(1, "Mailbox signature found\n");
- return i;
- }
- else
- {
- dprintk(0, "Mailbox signature values not found!\n");
- return -1;
- }
+ dprintk(0, "Mailbox signature values not found!\n");
+ return -1;
}
-int mpegport_load_firmware(struct cx8800_dev *dev)
+static int blackbird_load_firmware(struct cx8802_dev *dev)
{
- dprintk(1,"Loading firmware\n");
+ static const unsigned char magic[8] = {
+ 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+ };
+ const struct firmware *firmware;
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");
+ u32 checksum = 0;
+ u32 *dataptr;
- /* without this, the encoder chip is just a dead chip */
+ retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
+ retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+ retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ msleep(1);
+ retval |= register_write(dev->core, IVTV_REG_APU, 0);
- /* 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 with register_write\n");
+ retval = request_firmware(&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");
+ dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
+ BLACKBIRD_FIRM_ENC_FILENAME);
+ dprintk(0, "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\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);
+ if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+ dprintk(0, "ERROR: Firmware size mismatch (have %ld, expected %d)\n",
+ 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");
+ if (0 != memcmp(firmware->data, magic, 8)) {
+ dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\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++) {
+ dprintk(1,"Loading firmware ...\n");
+ dataptr = (u32*)firmware->data;
+ for (i = 0; i < (firmware->size >> 2); i++) {
value = *dataptr;
checksum += ~value;
- memory_write(dev, i, value);
+ memory_write(dev->core, 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);
+ memory_read(dev->core, i, &value);
checksum -= ~value;
}
-
if (checksum) {
- dprintk(0, "ERROR: Firmware Upload Failed (memory checksums don't match).\n");
+ dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n");
return -1;
}
-
+ release_firmware(firmware);
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_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+ retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+ msleep(1);
- 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);
+ retval |= register_read(dev->core, IVTV_REG_VPU, &value);
+ retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
- if (retval < 0) dprintk(0, "Error with register_write\n");
+ if (retval < 0)
+ dprintk(0, "Error with register_write\n");
return 0;
}
-void mpegport_codec_settings(struct cx8800_dev *dev)
+static void blackbird_codec_settings(struct cx8802_dev *dev)
{
+ int bitrate_mode = 1;
+ int bitrate = 7500000;
+ int bitrate_peak = 7500000;
+
/* 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 */
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 0); /* program stream */
+ //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 2); /* MPEG1 stream */
+ //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 3); /* PES A/V */
+ //blackbird_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 */
+ blackbird_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);
+ blackbird_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);
+ blackbird_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);
+ blackbird_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 */
+ blackbird_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);
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 15, 3);
+ //blackbird_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);
+ blackbird_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));
+ blackbird_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);
+ blackbird_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));
+ blackbird_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);
+ blackbird_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);
+ blackbird_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);
+ blackbird_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);
+ blackbird_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);
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0);
}
-int mpegport_initialize_codec(struct cx8800_dev *dev)
+static int blackbird_initialize_codec(struct cx8802_dev *dev)
{
+ struct cx88_core *core = dev->core;
+ int version;
int retval;
+
dprintk(1,"Initialize codec\n");
-
- retval = mpegport_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+ retval = blackbird_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);
+ msleep(1);
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; }
+ msleep(1);
+ retval = blackbird_load_firmware(dev);
+ if (retval < 0)
+ return retval;
+
+ dev->mailbox = blackbird_find_mailbox(dev);
+ if (dev->mailbox < 0)
+ return -1;
- retval = mpegport_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+ retval = blackbird_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);
+ retval = blackbird_api_cmd(dev, IVTV_API_ENC_GETVER, 0, 1, &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");
+ dprintk(0, "Firmware version is 0x%08x\n", version);
}
-
- udelay(500);
+ msleep(1);
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? */
+#if 0 /* FIXME */
set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED);
+#endif
+ blackbird_codec_settings(dev);
+ msleep(1);
- 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);
+ //blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
+ //blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180);
+ blackbird_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 */
+ blackbird_api_cmd(dev, IVTV_API_INITIALIZE_INPUT, 0, 0); /* initialize the video input */
- udelay(500);
+ msleep(1);
- 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 */
+ blackbird_api_cmd(dev, IVTV_API_MUTE_VIDEO, 1, 0, 0);
+ msleep(1);
+ blackbird_api_cmd(dev, IVTV_API_MUTE_AUDIO, 1, 0, 0);
+ msleep(1);
- udelay(500);
+ blackbird_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); /* start capturing to the host interface */
+ //blackbird_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0); /* start capturing to the host interface */
+ msleep(1);
- mpegport_api_cmd(dev, IVTV_API_REFRESH_INPUT, 0,0);
- return retval;
+ blackbird_api_cmd(dev, IVTV_API_REFRESH_INPUT, 0,0);
+ return 0;
}
-#endif
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct file *file, unsigned int *count, unsigned int *size)
+{
+ struct cx8802_fh *fh = file->private_data;
+
+ fh->dev->ts_packet_size = 512;
+ fh->dev->ts_packet_count = 100;
+
+ *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
+ if (0 == *count)
+ *count = mpegbufs;
+ if (*count < 2)
+ *count = 2;
+ if (*count > 32)
+ *count = 32;
+ return 0;
+}
+
+static int
+bb_buf_prepare(struct file *file, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx8802_fh *fh = file->private_data;
+ return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb);
+}
+
+static void
+bb_buf_queue(struct file *file, struct videobuf_buffer *vb)
+{
+ struct cx8802_fh *fh = file->private_data;
+ cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb);
+}
+
+static void bb_buf_release(struct file *file, struct videobuf_buffer *vb)
+{
+ struct cx8802_fh *fh = file->private_data;
+ cx88_free_buffer(fh->dev->pci, (struct cx88_buffer*)vb);
+}
+
+static struct videobuf_queue_ops blackbird_qops = {
+ .buf_setup = bb_buf_setup,
+ .buf_prepare = bb_buf_prepare,
+ .buf_queue = bb_buf_queue,
+ .buf_release = bb_buf_release,
+};
/* ------------------------------------------------------------------ */
@@ -587,13 +594,10 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
struct cx8802_fh *fh = file->private_data;
-
-#if 0
struct cx8802_dev *dev = fh->dev;
- if (mpeg_debug > 1)
+ if (debug > 1)
cx88_print_ioctl(dev->core->name,cmd);
-#endif
switch (cmd) {
@@ -670,16 +674,14 @@ static int mpeg_open(struct inode *inode, struct file *file)
list_for_each(list,&cx8802_devlist) {
h = list_entry(list, struct cx8802_dev, devlist);
if (h->mpeg_dev->minor == minor)
- dev = h;
+ dev = h;
}
if (NULL == dev)
return -ENODEV;
-#if 0 /* FIXME */
- if (mpegport_initialize_codec(dev) < 0)
+ if (blackbird_initialize_codec(dev) < 0)
return -EINVAL;
dprintk(1,"open minor=%d\n",minor);
-#endif
/* allocate + initialize per filehandle data */
fh = kmalloc(sizeof(*fh),GFP_KERNEL);
@@ -689,7 +691,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
- videobuf_queue_init(&fh->mpegq, &cx8802_mpeg_qops,
+ videobuf_queue_init(&fh->mpegq, &blackbird_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
@@ -703,9 +705,7 @@ 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
+ blackbird_api_cmd(fh->dev, IVTV_API_END_CAPTURE, 3, 0, 1, 0, 0x13);
/* stop mpeg capture */
if (fh->mpegq.streaming)
@@ -765,7 +765,7 @@ static struct video_device cx8802_mpeg_template =
/* ------------------------------------------------------------------ */
-static void cx8802_unregister_video(struct cx8802_dev *dev)
+static void blackbird_unregister_video(struct cx8802_dev *dev)
{
if (dev->mpeg_dev) {
if (-1 != dev->mpeg_dev->minor)
@@ -776,7 +776,7 @@ static void cx8802_unregister_video(struct cx8802_dev *dev)
}
}
-static int cx8802_register_video(struct cx8802_dev *dev)
+static int blackbird_register_video(struct cx8802_dev *dev)
{
int err;
@@ -792,10 +792,105 @@ static int cx8802_register_video(struct cx8802_dev *dev)
dev->core->name,dev->mpeg_dev->minor & 0x1f);
}
-#if 0
-module_init(cx8802_init);
-module_exit(cx8802_fini);
+/* ----------------------------------------------------------- */
+
+static int __devinit blackbird_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx8802_dev *dev;
+ struct cx88_core *core;
+ int err;
+
+ /* general setup */
+ core = cx88_core_get(pci_dev);
+ if (NULL == core)
+ return -EINVAL;
+
+ err = -ENODEV;
+ if (!cx88_boards[core->board].blackbird)
+ goto fail_core;
+
+ err = -ENOMEM;
+ dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev)
+ goto fail_core;
+ memset(dev,0,sizeof(*dev));
+ dev->pci = pci_dev;
+ dev->core = core;
+
+ err = cx8802_init_common(dev);
+ if (0 != err)
+ goto fail_free;
+
+ /* blackbird stuff */
+ printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n",
+ core->name);
+ host_setup(dev->core);
+
+ list_add_tail(&dev->devlist,&cx8802_devlist);
+ blackbird_register_video(dev);
+ return 0;
+
+ fail_free:
+ kfree(dev);
+ fail_core:
+ cx88_core_put(core,pci_dev);
+ return err;
+}
+
+static void __devexit blackbird_remove(struct pci_dev *pci_dev)
+{
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+
+ /* blackbird */
+ blackbird_unregister_video(dev);
+ list_del(&dev->devlist);
+
+ /* common */
+ cx8802_fini_common(dev);
+ cx88_core_put(dev->core,dev->pci);
+ kfree(dev);
+}
+
+static 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 blackbird_pci_driver = {
+ .name = "cx8802",
+ .id_table = cx8802_pci_tbl,
+ .probe = blackbird_probe,
+ .remove = blackbird_remove,
+};
+
+static int blackbird_init(void)
+{
+ printk(KERN_INFO "cx2388x blackbird 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(&blackbird_pci_driver);
+}
+
+static void blackbird_fini(void)
+{
+ pci_unregister_driver(&blackbird_pci_driver);
+}
+
+module_init(blackbird_init);
+module_exit(blackbird_fini);
/* ----------------------------------------------------------- */
/*
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index 8098d9ad3..4d1ab117a 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -166,21 +166,18 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- .gpio3 = 0x00000000,
}},
.radio = {
.type = CX88_RADIO,
@@ -259,23 +256,14 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000fde6,
- .gpio1 = 0x00000000, // possibly for mpeg data
- .gpio2 = 0x000000e9,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
- .gpio1 = 0x00000000, // possibly for mpeg data
- .gpio2 = 0x000000e9,
- .gpio3 = 0x00000000,
}},
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0000fde2,
- .gpio1 = 0x00000000,
- .gpio2 = 0x000000e9,
- .gpio3 = 0x00000000,
},
.blackbird = 1,
},
@@ -287,23 +275,17 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00000fbf,
- .gpio1 = 0x000000c0,
.gpio2 = 0x0000fc08,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00000fbf,
- .gpio1 = 0x000000c0,
.gpio2 = 0x0000fc68,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00000fbf,
- .gpio1 = 0x000000c0,
.gpio2 = 0x0000fc68,
- .gpio3 = 0x00000000,
}},
},
[CX88_BOARD_KWORLD_DVB_T] = {
@@ -341,6 +323,31 @@ struct cx88_board cx88_boards[] = {
}
#endif
},
+ [CX88_BOARD_KWORLD_LTV883] = {
+ .name = "KWorld LTV883RF",
+ .tuner_type = 48,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x07f8,
+ },{
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0x07f9, // mono from tuner chip
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000007fa,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000007fa,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x000007f8,
+ },
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -664,6 +671,7 @@ void cx88_card_setup(struct cx88_core *core)
break;
case CX88_BOARD_ASUS_PVR_416:
case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+ case CX88_BOARD_KWORLD_LTV883:
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 8661674fd..0c338a944 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -56,6 +56,10 @@ 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 (core_debug >= level) \
printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
@@ -653,6 +657,300 @@ int cx88_reset(struct cx88_core *core)
/* ------------------------------------------------------------------ */
+static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 922 : 754;
+}
+
+static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 186 : 135;
+}
+
+static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+}
+
+static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+{
+ static const unsigned int ntsc = 28636360;
+ static const unsigned int pal = 35468950;
+
+ return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
+}
+
+static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50)
+ ? HLNotchFilter135PAL
+ : HLNotchFilter135NTSC;
+}
+
+static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
+}
+
+static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+}
+
+int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
+ enum v4l2_field field)
+{
+ unsigned int swidth = norm_swidth(core->tvnorm);
+ unsigned int sheight = norm_maxh(core->tvnorm);
+ u32 value;
+
+ dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
+ V4L2_FIELD_HAS_TOP(field) ? "T" : "",
+ V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+ core->tvnorm->name);
+ if (!V4L2_FIELD_HAS_BOTH(field))
+ height *= 2;
+
+ // recalc H delay and scale registers
+ value = (width * norm_hdelay(core->tvnorm)) / swidth;
+ value &= 0x3fe;
+ cx_write(MO_HDELAY_EVEN, value);
+ cx_write(MO_HDELAY_ODD, value);
+ dprintk(1,"set_scale: hdelay 0x%04x\n", value);
+
+ value = (swidth * 4096 / width) - 4096;
+ cx_write(MO_HSCALE_EVEN, value);
+ cx_write(MO_HSCALE_ODD, value);
+ dprintk(1,"set_scale: hscale 0x%04x\n", value);
+
+ cx_write(MO_HACTIVE_EVEN, width);
+ cx_write(MO_HACTIVE_ODD, width);
+ dprintk(1,"set_scale: hactive 0x%04x\n", width);
+
+ // recalc V scale Register (delay is constant)
+ cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
+ cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
+ dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
+
+ value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
+ cx_write(MO_VSCALE_EVEN, value);
+ cx_write(MO_VSCALE_ODD, value);
+ dprintk(1,"set_scale: vscale 0x%04x\n", value);
+
+ cx_write(MO_VACTIVE_EVEN, sheight);
+ cx_write(MO_VACTIVE_ODD, sheight);
+ dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
+
+ // setup filters
+ value = 0;
+ value |= (1 << 19); // CFILT (default)
+ if (core->tvnorm->id & V4L2_STD_SECAM) {
+ value |= (1 << 15);
+ value |= (1 << 16);
+ }
+ if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+ value |= (1 << 13) | (1 << 5);
+ if (V4L2_FIELD_INTERLACED == field)
+ value |= (1 << 3); // VINT (interlaced vertical scaling)
+ if (width < 385)
+ value |= (1 << 0); // 3-tap interpolation
+ if (width < 193)
+ value |= (1 << 1); // 5-tap interpolation
+
+ cx_write(MO_FILTER_EVEN, value);
+ cx_write(MO_FILTER_ODD, value);
+ dprintk(1,"set_scale: filter 0x%04x\n", value);
+
+ return 0;
+}
+
+static const u32 xtal = 28636363;
+
+static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
+{
+ static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+ u64 pll;
+ u32 reg;
+ int i;
+
+ if (prescale < 2)
+ prescale = 2;
+ if (prescale > 5)
+ prescale = 5;
+
+ pll = ofreq * 8 * prescale * (u64)(1 << 20);
+ do_div(pll,xtal);
+ reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
+ if (((reg >> 20) & 0x3f) < 14) {
+ printk("%s/0: pll out of range\n",core->name);
+ return -1;
+ }
+
+ dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
+ reg, cx_read(MO_PLL_REG), ofreq);
+ cx_write(MO_PLL_REG, reg);
+ for (i = 0; i < 10; i++) {
+ reg = cx_read(MO_DEVICE_STATUS);
+ if (reg & (1<<2)) {
+ dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
+ prescale,ofreq);
+ return 0;
+ }
+ dprintk(1,"pll not locked yet, waiting ...\n");
+ msleep(100);
+ }
+ dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
+ return -1;
+}
+
+static int set_tvaudio(struct cx88_core *core)
+{
+ struct cx88_tvnorm *norm = core->tvnorm;
+
+ if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
+ return 0;
+
+ if (V4L2_STD_PAL_BG & norm->id) {
+ core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
+
+ } else if (V4L2_STD_PAL_DK & norm->id) {
+ core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
+
+ } else if (V4L2_STD_PAL_I & norm->id) {
+ core->tvaudio = WW_NICAM_I;
+
+ } else if (V4L2_STD_SECAM_L & norm->id) {
+ core->tvaudio = WW_SYSTEM_L_AM;
+
+ } else if (V4L2_STD_SECAM_DK & norm->id) {
+ core->tvaudio = WW_A2_DK;
+
+ } else if ((V4L2_STD_NTSC_M & norm->id) ||
+ (V4L2_STD_PAL_M & norm->id)) {
+ core->tvaudio = WW_BTSC;
+
+ } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+ core->tvaudio = WW_EIAJ;
+
+ } else {
+ printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
+ core->name, norm->name);
+ core->tvaudio = 0;
+ return 0;
+ }
+
+ cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
+ cx88_set_tvaudio(core);
+ // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
+
+ cx_write(MO_AUDD_LNGTH, 128/8); /* fifo size */
+ cx_write(MO_AUDR_LNGTH, 128/8); /* fifo size */
+ cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
+ return 0;
+}
+
+int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+{
+ u32 fsc8;
+ u32 adc_clock;
+ u32 vdec_clock;
+ u32 step_db,step_dr;
+ u64 tmp64;
+ u32 bdelay,agcdelay,htotal;
+
+ core->tvnorm = norm;
+ fsc8 = norm_fsc8(norm);
+ adc_clock = xtal;
+ vdec_clock = fsc8;
+ step_db = fsc8;
+ step_dr = fsc8;
+
+ if (norm->id & V4L2_STD_SECAM) {
+ step_db = 4250000 * 8;
+ step_dr = 4406250 * 8;
+ }
+
+ dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
+ norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+ set_pll(core,2,vdec_clock);
+
+ dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
+ norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+ cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+
+#if 1
+ // FIXME: as-is from DScaler
+ dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
+ norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
+ cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+#endif
+
+ // MO_SCONV_REG = adc clock / video dec clock * 2^17
+ tmp64 = adc_clock * (u64)(1 << 17);
+ do_div(tmp64, vdec_clock);
+ dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
+ (u32)tmp64, cx_read(MO_SCONV_REG));
+ cx_write(MO_SCONV_REG, (u32)tmp64);
+
+ // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
+ tmp64 = step_db * (u64)(1 << 22);
+ do_div(tmp64, vdec_clock);
+ dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
+ (u32)tmp64, cx_read(MO_SUB_STEP));
+ cx_write(MO_SUB_STEP, (u32)tmp64);
+
+ // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
+ tmp64 = step_dr * (u64)(1 << 22);
+ do_div(tmp64, vdec_clock);
+ dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
+ (u32)tmp64, cx_read(MO_SUB_STEP_DR));
+ cx_write(MO_SUB_STEP_DR, (u32)tmp64);
+
+ // bdelay + agcdelay
+ bdelay = vdec_clock * 65 / 20000000 + 21;
+ agcdelay = vdec_clock * 68 / 20000000 + 15;
+ dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
+ (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
+ cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
+
+ // htotal
+ tmp64 = norm_htotal(norm) * (u64)vdec_clock;
+ do_div(tmp64, fsc8);
+ htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
+ dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
+ htotal, cx_read(MO_HTOTAL), (u32)tmp64);
+ cx_write(MO_HTOTAL, htotal);
+
+ // vbi stuff
+ cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
+ norm_vbipack(norm)));
+
+ // audio
+ set_tvaudio(core);
+
+ // tell i2c chips
+#ifdef V4L2_I2C_CLIENTS
+ cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+#else
+ {
+ struct video_channel c;
+ memset(&c,0,sizeof(c));
+ c.channel = core->input;
+ c.norm = VIDEO_MODE_PAL;
+ if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
+ c.norm = VIDEO_MODE_NTSC;
+ if (norm->id & V4L2_STD_SECAM)
+ c.norm = VIDEO_MODE_SECAM;
+ cx88_call_i2c_clients(core,VIDIOCSCHAN,&c);
+ }
+#endif
+
+ // done
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
static int cx88_pci_quirks(char *name, struct pci_dev *pci)
{
unsigned int lat = UNSET;
@@ -861,6 +1159,9 @@ EXPORT_SYMBOL(cx88_sram_channels);
EXPORT_SYMBOL(cx88_sram_channel_setup);
EXPORT_SYMBOL(cx88_sram_channel_dump);
+EXPORT_SYMBOL(cx88_set_tvnorm);
+EXPORT_SYMBOL(cx88_set_scale);
+
EXPORT_SYMBOL(cx88_vdev_init);
EXPORT_SYMBOL(cx88_core_get);
EXPORT_SYMBOL(cx88_core_put);
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index 08cc56d27..398fbbd16 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -23,342 +23,349 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
#include "cx88.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-/* ------------------------------------------------------------------ */
+static unsigned int debug = 0;
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
-#if 0
-static void cx88_dvb_tasklet(unsigned long data)
-{
- struct cx8800_dvb *dvb = (struct cx8800_dvb *)data;
- struct cx8800_dev *dev = dvb->dev;
- struct cx88_dmaqueue *q = &dvb->tsq;
- struct cx88_buffer *buf;
- unsigned long flags;
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg)
- /* Process any pending buffers */
- spin_lock_irqsave(&dev->slock, flags);
- while (! list_empty(&q->queued)) {
- /* get items */
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
- spin_unlock_irqrestore(&dev->slock, flags);
-
- /* Hand the received frames to the software filter */
- (dvb->ts_includes_fec ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
- (&dvb->demux, (char *)buf->vb.dma.vmalloc,
- buf->vb.field_count * buf->bpl);
-
- /* Reactivate the buffer */
- spin_lock_irqsave(&dev->slock, flags);
- list_del(&buf->vb.queue);
- activate_ts_buffer(dvb, buf, 1);
- }
- spin_unlock_irqrestore(&dev->slock, flags);
-}
+/* ------------------------------------------------------------------ */
-static void cx8800_wakeup_dvb_tasklet(struct cx8800_dvb *dvb,
- unsigned int maxframe, int timeout_case)
+static int dvb_buf_setup(struct file *file, unsigned int *count, unsigned int *size)
{
- struct cx88_dmaqueue *q = &dvb->tsq;
- struct cx88_buffer *buf;
- int processed_buffers = 0;
-
- /* Called with dev->slock held */
-
- dprintk(2, "cx8800_wakeup_dvb_tasklet called, maxframe: %d, "
- "timeout_case: %d\n", maxframe, timeout_case);
-
- while (! list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
-
- /* Calculate how many frames that are waiting for processing */
- maxframe &= 0xffff;
- buf->count &= 0xffff;
- buf->vb.field_count = (maxframe - buf->count) & 0xffff;
-
- dprintk(2, "[%p/%d] wakeup reg=%d buf=%d, field_count=%d, "
- "processed=%d\n", buf, buf->vb.i, maxframe, buf->count,
- buf->vb.field_count, processed_buffers);
-
- /* Reject any incomplete buffer if we aren't handling a timeout,
- * as data transfer into it is still occurring. */
- if (buf->vb.field_count < buf->vb.height && !timeout_case) {
- if (! processed_buffers) {
- dprintk(2, "incomplete buffer: mf: %d, count: "
- "%d, fc: %d height: %d\n", maxframe,
- buf->count, buf->vb.field_count,
- buf->vb.height);
- return; /* Don't re-timeout... */
- }
- break;
- }
+ struct cx8802_dev *dev = file->private_data;
- /* We've got no frames to process, so just reschedule
- * the timeout. */
- if (buf->vb.field_count == 0) {
- dprintk(2, "no frames... %d %d\n", maxframe,
- buf->count);
- break;
- }
-
- /* We can't possibly have more frames than we have size for
- * in the buffer, so trim back how many we think we have. */
- if (buf->vb.field_count > buf->vb.height) {
- if (buf->vb.field_count > buf->vb.height * 2 &&
- ++too_many_frames_in_one_interrupt == 10) {
- printk(KERN_WARNING "%s: you should consider"
- "increasing ts_frames_per_irq (%d "
- "frame/irq overload)\n", dvb->dev->name,
- (buf->vb.field_count - buf->vb.height));
- }
- buf->vb.field_count = buf->vb.height;
- }
-
- /* Mark the buffer as done. */
- buf->vb.state = timeout_case ? STATE_ERROR : STATE_DONE;
-
- /* Move the buffer from the active queue to the
- * queued-for-processing queue */
- list_move_tail(&buf->vb.queue, &q->queued);
-
- /* Schedule the tasklet to process them */
- tasklet_schedule(&dvb->dvb_tasklet);
-
- /* Don't queue more than one buffer if we timed out. */
- if (timeout_case)
- break;
+ dev->ts_packet_size = 188 * 4;
+ dev->ts_packet_count = 32;
- /* Record that we processed a buffer. */
- processed_buffers++;
- }
+ *size = dev->ts_packet_size * dev->ts_packet_count;
+ *count = 32;
+ return 0;
+}
- if (list_empty(&q->active)) {
- del_timer(&q->timeout);
- } else {
- mod_timer(&q->timeout, jiffies + TS_BUFFER_TIMEOUT);
- }
+static int dvb_buf_prepare(struct file *file, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx8802_dev *dev = file->private_data;
+ return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb);
}
-/* ---------------------------------------------------------------------------- */
+static void dvb_buf_queue(struct file *file, struct videobuf_buffer *vb)
+{
+ struct cx8802_dev *dev = file->private_data;
+ cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
+}
-static int master_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg msgs[],
- int num)
+static void dvb_buf_release(struct file *file, struct videobuf_buffer *vb)
{
- struct cx8800_dvb *dvb = (struct cx8800_dvb *)i2c->data;
- struct cx8800_dev *dev = dvb->dev;
- int retval;
+ struct cx8802_dev *dev = file->private_data;
+ cx88_free_buffer(dev->pci, (struct cx88_buffer*)vb);
+}
- if (down_interruptible(&dvb->dvb_i2c_lock))
- return -ERESTARTSYS;
+struct videobuf_queue_ops dvb_qops = {
+ .buf_setup = dvb_buf_setup,
+ .buf_prepare = dvb_buf_prepare,
+ .buf_queue = dvb_buf_queue,
+ .buf_release = dvb_buf_release,
+};
- retval = i2c_transfer(&dev->i2c_adap, (struct i2c_msg *)msgs, num);
+static int dvb_thread(void *data)
+{
+ struct cx8802_dev *dev = data;
+ struct videobuf_buffer *buf;
+ struct file *file;
+ unsigned long flags;
+ int err;
+
+ dprintk(1,"cx88: dvb thread started\n");
+ file = get_empty_filp();
+ file->private_data = dev;
+ videobuf_read_start(file, &dev->dvbq);
+
+ for (;;) {
+ if (kthread_should_stop())
+ break;
- up(&dvb->dvb_i2c_lock);
+ /* fetch next buffer */
+ buf = list_entry(dev->dvbq.stream.next,
+ struct videobuf_buffer, stream);
+ list_del(&buf->stream);
+ err = videobuf_waiton(buf,0,0);
+
+ /* feed buffer data to demux */
+ if (buf->state == STATE_DONE)
+ dvb_dmx_swfilter(&dev->demux, buf->dma.vmalloc,
+ buf->size);
+
+ /* requeue buffer */
+ list_add_tail(&buf->stream,&dev->dvbq.stream);
+ spin_lock_irqsave(dev->dvbq.irqlock,flags);
+ dev->dvbq.ops->buf_queue(file,buf);
+ spin_unlock_irqrestore(dev->dvbq.irqlock,flags);
+ }
- return retval;
+ videobuf_read_stop(file, &dev->dvbq);
+ put_filp(file);
+ dprintk(1,"cx88: dvb thread stopped\n");
+ return 0;
}
-static int dvb_cx8800_start_feed(struct dvb_demux_feed *feed)
+/* ---------------------------------------------------------------------------- */
+
+static int dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct cx8800_dvb *dvb = demux->priv;
+ struct cx8802_dev *dev = demux->priv;
+ int rc = 0;
dprintk(2, "dvb_cx8800_start_feed\n");
if (!demux->dmx.frontend)
return -EINVAL;
+ if (dev->dvb_thread)
+ return -EINVAL;
- return start_ts_capture(dvb);
+ dev->dvb_thread = kthread_run(dvb_thread, dev, "%s dvb", dev->core->name);
+ if (IS_ERR(dev->dvb_thread)) {
+ rc = PTR_ERR(dev->dvb_thread);
+ dev->dvb_thread = NULL;
+ }
+ return rc;
}
-static int dvb_cx8800_stop_feed(struct dvb_demux_feed *feed)
+static int dvb_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct cx8800_dvb *dvb = demux->priv;
+ struct cx8802_dev *dev = demux->priv;
+ int err;
dprintk(2, "dvb_cx8800_stop_feed\n");
- if (!demux->dmx.frontend)
+ if (NULL == dev->dvb_thread)
return -EINVAL;
-
- return stop_ts_capture(dvb);
+ err = kthread_stop(dev->dvb_thread);
+ dev->dvb_thread = NULL;
+ return err;
}
-static void cx8800_ts_release_dev(struct cx8800_dev *dev)
+static void dvb_unregister(struct cx8802_dev *dev)
{
- struct cx8800_dvb *dvb = dev->dvb;
-
- /* Force us to stop any feed */
- spin_lock(&dvb->feedlock);
- if (dvb->ts_feeding != 0) {
- spin_unlock(&dvb->feedlock);
- printk("Error: releasing a card while feed in progress\n");
- stop_ts_capture(dvb);
- } else
- spin_unlock(&dvb->feedlock);
-
-
- /* release everything we registered */
- dvb_net_release(&dvb->dvbnet);
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- dvb_dmxdev_release(&dvb->dmxdev);
- dvb_dmx_release(&dvb->demux);
- dvb_unregister_i2c_bus(master_xfer, dvb->dvb_adapter, 0);
- dvb_unregister_adapter(dvb->dvb_adapter);
- btcx_riscmem_free(dev->pci, &dvb->tsq.stopper);
-
- /* Free ourselves */
- kfree(dvb);
- dev->dvb = NULL;
- return;
-}
+#if 1 /* really needed? */
+ if (NULL != dev->dvb_thread) {
+ kthread_stop(dev->dvb_thread);
+ BUG();
+ }
+#endif
-static void cx8800_ts_resume_dev(struct cx8800_dev *dev)
-{
- /* Called with dev->slock held */
- cx8800_restart_ts_queue(dev->dvb);
+ dvb_net_release(&dev->dvbnet);
+ dev->demux.dmx.remove_frontend(&dev->demux.dmx, &dev->fe_mem);
+ dev->demux.dmx.remove_frontend(&dev->demux.dmx, &dev->fe_hw);
+ dvb_dmxdev_release(&dev->dmxdev);
+ dvb_dmx_release(&dev->demux);
+ dvb_unregister_adapter(dev->dvb_adapter);
+ return;
}
-static int cx8800_ts_attach_dev(struct cx8800_dev *dev)
+static int dvb_register(struct cx8802_dev *dev)
{
- struct cx8800_dvb *dvb;
int result;
+#if 0 /* hmm, this is board specific I guess? move to cx88-cards.c? */
/* Take DVB hardware out of reset */
cx_set(MO_GP0_IO, cx88_boards[dev->board].ts.gpio0);
cx_clear(MO_GP0_IO, cx88_boards[dev->board].ts.gpio0 & 0xff);
- udelay(500);
+ msleep(1);
cx_set(MO_GP0_IO, cx88_boards[dev->board].ts.gpio0);
+#endif
- /* Allocate a DVB structure */
- dvb = kmalloc(sizeof(struct cx8800_dvb), GFP_KERNEL);
- if (dvb == NULL) {
- result = -ENOMEM;
- goto fail;
- }
- memset(dvb, 0, sizeof(struct cx8800_dvb));
-
- /* Record our device and details */
- dvb->dev = dev;
- dvb->irq_handler = cx8800_ts_irq;
- dvb->release_dev = cx8800_ts_release_dev;
- dvb->resume_dev = cx8800_ts_resume_dev;
-
- /* init TS dma queues */
- INIT_LIST_HEAD(&dvb->tsq.active);
- INIT_LIST_HEAD(&dvb->tsq.queued);
- dvb->tsq.timeout.function = cx8800_ts_timeout;
- dvb->tsq.timeout.data = (unsigned long) dvb;
- init_timer(&dvb->tsq.timeout);
- cx88_risc_stopper(dev->pci, &dvb->tsq.stopper,
- MO_TS_DMACNTRL, 0x11, 0x00);
-
- /* init TS feed spinlock */
- dvb->feedlock = SPIN_LOCK_UNLOCKED;
-
- /* Clear any pending interrupts */
- cx8800_stop_ts_dma(dvb);
-
- if ((result =
- dvb_register_adapter(&dvb->dvb_adapter, dev->name,
- THIS_MODULE)) < 0) {
- printk(KERN_WARNING
- "%s: dvb_register_adapter failed (errno = %d)\n",
- dev->name, result);
- goto fail;
+ result = dvb_register_adapter(&dev->dvb_adapter, dev->core->name,
+ THIS_MODULE);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+ dev->core->name, result);
+ goto fail1;
}
- init_MUTEX(&dvb->dvb_i2c_lock);
-
- if (! dvb_register_i2c_bus(master_xfer, dvb, dvb->dvb_adapter, 0)) {
- printk(KERN_WARNING "%s: dvb_register_i2c_bus failed\n",
- dev->name);
- result = -EFAULT;
+ dev->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dev->demux.priv = dev;
+ dev->demux.filternum = 256;
+ dev->demux.feednum = 256;
+ dev->demux.start_feed = dvb_start_feed;
+ dev->demux.stop_feed = dvb_stop_feed;
+ result = dvb_dmx_init(&dev->demux);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dev->core->name, result);
goto fail2;
}
- memset(&dvb->demux, 0, sizeof(struct dvb_demux));
-
- dvb->demux.dmx.capabilities =
- DMX_TS_FILTERING | DMX_SECTION_FILTERING |
- DMX_MEMORY_BASED_FILTERING;
-
- dvb->demux.priv = dvb;
- dvb->demux.filternum = 256;
- dvb->demux.feednum = 256;
- dvb->demux.start_feed = dvb_cx8800_start_feed;
- dvb->demux.stop_feed = dvb_cx8800_stop_feed;
- dvb->demux.write_to_decoder = NULL;
-
- if ((result = dvb_dmx_init(&dvb->demux)) < 0) {
- printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
- dev->name, result);
+ dev->dmxdev.filternum = 256;
+ dev->dmxdev.demux = &dev->demux.dmx;
+ dev->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dev->dmxdev, dev->dvb_adapter);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dev->core->name, result);
goto fail3;
}
- dvb->dmxdev.filternum = 256;
- dvb->dmxdev.demux = &dvb->demux.dmx;
- dvb->dmxdev.capabilities = 0;
-
- if ((result = dvb_dmxdev_init(&dvb->dmxdev, dvb->dvb_adapter)) < 0) {
- printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
- dev->name, result);
+ dev->fe_hw.source = DMX_FRONTEND_0;
+ result = dev->demux.dmx.add_frontend(&dev->demux.dmx, &dev->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dev->core->name, result);
goto fail4;
}
- dvb->fe_hw.source = DMX_FRONTEND_0;
-
- if ((result =
- dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw)) < 0) {
- printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
- dev->name, result);
+ dev->fe_mem.source = DMX_MEMORY_FE;
+ result = dev->demux.dmx.add_frontend(&dev->demux.dmx, &dev->fe_mem);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontent failed (DMX_MEMORY_FE, errno = %d)\n",
+ dev->core->name, result);
goto fail5;
}
- dvb->fe_mem.source = DMX_MEMORY_FE;
-
- if ((result =
- dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem)) < 0) {
- printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
- dev->name, result);
+ result = dev->demux.dmx.connect_frontend(&dev->demux.dmx, &dev->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: connect_frontent failed (errno = %d)\n",
+ dev->core->name, result);
goto fail6;
}
- if ((result =
- dvb->demux.dmx.connect_frontend(&dvb->demux.dmx,
- &dvb->fe_hw)) < 0) {
- printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
- dev->name, result);
- goto fail7;
- }
-
- dvb_net_init(dvb->dvb_adapter, &dvb->dvbnet, &dvb->demux.dmx);
-
- dev->dvb = dvb;
- printk(KERN_INFO "DVB attached to dev %p, dvb: %p\n", dev, dvb);
-
+ dvb_net_init(dev->dvb_adapter, &dev->dvbnet, &dev->demux.dmx);
return 0;
-fail7:
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
fail6:
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dev->demux.dmx.remove_frontend(&dev->demux.dmx, &dev->fe_mem);
fail5:
- dvb_dmxdev_release(&dvb->dmxdev);
+ dev->demux.dmx.remove_frontend(&dev->demux.dmx, &dev->fe_hw);
fail4:
- dvb_dmx_release(&dvb->demux);
+ dvb_dmxdev_release(&dev->dmxdev);
fail3:
- dvb_unregister_i2c_bus(master_xfer, dvb->dvb_adapter, 0);
+ dvb_dmx_release(&dev->demux);
fail2:
- dvb_unregister_adapter(dvb->dvb_adapter);
-fail:
+ dvb_unregister_adapter(dev->dvb_adapter);
+fail1:
return result;
}
+/* ----------------------------------------------------------- */
+
+static int __devinit dvb_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx8802_dev *dev;
+ struct cx88_core *core;
+ int err;
+
+ /* general setup */
+ core = cx88_core_get(pci_dev);
+ if (NULL == core)
+ return -EINVAL;
+
+ err = -ENODEV;
+ if (!cx88_boards[core->board].dvb)
+ goto fail_core;
+
+ err = -ENOMEM;
+ dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev)
+ goto fail_core;
+ memset(dev,0,sizeof(*dev));
+ dev->pci = pci_dev;
+ dev->core = core;
+
+ err = cx8802_init_common(dev);
+ if (0 != err)
+ goto fail_free;
+
+ /* dvb stuff */
+ printk("%s/2: cx23416 based dvb card\n", core->name);
+ videobuf_queue_init(&dev->dvbq, &dvb_qops,
+ dev->pci, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_TOP,
+ sizeof(struct cx88_buffer));
+ init_MUTEX(&dev->dvbq.lock);
+ dvb_register(dev);
+
+ return 0;
+
+ fail_free:
+ kfree(dev);
+ fail_core:
+ cx88_core_put(core,pci_dev);
+ return err;
+}
+
+static void __devexit dvb_remove(struct pci_dev *pci_dev)
+{
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+
+ /* dvb */
+ dvb_unregister(dev);
+
+ /* common */
+ cx8802_fini_common(dev);
+ cx88_core_put(dev->core,dev->pci);
+ kfree(dev);
+}
+
+static 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 dvb_pci_driver = {
+ .name = "cx8802",
+ .id_table = cx8802_pci_tbl,
+ .probe = dvb_probe,
+ .remove = dvb_remove,
+};
+
+static int dvb_init(void)
+{
+ printk(KERN_INFO "cx2388x dvb 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(&dvb_pci_driver);
+}
+
+static void dvb_fini(void)
+{
+ pci_unregister_driver(&dvb_pci_driver);
+}
+
+module_init(dvb_init);
+module_exit(dvb_fini);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c
index 9d92fce36..735356325 100644
--- a/linux/drivers/media/video/cx88/cx88-mpeg.c
+++ b/linux/drivers/media/video/cx88/cx88-mpeg.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-mpeg.c,v 1.4 2004/07/30 15:26:01 kraxel Exp $
+ * $Id: cx88-mpeg.c,v 1.5 2004/08/25 14:47:53 kraxel Exp $
*
* Support for the mpeg transport stream transfers
* PCI function #2 of the cx2388x.
@@ -30,10 +30,6 @@
#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 for cx2388x based TV cards");
@@ -41,19 +37,13 @@ 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]");
+static unsigned int debug = 0;
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
-#define dprintk(level,fmt, arg...) if (mpeg_debug >= level) \
+#define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg)
-LIST_HEAD(cx8802_devlist);
-
/* ------------------------------------------------------------------ */
int cx8802_start_dma(struct cx8802_dev *dev,
@@ -66,32 +56,37 @@ int cx8802_start_dma(struct cx8802_dev *dev,
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
- PACKET_SIZE, buf->risc.dma);
-
-#if 0 /* config stuff from DVB */
- /* Setup TS portion of chip */
- cx_write(TS_GEN_CNTRL, 0x0c);
-
- /* write TS length to chip */
- cx_write(MO_TS_LNGTH, buf->bpl);
-#endif
-
-#if 0 /* config stuff for from blackbird ... */
- cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
-
-
- 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);
+ dev->ts_packet_size, buf->risc.dma);
+
+#if 1
+ /* FIXME: this needs a review.
+ * also: move to cx88-blackbird + cx88-dvb source files? */
+
+ if (cx88_boards[core->board].dvb) {
+ /* Setup TS portion of chip */
+ cx_write(TS_GEN_CNTRL, 0x0c);
+
+ /* write TS length to chip */
+ cx_write(MO_TS_LNGTH, buf->bpl);
+ }
- 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);
+ if (cx88_boards[core->board].blackbird) {
+ cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
+
+
+ // 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);
+
+ 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);
+ }
#endif
/* reset counter */
@@ -131,37 +126,20 @@ int cx8802_restart_queue(struct cx8802_dev *dev,
/* ------------------------------------------------------------------ */
-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)
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
{
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
- struct cx88_buffer *buf = (struct cx88_buffer*)vb;
+ int size = dev->ts_packet_size * dev->ts_packet_count;
int rc;
dprintk(1, "%s: %p\n", __FUNCTION__, buf);
- if (0 != buf->vb.baddr && buf->vb.bsize < BUFFER_SIZE)
+ if (0 != buf->vb.baddr && buf->vb.bsize < 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;
+ buf->vb.width = dev->ts_packet_size;
+ buf->vb.height = dev->ts_packet_count;
+ buf->vb.size = size;
+ buf->vb.field = V4L2_FIELD_TOP;
if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
goto fail;
@@ -179,13 +157,9 @@ mpeg_buf_prepare(struct file *file, struct videobuf_buffer *vb,
return rc;
}
-static void
-mpeg_buf_queue(struct file *file, struct videobuf_buffer *vb)
+void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
{
- 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 */
@@ -212,30 +186,13 @@ mpeg_buf_queue(struct file *file, struct videobuf_buffer *vb)
}
}
-static void mpeg_buf_release(struct file *file, struct videobuf_buffer *vb)
+void cx8802_buf_release(struct cx8802_dev *dev, struct cx88_buffer *buf)
{
- 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,
-};
-
/* ----------------------------------------------------------- */
-/* exported stuff */
static void cx8802_timeout(unsigned long data)
{
@@ -279,7 +236,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
return;
cx_write(MO_TS_INTSTAT, status);
- if (mpeg_debug || (status & mask & ~0xff))
+ if (debug || (status & mask & ~0xff))
cx88_print_irqbits(core->name, "irq mpeg ",
cx88_vid_irqs, status, mask);
@@ -337,63 +294,27 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
}
/* ----------------------------------------------------------- */
+/* exported stuff */
-static int __devinit cx8802_initdev(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
+int cx8802_init_common(struct cx8802_dev *dev)
{
- 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;
+ if (pci_enable_device(dev->pci))
+ return -EIO;
+ pci_set_master(dev->pci);
+ if (!pci_dma_supported(dev->pci,0xffffffff)) {
+ printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
+ return -EIO;
}
- 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);
+ pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
+ pci_read_config_byte(dev->pci, 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;
- }
-
- /* look what exactly we have ... */
- if (cx88_boards[core->board].blackbird) {
- printk("%s/2: cx23416 based mpeg encoder (blackbird design)\n",
- core->name);
- /* todo: register v4l device, init cx23416 encoder */
- } else if (cx88_boards[core->board].dvb) {
- printk("%s/2: has DVB support\n",
- core->name);
- /* todo: register dvb device */
- } 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;
- }
+ "latency: %d, mmio: 0x%lx\n", dev->core->name,
+ pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
+ dev->pci_lat,pci_resource_start(dev->pci,0));
/* initialize driver struct */
init_MUTEX(&dev->lock);
@@ -414,12 +335,12 @@ static int __devinit cx8802_initdev(struct pci_dev *pci_dev,
#endif
/* get irq */
- err = request_irq(pci_dev->irq, cx8802_irq,
- SA_SHIRQ | SA_INTERRUPT, core->name, dev);
+ err = request_irq(dev->pci->irq, cx8802_irq,
+ SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
- core->name,pci_dev->irq);
- goto fail_core;
+ dev->core->name, dev->pci->irq);
+ return err;
}
#if 0 /* FIXME */
@@ -428,80 +349,33 @@ static int __devinit cx8802_initdev(struct pci_dev *pci_dev,
#endif
/* everything worked */
- list_add_tail(&dev->devlist,&cx8802_devlist);
- pci_set_drvdata(pci_dev,dev);
+ pci_set_drvdata(dev->pci,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)
+void cx8802_fini_common(struct cx8802_dev *dev)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
-
#if 0
cx8802_shutdown(dev);
#endif
- pci_disable_device(pci_dev);
+ pci_disable_device(dev->pci);
/* unregister stuff */
- free_irq(pci_dev->irq, dev);
- pci_set_drvdata(pci_dev, NULL);
+ free_irq(dev->pci->irq, dev);
+ pci_set_drvdata(dev->pci, 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);
-}
+EXPORT_SYMBOL(cx8802_buf_prepare);
+EXPORT_SYMBOL(cx8802_buf_queue);
-module_init(cx8802_init);
-module_exit(cx8802_fini);
+EXPORT_SYMBOL(cx8802_init_common);
+EXPORT_SYMBOL(cx8802_fini_common);
/* ----------------------------------------------------------- */
/*
diff --git a/linux/drivers/media/video/cx88/cx88-tvaudio.c b/linux/drivers/media/video/cx88/cx88-tvaudio.c
index a4abb2d49..0929fa2a4 100644
--- a/linux/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/linux/drivers/media/video/cx88/cx88-tvaudio.c
@@ -49,6 +49,8 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
#include "cx88.h"
@@ -259,10 +261,8 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap)
set_audio_finish(core);
}
-static void set_audio_standard_NICAM(struct cx8800_dev *dev)
+static void set_audio_standard_NICAM(struct cx88_core *core)
{
- struct cx88_core *core = dev->core;
-
static const struct rlist nicam_common[] = {
/* from dscaler */
{ AUD_RATE_ADJ1, 0x00000010 },
@@ -321,7 +321,7 @@ static void set_audio_standard_NICAM(struct cx8800_dev *dev)
set_audio_start(core, 0x0010,
EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
set_audio_registers(core, nicam_common);
- switch (dev->tvaudio) {
+ switch (core->tvaudio) {
case WW_NICAM_I:
dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
set_audio_registers(core, nicam_pal_i);
@@ -457,10 +457,8 @@ static void set_audio_standard_NICAM_L(struct cx88_core *core)
set_audio_finish(core);
}
-static void set_audio_standard_A2(struct cx8800_dev *dev)
+static void set_audio_standard_A2(struct cx88_core *core)
{
- struct cx88_core *core = dev->core;
-
/* from dscaler cvs */
static const struct rlist a2_common[] = {
{ AUD_PDF_DDS_CNST_BYTE2, 0x06 },
@@ -551,7 +549,7 @@ static void set_audio_standard_A2(struct cx8800_dev *dev)
set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
set_audio_registers(core, a2_common);
- switch (dev->tvaudio) {
+ switch (core->tvaudio) {
case WW_A2_BG:
dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
set_audio_registers(core, a2_table1);
@@ -632,62 +630,61 @@ static void set_audio_standard_FM(struct cx88_core *core)
/* ----------------------------------------------------------- */
-void cx88_set_tvaudio(struct cx8800_dev *dev)
+void cx88_set_tvaudio(struct cx88_core *core)
{
- switch (dev->tvaudio) {
+ switch (core->tvaudio) {
case WW_BTSC:
- set_audio_standard_BTSC(dev->core,0);
+ set_audio_standard_BTSC(core,0);
break;
case WW_NICAM_I:
case WW_NICAM_BGDKL:
- set_audio_standard_NICAM(dev);
+ set_audio_standard_NICAM(core);
break;
case WW_A2_BG:
case WW_A2_DK:
case WW_A2_M:
- set_audio_standard_A2(dev);
+ set_audio_standard_A2(core);
break;
case WW_EIAJ:
- set_audio_standard_EIAJ(dev->core);
+ set_audio_standard_EIAJ(core);
break;
case WW_FM:
- set_audio_standard_FM(dev->core);
+ set_audio_standard_FM(core);
break;
case WW_SYSTEM_L_AM:
- set_audio_standard_NICAM_L(dev->core);
+ set_audio_standard_NICAM_L(core);
break;
case WW_NONE:
default:
printk("%s/0: unknown tv audio mode [%d]\n",
- dev->core->name, dev->tvaudio);
+ core->name, core->tvaudio);
break;
}
return;
}
-void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
+void cx88_get_stereo(struct cx88_core *core, 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);
mode = reg & 0x03;
pilot = (reg >> 2) & 0x03;
- if (dev->astat != reg)
+ if (core->astat != reg)
dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
reg, m[mode], p[pilot],
aud_ctl_names[cx_read(AUD_CTL) & 63]);
- dev->astat = reg;
+ core->astat = reg;
t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
t->audmode = V4L2_TUNER_MODE_MONO;
- switch (dev->tvaudio) {
+ switch (core->tvaudio) {
case WW_A2_BG:
case WW_A2_DK:
case WW_A2_M:
@@ -715,13 +712,12 @@ void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
return;
}
-void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
+void cx88_set_stereo(struct cx88_core *core, u32 mode)
{
- struct cx88_core *core = dev->core;
u32 ctl = UNSET;
u32 mask = UNSET;
- switch (dev->tvaudio) {
+ switch (core->tvaudio) {
case WW_A2_BG:
case WW_A2_DK:
case WW_A2_M:
@@ -783,40 +779,33 @@ void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
return;
}
-/* just monitor the audio status for now ... */
int cx88_audio_thread(void *data)
{
- struct cx8800_dev *dev = data;
- struct cx88_core *core = dev->core;
+ struct cx88_core *core = data;
struct v4l2_tuner t;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
- lock_kernel();
- daemonize();
- sigfillset(&current->blocked);
- strcpy(current->comm,"msp3400");
- unlock_kernel();
-#else
- daemonize("msp3400");
- allow_signal(SIGTERM);
-#endif
dprintk("cx88: tvaudio thread started\n");
-
for (;;) {
- msleep(1000);
- if (signal_pending(current))
- break;
- if (dev->shutdown)
+ if (kthread_should_stop())
break;
+ /* just monitor the audio status for now ... */
memset(&t,0,sizeof(t));
- cx88_get_stereo(dev,&t);
+ cx88_get_stereo(core,&t);
+ msleep(1000);
}
dprintk("cx88: tvaudio thread exiting\n");
- complete_and_exit(&dev->texit, 0);
+ return 0;
}
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx88_set_tvaudio);
+EXPORT_SYMBOL(cx88_set_stereo);
+EXPORT_SYMBOL(cx88_get_stereo);
+EXPORT_SYMBOL(cx88_audio_thread);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/linux/drivers/media/video/cx88/cx88-vbi.c b/linux/drivers/media/video/cx88/cx88-vbi.c
index 23fd96b83..09829a10f 100644
--- a/linux/drivers/media/video/cx88/cx88-vbi.c
+++ b/linux/drivers/media/video/cx88/cx88-vbi.c
@@ -28,13 +28,13 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
- if (dev->tvnorm->id & V4L2_STD_525_60) {
+ if (dev->core->tvnorm->id & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
f->fmt.vbi.start[0] = 10 -1;
f->fmt.vbi.start[1] = 273 -1;
- } else if (V4L2_STD_625_50) {
+ } else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
/* pal */
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.start[0] = 7 -1;
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index fe87431a6..31df4ae75 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-video.c,v 1.31 2004/07/30 13:43:39 kraxel Exp $
+ * $Id: cx88-video.c,v 1.32 2004/08/25 14:47:53 kraxel Exp $
*
* device driver for Conexant 2388x based TV cards
* video4linux video interface
@@ -28,12 +28,12 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
#include <asm/div64.h>
#include "cx88.h"
-#define V4L2_I2C_CLIENTS 1
-
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -64,10 +64,6 @@ static unsigned int vid_limit = 16;
MODULE_PARM(vid_limit,"i");
MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
-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/0: " fmt, dev->core->name , ## arg)
@@ -78,58 +74,7 @@ static LIST_HEAD(cx8800_devlist);
/* ------------------------------------------------------------------- */
/* static data */
-static unsigned int inline norm_swidth(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 922 : 754;
-}
-
-static unsigned int inline norm_hdelay(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 186 : 135;
-}
-
-static unsigned int inline norm_vdelay(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
-}
-
-static unsigned int inline norm_maxw(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 768 : 640;
-// return (norm->id & V4L2_STD_625_50) ? 720 : 640;
-}
-
-static unsigned int inline norm_maxh(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 576 : 480;
-}
-
-static unsigned int inline norm_fsc8(struct cx8800_tvnorm *norm)
-{
- static const unsigned int ntsc = 28636360;
- static const unsigned int pal = 35468950;
-
- return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
-}
-
-static unsigned int inline norm_notchfilter(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50)
- ? HLNotchFilter135PAL
- : HLNotchFilter135NTSC;
-}
-
-static unsigned int inline norm_htotal(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
-}
-
-static unsigned int inline norm_vbipack(struct cx8800_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50) ? 511 : 288;
-}
-
-static struct cx8800_tvnorm tvnorms[] = {
+static struct cx88_tvnorm tvnorms[] = {
{
.name = "NTSC-M",
.id = V4L2_STD_NTSC_M,
@@ -432,261 +377,6 @@ void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
/* ------------------------------------------------------------------ */
-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;
-
- if (prescale < 2)
- prescale = 2;
- if (prescale > 5)
- prescale = 5;
-
- pll = ofreq * 8 * prescale * (u64)(1 << 20);
- do_div(pll,xtal);
- reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
- if (((reg >> 20) & 0x3f) < 14) {
- printk("%s/0: pll out of range\n",core->name);
- return -1;
- }
-
- dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
- reg, cx_read(MO_PLL_REG), ofreq);
- cx_write(MO_PLL_REG, reg);
- for (i = 0; i < 10; i++) {
- reg = cx_read(MO_DEVICE_STATUS);
- if (reg & (1<<2)) {
- dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
- prescale,ofreq);
- return 0;
- }
- dprintk(1,"pll not locked yet, waiting ...\n");
- msleep(100);
- }
- dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
- return -1;
-}
-
-static int set_tvaudio(struct cx8800_dev *dev)
-{
- struct cx88_core *core = dev->core;
-
- if (CX88_VMUX_TELEVISION != INPUT(dev->input)->type)
- return 0;
-
- if (V4L2_STD_PAL_BG & dev->tvnorm->id) {
- dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
-
- } else if (V4L2_STD_PAL_DK & dev->tvnorm->id) {
- dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
-
- } else if (V4L2_STD_PAL_I & dev->tvnorm->id) {
- dev->tvaudio = WW_NICAM_I;
-
- } else if (V4L2_STD_SECAM_L & dev->tvnorm->id) {
- dev->tvaudio = WW_SYSTEM_L_AM;
-
- } else if (V4L2_STD_SECAM_DK & dev->tvnorm->id) {
- dev->tvaudio = WW_A2_DK;
-
- } else if ((V4L2_STD_NTSC_M & dev->tvnorm->id) ||
- (V4L2_STD_PAL_M & dev->tvnorm->id)) {
- dev->tvaudio = WW_BTSC;
-
- } else if (V4L2_STD_NTSC_M_JP & dev->tvnorm->id) {
- dev->tvaudio = WW_EIAJ;
-
- } else {
- printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
- core->name, dev->tvnorm->name);
- dev->tvaudio = 0;
- return 0;
- }
-
- cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
- cx88_set_tvaudio(dev);
- // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
-
- cx_write(MO_AUDD_LNGTH, 128/8); /* fifo size */
- cx_write(MO_AUDR_LNGTH, 128/8); /* fifo size */
- cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
- return 0;
-}
-
-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;
- u32 step_db,step_dr;
- u64 tmp64;
- u32 bdelay,agcdelay,htotal;
-
- dev->tvnorm = norm;
- fsc8 = norm_fsc8(norm);
- adc_clock = xtal;
- vdec_clock = fsc8;
- step_db = fsc8;
- step_dr = fsc8;
-
- if (norm->id & V4L2_STD_SECAM) {
- step_db = 4250000 * 8;
- step_dr = 4406250 * 8;
- }
-
- dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
- norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
- set_pll(dev,2,vdec_clock);
-
- dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
-
-#if 1
- // FIXME: as-is from DScaler
- dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
- cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
-#endif
-
- // MO_SCONV_REG = adc clock / video dec clock * 2^17
- tmp64 = adc_clock * (u64)(1 << 17);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SCONV_REG));
- cx_write(MO_SCONV_REG, (u32)tmp64);
-
- // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
- tmp64 = step_db * (u64)(1 << 22);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SUB_STEP));
- cx_write(MO_SUB_STEP, (u32)tmp64);
-
- // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
- tmp64 = step_dr * (u64)(1 << 22);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SUB_STEP_DR));
- cx_write(MO_SUB_STEP_DR, (u32)tmp64);
-
- // bdelay + agcdelay
- bdelay = vdec_clock * 65 / 20000000 + 21;
- agcdelay = vdec_clock * 68 / 20000000 + 15;
- dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
- (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
- cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
-
- // htotal
- tmp64 = norm_htotal(norm) * (u64)vdec_clock;
- do_div(tmp64, fsc8);
- htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
- dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
- htotal, cx_read(MO_HTOTAL), (u32)tmp64);
- cx_write(MO_HTOTAL, htotal);
-
- // vbi stuff
- cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
- norm_vbipack(norm)));
-
- // audio
- set_tvaudio(dev);
-
- // tell i2c chips
-#ifdef V4L2_I2C_CLIENTS
- cx88_call_i2c_clients(dev->core,VIDIOC_S_STD,&norm->id);
-#else
- {
- struct video_channel c;
- memset(&c,0,sizeof(c));
- c.channel = dev->input;
- c.norm = VIDEO_MODE_PAL;
- if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
- c.norm = VIDEO_MODE_NTSC;
- if (norm->id & V4L2_STD_SECAM)
- c.norm = VIDEO_MODE_SECAM;
- cx88_call_i2c_clients(dev->core,VIDIOCSCHAN,&c);
- }
-#endif
-
- // done
- return 0;
-}
-
-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;
-
- dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
- V4L2_FIELD_HAS_TOP(field) ? "T" : "",
- V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
- dev->tvnorm->name);
- if (!V4L2_FIELD_HAS_BOTH(field))
- height *= 2;
-
- // recalc H delay and scale registers
- value = (width * norm_hdelay(dev->tvnorm)) / swidth;
- value &= 0x3fe;
- cx_write(MO_HDELAY_EVEN, value);
- cx_write(MO_HDELAY_ODD, value);
- dprintk(1,"set_scale: hdelay 0x%04x\n", value);
-
- value = (swidth * 4096 / width) - 4096;
- cx_write(MO_HSCALE_EVEN, value);
- cx_write(MO_HSCALE_ODD, value);
- dprintk(1,"set_scale: hscale 0x%04x\n", value);
-
- cx_write(MO_HACTIVE_EVEN, width);
- cx_write(MO_HACTIVE_ODD, width);
- dprintk(1,"set_scale: hactive 0x%04x\n", width);
-
- // recalc V scale Register (delay is constant)
- cx_write(MO_VDELAY_EVEN, norm_vdelay(dev->tvnorm));
- cx_write(MO_VDELAY_ODD, norm_vdelay(dev->tvnorm));
- dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(dev->tvnorm));
-
- value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
- cx_write(MO_VSCALE_EVEN, value);
- cx_write(MO_VSCALE_ODD, value);
- dprintk(1,"set_scale: vscale 0x%04x\n", value);
-
- cx_write(MO_VACTIVE_EVEN, sheight);
- cx_write(MO_VACTIVE_ODD, sheight);
- dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
-
- // setup filters
- value = 0;
- value |= (1 << 19); // CFILT (default)
- if (dev->tvnorm->id & V4L2_STD_SECAM) {
- value |= (1 << 15);
- value |= (1 << 16);
- }
- if (INPUT(dev->input)->type == CX88_VMUX_SVIDEO)
- value |= (1 << 13) | (1 << 5);
- if (V4L2_FIELD_INTERLACED == field)
- value |= (1 << 3); // VINT (interlaced vertical scaling)
- if (width < 385)
- value |= (1 << 0); // 3-tap interpolation
- if (width < 193)
- value |= (1 << 1); // 5-tap interpolation
-
- cx_write(MO_FILTER_EVEN, value);
- cx_write(MO_FILTER_ODD, value);
- dprintk(1,"set_scale: filter 0x%04x\n", value);
-
- return 0;
-}
-
static int video_mux(struct cx8800_dev *dev, unsigned int input)
{
struct cx88_core *core = dev->core;
@@ -695,7 +385,7 @@ static int video_mux(struct cx8800_dev *dev, unsigned int input)
input, INPUT(input)->vmux,
INPUT(input)->gpio0,INPUT(input)->gpio1,
INPUT(input)->gpio2,INPUT(input)->gpio3);
- dev->input = input;
+ dev->core->input = input;
cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14);
cx_write(MO_GP0_IO, INPUT(input)->gpio0);
cx_write(MO_GP1_IO, INPUT(input)->gpio1);
@@ -730,7 +420,7 @@ static int start_video_dma(struct cx8800_dev *dev,
/* setup fifo + format */
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);
+ cx88_set_scale(dev->core, buf->vb.width, buf->vb.height, buf->vb.field);
cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma);
/* reset counter */
@@ -827,8 +517,8 @@ buffer_prepare(struct file *file, struct videobuf_buffer *vb,
int rc, init_buffer = 0;
BUG_ON(NULL == fh->fmt);
- if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) ||
- fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
+ if (fh->width < 48 || fh->width > norm_maxw(dev->core->tvnorm) ||
+ fh->height < 32 || fh->height > norm_maxh(dev->core->tvnorm))
return -EINVAL;
buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
@@ -1092,8 +782,8 @@ static int verify_window(struct cx8800_dev *dev, struct v4l2_window *win)
return -EINVAL;
field = win->field;
- maxw = norm_maxw(dev->tvnorm);
- maxh = norm_maxh(dev->tvnorm);
+ maxw = norm_maxw(core->tvnorm);
+ maxh = norm_maxh(core->tvnorm);
if (V4L2_FIELD_ANY == field) {
field = (win->w.height > maxh/2)
@@ -1286,9 +976,9 @@ static int video_open(struct inode *inode, struct file *file)
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);
+ dev->core->tvaudio = WW_FM;
+ cx88_set_tvaudio(core);
+ cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO);
cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL);
}
@@ -1503,8 +1193,8 @@ static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
return -EINVAL;
field = f->fmt.pix.field;
- maxw = norm_maxw(dev->tvnorm);
- maxh = norm_maxh(dev->tvnorm);
+ maxw = norm_maxw(dev->core->tvnorm);
+ maxh = norm_maxh(dev->core->tvnorm);
if (V4L2_FIELD_ANY == field) {
field = (f->fmt.pix.height > maxh/2)
@@ -1636,7 +1326,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
v4l2_std_id *id = arg;
- *id = dev->tvnorm->id;
+ *id = core->tvnorm->id;
return 0;
}
case VIDIOC_S_STD:
@@ -1651,7 +1341,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
down(&dev->lock);
- set_tvnorm(dev,&tvnorms[i]);
+ cx88_set_tvnorm(dev->core,&tvnorms[i]);
up(&dev->lock);
return 0;
}
@@ -1691,7 +1381,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
unsigned int *i = arg;
- *i = dev->input;
+ *i = dev->core->input;
return 0;
}
case VIDIOC_S_INPUT:
@@ -1787,7 +1477,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
- cx88_get_stereo(dev ,t);
+ cx88_get_stereo(core ,t);
reg = cx_read(MO_DEVICE_STATUS);
t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
return 0;
@@ -1800,7 +1490,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (0 != t->index)
return -EINVAL;
- cx88_set_stereo(dev,t->audmode);
+ cx88_set_stereo(core, t->audmode);
return 0;
}
case VIDIOC_G_FREQUENCY:
@@ -2266,7 +1956,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* initialize driver struct */
init_MUTEX(&dev->lock);
dev->slock = SPIN_LOCK_UNLOCKED;
- dev->tvnorm = tvnorms;
+ core->tvnorm = tvnorms;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
@@ -2350,13 +2040,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* initial device configuration */
down(&dev->lock);
init_controls(dev);
- set_tvnorm(dev,tvnorms);
+ cx88_set_tvnorm(dev->core,tvnorms);
video_mux(dev,0);
up(&dev->lock);
/* start tvaudio thread */
- init_completion(&dev->texit);
- dev->tpid = kernel_thread(cx88_audio_thread, dev, 0);
+ core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
return 0;
fail_unreg:
@@ -2374,9 +2063,10 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
/* stop thread */
- dev->shutdown = 1;
- if (dev->tpid >= 0)
- wait_for_completion(&dev->texit);
+ if (dev->core->kthread) {
+ kthread_stop(dev->core->kthread);
+ dev->core->kthread = NULL;
+ }
cx88_shutdown(dev->core); /* FIXME */
pci_disable_device(pci_dev);
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index aa32b1e4b..d4fc1d58a 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -1,5 +1,5 @@
/*
- * $Id: cx88.h,v 1.24 2004/08/23 10:38:54 kraxel Exp $
+ * $Id: cx88.h,v 1.25 2004/08/25 14:47:54 kraxel Exp $
*
* v4l2 device driver for cx2388x based TV cards
*
@@ -26,6 +26,12 @@
#include <linux/videodev.h>
#include <linux/kdev_t.h>
+#include <dvbdev.h>
+#include <dmxdev.h>
+#include <dvb_demux.h>
+#include <dvb_net.h>
+#include <dvb_frontend.h>
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,64)
#include "video-buf.h"
#include "tuner.h"
@@ -57,6 +63,8 @@
/* ----------------------------------------------------------- */
/* defines and enums */
+#define V4L2_I2C_CLIENTS 1
+
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
@@ -69,15 +77,29 @@
#define SHADOW_MAX 2
/* ----------------------------------------------------------- */
-/* static data */
+/* tv norms */
-struct cx8800_tvnorm {
+struct cx88_tvnorm {
char *name;
v4l2_std_id id;
u32 cxiformat;
u32 cxoformat;
};
+static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 768 : 640;
+// return (norm->id & V4L2_STD_625_50) ? 720 : 640;
+}
+
+static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 576 : 480;
+}
+
+/* ----------------------------------------------------------- */
+/* static data */
+
struct cx8800_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
@@ -141,6 +163,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_MSI_TVANYWHERE 13
#define CX88_BOARD_KWORLD_DVB_T 14
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
+#define CX88_BOARD_KWORLD_LTV883 16
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -176,7 +199,7 @@ struct cx88_subid {
u32 card;
};
-#define INPUT(nr) (&cx88_boards[dev->core->board].input[nr])
+#define INPUT(nr) (&cx88_boards[core->board].input[nr])
/* ----------------------------------------------------------- */
/* device / file handle status */
@@ -234,6 +257,13 @@ struct cx88_core {
unsigned int tuner_type;
unsigned int tda9887_conf;
unsigned int has_radio;
+
+ /* state info */
+ struct task_struct *kthread;
+ struct cx88_tvnorm *tvnorm;
+ u32 tvaudio;
+ u32 input;
+ u32 astat;
};
struct cx8800_dev;
@@ -283,26 +313,21 @@ struct cx8800_dev {
struct pci_dev *pci;
unsigned char pci_rev,pci_lat;
+#if 0
/* video overlay */
struct v4l2_framebuffer fbuf;
struct cx88_buffer *screen;
+#endif
/* capture queues */
struct cx88_dmaqueue vidq;
struct cx88_dmaqueue vbiq;
/* various v4l controls */
- struct cx8800_tvnorm *tvnorm;
- u32 tvaudio;
- u32 input;
u32 freq;
/* other global state info */
- int shutdown;
- pid_t tpid;
- struct completion texit;
struct cx8800_suspend_state state;
- u32 astat;
};
/* ----------------------------------------------------------- */
@@ -326,19 +351,32 @@ struct cx8802_fh {
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;
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+
+ /* for blackbird only */
+ struct list_head devlist;
+ struct video_device *mpeg_dev;
+ u32 mailbox;
+
+ /* for dvb only */
+ struct videobuf_queue dvbq;
+ struct task_struct *dvb_thread;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net dvbnet;
};
/* ----------------------------------------------------------- */
@@ -397,6 +435,11 @@ extern int cx88_sram_channel_setup(struct cx88_core *core,
unsigned int bpl, u32 risc);
extern void cx88_sram_channel_dump(struct cx88_core *core,
struct sram_channel *ch);
+
+extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
+ unsigned int height, enum v4l2_field field);
+extern int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm);
+
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
struct video_device *template,
@@ -454,16 +497,19 @@ extern void cx88_card_setup(struct cx88_core *core);
#define WW_I2SPT 11
#define WW_FM 12
-void cx88_set_tvaudio(struct cx8800_dev *dev);
-void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t);
-void cx88_set_stereo(struct cx8800_dev *dev, u32 mode);
+void cx88_set_tvaudio(struct cx88_core *core);
+void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
+void cx88_set_stereo(struct cx88_core *core, u32 mode);
int cx88_audio_thread(void *data);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
-extern struct list_head cx8802_devlist;
-extern struct videobuf_queue_ops cx8802_mpeg_qops;
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
+void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
+
+int cx8802_init_common(struct cx8802_dev *dev);
+void cx8802_fini_common(struct cx8802_dev *dev);
/*
* Local variables:
diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h
index f90d882c4..9597ffeb0 100644
--- a/linux/include/media/tuner.h
+++ b/linux/include/media/tuner.h
@@ -71,6 +71,7 @@
#define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */
#define TUNER_MICROTUNE_4049FM5 45
#define TUNER_LG_NTSC_TAPE 47
+#define TUNER_TNF_8831BGFF 48
#define NOTUNER 0
#define PAL 1 /* PAL_BG */