#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;
        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;
 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
                .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;
        }
 
        /* 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:
        {
                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;
                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:
                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:
                        .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:
        {
                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;
                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;
 
        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));
 {
        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) {
        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;
                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 */
                        }
                        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;
 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);