#include "mt2063.h"
 #include "dvb_ca_en50221.h"
 
+/* HACK: Should be moved to the right place */
+#define USB_PID_AZUREWAVE_6007         0xccd
+#define USB_PID_TERRATEC_H7            0x10b4
+
 /* debug */
 int dvb_usb_az6007_debug;
 module_param_named(debug,dvb_usb_az6007_debug, int, 0644);
        struct dvb_ca_en50221 ca;
        struct mutex ca_mutex;
        u8 power_state;
-};
 
-struct drxk3913_config az6007_drxk3913_config_DVBT = { 
-       .demod_address = 0x52,
-       .min_delay_ms = 100,
-       .standard       = MTTUNEA_DVBT,
-       .set_tuner = mt2063_setTune,
-       .tuner_getlocked = mt2063_lockStatus,
-       .tuner_MT2063_Open = tuner_MT2063_Open,
-       .tuner_MT2063_SoftwareShutdown = tuner_MT2063_SoftwareShutdown,
-       .tuner_MT2063_ClearPowerMaskBits = tuner_MT2063_ClearPowerMaskBits,
+       /* Due to DRX-K - probably need changes */
+       int (*gate_ctrl)(struct dvb_frontend *, int);
+       struct semaphore      pll_mutex;
+       bool                    dont_attach_fe1;
 };
 
-struct drxk3913_config az6007_drxk3913_config_DVBC = { 
-       .demod_address = 0x52,
-       .min_delay_ms = 100,
-       .standard       = MTTUNEA_DVBC,
-       .set_tuner = mt2063_setTune,
-       .tuner_getlocked = mt2063_lockStatus,
-       .tuner_MT2063_Open = tuner_MT2063_Open,
-       .tuner_MT2063_SoftwareShutdown = tuner_MT2063_SoftwareShutdown,
-       .tuner_MT2063_ClearPowerMaskBits = tuner_MT2063_ClearPowerMaskBits,
+struct drxk_config terratec_h7_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .no_i2c_bridge = 1,
+       .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
 };
 
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct dvb_usb_adapter *adap = fe->sec_priv;
+       struct az6007_device_state *st = adap->priv;
+       int status;
+
+       if (!adap || !st)
+               return -EINVAL;
+
+       if (enable) {
+               down(&st->pll_mutex);
+               status = st->gate_ctrl(fe, 1);
+       } else {
+               status = st->gate_ctrl(fe, 0);
+               up(&st->pll_mutex);
+       }
+       return status;
+}
+
 struct mt2063_config az6007_mt2063_config = {
        .tuner_address = 0xc0,
        .refclock = 36125000,
 {
        int ret;
 
-#if 0  
+#if 0
        int i=0, cyc=0, rem=0;
        cyc = blen/64;
        rem = blen%64;
        deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
        debug_dump(b,blen,deb_xfer);
 
-       
+
 #if 0
        if (blen>64)
        {
                                5000)) != 64) {
                                warn("usb out operation failed. (%d)",ret);
                                return -EIO;
-                       }       
+                       }
                }
 
                if (rem>0)
                }
        }
        else
-#endif         
+#endif
        {
                if ((ret = usb_control_msg(d->udev,
                                usb_sndctrlpipe(d->udev,0),
                        return -EIO;
                }
        }
-       
+
        return 0;
 }
 
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key az6007_rc_keys[] = {
-       { 0x00, 0x01, KEY_1 },
-       { 0x00, 0x02, KEY_2 },
+struct rc_map_table rc_map_az6007_table[] = {
+       { 0x0001, KEY_1 },
+       { 0x0002, KEY_2 },
 };
 
 /* remote control stuff (does not work with my box) */
        int i;
 
 /* remove the following return to enabled remote querying */
-       
+
 
        az6007_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
 
        int blen;
 
        info("az6007_frontend_reset adap=%p adap->dev=%p\n", adap, adap->dev);
-       
+
        //reset demodulator
        req = 0xC0;
        value = 1;//high
                err("az6007_frontend_reset failed 1 !!!");
                   return -EIO;
        }
-       
+
        req = 0xC0;
        value = 0;//low
        index = 3;
                err("az6007_frontend_reset failed 3 !!!");
                   return -EIO;
        }
-       
+
        msleep_interruptible(200);
-       
+
        info("reset az6007 frontend\n");
