Skip to content

Commit

Permalink
V4L/DVB (11964): b2c2: Fix problems with frontend attachment
Browse files Browse the repository at this point in the history
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: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Patrick Boettcher <pboettcher@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Trent Piepho authored and Mauro Carvalho Chehab committed Jun 16, 2009
1 parent f6a061b commit eccd15a
Showing 1 changed file with 113 additions and 83 deletions.
196 changes: 113 additions & 83 deletions drivers/media/dvb/b2c2/flexcop-fe-tuner.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,23 +175,23 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
return 0;
}

static void skystar2_rev23_attach(struct flexcop_device *fc,
static int skystar2_rev23_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(mt312_attach,
&skystar23_samsung_tbdu18132_config, i2c);
fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
if (fc->fe != NULL) {
struct dvb_frontend_ops *ops = &fc->fe->ops;
ops->tuner_ops.set_params \
= skystar23_samsung_tbdu18132_tuner_set_params;
ops->tuner_ops.set_params =
skystar23_samsung_tbdu18132_tuner_set_params;
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
ops->set_tone = flexcop_set_tone;
ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;
fc->dev_type = FC_SKY_REV23;
return 1;
}
return 0;
}
#endif

Expand Down Expand Up @@ -307,7 +307,7 @@ static struct stv0299_config samsung_tbmu24112_config = {
.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)
{
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
Expand All @@ -317,7 +317,9 @@ static void skystar2_rev26_attach(struct flexcop_device *fc,
ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;
return 1;
}
return 0;
}
#endif

Expand All @@ -334,43 +336,54 @@ static struct itd1000_config skystar2_rev2_7_itd1000_config = {
.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)
{
flexcop_ibi_value r108;
struct i2c_adapter *i2c_tuner;

/* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(s5h1420_attach,
&skystar2_rev2_7_s5h1420_config, i2c);
if (fc->fe != NULL) {
flexcop_ibi_value r108;
struct i2c_adapter *i2c_tuner \
= s5h1420_get_tuner_i2c_adapter(fc->fe);
struct dvb_frontend_ops *ops = &fc->fe->ops;
fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
i2c);
if (!fc->fe)
goto fail;

fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;

/* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[2].no_base_addr = 1;
if (dvb_attach(isl6421_attach, fc->fe,
&fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
err("ISL6421 could NOT be attached");
else
info("ISL6421 successfully attached");

/* the ITD1000 requires a lower i2c clock - is it a problem ? */
r108.raw = 0x00000506;
fc->write_ibi_reg(fc, tw_sm_c_108, r108);
if (i2c_tuner) {
if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
&skystar2_rev2_7_itd1000_config) == NULL)
err("ITD1000 could NOT be attached");
else
info("ITD1000 successfully attached");
}
} else
fc->fc_i2c_adap[0].no_base_addr = 0;
/* for the next devices we need it again */
i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
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 */
fc->fc_i2c_adap[2].no_base_addr = 1;
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0x08, 1, 1)) {
err("ISL6421 could NOT be attached");
goto fail_isl;
}
info("ISL6421 successfully attached");

/* the ITD1000 requires a lower i2c clock - is it a problem ? */
r108.raw = 0x00000506;
fc->write_ibi_reg(fc, tw_sm_c_108, r108);
if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
&skystar2_rev2_7_itd1000_config)) {
err("ITD1000 could NOT be attached");
/* Should i2c clock be restored? */
goto fail_isl;
}
info("ITD1000 successfully attached");

return 1;

fail_isl:
fc->fc_i2c_adap[2].no_base_addr = 0;
fail:
/* for the next devices we need it again */
fc->fc_i2c_adap[0].no_base_addr = 0;
return 0;
}
#endif

