Commit 66190a27 authored by Oliver Endriss's avatar Oliver Endriss Committed by Mauro Carvalho Chehab

V4L/DVB (3281): av7110 driver: improved recovery from ARM crash and crash detection


- Improved recovery from ARM crash and the way a crash is detected.
Minor white space clean-up, debug output fixed.
Signed-off-by: default avatarOliver Endriss <o.endriss@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent da4ae5a7
......@@ -196,17 +196,15 @@ static void recover_arm(struct av7110 *av7110)
av7110_bootarm(av7110);
msleep(100);
restart_feeds(av7110);
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
}
static void arm_error(struct av7110 *av7110)
{
dprintk(4, "%p\n",av7110);
init_av7110_av(av7110);
av7110->arm_errors++;
av7110->arm_ready = 0;
recover_arm(av7110);
/* card-specific recovery */
if (av7110->recover)
av7110->recover(av7110);
restart_feeds(av7110);
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
}
static void av7110_arm_sync(struct av7110 *av7110)
......@@ -246,26 +244,22 @@ static int arm_thread(void *data)
if (down_interruptible(&av7110->dcomlock))
break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
up(&av7110->dcomlock);
if (newloops == av7110->arm_loops) {
if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
av7110->dvb_adapter.num);
arm_error(av7110);
av7710_set_video_mode(av7110, vidmode);
init_av7110_av(av7110);
recover_arm(av7110);
if (down_interruptible(&av7110->dcomlock))
break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
up(&av7110->dcomlock);
}
av7110->arm_loops = newloops;
av7110->arm_errors = 0;
}
av7110->arm_thread = NULL;
......@@ -516,10 +510,6 @@ static void gpioirq(unsigned long data)
iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
av7110->video_size.h = h_ar & 0xfff;
dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
av7110->video_size.w,
av7110->video_size.h,
av7110->video_size.aspect_ratio);
event.type = VIDEO_EVENT_SIZE_CHANGED;
event.u.size.w = av7110->video_size.w;
......@@ -541,6 +531,11 @@ static void gpioirq(unsigned long data)
event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
av7110->videostate.video_format = VIDEO_FORMAT_4_3;
}
dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
av7110->video_size.w, av7110->video_size.h,
av7110->video_size.aspect_ratio);
dvb_video_add_event(av7110, &event);
break;
}
......@@ -1054,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110)
struct dvb_demux *dvbdmx = &av7110->demux;
struct dvb_demux_feed *feed;
int mode;
int i;
int i, j;
dprintk(4, "%p\n", av7110);
......@@ -1062,11 +1057,22 @@ static void restart_feeds(struct av7110 *av7110)
av7110->playing = 0;
av7110->rec_mode = 0;
for (i = 0; i < dvbdmx->filternum; i++) {
for (i = 0; i < dvbdmx->feednum; i++) {
feed = &dvbdmx->feed[i];
if (feed->state == DMX_STATE_GO)
if (feed->state == DMX_STATE_GO) {
if (feed->type == DMX_TYPE_SEC) {
for (j = 0; j < dvbdmx->filternum; j++) {
if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
continue;
if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
continue;
if (dvbdmx->filter[j].state == DMX_STATE_GO)
dvbdmx->filter[j].state = DMX_STATE_READY;
}
}
av7110_start_feed(feed);
}
}
if (mode)
av7110_av_start_play(av7110, mode);
......@@ -2121,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret)
if (!ret) {
av7110->saved_fe_params = *params;
ret = av7110->fe_set_frontend(fe, params);
}
return ret;
}
......@@ -2164,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret)
if (!ret) {
av7110->saved_master_cmd = *cmd;
ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
}
return ret;
}
......@@ -2174,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret)
if (!ret) {
av7110->saved_minicmd = minicmd;
ret = av7110->fe_diseqc_send_burst(fe, minicmd);
}
return ret;
}
......@@ -2184,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret)
if (!ret) {
av7110->saved_tone = tone;
ret = av7110->fe_set_tone(fe, tone);
}
return ret;
}
......@@ -2194,8 +2208,10 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret)
if (!ret) {
av7110->saved_voltage = voltage;
ret = av7110->fe_set_voltage(fe, voltage);
}
return ret;
}
......@@ -2209,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
return ret;
}
static void dvb_s_recover(struct av7110* av7110)
{
av7110_fe_init(av7110->fe);
av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
if (av7110->saved_master_cmd.msg_len) {
msleep(20);
av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
}
msleep(20);
av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
msleep(20);
av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
}
static u8 read_pwm(struct av7110* av7110)
{
u8 b = 0xff;
......@@ -2246,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
......@@ -2255,6 +2289,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
......@@ -2264,6 +2299,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
......@@ -2300,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
......@@ -2328,6 +2365,7 @@ static int frontend_init(struct av7110 *av7110)
if (av7110->fe) {
av7110->fe->ops->set_voltage = lnbp21_set_voltage;
av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
av7110->recover = dvb_s_recover;
}
break;
}
......
......@@ -246,6 +246,15 @@ struct av7110 {
struct dvb_frontend* fe;
fe_status_t fe_status;
/* crash recovery */
void (*recover)(struct av7110* av7110);
struct dvb_frontend_parameters saved_fe_params;
fe_sec_voltage_t saved_voltage;
fe_sec_tone_mode_t saved_tone;
struct dvb_diseqc_master_cmd saved_master_cmd;
fe_sec_mini_cmd_t saved_minicmd;
int (*fe_init)(struct dvb_frontend* fe);
int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
......
......@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
dprintk(4, "%p\n", av7110);
av7110->arm_ready = 0;
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
/* Disable DEBI and GPIO irq */
......@@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
break;
if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
av7110->arm_errors++;
return -ETIMEDOUT;
}
msleep(1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment