2005-03-08 11:16:38

by Gerd Knorr

[permalink] [raw]
Subject: [patch] v4l: cx88 driver update

Hi,

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 <[email protected]>
---
drivers/media/video/Kconfig | 10
drivers/media/video/cx88/Makefile | 3
drivers/media/video/cx88/cx88-blackbird.c | 27 -
drivers/media/video/cx88/cx88-cards.c | 393 ++++++++++---------
drivers/media/video/cx88/cx88-core.c | 42 +-
drivers/media/video/cx88/cx88-dvb.c | 185 +++++---
drivers/media/video/cx88/cx88-i2c.c | 3
drivers/media/video/cx88/cx88-input.c | 396 +++++++++++++++++++
drivers/media/video/cx88/cx88-mpeg.c | 44 +-
drivers/media/video/cx88/cx88-tvaudio.c | 455 +++++++++++++++-------
drivers/media/video/cx88/cx88-vbi.c | 5
drivers/media/video/cx88/cx88-video.c | 34 -
drivers/media/video/cx88/cx88.h | 38 +
13 files changed, 1189 insertions(+), 446 deletions(-)

Index: linux-2.6.11/drivers/media/video/cx88/cx88-cards.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-cards.c 2005-03-07 10:14:56.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-cards.c 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/pci.h>
#include <linux/delay.h>

-#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 <[email protected]>
+ // 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;
-
- 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;
+ struct tveeprom tv;

- 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;
Index: linux-2.6.11/drivers/media/video/cx88/cx88-core.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-core.c 2005-03-07 10:13:16.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-core.c 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -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);
Index: linux-2.6.11/drivers/media/video/cx88/cx88-blackbird.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-blackbird.c 2005-03-08 10:33:15.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-blackbird.c 2005-03-08 10:33:20.000000000 +0100
@@ -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 <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
@@ -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[] = {
Index: linux-2.6.11/drivers/media/video/Kconfig
===================================================================
--- linux-2.6.11.orig/drivers/media/video/Kconfig 2005-03-07 10:15:21.000000000 +0100
+++ linux-2.6.11/drivers/media/video/Kconfig 2005-03-08 10:33:15.000000000 +0100
@@ -305,11 +305,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.
@@ -319,10 +322,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
Index: linux-2.6.11/drivers/media/video/cx88/cx88-video.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-video.c 2005-03-08 10:33:15.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-video.c 2005-03-08 10:33:20.000000000 +0100
@@ -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 <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -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
Index: linux-2.6.11/drivers/media/video/cx88/cx88-mpeg.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-mpeg.c 2005-03-07 10:16:04.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-mpeg.c 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
@@ -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
Index: linux-2.6.11/drivers/media/video/cx88/cx88-tvaudio.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-tvaudio.c 2005-03-07 10:13:41.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-tvaudio.c 2005-03-08 10:33:20.000000000 +0100
@@ -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 <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -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 },
+ static const struct rlist nicam_l_mono[] = {
+ { AUD_ERRLOGPERIOD_R, 0x00000064 },
+ { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
+ { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
+ { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },

- { 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 },
+ { 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 },

- { /* end of list */ },
- };
+ { 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 },

- dprintk("%s (status: unknown)\n",__FUNCTION__);
- set_audio_start(core, 0x0004,
- 0 /* FIXME */);
- set_audio_registers(core, nicam_l);
+ // 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 */ },
+ };
+
+ 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);
+
+ 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);
Index: linux-2.6.11/drivers/media/video/cx88/cx88-dvb.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-dvb.c 2005-03-08 10:33:15.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-dvb.c 2005-03-08 10:33:20.000000000 +0100
@@ -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 <linux/file.h>
#include <linux/suspend.h>

+/* 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 <[email protected]>");
@@ -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;
+ 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 };

- if (params->frequency == 0) bs = 0x03;
- else if (params->frequency < 157500000) bs = 0x01;
- else if (params->frequency < 443250000) bs = 0x02;
- else bs = 0x04;
+ 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));

- pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */
- pllbuf[1] = div >> 8;
- pllbuf[2] = div & 0xff;
- pllbuf[3] = cp;
- pllbuf[4] = bs;
+ 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)
+static int mt352_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;
+ 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);
- if (dev->dvb.frontend) {
- dev->dvb.frontend->ops->info.frequency_min = 174000000;
- dev->dvb.frontend->ops->info.frequency_max = 862000000;
- }
break;
+#if HAVE_OR51132
+ case CX88_BOARD_PCHDTV_HD3000:
+ dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
+ &dev->core->i2c_adap);
+ 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);
}

/* ----------------------------------------------------------- */
Index: linux-2.6.11/drivers/media/video/cx88/cx88-input.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11/drivers/media/video/cx88/cx88-input.c 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <media/ir-common.h>
+
+#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:
+ */
Index: linux-2.6.11/drivers/media/video/cx88/cx88-vbi.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-vbi.c 2005-03-07 10:13:49.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-vbi.c 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/kernel.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>

@@ -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 */
Index: linux-2.6.11/drivers/media/video/cx88/cx88.h
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88.h 2005-03-07 10:15:48.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88.h 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/kdev_t.h>

#include <media/tuner.h>
+#include <media/tveeprom.h>
#include <media/audiochip.h>
#include <media/video-buf.h>
#include <media/video-buf-dvb.h>
@@ -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);

/*
Index: linux-2.6.11/drivers/media/video/cx88/Makefile
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/Makefile 2005-03-07 10:13:03.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/Makefile 2005-03-08 10:33:15.000000000 +0100
@@ -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

Index: linux-2.6.11/drivers/media/video/cx88/cx88-i2c.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-i2c.c 2005-03-07 10:13:32.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-i2c.c 2005-03-08 10:33:15.000000000 +0100
@@ -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 <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>

#include <asm/io.h>

--
#define printk(args...) fprintf(stderr, ## args)