Commit eccd15aa authored by Trent Piepho's avatar Trent Piepho Committed by Mauro Carvalho Chehab

V4L/DVB (11964): b2c2: Fix problems with frontend attachment

The frontend attachment code didn't handle cases where the frontend
partially failed to attach.  For instance, when the demod was attached
successfully but the tuner driver wasn't compiled or fails to init for some
reason.  In these cases we try to clean up the partial attachment and fail
instead of proceeding with a broken frontend.

If frontend registration fails, clean up with dvb_frontend_detach() rather
than just calling the frontend's main release method.  The former does some
additional stuff, like release an attached tuner and take care of putting
symbols when dynamic binding is used.

In skystar2_rev23_attach() it's not necessary to set fc->dev_type, that
gets set before skystar2_rev23_attach() is called.
Signed-off-by: default avatarTrent Piepho <xyzzy@speakeasy.org>
Signed-off-by: default avatarPatrick Boettcher <pboettcher@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent f6a061bb
...@@ -175,23 +175,23 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe, ...@@ -175,23 +175,23 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
return 0; return 0;
} }
static void skystar2_rev23_attach(struct flexcop_device *fc, static int skystar2_rev23_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(mt312_attach, fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
&skystar23_samsung_tbdu18132_config, i2c);
if (fc->fe != NULL) { if (fc->fe != NULL) {
struct dvb_frontend_ops *ops = &fc->fe->ops; struct dvb_frontend_ops *ops = &fc->fe->ops;
ops->tuner_ops.set_params \ ops->tuner_ops.set_params =
= skystar23_samsung_tbdu18132_tuner_set_params; skystar23_samsung_tbdu18132_tuner_set_params;
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
ops->diseqc_send_burst = flexcop_diseqc_send_burst; ops->diseqc_send_burst = flexcop_diseqc_send_burst;
ops->set_tone = flexcop_set_tone; ops->set_tone = flexcop_set_tone;
ops->set_voltage = flexcop_set_voltage; ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep; fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep; ops->sleep = flexcop_sleep;
fc->dev_type = FC_SKY_REV23; return 1;
} }
return 0;
} }
#endif #endif
...@@ -307,7 +307,7 @@ static struct stv0299_config samsung_tbmu24112_config = { ...@@ -307,7 +307,7 @@ static struct stv0299_config samsung_tbmu24112_config = {
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate, .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
}; };
static void skystar2_rev26_attach(struct flexcop_device *fc, static int skystar2_rev26_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
...@@ -317,7 +317,9 @@ static void skystar2_rev26_attach(struct flexcop_device *fc, ...@@ -317,7 +317,9 @@ static void skystar2_rev26_attach(struct flexcop_device *fc,
ops->set_voltage = flexcop_set_voltage; ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep; fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep; ops->sleep = flexcop_sleep;
return 1;
} }
return 0;
} }
#endif #endif
...@@ -334,43 +336,54 @@ static struct itd1000_config skystar2_rev2_7_itd1000_config = { ...@@ -334,43 +336,54 @@ static struct itd1000_config skystar2_rev2_7_itd1000_config = {
.i2c_address = 0x61, .i2c_address = 0x61,
}; };
static void skystar2_rev27_attach(struct flexcop_device *fc, static int skystar2_rev27_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
flexcop_ibi_value r108;
struct i2c_adapter *i2c_tuner;
/* enable no_base_addr - no repeated start when reading */ /* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[0].no_base_addr = 1; fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(s5h1420_attach, fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
&skystar2_rev2_7_s5h1420_config, i2c); i2c);
if (fc->fe != NULL) { if (!fc->fe)
flexcop_ibi_value r108; goto fail;
struct i2c_adapter *i2c_tuner \
= s5h1420_get_tuner_i2c_adapter(fc->fe);
struct dvb_frontend_ops *ops = &fc->fe->ops;
fc->fe_sleep = ops->sleep; i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
ops->sleep = flexcop_sleep; if (!i2c_tuner)
goto fail;
fc->fe_sleep = fc->fe->ops.sleep;
fc->fe->ops.sleep = flexcop_sleep;
/* enable no_base_addr - no repeated start when reading */ /* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[2].no_base_addr = 1; fc->fc_i2c_adap[2].no_base_addr = 1;
if (dvb_attach(isl6421_attach, fc->fe, if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
&fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL) 0x08, 1, 1)) {
err("ISL6421 could NOT be attached"); err("ISL6421 could NOT be attached");
else goto fail_isl;
}
info("ISL6421 successfully attached"); info("ISL6421 successfully attached");
/* the ITD1000 requires a lower i2c clock - is it a problem ? */ /* the ITD1000 requires a lower i2c clock - is it a problem ? */
r108.raw = 0x00000506; r108.raw = 0x00000506;
fc->write_ibi_reg(fc, tw_sm_c_108, r108); fc->write_ibi_reg(fc, tw_sm_c_108, r108);
if (i2c_tuner) { if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config)) {
&skystar2_rev2_7_itd1000_config) == NULL)
err("ITD1000 could NOT be attached"); err("ITD1000 could NOT be attached");
else /* Should i2c clock be restored? */
info("ITD1000 successfully attached"); goto fail_isl;
} }
} else info("ITD1000 successfully attached");
fc->fc_i2c_adap[0].no_base_addr = 0;
return 1;
fail_isl:
fc->fc_i2c_adap[2].no_base_addr = 0;
fail:
/* for the next devices we need it again */ /* for the next devices we need it again */
fc->fc_i2c_adap[0].no_base_addr = 0;
return 0;
} }
#endif #endif
...@@ -387,32 +400,38 @@ static const struct cx24113_config skystar2_rev2_8_cx24113_config = { ...@@ -387,32 +400,38 @@ static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
.xtal_khz = 10111, .xtal_khz = 10111,
}; };
static void skystar2_rev28_attach(struct flexcop_device *fc, static int skystar2_rev28_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(cx24123_attach, struct i2c_adapter *i2c_tuner;
&skystar2_rev2_8_cx24123_config, i2c);
if (fc->fe != NULL) { fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
struct i2c_adapter *i2c_tuner \ i2c);
= cx24123_get_tuner_i2c_adapter(fc->fe); if (!fc->fe)
if (i2c_tuner != NULL) { return 0;
if (dvb_attach(cx24113_attach, fc->fe,
&skystar2_rev2_8_cx24113_config, i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
i2c_tuner) == NULL) if (!i2c_tuner)
return 0;
if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
i2c_tuner)) {
err("CX24113 could NOT be attached"); err("CX24113 could NOT be attached");
else return 0;
info("CX24113 successfully attached");
} }
info("CX24113 successfully attached");
fc->fc_i2c_adap[2].no_base_addr = 1; fc->fc_i2c_adap[2].no_base_addr = 1;
if (dvb_attach(isl6421_attach, fc->fe, if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
&fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) 0x08, 0, 0)) {
err("ISL6421 could NOT be attached"); err("ISL6421 could NOT be attached");
else fc->fc_i2c_adap[2].no_base_addr = 0;
return 0;
}
info("ISL6421 successfully attached"); info("ISL6421 successfully attached");
/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
* IR-receiver (PIC16F818) - but the card has no input for that ??? */ * IR-receiver (PIC16F818) - but the card has no input for that ??? */
} return 1;
} }
#endif #endif
...@@ -466,12 +485,15 @@ static struct mt352_config samsung_tdtc9251dh0_config = { ...@@ -466,12 +485,15 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_init = samsung_tdtc9251dh0_demod_init, .demod_init = samsung_tdtc9251dh0_demod_init,
}; };
static void airstar_dvbt_attach(struct flexcop_device *fc, static int airstar_dvbt_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
if (fc->fe != NULL) if (fc->fe != NULL) {
fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
return 1;
}
return 0;
} }
#endif #endif
...@@ -489,10 +511,11 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = { ...@@ -489,10 +511,11 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
.request_firmware = flexcop_fe_request_firmware, .request_firmware = flexcop_fe_request_firmware,
}; };
static void airstar_atsc1_attach(struct flexcop_device *fc, static int airstar_atsc1_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
return fc->fe != NULL;
} }
#endif #endif
...@@ -502,12 +525,14 @@ static struct nxt200x_config samsung_tbmv_config = { ...@@ -502,12 +525,14 @@ static struct nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a, .demod_address = 0x0a,
}; };
static void airstar_atsc2_attach(struct flexcop_device *fc, static int airstar_atsc2_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
if (fc->fe != NULL) if (!fc->fe)
dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, return 0;
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
DVB_PLL_SAMSUNG_TBMV); DVB_PLL_SAMSUNG_TBMV);
} }
#endif #endif
...@@ -521,14 +546,15 @@ static struct lgdt330x_config air2pc_atsc_hd5000_config = { ...@@ -521,14 +546,15 @@ static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.clock_polarity_flip = 1, .clock_polarity_flip = 1,
}; };
static void airstar_atsc3_attach(struct flexcop_device *fc, static int airstar_atsc3_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
if (fc->fe != NULL) { if (!fc->fe)
dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, return 0;
return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
TUNER_LG_TDVS_H06XF); TUNER_LG_TDVS_H06XF);
}
} }
#endif #endif
...@@ -659,22 +685,24 @@ static struct stv0297_config alps_tdee4_stv0297_config = { ...@@ -659,22 +685,24 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
.inittab = alps_tdee4_stv0297_inittab, .inittab = alps_tdee4_stv0297_inittab,
}; };
static void cablestar2_attach(struct flexcop_device *fc, static int cablestar2_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c) struct i2c_adapter *i2c)
{ {
fc->fc_i2c_adap[0].no_base_addr = 1; fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
if (fc->fe != NULL) if (!fc->fe) {
fc->fe->ops.tuner_ops.set_params \ /* Reset for next frontend to try */
= alps_tdee4_stv0297_tuner_set_params;
else
fc->fc_i2c_adap[0].no_base_addr = 0; fc->fc_i2c_adap[0].no_base_addr = 0;
return 0;
}
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
return 1;
} }
#endif #endif
static struct { static struct {
flexcop_device_type_t type; flexcop_device_type_t type;
void (*attach)(struct flexcop_device *, struct i2c_adapter *); int (*attach)(struct flexcop_device *, struct i2c_adapter *);
} flexcop_frontends[] = { } flexcop_frontends[] = {
#if defined(CONFIG_DVB_S5H1420_MODULE) #if defined(CONFIG_DVB_S5H1420_MODULE)
{ FC_SKY_REV27, skystar2_rev27_attach }, { FC_SKY_REV27, skystar2_rev27_attach },
...@@ -713,9 +741,13 @@ int flexcop_frontend_init(struct flexcop_device *fc) ...@@ -713,9 +741,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* type needs to be set before, because of some workarounds /* type needs to be set before, because of some workarounds
* done based on the probed card type */ * done based on the probed card type */
fc->dev_type = flexcop_frontends[i].type; fc->dev_type = flexcop_frontends[i].type;
flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap); if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
if (fc->fe != NULL)
goto fe_found; goto fe_found;
/* Clean up partially attached frontend */
if (fc->fe) {
dvb_frontend_detach(fc->fe);
fc->fe = NULL;
}
} }
fc->dev_type = FC_UNK; fc->dev_type = FC_UNK;
err("no frontend driver found for this B2C2/FlexCop adapter"); err("no frontend driver found for this B2C2/FlexCop adapter");
...@@ -724,10 +756,8 @@ int flexcop_frontend_init(struct flexcop_device *fc) ...@@ -724,10 +756,8 @@ int flexcop_frontend_init(struct flexcop_device *fc)
fe_found: fe_found:
info("found '%s' .", fc->fe->ops.info.name); info("found '%s' .", fc->fe->ops.info.name);
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
struct dvb_frontend_ops *ops = &fc->fe->ops;
err("frontend registration failed!"); err("frontend registration failed!");
if (ops->release != NULL) dvb_frontend_detach(fc->fe);
ops->release(fc->fe);
fc->fe = NULL; fc->fe = NULL;
return -EINVAL; return -EINVAL;
} }
......
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