Hi, bear with me and hopefully we can get this blasted card fixed once and for all. I can test the DVBT cards, and you guys can test DVBS and DVBC respectively. So, attached is a patch (against hg latest) which attempts to fix the following: 1) rewrite cam detection code to work more reliably. 2) reinitialise the tda10046 after cam reset. 3) set the tda10021 into the correct transport stream mode depending on whether the CAM is in or out. 4) Don't reinitialise the tda10021 or stv0299 on cam reset. Can you let me know how it goes. I _really_ want to get this sorted, it seems to keep coming back :( Please reply to this thread so we can keep track of how things are going.
diff -r 0a8f56ab07fa linux/drivers/media/dvb/frontends/tda10021.c --- a/linux/drivers/media/dvb/frontends/tda10021.c Mon Apr 17 16:44:02 2006 -0300 +++ b/linux/drivers/media/dvb/frontends/tda10021.c Fri Apr 21 00:09:34 2006 +0100 @@ -89,6 +89,14 @@ static int tda10021_writereg (struct tda msleep(10); return (ret != 1) ? -EREMOTEIO : 0; } + +int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data) +{ + struct tda10021_state* state = fe->demodulator_priv; + + return tda10021_writereg(state, reg, data); +} +EXPORT_SYMBOL(tda10021_write_byte); static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) { diff -r 0a8f56ab07fa linux/drivers/media/dvb/frontends/tda10021.h --- a/linux/drivers/media/dvb/frontends/tda10021.h Mon Apr 17 16:44:02 2006 -0300 +++ b/linux/drivers/media/dvb/frontends/tda10021.h Fri Apr 21 00:09:34 2006 +0100 @@ -39,4 +39,6 @@ extern struct dvb_frontend* tda10021_att extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct i2c_adapter* i2c, u8 pwm); +extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data); + #endif // TDA10021_H diff -r 0a8f56ab07fa linux/drivers/media/dvb/ttpci/budget-av.c --- a/linux/drivers/media/dvb/ttpci/budget-av.c Mon Apr 17 16:44:02 2006 -0300 +++ b/linux/drivers/media/dvb/ttpci/budget-av.c Fri Apr 21 00:09:34 2006 +0100 @@ -50,6 +50,12 @@ #define DEBICICAM 0x02420000 +#define SLOTSTATUS_NONE 1 +#define SLOTSTATUS_PRESENT 2 +#define SLOTSTATUS_RESET 4 +#define SLOTSTATUS_READY 8 +#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) + struct budget_av { struct budget budget; struct video_device *vd; @@ -58,6 +64,10 @@ struct budget_av { struct tasklet_struct ciintf_irq_tasklet; int slot_status; struct dvb_ca_en50221 ca; + int reinitialise_demod; + int tda10021_poclkp; + int tda10021_ts_enabled; + int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); }; /* GPIO Connections: @@ -120,7 +130,6 @@ static int ciintf_read_attribute_mem(str static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) { struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; if (slot != 0) return -EINVAL; @@ -128,17 +137,12 @@ static int ciintf_read_attribute_mem(str saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; - return result; + return ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); } static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) { struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; if (slot != 0) return -EINVAL; @@ -146,17 +150,12 @@ static int ciintf_write_attribute_mem(st saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; - return result; + return ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); } static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) { struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; if (slot != 0) return -EINVAL; @@ -164,17 +163,12 @@ static int ciintf_read_cam_control(struc saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); udelay(1); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; - return result; + return ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); } static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) { struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; if (slot != 0) return -EINVAL; @@ -182,23 +176,19 @@ static int ciintf_write_cam_control(stru saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); udelay(1); - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; - return result; + return ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); } static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int timeout = 50; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; dprintk(1, "ciintf_slot_reset\n"); + budget_av->slot_status = SLOTSTATUS_RESET; saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ @@ -208,20 +198,16 @@ static int ciintf_slot_reset(struct dvb_ msleep(20); /* 20 ms Vcc settling time */ saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ - - /* This should have been based on pin 16 READY of the pcmcia port, - * but AFAICS it is not routed to the saa7146 */ - while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) - msleep(100); - - /* reinitialise the frontend */ - dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); - - if (timeout <= 0) - { - printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - return -ETIMEDOUT; + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + msleep(20); + + /* reinitialise the frontend if necessary */ + if (budget_av->reinitialise_demod) + dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + + /* setup tda10021 if necessary */ + if (budget_av->tda10021_poclkp && budget_av->tda10021_ts_enabled) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); } return 0; @@ -237,8 +223,15 @@ static int ciintf_slot_shutdown(struct d dprintk(1, "ciintf_slot_shutdown\n"); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - budget_av->slot_status = 0; + budget_av->slot_status = SLOTSTATUS_NONE; + + /* set tda10021 back to original clock configuration when cam removed */ + if (budget_av->tda10021_poclkp) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); + budget_av->tda10021_ts_enabled = 0; + } return 0; } @@ -253,6 +246,13 @@ static int ciintf_slot_ts_enable(struct dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + + /* tda10021 seems to need a different TS clock config when data is routed to the CAM */ + if (budget_av->tda10021_poclkp) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); + budget_av->tda10021_ts_enabled = 1; + } + return 0; } @@ -260,50 +260,44 @@ static int ciintf_poll_slot_status(struc { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int cam_present = 0; if (slot != 0) return -EINVAL; - if (!budget_av->slot_status) - { - // first of all test the card detect line - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - udelay(1); - if (saa7146_read(saa, PSR) & MASK_06) - { - cam_present = 1; + /* we used to test the card detect line here, but that doesn't work + * with some cams on this interface (e.g. topuptv), so it was removed. + * Instead we try and read from IO memory. If there is no CAM, we will + * get a timeout. */ + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) { + if (budget_av->slot_status == SLOTSTATUS_NONE) { + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ + budget_av->slot_status = SLOTSTATUS_PRESENT; + printk(KERN_INFO "budget-av: cam inserted\n"); } - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - - // that is unreliable however, so try and read from IO memory - if (!cam_present) - { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) - { - cam_present = 1; + } else { + if (budget_av->slot_status != SLOTSTATUS_NONE) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected\n"); + } + } + + /* during a reset, read from the attribute memory to know when CAM is ready */ + if (budget_av->slot_status & SLOTSTATUS_RESET) { + if (budget_av->slot_status & SLOTSTATUS_RESET) { + if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { + budget_av->slot_status = SLOTSTATUS_READY; } } - - // did we find something? - if (cam_present) { - printk(KERN_INFO "budget-av: cam inserted\n"); - budget_av->slot_status = 1; + } + + /* work out correct return code */ + if (budget_av->slot_status != SLOTSTATUS_NONE) { + if (budget_av->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; } - } else if (!open) { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) - { - printk(KERN_INFO "budget-av: cam ejected\n"); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - budget_av->slot_status = 0; - } - } - - if (budget_av->slot_status == 1) - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } return 0; } @@ -333,6 +327,8 @@ static int ciintf_init(struct budget_av budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_av->ca.poll_slot_status = ciintf_poll_slot_status; budget_av->ca.data = budget_av; + budget_av->budget.ci_present = 1; + budget_av->slot_status = SLOTSTATUS_NONE; if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, &budget_av->ca, 0, 1)) != 0) { @@ -341,7 +337,6 @@ static int ciintf_init(struct budget_av } printk(KERN_INFO "budget-av: ci interface initialised.\n"); - budget_av->budget.ci_present = 1; return 0; error: @@ -1012,6 +1007,23 @@ static u8 read_pwm(struct budget_av *bud #define SUBID_DVBT_KNC1 0x0030 #define SUBID_DVBT_CINERGY1200 0x1157 + +static int tda10021_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct budget_av* budget_av = fe->dvb->priv; + int result; + + result = budget_av->tda10021_set_frontend(fe, p); + if (budget_av->tda10021_ts_enabled) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); + } else { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); + } + + return result; +} + static void frontend_init(struct budget_av *budget_av) { struct saa7146_dev * saa = budget_av->budget.dev; @@ -1065,10 +1077,14 @@ static void frontend_init(struct budget_ fe = tda10021_attach(&philips_cu1216_config, &budget_av->budget.i2c_adap, read_pwm(budget_av)); + budget_av->tda10021_poclkp = 1; + budget_av->tda10021_set_frontend = fe->ops->set_frontend; + fe->ops->set_frontend = tda10021_set_frontend; break; case SUBID_DVBT_KNC1: case SUBID_DVBT_KNC1_PLUS: + budget_av->reinitialise_demod = 1; fe = tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); break;
_______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb