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

Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 6d4b921..578414e 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -33,6 +33,46 @@
 
 #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 {
 	/* device */
 	struct dvb_frontend fe;
@@ -139,22 +179,6 @@
 	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)
 {
 	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -191,7 +215,6 @@
 static struct analog_demod_ops tuner_core_ops = {
 	.set_params     = fe_set_params,
 	.standby        = fe_standby,
-	.release        = fe_release,
 	.has_signal     = fe_has_signal,
 	.set_config     = fe_set_config,
 	.tuner_status   = tuner_status
@@ -323,7 +346,8 @@
 		.lna_cfg        = t->config,
 		.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;
@@ -356,12 +380,13 @@
 	}
 
 	/* discard private data, in case set_type() was previously called */
-	if (analog_ops->release)
-		analog_ops->release(&t->fe);
+	tuner_detach(&t->fe);
+	t->fe.analog_demod_priv = NULL;
 
 	switch (t->type) {
 	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;
 	case TUNER_PHILIPS_TDA8290:
 	{
@@ -369,12 +394,14 @@
 		break;
 	}
 	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;
 		t->mode_mask = T_RADIO;
 		break;
 	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;
 		t->mode_mask = T_RADIO;
 		break;
@@ -388,8 +415,8 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0x54;
 		i2c_master_send(c, buffer, 4);
-		if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
-					t->type))
+		if (!dvb_attach(simple_tuner_attach, &t->fe,
+				t->i2c->adapter, t->i2c->addr, t->type))
 			goto attach_failed;
 		break;
 	case TUNER_PHILIPS_TD1316:
@@ -397,9 +424,9 @@
 		buffer[1] = 0xdc;
 		buffer[2] = 0x86;
 		buffer[3] = 0xa4;
-		i2c_master_send(c,buffer,4);
-		if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
-					t->i2c->addr, t->type))
+		i2c_master_send(c, buffer, 4);
+		if (!dvb_attach(simple_tuner_attach, &t->fe,
+				t->i2c->adapter, t->i2c->addr, t->type))
 			goto attach_failed;
 		break;
 	case TUNER_XC2028:
@@ -409,12 +436,13 @@
 			.i2c_addr  = t->i2c->addr,
 			.callback  = t->tuner_callback,
 		};
-		if (!xc2028_attach(&t->fe, &cfg))
+		if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
 			goto attach_failed;
 		break;
 	}
 	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;
 	case TUNER_XC5000:
 	{
@@ -424,7 +452,8 @@
 		xc5000_cfg.if_khz	  = 5380;
 		xc5000_cfg.priv           = c->adapter->algo_data;
 		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;
 
 		xc_tuner_ops = &t->fe.ops.tuner_ops;
@@ -433,8 +462,8 @@
 		break;
 	}
 	default:
-		if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
-					t->i2c->addr, t->type))
+		if (!dvb_attach(simple_tuner_attach, &t->fe,
+				t->i2c->adapter, t->i2c->addr, t->type))
 			goto attach_failed;
 
 		break;
@@ -442,12 +471,14 @@
 
 	if ((NULL == analog_ops->set_params) &&
 	    (fe_tuner_ops->set_analog_params)) {
+
 		strlcpy(t->i2c->name, fe_tuner_ops->info.name,
 			sizeof(t->i2c->name));
 
 		t->fe.analog_demod_priv = t;
 		memcpy(analog_ops, &tuner_core_ops,
 		       sizeof(struct analog_demod_ops));
+
 	} else {
 		strlcpy(t->i2c->name, analog_ops->info.name,
 			sizeof(t->i2c->name));
@@ -645,8 +676,8 @@
 {
 	struct tuner *t = fe->analog_demod_priv;
 	unsigned long freq, freq_fraction;
-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+	struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
 	const char *p;
 
 	switch (t->mode) {
@@ -1113,8 +1144,9 @@
 	if (!no_autodetect) {
 		switch (client->addr) {
 		case 0x10:
-			if (tea5761_autodetection(t->i2c->adapter,
-						  t->i2c->addr) >= 0) {
+			if (tuner_symbol_probe(tea5761_autodetection,
+					       t->i2c->adapter,
+					       t->i2c->addr) >= 0) {
 				t->type = TUNER_TEA5761;
 				t->mode_mask = T_RADIO;
 				t->mode = T_STANDBY;
@@ -1133,8 +1165,8 @@
 		case 0x4b:
 			/* If chip is not tda8290, don't register.
 			   since it can be tda9887*/
-			if (tda829x_probe(t->i2c->adapter,
-					  t->i2c->addr) == 0) {
+			if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
+					       t->i2c->addr) == 0) {
 				tuner_dbg("tda829x detected\n");
 			} else {
 				/* Default is being tda9887 */
@@ -1146,7 +1178,8 @@
 			}
 			break;
 		case 0x60:
-			if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
+			if (tuner_symbol_probe(tea5767_autodetection,
+					       t->i2c->adapter, t->i2c->addr)
 					!= EINVAL) {
 				t->type = TUNER_TEA5767;
 				t->mode_mask = T_RADIO;
@@ -1235,10 +1268,9 @@
 static int tuner_remove(struct i2c_client *client)
 {
 	struct tuner *t = i2c_get_clientdata(client);
-	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
-	if (analog_ops->release)
-		analog_ops->release(&t->fe);
+	tuner_detach(&t->fe);
+	t->fe.analog_demod_priv = NULL;
 
 	list_del(&t->list);
 	kfree(t);