Expand All @@ -387,32 +400,38 @@ static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
.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)
{
fc->fe = dvb_attach(cx24123_attach,
&skystar2_rev2_8_cx24123_config, i2c);
if (fc->fe != NULL) {
struct i2c_adapter *i2c_tuner \
= cx24123_get_tuner_i2c_adapter(fc->fe);
if (i2c_tuner != NULL) {
if (dvb_attach(cx24113_attach, fc->fe,
&skystar2_rev2_8_cx24113_config,
i2c_tuner) == NULL)
err("CX24113 could NOT be attached");
else
info("CX24113 successfully attached");
}
struct i2c_adapter *i2c_tuner;

fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
i2c);
if (!fc->fe)
return 0;

i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
if (!i2c_tuner)
return 0;

fc->fc_i2c_adap[2].no_base_addr = 1;
if (dvb_attach(isl6421_attach, fc->fe,
&fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
err("ISL6421 could NOT be attached");
else
info("ISL6421 successfully attached");
if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
i2c_tuner)) {
err("CX24113 could NOT be attached");
return 0;
}
info("CX24113 successfully attached");

fc->fc_i2c_adap[2].no_base_addr = 1;
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0x08, 0, 0)) {
err("ISL6421 could NOT be attached");
fc->fc_i2c_adap[2].no_base_addr = 0;
return 0;
}
info("ISL6421 successfully attached");
/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
* IR-receiver (PIC16F818) - but the card has no input for that ??? */
}
return 1;
}
#endif

Expand Down Expand Up @@ -466,12 +485,15 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
.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)
{
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;
return 1;
}
return 0;
}
#endif

Expand All @@ -489,10 +511,11 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
.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)
{
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
return fc->fe != NULL;
}
#endif

Expand All @@ -502,13 +525,15 @@ static struct nxt200x_config samsung_tbmv_config = {
.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)
{
fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
if (fc->fe != NULL)
dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
DVB_PLL_SAMSUNG_TBMV);
if (!fc->fe)
return 0;

return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
DVB_PLL_SAMSUNG_TBMV);
}
#endif

Expand All @@ -521,14 +546,15 @@ static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.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)
{
fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
if (fc->fe != NULL) {
dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
TUNER_LG_TDVS_H06XF);
}
if (!fc->fe)
return 0;

return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
TUNER_LG_TDVS_H06XF);
}
#endif

Expand Down Expand Up @@ -659,22 +685,24 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
.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)
{
fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
if (fc->fe != NULL)
fc->fe->ops.tuner_ops.set_params \
= alps_tdee4_stv0297_tuner_set_params;
else
if (!fc->fe) {
/* Reset for next frontend to try */
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

static struct {
flexcop_device_type_t type;
void (*attach)(struct flexcop_device *, struct i2c_adapter *);
int (*attach)(struct flexcop_device *, struct i2c_adapter *);
} flexcop_frontends[] = {
#if defined(CONFIG_DVB_S5H1420_MODULE)
{ FC_SKY_REV27, skystar2_rev27_attach },
Expand Down Expand Up @@ -713,9 +741,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* type needs to be set before, because of some workarounds
* done based on the probed card type */
fc->dev_type = flexcop_frontends[i].type;
flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap);
if (fc->fe != NULL)
if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
goto fe_found;
/* Clean up partially attached frontend */
if (fc->fe) {
dvb_frontend_detach(fc->fe);
fc->fe = NULL;
}
}
fc->dev_type = FC_UNK;
err("no frontend driver found for this B2C2/FlexCop adapter");
Expand All @@ -724,10 +756,8 @@ int flexcop_frontend_init(struct flexcop_device *fc)
fe_found:
info("found '%s' .", fc->fe->ops.info.name);
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
struct dvb_frontend_ops *ops = &fc->fe->ops;
err("frontend registration failed!");
if (ops->release != NULL)
ops->release(fc->fe);
dvb_frontend_detach(fc->fe);
fc->fe = NULL;
return -EINVAL;
}
Expand Down

0 comments on commit eccd15a

Please sign in to comment.