diff options
author | Gerd Knorr <devnull@localhost> | 2004-08-25 14:47:53 +0000 |
---|---|---|
committer | Gerd Knorr <devnull@localhost> | 2004-08-25 14:47:53 +0000 |
commit | 6550ed72a57b714bfb1a718538d1fb5c542aa470 (patch) | |
tree | 7e7eb707f80203ecdb680cfd8b3d7ac4f2d3af11 /linux | |
parent | f680c1f3f262eae1802d080db3eccee4f9da3f43 (diff) | |
download | mediapointer-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.c | 539 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-cards.c | 44 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-core.c | 301 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-dvb.c | 521 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-mpeg.c | 270 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-tvaudio.c | 79 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-vbi.c | 4 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-video.c | 364 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88.h | 86 | ||||
-rw-r--r-- | linux/include/media/tuner.h | 1 |
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(¤t->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 */ |