-       
+
        return 0;
 }
 
 
 static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
 {
+       struct az6007_device_state *st = adap->priv;
+
+       int result;
+
        az6007_frontend_poweron(adap);
        az6007_frontend_reset(adap);
 
        info("az6007_frontend_attach\n");
 
-       if (az6007_type == 0)
-       {
-               info("az6007_drxk3913_config_DVBT\n");
-               adap->fe = drxk3913_attach(&az6007_drxk3913_config_DVBT, &adap->dev->i2c_adap);
+       adap->fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
+                             &adap->dev->i2c_adap, &adap->fe2);
+       if (!adap->fe) {
+               result = -EINVAL;
+               goto out_free;
        }
-       else
-       {
-               info("az6007_drxk3913_config_DVBC\n");
-               adap->fe = drxk3913_attach(&az6007_drxk3913_config_DVBC, &adap->dev->i2c_adap);
-       }
-       if (adap->fe) {         
-               if (mt2063_attach(adap->fe, &az6007_mt2063_config, &adap->dev->i2c_adap)) {
-                       info("found STB6100 DVB-C/DVB-T frontend @0x%02x\n",az6007_mt2063_config.tuner_address);
-                       
-                       //vp6027_ci_init(adap);
-               } else {
-                       adap->fe = NULL;
-               }
-       }
-       else
-       {
-               adap->fe = NULL;        
-               err("no front-end attached\n");
+
+       /* FIXME: do we need a pll semaphore? */
+       adap->fe->sec_priv = adap;
+       sema_init(&st->pll_mutex, 1);
+       st->gate_ctrl = adap->fe->ops.i2c_gate_ctrl;
+       adap->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       adap->fe2->id = 1;
+
+       /* Attach mt2063 to DVB-C frontend */
+       if (adap->fe->ops.i2c_gate_ctrl)
+               adap->fe->ops.i2c_gate_ctrl(adap->fe, 1);
+       if (!dvb_attach(mt2063_attach, adap->fe, &az6007_mt2063_config,
+                       &adap->dev->i2c_adap)) {
+               result = -EINVAL;
+
+               goto out_free;
        }
-       //az6007_frontend_tsbypass(adap,0);
-       
+       if (adap->fe->ops.i2c_gate_ctrl)
+               adap->fe->ops.i2c_gate_ctrl(adap->fe, 0);
+
+       /* Hack - needed due to drxk */
+       adap->fe2->tuner_priv = adap->fe->tuner_priv;
+       memcpy(&adap->fe2->ops.tuner_ops,
+              &adap->fe->ops.tuner_ops,
+              sizeof(adap->fe->ops.tuner_ops));
        return 0;
+
+out_free:
+       if (adap->fe)
+               dvb_frontend_detach(adap->fe);
+       adap->fe = NULL;
+       adap->fe2 = NULL;
+
+       return result;
 }
 
 static struct dvb_usb_device_properties az6007_properties;
        int length;
        u8 req;
        u8 data[512];
-       
+
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
        if (num > 2)
                        //printk("Tuner Tuner ReadDATA len=%d ", len);
                        for (j=0; j<len; j++)
                        {
-                               msg[1].buf[j] = data[j+5];      
+                               msg[1].buf[j] = data[j+5];
                                //printk("data[%d]=%02x ", j, data[j+5]);
                        }
                        //printk("\n");
                        value = msg[0].addr | (1<<8);
                        length = msg[0].len - 1;
                        len = msg[0].len - 1;
-                       //printk("Demodulator WriteDATA len=%d ", len);                 
+                       //printk("Demodulator WriteDATA len=%d ", len);
                        for(j=0;j<len;j++)
                        {
                                data[j] = msg[0].buf[j+1];
                                //printk("data[%d]=%02x ", j, data[j]);
                        }
-                       //printk("\n");                 
+                       //printk("\n");
                        ret = az6007_usb_out_op(d,req,value,index,data,length);
                }
                else //read
                        //printk("Demodulator ReadDATA len=%d ", len);
                        for (j=0; j<len; j++)
                        {
-                               msg[0].buf[j] = data[j+5];      
+                               msg[0].buf[j] = data[j+5];
                                //printk("data[%d]=%02x ", j, data[j+5]);
                        }
                        //printk("\n");
 static int az6007_usb_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       az6007_led_on_off(intf, 0);     
-               
+       az6007_led_on_off(intf, 0);
+
        return dvb_usb_device_init(intf, &az6007_properties,
-                                  THIS_MODULE, NULL, adapter_nr);      
+                                  THIS_MODULE, NULL, adapter_nr);
 }
 
 static struct usb_device_id az6007_usb_table [] = {
        //.power_ctrl       = az6007_power_ctrl,
        .read_mac_address = az6007_read_mac_addr,
 
-       .rc_key_map       = az6007_rc_keys,
-       .rc_key_map_size  = ARRAY_SIZE(az6007_rc_keys),
-       .rc_interval      = 400,
-       .rc_query         = az6007_rc_query,
+       .rc.legacy = {
+               .rc_map_table  = rc_map_az6007_table,
+               .rc_map_size  = ARRAY_SIZE(rc_map_az6007_table),
+               .rc_interval      = 400,
+               .rc_query         = az6007_rc_query,
+       },
        .i2c_algo         = &az6007_i2c_algo,
 
        .num_device_descs = 2,
                  .cold_ids = { &az6007_usb_table[1], NULL },
                  .warm_ids = { NULL },
                },
-               { NULL },
+               { NULL },
        }
 };
-  
+
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver az6007_usb_driver = {
        .name           = "dvb_usb_az6007",