From: Gerd Knorr Finally the big cx88 driver update which makes the cx88-dvb driver compile and work for some cards. A number of changes accumulated over time ... * various new tv cards added / fixed. * added support for infrared remote controls. * some fixes in the blackbird (mpeg encoder) driver, starts working now. * configurarion for analog hauppauge cards now uses the tveeprom module. * kconfig fixups. * powermanagement fixups. * lot of tweaks for tv audio (make NICAM decoding work). * lot of changes in the dvb driver, still not working for all cards though as some more changes in the dvb subsystem are needed. Signed-off-by: Gerd Knorr Signed-off-by: Andrew Morton --- 25-akpm/drivers/media/video/Kconfig | 10 25-akpm/drivers/media/video/cx88/Makefile | 3 25-akpm/drivers/media/video/cx88/cx88-blackbird.c | 27 - 25-akpm/drivers/media/video/cx88/cx88-cards.c | 393 ++++++++++-------- 25-akpm/drivers/media/video/cx88/cx88-core.c | 42 +- 25-akpm/drivers/media/video/cx88/cx88-dvb.c | 193 +++++---- 25-akpm/drivers/media/video/cx88/cx88-i2c.c | 3 25-akpm/drivers/media/video/cx88/cx88-input.c | 396 +++++++++++++++++++ 25-akpm/drivers/media/video/cx88/cx88-mpeg.c | 44 +- 25-akpm/drivers/media/video/cx88/cx88-tvaudio.c | 457 +++++++++++++++------- 25-akpm/drivers/media/video/cx88/cx88-vbi.c | 5 25-akpm/drivers/media/video/cx88/cx88-video.c | 34 - 25-akpm/drivers/media/video/cx88/cx88.h | 38 + 13 files changed, 1194 insertions(+), 451 deletions(-) diff -puN drivers/media/video/cx88/cx88-blackbird.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-blackbird.c --- 25/drivers/media/video/cx88/cx88-blackbird.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-blackbird.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88-blackbird.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $ + * $Id: cx88-blackbird.c,v 1.26 2005/03/07 15:58:05 kraxel Exp $ * * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -207,10 +208,6 @@ static int register_write(struct cx88_co cx_read(P1_RADDR0); return wait_ready_gpio0_bit1(core,1); -#if 0 - udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */ - /* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */ -#endif } @@ -283,7 +280,7 @@ static int blackbird_api_cmd(struct cx88 timeout = jiffies + msecs_to_jiffies(10); for (;;) { memory_read(dev->core, dev->mailbox, &flag); - if (0 == (flag & 4)) + if (0 != (flag & 4)) break; if (time_after(jiffies,timeout)) { dprintk(0, "ERROR: API Mailbox timeout\n"); @@ -324,7 +321,7 @@ static int blackbird_find_mailbox(struct signaturecnt = 0; if (4 == signaturecnt) { dprintk(1, "Mailbox signature found\n"); - return i; + return i+1; } } dprintk(0, "Mailbox signature values not found!\n"); @@ -427,7 +424,8 @@ static void blackbird_codec_settings(str blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0); /* assign frame size */ - blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720); + blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, + dev->height, dev->width); /* assign aspect ratio */ blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2); @@ -629,8 +627,8 @@ static int mpeg_do_ioctl(struct inode *i memset(f,0,sizeof(*f)); f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.width = 720; - f->fmt.pix.height = 576; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = 1024 * 512 /* FIXME: BUFFER_SIZE */; } @@ -694,6 +692,10 @@ static int mpeg_open(struct inode *inode file->private_data = fh; fh->dev = dev; + /* FIXME: locking against other video device */ + cx88_set_scale(dev->core, dev->width, dev->height, + V4L2_FIELD_INTERLACED); + videobuf_queue_init(&fh->mpegq, &blackbird_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -715,6 +717,7 @@ static int mpeg_release(struct inode *in if (fh->mpegq.reading) videobuf_read_stop(&fh->mpegq); + videobuf_mmap_free(&fh->mpegq); file->private_data = NULL; kfree(fh); return 0; @@ -821,6 +824,8 @@ static int __devinit blackbird_probe(str memset(dev,0,sizeof(*dev)); dev->pci = pci_dev; dev->core = core; + dev->width = 720; + dev->height = 480; err = cx8802_init_common(dev); if (0 != err) @@ -852,6 +857,8 @@ static void __devexit blackbird_remove(s /* common */ cx8802_fini_common(dev); + cx88_core_put(dev->core,dev->pci); + kfree(dev); } static struct pci_device_id cx8802_pci_tbl[] = { diff -puN drivers/media/video/cx88/cx88-cards.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-cards.c --- 25/drivers/media/video/cx88/cx88-cards.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-cards.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88-cards.c,v 1.47 2004/11/03 09:04:50 kraxel Exp $ + * $Id: cx88-cards.c,v 1.66 2005/03/04 09:12:23 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -26,14 +26,7 @@ #include #include -#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) -# define WITH_DVB 1 -#endif - #include "cx88.h" -#ifdef WITH_DVB -#include "cx22702.h" -#endif /* ------------------------------------------------------------------ */ /* board config info */ @@ -59,6 +52,7 @@ struct cx88_board cx88_boards[] = { [CX88_BOARD_HAUPPAUGE] = { .name = "Hauppauge WinTV 34xxx models", .tuner_type = UNSET, + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -91,7 +85,7 @@ struct cx88_board cx88_boards[] = { }, [CX88_BOARD_PIXELVIEW] = { .name = "PixelView", - .tuner_type = UNSET, + .tuner_type = 5, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -126,7 +120,7 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0x03fe, }}, }, - [CX88_BOARD_WINFAST2000XP] = { + [CX88_BOARD_WINFAST2000XP_EXPERT] = { .name = "Leadtek Winfast 2000XP Expert", .tuner_type = 44, .tda9887_conf = TDA9887_PRESENT, @@ -217,26 +211,55 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - }}, + .gpio0 = 0x0035e700, + .gpio1 = 0x00003004, + .gpio2 = 0x0035e700, + .gpio3 = 0x02000000, + },{ + + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0035c700, + .gpio1 = 0x00003004, + .gpio2 = 0x0035c700, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0035c700, + .gpio1 = 0x0035c700, + .gpio2 = 0x02000000, + .gpio3 = 0x02000000, + }}, .radio = { - .type = CX88_RADIO, - }, + .type = CX88_RADIO, + .gpio0 = 0x0035d700, + .gpio1 = 0x00007004, + .gpio2 = 0x0035d700, + .gpio3 = 0x02000000, + }, }, [CX88_BOARD_LEADTEK_PVR2000] = { + // gpio values for PAL version from regspy by DScaler .name = "Leadtek PVR 2000", .tuner_type = 38, + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, + .gpio0 = 0x0000bde6, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + .gpio0 = 0x0000bde6, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, + .gpio0 = 0x0000bde6, }}, .radio = { .type = CX88_RADIO, + .gpio0 = 0x0000bd62, }, .blackbird = 1, }, @@ -320,14 +343,15 @@ struct cx88_board cx88_boards[] = { .name = "KWorld/VStream XPert DVB-T", .tuner_type = TUNER_ABSENT, .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, }}, .dvb = 1, }, @@ -452,6 +476,131 @@ struct cx88_board cx88_boards[] = { }}, .dvb = 1, }, + [CX88_BOARD_DNTV_LIVE_DVB_T] = { + .name = "digitalnow DNTV Live! DVB-T", + .tuner_type = TUNER_ABSENT, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00000700, + .gpio2 = 0x00000101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00000700, + .gpio2 = 0x00000101, + }}, + .dvb = 1, + }, + [CX88_BOARD_PCHDTV_HD3000] = { + .name = "pcHDTV HD3000 HDTV", + .tuner_type = TUNER_THOMSON_DTT7610, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00008484, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00008400, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00008400, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }}, + .radio = { + .type = CX88_RADIO, + .vmux = 2, + .gpio0 = 0x00008400, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }, + .dvb = 1, + }, + [CX88_BOARD_HAUPPAUGE_ROSLYN] = { + // entry added by Kaustubh D. Bhalerao + // GPIO values obtained from regspy, courtesy Sean Covel + .name = "Hauppauge WinTV 28xxx (Roslyn) models", + .tuner_type = UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xed12, // internal decoder + .gpio2 = 0x00ff, + },{ + .type = CX88_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, // mono from tuner chip + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xed92, + .gpio2 = 0x00ff, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xed96, + .gpio2 = 0x00ff, + }, + .blackbird = 1, + }, + [CX88_BOARD_DIGITALLOGIC_MEC] = { + /* params copied over from Leadtek PVR 2000 */ + .name = "Digital-Logic MICROSPACE Entertainment Center (MEC)", + /* not sure yet about the tuner type */ + .tuner_type = 38, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000bde6, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0000bde6, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000bde6, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0000bd62, + }, + .blackbird = 1, + }, + [CX88_BOARD_IODATA_GVBCTV7E] = { + .name = "IODATA GV/BCTV7E", + .tuner_type = TUNER_PHILIPS_FQ1286, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 1, + .gpio1 = 0x0000e03f, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 2, + .gpio1 = 0x0000e07f, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 3, + .gpio1 = 0x0000e07f, + }} + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -482,11 +631,11 @@ struct cx88_subid cx88_subids[] = { },{ .subvendor = 0x107d, .subdevice = 0x6611, - .card = CX88_BOARD_WINFAST2000XP, + .card = CX88_BOARD_WINFAST2000XP_EXPERT, },{ .subvendor = 0x107d, .subdevice = 0x6613, /* NTSC */ - .card = CX88_BOARD_WINFAST2000XP, + .card = CX88_BOARD_WINFAST2000XP_EXPERT, },{ .subvendor = 0x107d, .subdevice = 0x6620, @@ -543,6 +692,30 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x18AC, .subdevice = 0xDB10, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, + },{ + .subvendor = 0x1554, + .subdevice = 0x4811, + .card = CX88_BOARD_PIXELVIEW, + },{ + .subvendor = 0x7063, + .subdevice = 0x3000, /* HD-3000 card */ + .card = CX88_BOARD_PCHDTV_HD3000, + },{ + .subvendor = 0x17DE, + .subdevice = 0xA8A6, + .card = CX88_BOARD_DNTV_LIVE_DVB_T, + },{ + .subvendor = 0x0070, + .subdevice = 0x2801, + .card = CX88_BOARD_HAUPPAUGE_ROSLYN, + },{ + .subvendor = 0x14F1, + .subdevice = 0x0342, + .card = CX88_BOARD_DIGITALLOGIC_MEC, + },{ + .subvendor = 0x10fc, + .subdevice = 0xd035, + .card = CX88_BOARD_IODATA_GVBCTV7E, } }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -552,7 +725,7 @@ const unsigned int cx88_idcount = ARRAY_ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) { - /* This is just for the Winfast 2000 XP board ATM; I don't have data on + /* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on * any others. * * Byte 0 is 1 on the NTSC board. @@ -569,108 +742,27 @@ static void __devinit leadtek_eeprom(str core->has_radio = 1; core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38; - printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: " + printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " "tuner=%d, eeprom[0]=0x%02x\n", core->name, core->tuner_type, eeprom_data[0]); } /* ----------------------------------------------------------------------- */ -/* some hauppauge specific stuff */ - -static struct { - int id; - char *name; -} hauppauge_tuner[] __devinitdata = { - { TUNER_ABSENT, "" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_PHILIPS_PAL, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" }, - { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, - { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, - { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, - { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, - { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ - { TUNER_ABSENT, "Philips FI1256MP" }, - { TUNER_ABSENT, "Samsung TCPQ9091P" }, - { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, - { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, - { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, - { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, - { TUNER_ABSENT, "Philips TD1536D_FH_44"}, - { TUNER_LG_NTSC_FM, "LG TPI8NSR01F"}, - { TUNER_LG_PAL_FM, "LG TPI8PSB01D"}, - { TUNER_LG_PAL, "LG TPI8PSB11D"}, - { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, - { TUNER_LG_PAL_I, "LG TAPC-I701D"} -}; static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) { - unsigned int blk2,tuner,radio,model; + struct tveeprom tv; - if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) { - printk(KERN_WARNING "%s: Hauppauge eeprom: invalid\n", - core->name); - return; - } - - /* Block 2 starts after len+3 bytes header */ - blk2 = eeprom_data[1] + 3; - - /* decode + use some config infos */ - model = eeprom_data[12] << 8 | eeprom_data[11]; - tuner = eeprom_data[9]; - radio = eeprom_data[blk2-1] & 0x01; - - if (tuner < ARRAY_SIZE(hauppauge_tuner)) - core->tuner_type = hauppauge_tuner[tuner].id; - if (radio) - core->has_radio = 1; - - printk(KERN_INFO "%s: hauppauge eeprom: model=%d, " - "tuner=%s (%d), radio=%s\n", - core->name, model, (tuner < ARRAY_SIZE(hauppauge_tuner) - ? hauppauge_tuner[tuner].name : "?"), - core->tuner_type, radio ? "yes" : "no"); + tveeprom_hauppauge_analog(&tv, eeprom_data); + core->tuner_type = tv.tuner_type; + core->has_radio = tv.has_radio; } -#ifdef WITH_DVB static int hauppauge_eeprom_dvb(struct cx88_core *core, u8 *ee) { int model; int tuner; - char *tname; /* Make sure we support the board model */ model = ee[0x1f] << 24 | ee[0x1e] << 16 | ee[0x1d] << 8 | ee[0x1c]; @@ -689,26 +781,18 @@ static int hauppauge_eeprom_dvb(struct c /* Make sure we support the tuner */ tuner = ee[0x2d]; switch(tuner) { - case 0x4B: - tname = "Thomson DTT 7595"; - core->pll_type = PLLTYPE_DTT7595; - break; - case 0x4C: - tname = "Thomson DTT 7592"; - core->pll_type = PLLTYPE_DTT7592; + case 0x4B: /* dtt 7595 */ + case 0x4C: /* dtt 7592 */ break; default: printk("%s: error: unknown hauppauge tuner 0x%02x\n", core->name, tuner); return -ENODEV; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%s (%d)\n", - core->name, model, tname, tuner); - - core->pll_addr = 0x61; - core->demod_addr = 0x43; + printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%d\n", + core->name, model, tuner); + return 0; } -#endif /* ----------------------------------------------------------------------- */ /* some GDI (was: Modular Technology) specific stuff */ @@ -763,36 +847,6 @@ static void gdi_eeprom(struct cx88_core /* ----------------------------------------------------------------------- */ -static int -i2c_eeprom(struct i2c_client *c, unsigned char *eedata, int len) -{ - unsigned char buf; - int err; - - c->addr = 0xa0 >> 1; - buf = 0; - if (1 != (err = i2c_master_send(c,&buf,1))) { - printk(KERN_INFO "cx88: Huh, no eeprom present (err=%d)?\n", - err); - return -1; - } - if (len != (err = i2c_master_recv(c,eedata,len))) { - printk(KERN_WARNING "cx88: i2c eeprom read error (err=%d)\n", - err); - return -1; - } -#if 0 - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "cx88 ee: %02x:",i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } -#endif - return 0; -} - void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { int i; @@ -823,41 +877,46 @@ void cx88_card_setup(struct cx88_core *c { static u8 eeprom[128]; + if (0 == core->i2c_rc) { + core->i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); + } + switch (core->board) { case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - hauppauge_eeprom(core,eeprom+8); + hauppauge_eeprom(core,eeprom+8); break; case CX88_BOARD_GDI: if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - gdi_eeprom(core,eeprom); + gdi_eeprom(core,eeprom); break; - case CX88_BOARD_WINFAST2000XP: + case CX88_BOARD_WINFAST2000XP_EXPERT: if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - leadtek_eeprom(core,eeprom); + leadtek_eeprom(core,eeprom); + break; + case CX88_BOARD_HAUPPAUGE_DVB_T1: + if (0 == core->i2c_rc) + hauppauge_eeprom_dvb(core,eeprom); break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - /* Tuner reset is hooked to the tuner out of reset */ + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: + /* GPIO0:0 is hooked to mt352 reset pin */ cx_set(MO_GP0_IO, 0x00000101); cx_clear(MO_GP0_IO, 0x00000001); msleep(1); cx_set(MO_GP0_IO, 0x00000101); break; -#ifdef WITH_DVB - case CX88_BOARD_HAUPPAUGE_DVB_T1: - if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - hauppauge_eeprom_dvb(core,eeprom); - break; - case CX88_BOARD_CONEXANT_DVB_T1: - core->pll_type = PLLTYPE_DTT7579; - core->pll_addr = 0x60; - core->demod_addr = 0x43; + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_DNTV_LIVE_DVB_T: + cx_set(MO_GP0_IO, 0x00000707); + cx_set(MO_GP2_IO, 0x00000101); + cx_clear(MO_GP2_IO, 0x00000001); + msleep(1); + cx_clear(MO_GP0_IO, 0x00000007); + cx_set(MO_GP2_IO, 0x00000101); break; -#endif } if (cx88_boards[core->board].radio.type == CX88_RADIO) core->has_radio = 1; diff -puN drivers/media/video/cx88/cx88-core.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-core.c --- 25/drivers/media/video/cx88/cx88-core.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-core.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88-core.c,v 1.15 2004/10/25 11:26:36 kraxel Exp $ + * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,10 @@ static unsigned int nicam = 0; module_param(nicam,int,0644); MODULE_PARM_DESC(nicam,"tv audio is nicam"); +static unsigned int nocomb = 0; +module_param(nocomb,int,0644); +MODULE_PARM_DESC(nocomb,"disable comb filter"); + #define dprintk(level,fmt, arg...) if (core_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) @@ -462,6 +467,7 @@ int cx88_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } +#if 0 /* currently unused, but useful for debugging */ void cx88_risc_disasm(struct cx88_core *core, struct btcx_riscmem *risc) { @@ -479,6 +485,7 @@ void cx88_risc_disasm(struct cx88_core * break; } } +#endif void cx88_sram_channel_dump(struct cx88_core *core, struct sram_channel *ch) @@ -579,10 +586,19 @@ void cx88_print_irqbits(char *name, char /* ------------------------------------------------------------------ */ -void cx88_irq(struct cx88_core *core, u32 status, u32 mask) +int cx88_core_irq(struct cx88_core *core, u32 status) { - cx88_print_irqbits(core->name, "irq pci", - cx88_pci_irqs, status, mask); + int handled = 0; + + if (status & (1<<18)) { + cx88_ir_irq(core); + handled++; + } + if (!handled) + cx88_print_irqbits(core->name, "irq pci", + cx88_pci_irqs, status, + core->pci_irqmask); + return handled; } void cx88_wakeup(struct cx88_core *core, @@ -800,6 +816,8 @@ int cx88_set_scale(struct cx88_core *cor value |= (1 << 0); // 3-tap interpolation if (width < 193) value |= (1 << 1); // 5-tap interpolation + if (nocomb) + value |= (3 << 5); // disable comb filter cx_write(MO_FILTER_EVEN, value); cx_write(MO_FILTER_ODD, value); @@ -887,8 +905,8 @@ static int set_tvaudio(struct cx88_core 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_AUDD_LNGTH, 128); /* fifo size */ + cx_write(MO_AUDR_LNGTH, 128); /* fifo size */ cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */ return 0; } @@ -969,6 +987,9 @@ int cx88_set_tvnorm(struct cx88_core *co cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */ norm_vbipack(norm))); + // this is needed as well to set all tvnorm parameter + cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED); + // audio set_tvaudio(core); @@ -1105,9 +1126,10 @@ struct cx88_core* cx88_core_get(struct p goto fail_unlock; memset(core,0,sizeof(*core)); + atomic_inc(&core->refcount); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); - atomic_inc(&core->refcount); + core->pci_irqmask = 0x00fc00; core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); @@ -1150,6 +1172,7 @@ struct cx88_core* cx88_core_get(struct p cx88_reset(core); cx88_i2c_init(core,pci); cx88_card_setup(core); + cx88_ir_init(core,pci); up(&devlist); return core; @@ -1170,6 +1193,7 @@ void cx88_core_put(struct cx88_core *cor return; down(&devlist); + cx88_ir_fini(core); if (0 == core->i2c_rc) i2c_bit_del_bus(&core->i2c_adap); list_del(&core->devlist); @@ -1187,7 +1211,7 @@ EXPORT_SYMBOL(cx88_vid_irqs); EXPORT_SYMBOL(cx88_mpeg_irqs); EXPORT_SYMBOL(cx88_print_irqbits); -EXPORT_SYMBOL(cx88_irq); +EXPORT_SYMBOL(cx88_core_irq); EXPORT_SYMBOL(cx88_wakeup); EXPORT_SYMBOL(cx88_reset); EXPORT_SYMBOL(cx88_shutdown); @@ -1197,8 +1221,6 @@ EXPORT_SYMBOL(cx88_risc_databuffer); EXPORT_SYMBOL(cx88_risc_stopper); EXPORT_SYMBOL(cx88_free_buffer); -EXPORT_SYMBOL(cx88_risc_disasm); - EXPORT_SYMBOL(cx88_sram_channels); EXPORT_SYMBOL(cx88_sram_channel_setup); EXPORT_SYMBOL(cx88_sram_channel_dump); diff -puN drivers/media/video/cx88/cx88-dvb.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-dvb.c --- 25/drivers/media/video/cx88/cx88-dvb.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-dvb.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $ + * $Id: cx88-dvb.c,v 1.31 2005/03/07 15:58:05 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -30,10 +30,20 @@ #include #include +/* those two frontends need merging via linuxtv cvs ... */ +#define HAVE_CX22702 0 +#define HAVE_OR51132 0 + #include "cx88.h" -#include "cx22702.h" +#include "dvb-pll.h" #include "mt352.h" -#include "mt352_priv.h" /* FIXME */ +#include "mt352_priv.h" +#if HAVE_CX22702 +# include "cx22702.h" +#endif +#if HAVE_OR51132 +# include "or51132.h" +#endif MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe "); @@ -110,111 +120,144 @@ static int dvico_fusionhdtv_demod_init(s return 0; } -#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - -static int lg_z201_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, u8* pllbuf) +static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe) { - u32 div; - unsigned char cp = 0; - unsigned char bs = 0; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency < 542000000) cp = 0xbc; - else if (params->frequency < 830000000) cp = 0xf4; - else cp = 0xfc; - - if (params->frequency == 0) bs = 0x03; - else if (params->frequency < 157500000) bs = 0x01; - else if (params->frequency < 443250000) bs = 0x02; - else bs = 0x04; - - pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */ - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; + static u8 clock_config [] = { 0x89, 0x38, 0x39 }; + static u8 reset [] = { 0x50, 0x80 }; + static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static u8 dntv_extra[] = { 0xB5, 0x7A }; + static u8 capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(2000); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + udelay(2000); + mt352_write(fe, dntv_extra, sizeof(dntv_extra)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); return 0; } -static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, - u8* pllbuf) -{ - u32 div; - unsigned char cp = 0; - unsigned char bs = 0; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency < 542000000) cp = 0xb4; - else if (params->frequency < 771000000) cp = 0xbc; - else cp = 0xf4; - - if (params->frequency == 0) bs = 0x03; - else if (params->frequency < 443250000) bs = 0x02; - else bs = 0x08; - - pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; - +static int mt352_pll_set(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + u8* pllbuf) +{ + struct cx8802_dev *dev= fe->dvb->priv; + + pllbuf[0] = dev->core->pll_addr << 1; + dvb_pll_configure(dev->core->pll_desc, pllbuf+1, + params->frequency, + params->u.ofdm.bandwidth); return 0; } -struct mt352_config dvico_fusionhdtv_dvbt1 = { +static struct mt352_config dvico_fusionhdtv = { .demod_address = 0x0F, .demod_init = dvico_fusionhdtv_demod_init, - .pll_set = lg_z201_pll_set, + .pll_set = mt352_pll_set, }; -struct mt352_config dvico_fusionhdtv_dvbt_plus = { - .demod_address = 0x0F, - .demod_init = dvico_fusionhdtv_demod_init, - .pll_set = thomson_dtt7579_pll_set, +static struct mt352_config dntv_live_dvbt_config = { + .demod_address = 0x0f, + .demod_init = dntv_live_dvbt_demod_init, + .pll_set = mt352_pll_set, +}; + +#if HAVE_CX22702 +static struct cx22702_config connexant_refboard_config = { + .demod_address = 0x43, + .pll_address = 0x60, + .pll_desc = &dvb_pll_thomson_dtt7579, +}; + +static struct cx22702_config hauppauge_novat_config = { + .demod_address = 0x43, + .pll_address = 0x61, + .pll_desc = &dvb_pll_thomson_dtt759x, }; +#endif + +#if HAVE_OR51132 +static int or51132_set_ts_param(struct dvb_frontend* fe, + int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; + return 0; +} + +struct or51132_config pchdtv_hd3000 = { + .demod_address = 0x15, + .pll_address = 0x61, + .pll_desc = &dvb_pll_thomson_dtt7610, + .set_ts_params = or51132_set_ts_param, +}; +#endif static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ dev->dvb.name = dev->core->name; + dev->ts_gen_cntrl = 0x0c; /* init frontend */ switch (dev->core->board) { +#if HAVE_CX22702 case CX88_BOARD_HAUPPAUGE_DVB_T1: + dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config, + &dev->core->i2c_adap); + break; case CX88_BOARD_CONEXANT_DVB_T1: - dev->dvb.frontend = cx22702_create(&dev->core->i2c_adap, - dev->core->pll_addr, - dev->core->pll_type, - dev->core->demod_addr); + dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, + &dev->core->i2c_adap); break; +#endif case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt1, + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_lg_z201; + dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv, &dev->core->i2c_adap); - if (dev->dvb.frontend) { - dev->dvb.frontend->ops->info.frequency_min = 174000000; - dev->dvb.frontend->ops->info.frequency_max = 862000000; - } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: - dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt_plus, + dev->core->pll_addr = 0x60; + dev->core->pll_desc = &dvb_pll_thomson_dtt7579; + dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv, + &dev->core->i2c_adap); + break; + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_DNTV_LIVE_DVB_T: + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_unknown_1; + dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config, + &dev->core->i2c_adap); + break; +#if HAVE_OR51132 + case CX88_BOARD_PCHDTV_HD3000: + dev->dvb.frontend = or51132_attach(&pchdtv_hd3000, &dev->core->i2c_adap); - if (dev->dvb.frontend) { - dev->dvb.frontend->ops->info.frequency_min = 174000000; - dev->dvb.frontend->ops->info.frequency_max = 862000000; - } break; +#endif default: - printk("%s: FIXME: frontend handling not here yet ...\n", - dev->core->name); + printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n" + "%s: you might want to look out for patches here:\n" + "%s: http://dl.bytesex.org/patches/\n", + dev->core->name, dev->core->name, dev->core->name); break; } - if (NULL == dev->dvb.frontend) + if (NULL == dev->dvb.frontend) { + printk("%s: frontend initialization failed\n",dev->core->name); return -1; + } + + if (dev->core->pll_desc) { + dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min; + dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max; + } /* Copy the board name into the DVB structure */ strlcpy(dev->dvb.frontend->ops->info.name, @@ -222,7 +265,7 @@ static int dvb_register(struct cx8802_de sizeof(dev->dvb.frontend->ops->info.name)); /* register everything */ - return videobuf_dvb_register(&dev->dvb); + return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); } /* ----------------------------------------------------------- */ diff -puN drivers/media/video/cx88/cx88.h~v4l-cx88-driver-update drivers/media/video/cx88/cx88.h --- 25/drivers/media/video/cx88/cx88.h~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88.h 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88.h,v 1.40 2004/11/03 09:04:51 kraxel Exp $ + * $Id: cx88.h,v 1.56 2005/03/04 09:12:23 kraxel Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -139,7 +140,7 @@ extern struct sram_channel cx88_sram_cha #define CX88_BOARD_GDI 2 #define CX88_BOARD_PIXELVIEW 3 #define CX88_BOARD_ATI_WONDER_PRO 4 -#define CX88_BOARD_WINFAST2000XP 5 +#define CX88_BOARD_WINFAST2000XP_EXPERT 5 #define CX88_BOARD_AVERTV_303 6 #define CX88_BOARD_MSI_TVANYWHERE_MASTER 7 #define CX88_BOARD_WINFAST_DV2000 8 @@ -156,6 +157,11 @@ extern struct sram_channel cx88_sram_cha #define CX88_BOARD_CONEXANT_DVB_T1 19 #define CX88_BOARD_PROVIDEO_PV259 20 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21 +#define CX88_BOARD_PCHDTV_HD3000 22 +#define CX88_BOARD_DNTV_LIVE_DVB_T 23 +#define CX88_BOARD_HAUPPAUGE_ROSLYN 24 +#define CX88_BOARD_DIGITALLOGIC_MEC 25 +#define CX88_BOARD_IODATA_GVBCTV7E 26 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -238,6 +244,7 @@ struct cx88_core { u32 __iomem *lmmio; u8 __iomem *bmmio; u32 shadow[SHADOW_MAX]; + int pci_irqmask; /* i2c i/o */ struct i2c_adapter i2c_adap; @@ -252,16 +259,20 @@ struct cx88_core { unsigned int has_radio; /* config info -- dvb */ - unsigned int pll_type; + struct dvb_pll_desc *pll_desc; unsigned int pll_addr; - unsigned int demod_addr; /* state info */ struct task_struct *kthread; struct cx88_tvnorm *tvnorm; u32 tvaudio; + u32 audiomode_manual; + u32 audiomode_current; u32 input; u32 astat; + + /* IR remote control state */ + struct cx88_IR *ir; }; struct cx8800_dev; @@ -371,11 +382,16 @@ struct cx8802_dev { struct list_head devlist; struct video_device *mpeg_dev; u32 mailbox; + int width; + int height; /* for dvb only */ struct videobuf_dvb dvb; void* fe_handle; int (*fe_release)(void *handle); + + /* for switching modulation types */ + unsigned char ts_gen_cntrl; }; /* ----------------------------------------------------------- */ @@ -411,7 +427,7 @@ extern void cx88_print_irqbits(char *nam u32 bits, u32 mask); extern void cx88_print_ioctl(char *name, unsigned int cmd); -extern void cx88_irq(struct cx88_core *core, u32 status, u32 mask); +extern int cx88_core_irq(struct cx88_core *core, u32 status); extern void cx88_wakeup(struct cx88_core *core, struct cx88_dmaqueue *q, u32 count); extern void cx88_shutdown(struct cx88_core *core); @@ -503,11 +519,19 @@ extern void cx88_card_setup(struct cx88_ #define WW_FM 12 void cx88_set_tvaudio(struct cx88_core *core); +void cx88_newstation(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); +void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); int cx88_audio_thread(void *data); /* ----------------------------------------------------------- */ +/* cx88-input.c */ + +int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); +int cx88_ir_fini(struct cx88_core *core); +void cx88_ir_irq(struct cx88_core *core); + +/* ----------------------------------------------------------- */ /* cx88-mpeg.c */ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf); @@ -517,7 +541,7 @@ void cx8802_cancel_buffers(struct cx8802 int cx8802_init_common(struct cx8802_dev *dev); void cx8802_fini_common(struct cx8802_dev *dev); -int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state); +int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); int cx8802_resume_common(struct pci_dev *pci_dev); /* diff -puN drivers/media/video/cx88/cx88-i2c.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-i2c.c --- 25/drivers/media/video/cx88/cx88-i2c.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-i2c.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - $Id: cx88-i2c.c,v 1.18 2004/10/13 10:39:00 kraxel Exp $ + $Id: cx88-i2c.c,v 1.20 2005/02/15 15:59:35 kraxel Exp $ cx88-i2c.c -- all the i2c code is here @@ -25,6 +25,7 @@ */ #include +#include #include #include diff -puN /dev/null drivers/media/video/cx88/cx88-input.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/media/video/cx88/cx88-input.c 2005-03-11 12:32:23.000000000 -0800 @@ -0,0 +1,396 @@ +/* + * $Id: cx88-input.c,v 1.9 2005/03/04 09:12:23 kraxel Exp $ + * + * Device driver for GPIO attached remote control interfaces + * on Conexant 2388x based TV/DVB cards. + * + * Copyright (c) 2003 Pavel Machek + * Copyright (c) 2004 Gerd Knorr + * Copyright (c) 2004 Chris Pascoe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "cx88.h" + +/* ---------------------------------------------------------------------- */ + +/* DigitalNow DNTV Live DVB-T Remote */ +static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = { + [ 0x00 ] = KEY_ESC, // 'go up a level?' + [ 0x01 ] = KEY_KP1, // '1' + [ 0x02 ] = KEY_KP2, // '2' + [ 0x03 ] = KEY_KP3, // '3' + [ 0x04 ] = KEY_KP4, // '4' + [ 0x05 ] = KEY_KP5, // '5' + [ 0x06 ] = KEY_KP6, // '6' + [ 0x07 ] = KEY_KP7, // '7' + [ 0x08 ] = KEY_KP8, // '8' + [ 0x09 ] = KEY_KP9, // '9' + [ 0x0a ] = KEY_KP0, // '0' + [ 0x0b ] = KEY_TUNER, // 'tv/fm' + [ 0x0c ] = KEY_SEARCH, // 'scan' + [ 0x0d ] = KEY_STOP, // 'stop' + [ 0x0e ] = KEY_PAUSE, // 'pause' + [ 0x0f ] = KEY_LIST, // 'source' + + [ 0x10 ] = KEY_MUTE, // 'mute' + [ 0x11 ] = KEY_REWIND, // 'backward <<' + [ 0x12 ] = KEY_POWER, // 'power' + [ 0x13 ] = KEY_S, // 'snap' + [ 0x14 ] = KEY_AUDIO, // 'stereo' + [ 0x15 ] = KEY_CLEAR, // 'reset' + [ 0x16 ] = KEY_PLAY, // 'play' + [ 0x17 ] = KEY_ENTER, // 'enter' + [ 0x18 ] = KEY_ZOOM, // 'full screen' + [ 0x19 ] = KEY_FASTFORWARD, // 'forward >>' + [ 0x1a ] = KEY_CHANNELUP, // 'channel +' + [ 0x1b ] = KEY_VOLUMEUP, // 'volume +' + [ 0x1c ] = KEY_INFO, // 'preview' + [ 0x1d ] = KEY_RECORD, // 'record' + [ 0x1e ] = KEY_CHANNELDOWN, // 'channel -' + [ 0x1f ] = KEY_VOLUMEDOWN, // 'volume -' +}; + +/* ---------------------------------------------------------------------- */ + +/* IO-DATA BCTV7E Remote */ +static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = { + [ 0x40 ] = KEY_TV, // TV + [ 0x20 ] = KEY_RADIO, // FM + [ 0x60 ] = KEY_EPG, // EPG + [ 0x00 ] = KEY_POWER, // power + + [ 0x50 ] = KEY_KP1, // 1 + [ 0x30 ] = KEY_KP2, // 2 + [ 0x70 ] = KEY_KP3, // 3 + [ 0x10 ] = KEY_L, // Live + + [ 0x48 ] = KEY_KP4, // 4 + [ 0x28 ] = KEY_KP5, // 5 + [ 0x68 ] = KEY_KP6, // 6 + [ 0x08 ] = KEY_T, // Time Shift + + [ 0x58 ] = KEY_KP7, // 7 + [ 0x38 ] = KEY_KP8, // 8 + [ 0x78 ] = KEY_KP9, // 9 + [ 0x18 ] = KEY_PLAYPAUSE, // Play + + [ 0x44 ] = KEY_KP0, // 10 + [ 0x24 ] = KEY_ENTER, // 11 + [ 0x64 ] = KEY_ESC, // 12 + [ 0x04 ] = KEY_M, // Multi + + [ 0x54 ] = KEY_VIDEO, // VIDEO + [ 0x34 ] = KEY_CHANNELUP, // channel + + [ 0x74 ] = KEY_VOLUMEUP, // volume + + [ 0x14 ] = KEY_MUTE, // Mute + + [ 0x4c ] = KEY_S, // SVIDEO + [ 0x2c ] = KEY_CHANNELDOWN, // channel - + [ 0x6c ] = KEY_VOLUMEDOWN, // volume - + [ 0x0c ] = KEY_ZOOM, // Zoom + + [ 0x5c ] = KEY_PAUSE, // pause + [ 0x3c ] = KEY_C, // || (red) + [ 0x7c ] = KEY_RECORD, // recording + [ 0x1c ] = KEY_STOP, // stop + + [ 0x41 ] = KEY_REWIND, // backward << + [ 0x21 ] = KEY_PLAY, // play + [ 0x61 ] = KEY_FASTFORWARD, // forward >> + [ 0x01 ] = KEY_NEXT, // skip >| +}; + +/* ---------------------------------------------------------------------- */ + +struct cx88_IR { + struct cx88_core *core; + struct input_dev input; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* sample from gpio pin 16 */ + int sampling; + u32 samples[16]; + int scount; + unsigned long release; + + /* poll external decoder */ + int polling; + struct work_struct work; + struct timer_list timer; + u32 gpio_addr; + u32 last_gpio; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; +}; + +static int ir_debug = 0; +module_param(ir_debug, int, 0644); /* debug level [IR] */ +MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); + +#define ir_dprintk(fmt, arg...) if (ir_debug) \ + printk(KERN_DEBUG "%s IR: " fmt , ir->core->name, ## arg) + +/* ---------------------------------------------------------------------- */ + +static void cx88_ir_handle_key(struct cx88_IR *ir) +{ + struct cx88_core *core = ir->core; + u32 gpio, data; + + /* read gpio value */ + gpio = cx_read(ir->gpio_addr); + if (ir->polling) { + if (ir->last_gpio == gpio) + return; + ir->last_gpio = gpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if (ir->mask_keydown) { + /* bit set on keydown */ + if (gpio & ir->mask_keydown) { + ir_input_keydown(&ir->input,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->input,&ir->ir); + } + + } else if (ir->mask_keyup) { + /* bit cleared on keydown */ + if (0 == (gpio & ir->mask_keyup)) { + ir_input_keydown(&ir->input,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->input,&ir->ir); + } + + } else { + /* can't distinguish keydown/up :-/ */ + ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_nokey(&ir->input,&ir->ir); + } +} + +static void ir_timer(unsigned long data) +{ + struct cx88_IR *ir = (struct cx88_IR*)data; + + schedule_work(&ir->work); +} + +static void cx88_ir_work(void *data) +{ + struct cx88_IR *ir = data; + unsigned long timeout; + + cx88_ir_handle_key(ir); + timeout = jiffies + (ir->polling * HZ / 1000); + mod_timer(&ir->timer, timeout); +} + +/* ---------------------------------------------------------------------- */ + +int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) +{ + struct cx88_IR *ir; + IR_KEYTAB_TYPE *ir_codes = NULL; + int ir_type = IR_TYPE_OTHER; + + ir = kmalloc(sizeof(*ir),GFP_KERNEL); + if (NULL == ir) + return -ENOMEM; + memset(ir,0,sizeof(*ir)); + + /* detect & configure */ + switch (core->board) { + case CX88_BOARD_DNTV_LIVE_DVB_T: + ir_codes = ir_codes_dntv_live_dvb_t; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x60; + ir->polling = 50; // ms + break; + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_DVB_T1: + ir_codes = ir_codes_hauppauge_new; + ir_type = IR_TYPE_RC5; + ir->sampling = 1; + break; + case CX88_BOARD_WINFAST2000XP_EXPERT: + ir_codes = ir_codes_winfast; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0x8f8; + ir->mask_keyup = 0x100; + ir->polling = 1; // ms + break; + case CX88_BOARD_IODATA_GVBCTV7E: + ir_codes = ir_codes_iodata_bctv7e; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0xfd; + ir->mask_keydown = 0x02; + ir->polling = 5; // ms + break; + } + if (NULL == ir_codes) { + kfree(ir); + return -ENODEV; + } + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", + cx88_boards[core->board].name); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(pci)); + + ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); + ir->input.name = ir->name; + ir->input.phys = ir->phys; + ir->input.id.bustype = BUS_PCI; + ir->input.id.version = 1; + if (pci->subsystem_vendor) { + ir->input.id.vendor = pci->subsystem_vendor; + ir->input.id.product = pci->subsystem_device; + } else { + ir->input.id.vendor = pci->vendor; + ir->input.id.product = pci->device; + } + + /* record handles to ourself */ + ir->core = core; + core->ir = ir; + + if (ir->polling) { + INIT_WORK(&ir->work, cx88_ir_work, ir); + init_timer(&ir->timer); + ir->timer.function = ir_timer; + ir->timer.data = (unsigned long)ir; + schedule_work(&ir->work); + } + if (ir->sampling) { + core->pci_irqmask |= (1<<18); // IR_SMP_INT + cx_write(MO_DDS_IO, 0xa80a80); // 4 kHz sample rate + cx_write(MO_DDSCFG_IO, 0x5); // enable + } + + /* all done */ + input_register_device(&ir->input); + printk("%s: registered IR remote control\n", core->name); + + return 0; +} + +int cx88_ir_fini(struct cx88_core *core) +{ + struct cx88_IR *ir = core->ir; + + /* skip detach on non attached boards */ + if (NULL == ir) + return 0; + + if (ir->polling) { + del_timer(&ir->timer); + flush_scheduled_work(); + } + + input_unregister_device(&ir->input); + kfree(ir); + + /* done */ + core->ir = NULL; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +void cx88_ir_irq(struct cx88_core *core) +{ + struct cx88_IR *ir = core->ir; + u32 samples,rc5; + int i; + + if (NULL == ir) + return; + if (!ir->sampling) + return; + + samples = cx_read(MO_SAMPLE_IO); + if (0 != samples && 0xffffffff != samples) { + /* record sample data */ + if (ir->scount < ARRAY_SIZE(ir->samples)) + ir->samples[ir->scount++] = samples; + return; + } + if (!ir->scount) { + /* nothing to sample */ + if (ir->ir.keypressed && time_after(jiffies,ir->release)) + ir_input_nokey(&ir->input,&ir->ir); + return; + } + + /* have a complete sample */ + if (ir->scount < ARRAY_SIZE(ir->samples)) + ir->samples[ir->scount++] = samples; + for (i = 0; i < ir->scount; i++) + ir->samples[i] = ~ir->samples[i]; + if (ir_debug) + ir_dump_samples(ir->samples,ir->scount); + + /* decode it */ + switch (core->board) { + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_DVB_T1: + rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7); + ir_dprintk("biphase decoded: %x\n",rc5); + if ((rc5 & 0xfffff000) != 0x3000) + break; + ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5); + ir->release = jiffies + msecs_to_jiffies(120); + break; + } + + ir->scount = 0; + return; +} + +/* ---------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe"); +MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -puN drivers/media/video/cx88/cx88-mpeg.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-mpeg.c --- 25/drivers/media/video/cx88/cx88-mpeg.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-mpeg.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88-mpeg.c,v 1.14 2004/10/25 11:26:36 kraxel Exp $ + * $Id: cx88-mpeg.c,v 1.25 2005/03/07 14:18:00 kraxel Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -68,8 +69,14 @@ static int cx8802_start_dma(struct cx880 * 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); + /* negedge driven & software reset */ + cx_write(TS_GEN_CNTRL, 0x40); + udelay(100); + cx_write(MO_PINMUX_IO, 0x00); + cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00); + cx_write(TS_SOP_STAT,0x00); + cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); + udelay(100); } if (cx88_boards[core->board].blackbird) { @@ -93,7 +100,7 @@ static int cx8802_start_dma(struct cx880 q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, 0x00fc04); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); cx_write(MO_TS_INTMSK, 0x1f0011); /* start dma */ @@ -292,19 +299,18 @@ static irqreturn_t cx8802_irq(int irq, v { struct cx8802_dev *dev = dev_id; struct cx88_core *core = dev->core; - u32 status, mask; + u32 status; int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x04); - mask = cx_read(MO_PCI_INTMSK); - if (0 == (status & mask)) + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04); + if (0 == status) goto out; handled = 1; cx_write(MO_PCI_INTSTAT, status); - if (status & mask & ~0x1f) - cx88_irq(core,status,mask); + if (status & core->pci_irqmask) + cx88_core_irq(core,status); if (status & 0x04) cx8802_mpeg_irq(dev); }; @@ -323,6 +329,7 @@ static irqreturn_t cx8802_irq(int irq, v int cx8802_init_common(struct cx8802_dev *dev) { + struct cx88_core *core = dev->core; int err; /* pci init */ @@ -354,11 +361,6 @@ int cx8802_init_common(struct cx8802_dev cx88_risc_stopper(dev->pci,&dev->mpegq.stopper, MO_TS_DMACNTRL,0x11,0x00); -#if 0 /* FIXME */ - /* initialize hardware */ - cx8802_reset(dev); -#endif - /* get irq */ err = request_irq(dev->pci->irq, cx8802_irq, SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev); @@ -367,11 +369,7 @@ int cx8802_init_common(struct cx8802_dev dev->core->name, dev->pci->irq); return err; } - -#if 0 /* FIXME */ - /* register i2c bus + load i2c helpers */ - cx88_card_setup(dev); -#endif + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* everything worked */ pci_set_drvdata(dev->pci,dev); @@ -393,7 +391,7 @@ void cx8802_fini_common(struct cx8802_de /* ----------------------------------------------------------- */ -int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state) +int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -413,7 +411,7 @@ int cx8802_suspend_common(struct pci_dev #endif pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, state)) { + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -429,7 +427,7 @@ int cx8802_resume_common(struct pci_dev pci_enable_device(pci_dev); dev->state.disabled = 0; } - pci_set_power_state(pci_dev, 0); + pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); #if 1 diff -puN drivers/media/video/cx88/cx88-tvaudio.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-tvaudio.c --- 25/drivers/media/video/cx88/cx88-tvaudio.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-tvaudio.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - $Id: cx88-tvaudio.c,v 1.24 2004/10/25 11:51:00 kraxel Exp $ + $Id: cx88-tvaudio.c,v 1.34 2005/03/07 16:10:51 kraxel Exp $ cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver @@ -37,6 +37,7 @@ */ #include +#include #include #include #include @@ -56,7 +57,7 @@ #include "cx88.h" -static unsigned int audio_debug = 1; +static unsigned int audio_debug = 0; module_param(audio_debug,int,0644); MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]"); @@ -141,6 +142,13 @@ static void set_audio_finish(struct cx88 { u32 volume; + if (cx88_boards[core->board].blackbird) { + // 'pass-thru mode': this enables the i2s output to the mpeg encoder + cx_set(AUD_CTL, 0x2000); + cx_write(AUD_I2SOUTPUTCNTL, 1); + //cx_write(AUD_APB_IN_RATE_ADJ, 0); + } + // finish programming cx_write(AUD_SOFT_RESET, 0x0000); @@ -263,6 +271,7 @@ static void set_audio_standard_BTSC(stru set_audio_finish(core); } +#if 0 static void set_audio_standard_NICAM(struct cx88_core *core) { static const struct rlist nicam_common[] = { @@ -335,128 +344,243 @@ static void set_audio_standard_NICAM(str }; set_audio_finish(core); } +#endif -static void set_audio_standard_NICAM_L(struct cx88_core *core) +static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo) { - /* This is officially weird.. register dumps indicate windows - * uses audio mode 4.. A2. Let's operate and find out. */ + /* This is probably weird.. + * Let's operate and find out. */ - static const struct rlist nicam_l[] = { - // setup QAM registers - { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x3d }, - { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, - { AUD_QAM_MODE, 0x00 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x4a }, - - { AUD_POLY0_DDS_CONSTANT, 0x000e4db2 }, - { AUD_IIR1_0_SEL, 0x00000000 }, - { AUD_IIR1_1_SEL, 0x00000002 }, - { AUD_IIR1_2_SEL, 0x00000023 }, - { AUD_IIR1_3_SEL, 0x00000004 }, - { AUD_IIR1_4_SEL, 0x00000005 }, - { AUD_IIR1_5_SEL, 0x00000007 }, - { AUD_IIR1_0_SHIFT, 0x00000007 }, - { AUD_IIR1_1_SHIFT, 0x00000000 }, - { AUD_IIR1_2_SHIFT, 0x00000000 }, - { AUD_IIR1_3_SHIFT, 0x00000007 }, - { AUD_IIR1_4_SHIFT, 0x00000007 }, - { AUD_IIR1_5_SHIFT, 0x00000007 }, - { AUD_IIR2_0_SEL, 0x00000002 }, - { AUD_IIR2_1_SEL, 0x00000003 }, - { AUD_IIR2_2_SEL, 0x00000004 }, - { AUD_IIR2_3_SEL, 0x00000005 }, - { AUD_IIR3_0_SEL, 0x00000007 }, - { AUD_IIR3_1_SEL, 0x00000023 }, - { AUD_IIR3_2_SEL, 0x00000016 }, - { AUD_IIR4_0_SHIFT, 0x00000000 }, - { AUD_IIR4_1_SHIFT, 0x00000000 }, - { AUD_IIR3_2_SHIFT, 0x00000002 }, - { AUD_IIR4_0_SEL, 0x0000001d }, - { AUD_IIR4_1_SEL, 0x00000019 }, - { AUD_IIR4_2_SEL, 0x00000008 }, - { AUD_IIR4_0_SHIFT, 0x00000000 }, - { AUD_IIR4_1_SHIFT, 0x00000007 }, - { AUD_IIR4_2_SHIFT, 0x00000007 }, - { AUD_IIR4_0_CA0, 0x0003e57e }, - { AUD_IIR4_0_CA1, 0x00005e11 }, - { AUD_IIR4_0_CA2, 0x0003a7cf }, - { AUD_IIR4_0_CB0, 0x00002368 }, - { AUD_IIR4_0_CB1, 0x0003bf1b }, - { AUD_IIR4_1_CA0, 0x00006349 }, - { AUD_IIR4_1_CA1, 0x00006f27 }, - { AUD_IIR4_1_CA2, 0x0000e7a3 }, - { AUD_IIR4_1_CB0, 0x00005653 }, - { AUD_IIR4_1_CB1, 0x0000cf97 }, - { AUD_IIR4_2_CA0, 0x00006349 }, - { AUD_IIR4_2_CA1, 0x00006f27 }, - { AUD_IIR4_2_CA2, 0x0000e7a3 }, - { AUD_IIR4_2_CB0, 0x00005653 }, - { AUD_IIR4_2_CB1, 0x0000cf97 }, - { AUD_HP_MD_IIR4_1, 0x00000001 }, - { AUD_HP_PROG_IIR4_1, 0x0000001a }, - { AUD_DN0_FREQ, 0x00000000 }, - { AUD_DN1_FREQ, 0x00003318 }, - { AUD_DN1_SRC_SEL, 0x00000017 }, - { AUD_DN1_SHFT, 0x00000007 }, - { AUD_DN1_AFC, 0x00000000 }, - { AUD_DN1_FREQ_SHIFT, 0x00000000 }, - { AUD_DN2_FREQ, 0x00003551 }, - { AUD_DN2_SRC_SEL, 0x00000001 }, - { AUD_DN2_SHFT, 0x00000000 }, - { AUD_DN2_AFC, 0x00000002 }, - { AUD_DN2_FREQ_SHIFT, 0x00000000 }, - { AUD_PDET_SRC, 0x00000014 }, - { AUD_PDET_SHIFT, 0x00000000 }, - { AUD_DEEMPH0_SRC_SEL, 0x00000011 }, - { AUD_DEEMPH1_SRC_SEL, 0x00000011 }, - { AUD_DEEMPH0_SHIFT, 0x00000000 }, - { AUD_DEEMPH1_SHIFT, 0x00000000 }, - { AUD_DEEMPH0_G0, 0x00007000 }, - { AUD_DEEMPH0_A0, 0x00000000 }, - { AUD_DEEMPH0_B0, 0x00000000 }, - { AUD_DEEMPH0_A1, 0x00000000 }, - { AUD_DEEMPH0_B1, 0x00000000 }, - { AUD_DEEMPH1_G0, 0x00007000 }, - { AUD_DEEMPH1_A0, 0x00000000 }, - { AUD_DEEMPH1_B0, 0x00000000 }, - { AUD_DEEMPH1_A1, 0x00000000 }, - { AUD_DEEMPH1_B1, 0x00000000 }, - { AUD_DMD_RA_DDS, 0x00f5c285 }, - { AUD_RATE_ADJ1, 0x00000100 }, - { AUD_RATE_ADJ2, 0x00000200 }, - { AUD_RATE_ADJ3, 0x00000300 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00000500 }, - { AUD_C2_UP_THR, 0x00005400 }, - { AUD_C2_LO_THR, 0x00003000 }, - { AUD_C1_UP_THR, 0x00007000 }, - { AUD_C2_LO_THR, 0x00005400 }, - { AUD_CTL, 0x0000100c }, - { AUD_DCOC_0_SRC, 0x00000021 }, - { AUD_DCOC_1_SRC, 0x00000003 }, - { AUD_DCOC1_SHIFT, 0x00000000 }, - { AUD_DCOC_1_SHIFT_IN0, 0x0000000a }, - { AUD_DCOC_1_SHIFT_IN1, 0x00000008 }, - { AUD_DCOC_PASS_IN, 0x00000000 }, - { AUD_DCOC_2_SRC, 0x0000001b }, - { AUD_IIR4_0_SEL, 0x0000001d }, - { AUD_POLY0_DDS_CONSTANT, 0x000e4db2 }, - { AUD_PHASE_FIX_CTL, 0x00000000 }, - { AUD_CORDIC_SHIFT_1, 0x00000007 }, - { AUD_PLL_EN, 0x00000000 }, - { AUD_PLL_PRESCALE, 0x00000002 }, - { AUD_PLL_INT, 0x0000001e }, - { AUD_OUT1_SHIFT, 0x00000000 }, + static const struct rlist nicam_l_mono[] = { + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + + { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x3D }, + { AUD_QAM_MODE, 0x00 }, + { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x4a }, + + { AUD_DEEMPHGAIN_R, 0x6680 }, + { AUD_DEEMPHNUMER1_R, 0x353DE }, + { AUD_DEEMPHNUMER2_R, 0x1B1 }, + { AUD_DEEMPHDENOM1_R, 0x0F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x0 }, + { AUD_FM_MODE_ENABLE, 0x7 }, + { AUD_POLYPH80SCALEFAC, 0x3 }, + { AUD_AFE_12DB_EN, 0x1 }, + { AAGC_GAIN, 0x0 }, + { AAGC_HYST, 0x18 }, + { AAGC_DEF, 0x20 }, + { AUD_DN0_FREQ, 0x0 }, + { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 }, + { AUD_DCOC_0_SRC, 0x21 }, + { AUD_IIR1_0_SEL, 0x0 }, + { AUD_IIR1_0_SHIFT, 0x7 }, + { AUD_IIR1_1_SEL, 0x2 }, + { AUD_IIR1_1_SHIFT, 0x0 }, + { AUD_DCOC_1_SRC, 0x3 }, + { AUD_DCOC1_SHIFT, 0x0 }, + { AUD_DCOC_PASS_IN, 0x0 }, + { AUD_IIR1_2_SEL, 0x23 }, + { AUD_IIR1_2_SHIFT, 0x0 }, + { AUD_IIR1_3_SEL, 0x4 }, + { AUD_IIR1_3_SHIFT, 0x7 }, + { AUD_IIR1_4_SEL, 0x5 }, + { AUD_IIR1_4_SHIFT, 0x7 }, + { AUD_IIR3_0_SEL, 0x7 }, + { AUD_IIR3_0_SHIFT, 0x0 }, + { AUD_DEEMPH0_SRC_SEL, 0x11 }, + { AUD_DEEMPH0_SHIFT, 0x0 }, + { AUD_DEEMPH0_G0, 0x7000 }, + { AUD_DEEMPH0_A0, 0x0 }, + { AUD_DEEMPH0_B0, 0x0 }, + { AUD_DEEMPH0_A1, 0x0 }, + { AUD_DEEMPH0_B1, 0x0 }, + { AUD_DEEMPH1_SRC_SEL, 0x11 }, + { AUD_DEEMPH1_SHIFT, 0x0 }, + { AUD_DEEMPH1_G0, 0x7000 }, + { AUD_DEEMPH1_A0, 0x0 }, + { AUD_DEEMPH1_B0, 0x0 }, + { AUD_DEEMPH1_A1, 0x0 }, + { AUD_DEEMPH1_B1, 0x0 }, + { AUD_OUT0_SEL, 0x3F }, + { AUD_OUT1_SEL, 0x3F }, + { AUD_DMD_RA_DDS, 0x0F5C285 }, + { AUD_PLL_INT, 0x1E }, + { AUD_PLL_DDS, 0x0 }, + { AUD_PLL_FRAC, 0x0E542 }, + + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000100 }, + { AUD_RATE_ADJ2, 0x00000200 }, + { AUD_RATE_ADJ3, 0x00000300 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00000500 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + }; - { /* end of list */ }, - }; + static const struct rlist nicam_l[] = { + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000060 }, + { AUD_RATE_ADJ2, 0x000000F9 }, + { AUD_RATE_ADJ3, 0x000001CC }, + { AUD_RATE_ADJ4, 0x000002B3 }, + { AUD_RATE_ADJ5, 0x00000726 }, + { AUD_DEEMPHDENOM1_R, 0x0000F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_DMD_RA_DDS, 0x00C00000 }, + { AUD_PLL_INT, 0x0000001E }, + { AUD_PLL_DDS, 0x00000000 }, + { AUD_PLL_FRAC, 0x0000E542 }, + { AUD_START_TIMER, 0x00000000 }, + { AUD_DEEMPHNUMER1_R, 0x000353DE }, + { AUD_DEEMPHNUMER2_R, 0x000001B1 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x34 }, + { AUD_PHACC_FREQ_8LSB, 0x4C }, + { AUD_DEEMPHGAIN_R, 0x00006680 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + } ; + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); - dprintk("%s (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0004, - 0 /* FIXME */); - set_audio_registers(core, nicam_l); + if (!stereo) { + /* AM mono sound */ + set_audio_start(core, 0x0004, + 0x100c /* FIXME again */); + set_audio_registers(core, nicam_l_mono); + } else { + set_audio_start(core, 0x0010, + 0x1924 /* FIXME again */); + set_audio_registers(core, nicam_l); + } + set_audio_finish(core); + +} + +static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo) +{ + static const struct rlist pal_i_fm_mono[] = { + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x93}, + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000004}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000060}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AAGC_HYST, 0x0000000a}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_DN0_FREQ, 0x000035a3}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_CRDC0_SRC_SEL, 0x00000511}, + {AUD_IIR1_0_SEL, 0x00000001}, + {AUD_IIR1_1_SEL, 0x00000000}, + {AUD_IIR3_2_SEL, 0x00000003}, + {AUD_IIR3_2_SHIFT, 0x00000000}, + {AUD_IIR3_0_SEL, 0x00000002}, + {AUD_IIR2_0_SEL, 0x00000021}, + {AUD_IIR2_0_SHIFT, 0x00000002}, + {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, + {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, + }; + + static const struct rlist pal_i_nicam[] = { + { AUD_RATE_ADJ1, 0x00000010 }, + { AUD_RATE_ADJ2, 0x00000040 }, + { AUD_RATE_ADJ3, 0x00000100 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00001000 }, + // { AUD_DMD_RA_DDS, 0x00c0d5ce }, + { AUD_DEEMPHGAIN_R, 0x000023c2 }, + { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, + { AUD_DEEMPHNUMER2_R, 0x0003023e }, + { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000fff }, + { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, + { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x93 }, + { /* end of list */ }, + }; + + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + // FM mono + set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1); + set_audio_registers(core, pal_i_fm_mono); + } else { + // Nicam Stereo + set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); + set_audio_registers(core, pal_i_nicam); + } set_audio_finish(core); } @@ -553,13 +677,6 @@ static void set_audio_standard_A2(struct set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO); set_audio_registers(core, a2_common); switch (core->tvaudio) { - case WW_NICAM_I: - /* gives at least mono according to the dscaler guys */ - /* so use use that while nicam is broken ... */ - dprintk("%s PAL-I mono (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, a2_table1); - cx_write(AUD_CTL, EN_A2_FORCE_MONO1); - break; case WW_A2_BG: dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__); set_audio_registers(core, a2_table1); @@ -646,11 +763,12 @@ void cx88_set_tvaudio(struct cx88_core * case WW_BTSC: set_audio_standard_BTSC(core,0); break; - // case WW_NICAM_I: case WW_NICAM_BGDKL: - set_audio_standard_NICAM(core); + set_audio_standard_NICAM_L(core,0); break; case WW_NICAM_I: + set_audio_standard_PAL_I(core,0); + break; case WW_A2_BG: case WW_A2_DK: case WW_A2_M: @@ -663,7 +781,7 @@ void cx88_set_tvaudio(struct cx88_core * set_audio_standard_FM(core); break; case WW_SYSTEM_L_AM: - set_audio_standard_NICAM_L(core); + set_audio_standard_NICAM_L(core, 1); break; case WW_NONE: default: @@ -674,6 +792,19 @@ void cx88_set_tvaudio(struct cx88_core * return; } +void cx88_newstation(struct cx88_core *core) +{ + core->audiomode_manual = UNSET; + + switch (core->tvaudio) { + case WW_SYSTEM_L_AM: + /* try nicam ... */ + core->audiomode_current = V4L2_TUNER_MODE_STEREO; + set_audio_standard_NICAM_L(core, 1); + break; + } +} + void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) { static char *m[] = {"stereo", "dual mono", "mono", "sap"}; @@ -721,22 +852,37 @@ void cx88_get_stereo(struct cx88_core *c } break; case WW_NICAM_BGDKL: - if (0 == mode) + if (0 == mode) { t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + } break; + case WW_SYSTEM_L_AM: + if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) { + t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + } + break ; default: - t->rxsubchans = V4L2_TUNER_SUB_MONO; - t->audmode = V4L2_TUNER_MODE_MONO; + /* nothing */ break; } return; } -void cx88_set_stereo(struct cx88_core *core, u32 mode) +void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) { u32 ctl = UNSET; u32 mask = UNSET; + if (manual) { + core->audiomode_manual = mode; + } else { + if (UNSET != core->audiomode_manual) + return; + } + core->audiomode_current = mode; + switch (core->tvaudio) { case WW_BTSC: switch (mode) { @@ -789,6 +935,28 @@ void cx88_set_stereo(struct cx88_core *c break; } break; + case WW_SYSTEM_L_AM: + switch (mode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: /* FIXME */ + set_audio_standard_NICAM_L(core, 0); + break; + case V4L2_TUNER_MODE_STEREO: + set_audio_standard_NICAM_L(core, 1); + break; + } + break; + case WW_NICAM_I: + switch (mode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + set_audio_standard_PAL_I(core, 0); + break; + case V4L2_TUNER_MODE_STEREO: + set_audio_standard_PAL_I(core, 1); + break; + } + break; case WW_FM: switch (mode) { case V4L2_TUNER_MODE_MONO: @@ -804,13 +972,11 @@ void cx88_set_stereo(struct cx88_core *c } if (UNSET != ctl) { - cx_write(AUD_SOFT_RESET, 0x0001); - cx_andor(AUD_CTL, mask, ctl); - cx_write(AUD_SOFT_RESET, 0x0000); dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " "[status=0x%x,ctl=0x%x,vol=0x%x]\n", mask, ctl, cx_read(AUD_STATUS), cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); + cx_andor(AUD_CTL, mask, ctl); } return; } @@ -819,16 +985,32 @@ int cx88_audio_thread(void *data) { struct cx88_core *core = data; struct v4l2_tuner t; + u32 mode = 0; dprintk("cx88: tvaudio thread started\n"); for (;;) { + msleep_interruptible(1000); if (kthread_should_stop()) break; /* just monitor the audio status for now ... */ memset(&t,0,sizeof(t)); cx88_get_stereo(core,&t); - msleep_interruptible(1000); + + if (UNSET != core->audiomode_manual) + /* manually set, don't do anything. */ + continue; + + /* monitor signal */ + if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) + mode = V4L2_TUNER_MODE_STEREO; + else + mode = V4L2_TUNER_MODE_MONO; + if (mode == core->audiomode_current) + continue; + + /* automatically switch to best available mode */ + cx88_set_stereo(core, mode, 0); } dprintk("cx88: tvaudio thread exiting\n"); @@ -838,6 +1020,7 @@ int cx88_audio_thread(void *data) /* ----------------------------------------------------------- */ EXPORT_SYMBOL(cx88_set_tvaudio); +EXPORT_SYMBOL(cx88_newstation); EXPORT_SYMBOL(cx88_set_stereo); EXPORT_SYMBOL(cx88_get_stereo); EXPORT_SYMBOL(cx88_audio_thread); diff -puN drivers/media/video/cx88/cx88-vbi.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-vbi.c --- 25/drivers/media/video/cx88/cx88-vbi.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-vbi.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,8 +1,9 @@ /* - * $Id: cx88-vbi.c,v 1.14 2004/11/07 13:17:15 kraxel Exp $ + * $Id: cx88-vbi.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $ */ #include #include +#include #include #include @@ -64,7 +65,7 @@ int cx8800_start_vbi_dma(struct cx8800_d q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, 0x00fc01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); cx_set(MO_VID_INTMSK, 0x0f0088); /* enable capture */ diff -puN drivers/media/video/cx88/cx88-video.c~v4l-cx88-driver-update drivers/media/video/cx88/cx88-video.c --- 25/drivers/media/video/cx88/cx88-video.c~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/cx88-video.c 2005-03-11 12:32:23.000000000 -0800 @@ -1,5 +1,5 @@ /* - * $Id: cx88-video.c,v 1.46 2004/11/07 14:44:59 kraxel Exp $ + * $Id: cx88-video.c,v 1.58 2005/03/07 15:58:05 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -428,7 +429,7 @@ static int start_video_dma(struct cx8800 q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, 0x00fc01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); cx_set(MO_VID_INTMSK, 0x0f0011); /* enable capture */ @@ -994,7 +995,7 @@ static int video_open(struct inode *inod cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); dev->core->tvaudio = WW_FM; cx88_set_tvaudio(core); - cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO); + cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL); } @@ -1002,7 +1003,7 @@ static int video_open(struct inode *inod } static ssize_t -video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +video_read(struct file *file, char *data, size_t count, loff_t *ppos) { struct cx8800_fh *fh = file->private_data; @@ -1083,6 +1084,8 @@ static int video_release(struct inode *i res_free(dev,fh,RESOURCE_VBI); } + videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&fh->vbiq); file->private_data = NULL; kfree(fh); return 0; @@ -1338,7 +1341,6 @@ static int video_do_ioctl(struct inode * 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; - return 0; } @@ -1429,6 +1431,7 @@ static int video_do_ioctl(struct inode * if (*i >= 4) return -EINVAL; down(&dev->lock); + cx88_newstation(core); video_mux(dev,*i); up(&dev->lock); return 0; @@ -1560,7 +1563,7 @@ static int video_do_ioctl(struct inode * return -EINVAL; if (0 != t->index) return -EINVAL; - cx88_set_stereo(core, t->audmode); + cx88_set_stereo(core, t->audmode, 1); return 0; } case VIDIOC_G_FREQUENCY: @@ -1590,6 +1593,7 @@ static int video_do_ioctl(struct inode * return -EINVAL; down(&dev->lock); dev->freq = f->frequency; + cx88_newstation(core); #ifdef V4L2_I2C_CLIENTS cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f); #else @@ -1880,19 +1884,18 @@ static irqreturn_t cx8800_irq(int irq, v { struct cx8800_dev *dev = dev_id; struct cx88_core *core = dev->core; - u32 status, mask; + u32 status; int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x01); - mask = cx_read(MO_PCI_INTMSK); - if (0 == (status & mask)) + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01); + if (0 == status) goto out; cx_write(MO_PCI_INTSTAT, status); handled = 1; - if (status & mask & ~0x1f) - cx88_irq(core,status,mask); + if (status & core->pci_irqmask) + cx88_core_irq(core,status); if (status & 0x01) cx8800_vid_irq(dev); }; @@ -2055,6 +2058,7 @@ static int __devinit cx8800_initdev(stru core->name,pci_dev->irq); goto fail_core; } + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* load and configure helper modules */ if (TUNER_ABSENT != core->tuner_type) @@ -2156,7 +2160,7 @@ static void __devexit cx8800_finidev(str kfree(dev); } -static int cx8800_suspend(struct pci_dev *pci_dev, u32 state) +static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -2181,7 +2185,7 @@ static int cx8800_suspend(struct pci_dev #endif pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, state)) { + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -2197,7 +2201,7 @@ static int cx8800_resume(struct pci_dev pci_enable_device(pci_dev); dev->state.disabled = 0; } - pci_set_power_state(pci_dev, 0); + pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); #if 1 diff -puN drivers/media/video/cx88/Makefile~v4l-cx88-driver-update drivers/media/video/cx88/Makefile --- 25/drivers/media/video/cx88/Makefile~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/cx88/Makefile 2005-03-11 12:32:23.000000000 -0800 @@ -1,4 +1,5 @@ -cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o +cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ + cx88-input.o cx8800-objs := cx88-video.o cx88-vbi.o cx8802-objs := cx88-mpeg.o diff -puN drivers/media/video/Kconfig~v4l-cx88-driver-update drivers/media/video/Kconfig --- 25/drivers/media/video/Kconfig~v4l-cx88-driver-update 2005-03-11 12:32:23.000000000 -0800 +++ 25-akpm/drivers/media/video/Kconfig 2005-03-11 12:32:23.000000000 -0800 @@ -307,11 +307,14 @@ config VIDEO_HEXIUM_GEMINI config VIDEO_CX88 tristate "Conexant 2388x (bt878 successor) support" - depends on VIDEO_DEV && PCI && EXPERIMENTAL + depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL select I2C_ALGOBIT + select FW_LOADER select VIDEO_BTCX select VIDEO_BUF select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_IR ---help--- This is a video4linux driver for Conexant 2388x based TV cards. @@ -321,10 +324,11 @@ config VIDEO_CX88 config VIDEO_CX88_DVB tristate "DVB Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE && BROKEN + depends on VIDEO_CX88 && DVB_CORE select VIDEO_BUF_DVB + select DVB_MT352 ---help--- - This adds support for DVB cards based on the + This adds support for DVB/ATSC cards based on the Connexant 2388x chip. config VIDEO_OVCAMCHIP _