Commit a07c8779 authored by Michael Krufky's avatar Michael Krufky Committed by Mauro Carvalho Chehab

V4L/DVB (7789): tuner: remove static dependencies on analog tuner sub-modules

Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 4407a463
...@@ -578,16 +578,16 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) ...@@ -578,16 +578,16 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
if ((data == 0x83) || (data == 0x84)) { if ((data == 0x83) || (data == 0x84)) {
priv->ver |= TDA18271; priv->ver |= TDA18271;
tda18271_attach(fe, priv->tda827x_addr, dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
priv->i2c_props.adap, priv->i2c_props.adap, &tda829x_tda18271_config);
&tda829x_tda18271_config);
} else { } else {
if ((data & 0x3c) == 0) if ((data & 0x3c) == 0)
priv->ver |= TDA8275; priv->ver |= TDA8275;
else else
priv->ver |= TDA8275A; priv->ver |= TDA8275A;
tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); dvb_attach(tda827x_attach, fe, priv->tda827x_addr,
priv->i2c_props.adap, &priv->cfg);
priv->cfg.switch_addr = priv->i2c_props.addr; priv->cfg.switch_addr = priv->i2c_props.addr;
} }
if (fe->ops.tuner_ops.init) if (fe->ops.tuner_ops.init)
......
...@@ -33,6 +33,46 @@ ...@@ -33,6 +33,46 @@
#define PREFIX t->i2c->driver->driver.name #define PREFIX t->i2c->driver->driver.name
/** This macro allows us to probe dynamically, avoiding static links */
#ifdef CONFIG_DVB_CORE_ATTACH
#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
int __r = -EINVAL; \
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
if (__a) { \
__r = (int) __a(ARGS); \
} else { \
printk(KERN_ERR "TUNER: Unable to find " \
"symbol "#FUNCTION"()\n"); \
} \
symbol_put(FUNCTION); \
__r; \
})
static void tuner_detach(struct dvb_frontend *fe)
{
if (fe->ops.tuner_ops.release) {
fe->ops.tuner_ops.release(fe);
symbol_put_addr(fe->ops.tuner_ops.release);
}
if (fe->ops.analog_ops.release) {
fe->ops.analog_ops.release(fe);
symbol_put_addr(fe->ops.analog_ops.release);
}
}
#else
#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
FUNCTION(ARGS); \
})
static void tuner_detach(struct dvb_frontend *fe)
{
if (fe->ops.tuner_ops.release)
fe->ops.tuner_ops.release(fe);
if (fe->ops.analog_ops.release)
fe->ops.analog_ops.release(fe);
}
#endif
struct tuner { struct tuner {
/* device */ /* device */
struct dvb_frontend fe; struct dvb_frontend fe;
...@@ -139,22 +179,6 @@ static void fe_set_params(struct dvb_frontend *fe, ...@@ -139,22 +179,6 @@ static void fe_set_params(struct dvb_frontend *fe,
fe_tuner_ops->set_analog_params(fe, params); fe_tuner_ops->set_analog_params(fe, params);
} }
static void fe_release(struct dvb_frontend *fe)
{
if (fe->ops.tuner_ops.release)
fe->ops.tuner_ops.release(fe);
/* DO NOT kfree(fe->analog_demod_priv)
*
* If we are in this function, analog_demod_priv contains a pointer
* to struct tuner *t. This will be kfree'd in tuner_detach().
*
* Otherwise, fe->ops.analog_demod_ops->release will
* handle the cleanup for analog demodulator modules.
*/
fe->analog_demod_priv = NULL;
}
static void fe_standby(struct dvb_frontend *fe) static void fe_standby(struct dvb_frontend *fe)
{ {
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
...@@ -191,7 +215,6 @@ static void tuner_status(struct dvb_frontend *fe); ...@@ -191,7 +215,6 @@ static void tuner_status(struct dvb_frontend *fe);
static struct analog_demod_ops tuner_core_ops = { static struct analog_demod_ops tuner_core_ops = {
.set_params = fe_set_params, .set_params = fe_set_params,
.standby = fe_standby, .standby = fe_standby,
.release = fe_release,
.has_signal = fe_has_signal, .has_signal = fe_has_signal,
.set_config = fe_set_config, .set_config = fe_set_config,
.tuner_status = tuner_status .tuner_status = tuner_status
...@@ -323,7 +346,8 @@ static void attach_tda829x(struct tuner *t) ...@@ -323,7 +346,8 @@ static void attach_tda829x(struct tuner *t)
.lna_cfg = t->config, .lna_cfg = t->config,
.tuner_callback = t->tuner_callback, .tuner_callback = t->tuner_callback,
}; };
tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); dvb_attach(tda829x_attach,
&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
} }
static struct xc5000_config xc5000_cfg; static struct xc5000_config xc5000_cfg;
...@@ -356,12 +380,13 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -356,12 +380,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
} }
/* discard private data, in case set_type() was previously called */ /* discard private data, in case set_type() was previously called */
if (analog_ops->release) tuner_detach(&t->fe);
analog_ops->release(&t->fe); t->fe.analog_demod_priv = NULL;
switch (t->type) { switch (t->type) {
case TUNER_MT2032: case TUNER_MT2032:
microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); dvb_attach(microtune_attach,
&t->fe, t->i2c->adapter, t->i2c->addr);
break; break;
case TUNER_PHILIPS_TDA8290: case TUNER_PHILIPS_TDA8290:
{ {
...@@ -369,12 +394,14 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -369,12 +394,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
break; break;
} }
case TUNER_TEA5767: case TUNER_TEA5767:
if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) if (!dvb_attach(tea5767_attach, &t->fe,
t->i2c->adapter, t->i2c->addr))
goto attach_failed; goto attach_failed;
t->mode_mask = T_RADIO; t->mode_mask = T_RADIO;
break; break;
case TUNER_TEA5761: case TUNER_TEA5761:
if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) if (!dvb_attach(tea5761_attach, &t->fe,
t->i2c->adapter, t->i2c->addr))
goto attach_failed; goto attach_failed;
t->mode_mask = T_RADIO; t->mode_mask = T_RADIO;
break; break;
...@@ -388,8 +415,8 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -388,8 +415,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86; buffer[2] = 0x86;
buffer[3] = 0x54; buffer[3] = 0x54;
i2c_master_send(c, buffer, 4); i2c_master_send(c, buffer, 4);
if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, if (!dvb_attach(simple_tuner_attach, &t->fe,
t->type)) t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed; goto attach_failed;
break; break;
case TUNER_PHILIPS_TD1316: case TUNER_PHILIPS_TD1316:
...@@ -397,9 +424,9 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -397,9 +424,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[1] = 0xdc; buffer[1] = 0xdc;
buffer[2] = 0x86; buffer[2] = 0x86;
buffer[3] = 0xa4; buffer[3] = 0xa4;
i2c_master_send(c,buffer,4); i2c_master_send(c, buffer, 4);
if (!simple_tuner_attach(&t->fe, t->i2c->adapter, if (!dvb_attach(simple_tuner_attach, &t->fe,
t->i2c->addr, t->type)) t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed; goto attach_failed;
break; break;
case TUNER_XC2028: case TUNER_XC2028:
...@@ -409,12 +436,13 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -409,12 +436,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
.i2c_addr = t->i2c->addr, .i2c_addr = t->i2c->addr,
.callback = t->tuner_callback, .callback = t->tuner_callback,
}; };
if (!xc2028_attach(&t->fe, &cfg)) if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
goto attach_failed; goto attach_failed;
break; break;
} }
case TUNER_TDA9887: case TUNER_TDA9887:
tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); dvb_attach(tda9887_attach,
&t->fe, t->i2c->adapter, t->i2c->addr);
break; break;
case TUNER_XC5000: case TUNER_XC5000:
{ {
...@@ -424,7 +452,8 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -424,7 +452,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
xc5000_cfg.if_khz = 5380; xc5000_cfg.if_khz = 5380;
xc5000_cfg.priv = c->adapter->algo_data; xc5000_cfg.priv = c->adapter->algo_data;
xc5000_cfg.tuner_callback = t->tuner_callback; xc5000_cfg.tuner_callback = t->tuner_callback;
if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) if (!dvb_attach(xc5000_attach,
&t->fe, t->i2c->adapter, &xc5000_cfg))
goto attach_failed; goto attach_failed;
xc_tuner_ops = &t->fe.ops.tuner_ops; xc_tuner_ops = &t->fe.ops.tuner_ops;
...@@ -433,8 +462,8 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -433,8 +462,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
break; break;
} }
default: default:
if (!simple_tuner_attach(&t->fe, t->i2c->adapter, if (!dvb_attach(simple_tuner_attach, &t->fe,
t->i2c->addr, t->type)) t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed; goto attach_failed;
break; break;
...@@ -442,12 +471,14 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -442,12 +471,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
if ((NULL == analog_ops->set_params) && if ((NULL == analog_ops->set_params) &&
(fe_tuner_ops->set_analog_params)) { (fe_tuner_ops->set_analog_params)) {
strlcpy(t->i2c->name, fe_tuner_ops->info.name, strlcpy(t->i2c->name, fe_tuner_ops->info.name,
sizeof(t->i2c->name)); sizeof(t->i2c->name));
t->fe.analog_demod_priv = t; t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops, memcpy(analog_ops, &tuner_core_ops,
sizeof(struct analog_demod_ops)); sizeof(struct analog_demod_ops));
} else { } else {
strlcpy(t->i2c->name, analog_ops->info.name, strlcpy(t->i2c->name, analog_ops->info.name,
sizeof(t->i2c->name)); sizeof(t->i2c->name));
...@@ -645,8 +676,8 @@ static void tuner_status(struct dvb_frontend *fe) ...@@ -645,8 +676,8 @@ static void tuner_status(struct dvb_frontend *fe)
{ {
struct tuner *t = fe->analog_demod_priv; struct tuner *t = fe->analog_demod_priv;
unsigned long freq, freq_fraction; unsigned long freq, freq_fraction;
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
const char *p; const char *p;
switch (t->mode) { switch (t->mode) {
...@@ -1113,8 +1144,9 @@ static int tuner_probe(struct i2c_client *client) ...@@ -1113,8 +1144,9 @@ static int tuner_probe(struct i2c_client *client)
if (!no_autodetect) { if (!no_autodetect) {
switch (client->addr) { switch (client->addr) {
case 0x10: case 0x10:
if (tea5761_autodetection(t->i2c->adapter, if (tuner_symbol_probe(tea5761_autodetection,
t->i2c->addr) >= 0) { t->i2c->adapter,
t->i2c->addr) >= 0) {
t->type = TUNER_TEA5761; t->type = TUNER_TEA5761;
t->mode_mask = T_RADIO; t->mode_mask = T_RADIO;
t->mode = T_STANDBY; t->mode = T_STANDBY;
...@@ -1133,8 +1165,8 @@ static int tuner_probe(struct i2c_client *client) ...@@ -1133,8 +1165,8 @@ static int tuner_probe(struct i2c_client *client)
case 0x4b: case 0x4b:
/* If chip is not tda8290, don't register. /* If chip is not tda8290, don't register.
since it can be tda9887*/ since it can be tda9887*/
if (tda829x_probe(t->i2c->adapter, if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
t->i2c->addr) == 0) { t->i2c->addr) == 0) {
tuner_dbg("tda829x detected\n"); tuner_dbg("tda829x detected\n");
} else { } else {
/* Default is being tda9887 */ /* Default is being tda9887 */
...@@ -1146,7 +1178,8 @@ static int tuner_probe(struct i2c_client *client) ...@@ -1146,7 +1178,8 @@ static int tuner_probe(struct i2c_client *client)
} }
break; break;
case 0x60: case 0x60:
if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) if (tuner_symbol_probe(tea5767_autodetection,
t->i2c->adapter, t->i2c->addr)
!= EINVAL) { != EINVAL) {
t->type = TUNER_TEA5767; t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO; t->mode_mask = T_RADIO;
...@@ -1235,10 +1268,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) ...@@ -1235,10 +1268,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
static int tuner_remove(struct i2c_client *client) static int tuner_remove(struct i2c_client *client)
{ {
struct tuner *t = i2c_get_clientdata(client); struct tuner *t = i2c_get_clientdata(client);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
if (analog_ops->release) tuner_detach(&t->fe);
analog_ops->release(&t->fe); t->fe.analog_demod_priv = NULL;
list_del(&t->list); list_del(&t->list);
kfree(t); kfree(t);
......
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