fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / media / dvb / ttusb-dec / ttusb_dec.c
index cc48a65..bd6e7ba 100644 (file)
@@ -2,6 +2,7 @@
  * TTUSB DEC Driver
  *
  * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ * IR support by Peter Beutner <p.beutner@gmx.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  */
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
 #include <linux/interrupt.h>
 #include <linux/firmware.h>
-#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
 #include <linux/crc32.h>
-#else
-#warning "CRC checking of firmware not available"
-#endif
 #include <linux/init.h>
+#include <linux/input.h>
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
-#include "dvb_i2c.h"
 #include "dvb_filter.h"
 #include "dvb_frontend.h"
 #include "dvb_net.h"
+#include "ttusbdecfe.h"
+
+static int debug;
+static int output_pva;
+static int enable_rc;
 
-static int debug = 0;
-static int output_pva = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+module_param(output_pva, int, 0444);
+MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
+module_param(enable_rc, int, 0644);
+MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
 
 #define dprintk        if (debug) printk
 
 #define DRIVER_NAME            "TechnoTrend/Hauppauge DEC USB"
 
 #define COMMAND_PIPE           0x03
-#define RESULT_PIPE            0x84
-#define IN_PIPE                        0x88
+#define RESULT_PIPE            0x04
+#define IN_PIPE                        0x08
 #define OUT_PIPE               0x07
+#define IRQ_PIPE               0x0A
 
 #define COMMAND_PACKET_SIZE    0x3c
 #define ARM_PACKET_SIZE                0x1000
+#define IRQ_PACKET_SIZE                0x8
 
 #define ISO_BUF_COUNT          0x04
 #define FRAMES_PER_ISO_BUF     0x04
-#define ISO_FRAME_SIZE         0x03FF
+#define ISO_FRAME_SIZE         0x0380
 
 #define        MAX_PVA_LENGTH          6144
 
-#define LOF_HI                 10600000
-#define LOF_LO                 9750000
-
 enum ttusb_dec_model {
        TTUSB_DEC2000T,
        TTUSB_DEC2540T,
@@ -91,34 +98,34 @@ struct ttusb_dec {
        int                             can_playback;
 
        /* DVB bits */
-       struct dvb_adapter              *adapter;
+       struct dvb_adapter              adapter;
        struct dmxdev                   dmxdev;
        struct dvb_demux                demux;
        struct dmx_frontend             frontend;
-       struct dvb_i2c_bus              i2c_bus;
        struct dvb_net                  dvb_net;
-       struct dvb_frontend_info        *frontend_info;
-       int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
+       struct dvb_frontend*            fe;
 
        u16                     pid[DMX_PES_OTHER];
-       int                     hi_band;
-       int                     voltage;
 
        /* USB bits */
-       struct usb_device       *udev;
-       u8                      trans_count;
-       unsigned int            command_pipe;
-       unsigned int            result_pipe;
+       struct usb_device               *udev;
+       u8                              trans_count;
+       unsigned int                    command_pipe;
+       unsigned int                    result_pipe;
        unsigned int                    in_pipe;
        unsigned int                    out_pipe;
+       unsigned int                    irq_pipe;
        enum ttusb_dec_interface        interface;
-       struct semaphore        usb_sem;
+       struct mutex                    usb_mutex;
 
+       void                    *irq_buffer;
+       struct urb              *irq_urb;
+       dma_addr_t              irq_dma_handle;
        void                    *iso_buffer;
        dma_addr_t              iso_dma_handle;
        struct urb              *iso_urb[ISO_BUF_COUNT];
        int                     iso_stream_count;
-       struct semaphore        iso_sem;
+       struct mutex            iso_mutex;
 
        u8                              packet[MAX_PVA_LENGTH + 4];
        enum ttusb_dec_packet_type      packet_type;
@@ -146,6 +153,9 @@ struct ttusb_dec {
        struct list_head        filter_info_list;
        spinlock_t              filter_info_list_lock;
 
+       struct input_dev        *rc_input_dev;
+       char                    rc_phys[64];
+
        int                     active; /* Loaded successfully */
 };
 
@@ -161,35 +171,84 @@ struct filter_info {
        struct list_head        filter_info_list;
 };
 
-static struct dvb_frontend_info dec2000t_frontend_info = {
-       .name                   = "TechnoTrend/Hauppauge DEC2000-t Frontend",
-       .type                   = FE_OFDM,
-       .frequency_min          = 51000000,
-       .frequency_max          = 858000000,
-       .frequency_stepsize     = 62500,
-       .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-               FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-               FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-               FE_CAN_HIERARCHY_AUTO,
-};
-
-static struct dvb_frontend_info dec3000s_frontend_info = {
-       .name                   = "TechnoTrend/Hauppauge DEC3000-s Frontend",
-       .type                   = FE_QPSK,
-       .frequency_min          = 950000,
-       .frequency_max          = 2150000,
-       .frequency_stepsize     = 125,
-       .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-               FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-               FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-               FE_CAN_HIERARCHY_AUTO,
+static u16 rc_keys[] = {
+       KEY_POWER,
+       KEY_MUTE,
+       KEY_1,
+       KEY_2,
+       KEY_3,
+       KEY_4,
+       KEY_5,
+       KEY_6,
+       KEY_7,
+       KEY_8,
+       KEY_9,
+       KEY_0,
+       KEY_CHANNELUP,
+       KEY_VOLUMEDOWN,
+       KEY_OK,
+       KEY_VOLUMEUP,
+       KEY_CHANNELDOWN,
+       KEY_PREVIOUS,
+       KEY_ESC,
+       KEY_RED,
+       KEY_GREEN,
+       KEY_YELLOW,
+       KEY_BLUE,
+       KEY_OPTION,
+       KEY_M,
+       KEY_RADIO
 };
 
 static void ttusb_dec_set_model(struct ttusb_dec *dec,
                                enum ttusb_dec_model model);
 
+static void ttusb_dec_handle_irq( struct urb *urb)
+{
+       struct ttusb_dec * dec = urb->context;
+       char *buffer = dec->irq_buffer;
+       int retval;
+
+       switch(urb->status) {
+               case 0: /*success*/
+                       break;
+               case -ECONNRESET:
+               case -ENOENT:
+               case -ESHUTDOWN:
+               case -ETIME:
+                       /* this urb is dead, cleanup */
+                       dprintk("%s:urb shutting down with status: %d\n",
+                                       __FUNCTION__, urb->status);
+                       return;
+               default:
+                       dprintk("%s:nonzero status received: %d\n",
+                                       __FUNCTION__,urb->status);
+                       goto exit;
+       }
+
+       if( (buffer[0] == 0x1) && (buffer[2] == 0x15) )  {
+               /* IR - Event */
+               /* this is an fact a bit too simple implementation;
+                * the box also reports a keyrepeat signal
+                * (with buffer[3] == 0x40) in an intervall of ~100ms.
+                * But to handle this correctly we had to imlemenent some
+                * kind of timer which signals a 'key up' event if no
+                * keyrepeat signal is recieved for lets say 200ms.
+                * this should/could be added later ...
+                * for now lets report each signal as a key down and up*/
+               dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
+               input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);
+               input_sync(dec->rc_input_dev);
+               input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);
+               input_sync(dec->rc_input_dev);
+       }
+
+exit:  retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if(retval)
+               printk("%s - usb_commit_urb failed with result: %d\n",
+                       __FUNCTION__, retval);
+}
+
 static u16 crc16(u16 crc, const u8 *buf, size_t len)
 {
        u16 tmp;
@@ -211,14 +270,14 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        u8 *b;
 
        dprintk("%s\n", __FUNCTION__);
-       
+
        b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
        if (!b)
                return -ENOMEM;
 
-       if ((result = down_interruptible(&dec->usb_sem))) {
+       if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
                kfree(b);
-               printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
+               printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);
                return result;
        }
 
@@ -238,23 +297,23 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        }
 
        result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
-                             COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
+                             COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
 
        if (result) {
                printk("%s: command bulk message failed: error %d\n",
                       __FUNCTION__, result);
-               up(&dec->usb_sem);
+               mutex_unlock(&dec->usb_mutex);
                kfree(b);
                return result;
        }
 
        result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
-                             COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
+                             COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
 
        if (result) {
                printk("%s: result bulk message failed: error %d\n",
                       __FUNCTION__, result);
-               up(&dec->usb_sem);
+               mutex_unlock(&dec->usb_mutex);
                kfree(b);
                return result;
        } else {
@@ -270,7 +329,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
                if (cmd_result && b[3] > 0)
                        memcpy(cmd_result, &b[4], b[3]);
 
-               up(&dec->usb_sem);
+               mutex_unlock(&dec->usb_mutex);
 
                kfree(b);
                return 0;
@@ -312,7 +371,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
 
 static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
 {
-       struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+       struct ttusb_dec *dec = priv;
 
        dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
                                       &dec->audio_filter->feed->feed.ts,
@@ -323,7 +382,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
 
 static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
 {
-       struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+       struct ttusb_dec *dec = priv;
 
        dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
                                       &dec->video_filter->feed->feed.ts,
@@ -350,9 +409,9 @@ static void ttusb_dec_set_pids(struct ttusb_dec *dec)
 
        ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
 
-               dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
+       dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
                               ttusb_dec_audio_pes2ts_cb, dec);
-               dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
+       dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
                               ttusb_dec_video_pes2ts_cb, dec);
        dec->v_pes_length = 0;
        dec->v_pes_postbytes = 0;
@@ -375,7 +434,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
        case 0x01: {            /* VideoStream */
                int prebytes = pva[5] & 0x03;
                int postbytes = (pva[5] & 0x0c) >> 2;
-                       u16 v_pes_payload_length;
+               u16 v_pes_payload_length;
 
                if (output_pva) {
                        dec->video_filter->feed->cb.ts(pva, length, NULL, 0,
@@ -383,23 +442,23 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
                        return;
                }
 
-                       if (dec->v_pes_postbytes > 0 &&
-                           dec->v_pes_postbytes == prebytes) {
-                               memcpy(&dec->v_pes[dec->v_pes_length],
+               if (dec->v_pes_postbytes > 0 &&
+                   dec->v_pes_postbytes == prebytes) {
+                       memcpy(&dec->v_pes[dec->v_pes_length],
                               &pva[12], prebytes);
 
-                               dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
+                       dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
                                          dec->v_pes_length + prebytes, 1);
-                       }
+               }
 
                if (pva[5] & 0x10) {
-                               dec->v_pes[7] = 0x80;
-                               dec->v_pes[8] = 0x05;
+                       dec->v_pes[7] = 0x80;
+                       dec->v_pes[8] = 0x05;
 
                        dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5);
                        dec->v_pes[10] = ((pva[8] & 0x3f) << 2) |
                                         ((pva[9] & 0xc0) >> 6);
-                               dec->v_pes[11] = 0x01 |
+                       dec->v_pes[11] = 0x01 |
                                         ((pva[9] & 0x3f) << 2) |
                                         ((pva[10] & 0x80) >> 6);
                        dec->v_pes[12] = ((pva[10] & 0x7f) << 1) |
@@ -409,33 +468,33 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
                        memcpy(&dec->v_pes[14], &pva[12 + prebytes],
                               length - 12 - prebytes);
                        dec->v_pes_length = 14 + length - 12 - prebytes;
-                       } else {
-                               dec->v_pes[7] = 0x00;
-                               dec->v_pes[8] = 0x00;
+               } else {
+                       dec->v_pes[7] = 0x00;
+                       dec->v_pes[8] = 0x00;
 
                        memcpy(&dec->v_pes[9], &pva[8], length - 8);
                        dec->v_pes_length = 9 + length - 8;
-                       }
+               }
 
-                       dec->v_pes_postbytes = postbytes;
+               dec->v_pes_postbytes = postbytes;
 
-                       if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&
-                           dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&
-                           dec->v_pes[11 + dec->v_pes[8]] == 0x01)
-                               dec->v_pes[6] = 0x84;
-                       else
-                               dec->v_pes[6] = 0x80;
+               if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&
+                   dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&
+                   dec->v_pes[11 + dec->v_pes[8]] == 0x01)
+                       dec->v_pes[6] = 0x84;
+               else
+                       dec->v_pes[6] = 0x80;
 
-                       v_pes_payload_length = htons(dec->v_pes_length - 6 +
-                                                    postbytes);
-                       memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
+               v_pes_payload_length = htons(dec->v_pes_length - 6 +
+                                            postbytes);
+               memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
 
-                       if (postbytes == 0)
-                               dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
-                                                 dec->v_pes_length, 1);
+               if (postbytes == 0)
+                       dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
+                                         dec->v_pes_length, 1);
 
-                       break;
-               }
+               break;
+       }
 
        case 0x02:              /* MainAudioStream */
                if (output_pva) {
@@ -517,7 +576,7 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec)
        case TTUSB_DEC_PACKET_PVA:
                if (dec->pva_stream_count)
                        ttusb_dec_process_pva(dec, dec->packet,
-                                                dec->packet_payload_length);
+                                             dec->packet_payload_length);
                break;
 
        case TTUSB_DEC_PACKET_SECTION:
@@ -543,7 +602,7 @@ static void swap_bytes(u8 *b, int length)
        }
 }
 
-static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b,
+static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
                                        int length)
 {
        swap_bytes(b, length);
@@ -592,7 +651,7 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b,
                                                TTUSB_DEC_PACKET_EMPTY;
                                        dec->packet_payload_length = 2;
                                        dec->packet_state = 7;
-                       } else {
+                               } else {
                                        printk("%s: unknown packet type: "
                                               "%02x%02x\n", __FUNCTION__,
                                               dec->packet[0], dec->packet[1]);
@@ -628,23 +687,23 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b,
                        int remainder = dec->packet_payload_length -
                                        dec->packet_length;
 
-                               if (length >= remainder) {
+                       if (length >= remainder) {
                                memcpy(dec->packet + dec->packet_length,
-                                              b, remainder);
+                                      b, remainder);
                                dec->packet_length += remainder;
-                                       b += remainder;
-                                       length -= remainder;
+                               b += remainder;
+                               length -= remainder;
                                dec->packet_state++;
-                               } else {
+                       } else {
                                memcpy(&dec->packet[dec->packet_length],
-                                              b, length);
+                                      b, length);
                                dec->packet_length += length;
-                                       length = 0;
-                               }
-
-                               break;
+                               length = 0;
                        }
 
+                       break;
+               }
+
                case 7: {
                        int tail = 4;
 
@@ -697,7 +756,7 @@ static void ttusb_dec_process_urb_frame_list(unsigned long data)
        }
 }
 
-static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)
+static void ttusb_dec_process_urb(struct urb *urb)
 {
        struct ttusb_dec *dec = urb->context;
 
@@ -706,7 +765,6 @@ static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)
 
                for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {
                        struct usb_iso_packet_descriptor *d;
-
                        u8 *b;
                        int length;
                        struct urb_frame *frame;
@@ -779,17 +837,17 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
 
        dprintk("%s\n", __FUNCTION__);
 
-       if (down_interruptible(&dec->iso_sem))
+       if (mutex_lock_interruptible(&dec->iso_mutex))
                return;
 
        dec->iso_stream_count--;
 
        if (!dec->iso_stream_count) {
                for (i = 0; i < ISO_BUF_COUNT; i++)
-                       usb_unlink_urb(dec->iso_urb[i]);
+                       usb_kill_urb(dec->iso_urb[i]);
        }
 
-       up(&dec->iso_sem);
+       mutex_unlock(&dec->iso_mutex);
 }
 
 /* Setting the interface of the DEC tends to take down the USB communications
@@ -812,7 +870,7 @@ static int ttusb_dec_set_interface(struct ttusb_dec *dec,
                                                        b, NULL, NULL);
                        if (result)
                                return result;
-                       result = usb_set_interface(dec->udev, 0, 7);
+                       result = usb_set_interface(dec->udev, 0, 8);
                        break;
                case TTUSB_DEC_INTERFACE_OUT:
                        result = usb_set_interface(dec->udev, 0, 1);
@@ -834,7 +892,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
 
        dprintk("%s\n", __FUNCTION__);
 
-       if (down_interruptible(&dec->iso_sem))
+       if (mutex_lock_interruptible(&dec->iso_mutex))
                return -EAGAIN;
 
        if (!dec->iso_stream_count) {
@@ -851,11 +909,11 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
                                       "error %d\n", __FUNCTION__, i, result);
 
                                while (i) {
-                                       usb_unlink_urb(dec->iso_urb[i - 1]);
+                                       usb_kill_urb(dec->iso_urb[i - 1]);
                                        i--;
                                }
 
-                               up(&dec->iso_sem);
+                               mutex_unlock(&dec->iso_mutex);
                                return result;
                        }
                }
@@ -863,7 +921,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
 
        dec->iso_stream_count++;
 
-       up(&dec->iso_sem);
+       mutex_unlock(&dec->iso_mutex);
 
        return 0;
 }
@@ -909,8 +967,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
 
        case DMX_TS_PES_TELETEXT:
                dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
-               dprintk("  pes_type: DMX_TS_PES_TELETEXT\n");
-               break;
+               dprintk("  pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
+               return -ENOSYS;
 
        case DMX_TS_PES_PCR:
                dprintk("  pes_type: DMX_TS_PES_PCR\n");
@@ -919,8 +977,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
                break;
 
        case DMX_TS_PES_OTHER:
-               dprintk("  pes_type: DMX_TS_PES_OTHER\n");
-               break;
+               dprintk("  pes_type: DMX_TS_PES_OTHER(not supported)\n");
+               return -ENOSYS;
 
        default:
                dprintk("  pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
@@ -1078,8 +1136,7 @@ static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec)
        dprintk("%s\n", __FUNCTION__);
 
        for (i = 0; i < ISO_BUF_COUNT; i++)
-               if (dec->iso_urb[i])
-                       usb_free_urb(dec->iso_urb[i]);
+               usb_free_urb(dec->iso_urb[i]);
 
        pci_free_consistent(NULL,
                            ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF *
@@ -1097,10 +1154,10 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
                                               ISO_FRAME_SIZE *
                                               (FRAMES_PER_ISO_BUF *
                                                ISO_BUF_COUNT),
-                                              &dec->iso_dma_handle);
+                                              &dec->iso_dma_handle);
 
        memset(dec->iso_buffer, 0,
-              sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)));
+              ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT));
 
        for (i = 0; i < ISO_BUF_COUNT; i++) {
                struct urb *urb;
@@ -1120,12 +1177,51 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
 
 static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
 {
-       dec->urb_frame_list_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&dec->urb_frame_list_lock);
        INIT_LIST_HEAD(&dec->urb_frame_list);
        tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list,
                     (unsigned long)dec);
 }
 
+static int ttusb_init_rc( struct ttusb_dec *dec)
+{
+       struct input_dev *input_dev;
+       u8 b[] = { 0x00, 0x01 };
+       int i;
+       int err;
+
+       usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
+       strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       input_dev->name = "ttusb_dec remote control";
+       input_dev->phys = dec->rc_phys;
+       input_dev->evbit[0] = BIT(EV_KEY);
+       input_dev->keycodesize = sizeof(u16);
+       input_dev->keycodemax = 0x1a;
+       input_dev->keycode = rc_keys;
+
+       for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
+                 set_bit(rc_keys[i], input_dev->keybit);
+
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
+
+       dec->rc_input_dev = input_dev;
+       if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
+               printk("%s: usb_submit_urb failed\n",__FUNCTION__);
+       /* enable irq pipe */
+       ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
+
+       return 0;
+}
+
 static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
 {
        dprintk("%s\n", __FUNCTION__);
@@ -1136,19 +1232,37 @@ static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
        dec->v_pes[3] = 0xe0;
 }
 
-static void ttusb_dec_init_usb(struct ttusb_dec *dec)
+static int ttusb_dec_init_usb(struct ttusb_dec *dec)
 {
        dprintk("%s\n", __FUNCTION__);
 
-       sema_init(&dec->usb_sem, 1);
-       sema_init(&dec->iso_sem, 1);
+       mutex_init(&dec->usb_mutex);
+       mutex_init(&dec->iso_mutex);
 
        dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
        dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
        dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
        dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
+       dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);
+
+       if(enable_rc) {
+               dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if(!dec->irq_urb) {
+                       return -ENOMEM;
+               }
+               dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,
+                                       GFP_ATOMIC, &dec->irq_dma_handle);
+               if(!dec->irq_buffer) {
+                       return -ENOMEM;
+               }
+               usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,
+                                dec->irq_buffer, IRQ_PACKET_SIZE,
+                                ttusb_dec_handle_irq, dec, 1);
+               dec->irq_urb->transfer_dma = dec->irq_dma_handle;
+               dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       }
 
-       ttusb_dec_alloc_iso_urbs(dec);
+       return ttusb_dec_alloc_iso_urbs(dec);
 }
 
 static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
@@ -1165,10 +1279,9 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
        u16 firmware_csum = 0;
        u16 firmware_csum_ns;
        u32 firmware_size_nl;
-#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
        u32 crc32_csum, crc32_check, tmp;
-#endif
        const struct firmware *fw_entry = NULL;
+
        dprintk("%s\n", __FUNCTION__);
 
        if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
@@ -1183,13 +1296,13 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
        if (firmware_size < 60) {
                printk("%s: firmware size too small for DSP code (%zu < 60).\n",
                        __FUNCTION__, firmware_size);
+               release_firmware(fw_entry);
                return -1;
        }
 
        /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
           at offset 56 of file, so use it to check if the firmware file is
           valid. */
-#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
        crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
        memcpy(&tmp, &firmware[56], 4);
        crc32_check = htonl(tmp);
@@ -1197,9 +1310,9 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
                printk("%s: crc32 check of DSP code failed (calculated "
                       "0x%08x != 0x%08x in file), file invalid.\n",
                        __FUNCTION__, crc32_csum, crc32_check);
+               release_firmware(fw_entry);
                return -1;
        }
-#endif
        memcpy(idstring, &firmware[36], 20);
        idstring[20] = '\0';
        printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
@@ -1212,15 +1325,19 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
 
        result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
 
-       if (result)
+       if (result) {
+               release_firmware(fw_entry);
                return result;
+       }
 
        trans_count = 0;
        j = 0;
 
        b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);
-       if (b == NULL)
+       if (b == NULL) {
+               release_firmware(fw_entry);
                return -ENOMEM;
+       }
 
        for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
                size = firmware_size - i;
@@ -1238,17 +1355,18 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
                if (j >= ARM_PACKET_SIZE) {
                        result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
                                              ARM_PACKET_SIZE, &actual_len,
-                                             HZ / 10);
+                                             100);
                        j = 0;
                } else if (size < COMMAND_PACKET_SIZE) {
                        result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
                                              j - COMMAND_PACKET_SIZE + size,
-                                             &actual_len, HZ / 10);
+                                             &actual_len, 100);
                }
        }
 
        result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
 
+       release_firmware(fw_entry);
        kfree(b);
 
        return result;
@@ -1277,17 +1395,19 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
                        result = ttusb_dec_boot_dsp(dec);
                        if (result)
                                return result;
-               else
+                       else
                                return 1;
                } else {
                        /* We can't trust the USB IDs that some firmwares
                           give the box */
                        switch (model) {
+                       case 0x00070001:
                        case 0x00070008:
                        case 0x0007000c:
                                ttusb_dec_set_model(dec, TTUSB_DEC3000S);
                                break;
                        case 0x00070009:
+                       case 0x00070013:
                                ttusb_dec_set_model(dec, TTUSB_DEC2000T);
                                break;
                        case 0x00070011:
@@ -1305,7 +1425,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
                                dec->can_playback = 1;
 
                        return 0;
-       }
+               }
        }
        else
                return result;
@@ -1318,7 +1438,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
        dprintk("%s\n", __FUNCTION__);
 
        if ((result = dvb_register_adapter(&dec->adapter,
-                                          dec->model_name, THIS_MODULE)) < 0) {
+                                          dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
                printk("%s: dvb_register_adapter failed: error %d\n",
                       __FUNCTION__, result);
 
@@ -1338,7 +1458,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
                printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
                       result);
 
-               dvb_unregister_adapter(dec->adapter);
+               dvb_unregister_adapter(&dec->adapter);
 
                return result;
        }
@@ -1347,12 +1467,12 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
        dec->dmxdev.demux = &dec->demux.dmx;
        dec->dmxdev.capabilities = 0;
 
-       if ((result = dvb_dmxdev_init(&dec->dmxdev, dec->adapter)) < 0) {
+       if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) {
                printk("%s: dvb_dmxdev_init failed: error %d\n",
                       __FUNCTION__, result);
 
                dvb_dmx_release(&dec->demux);
-               dvb_unregister_adapter(dec->adapter);
+               dvb_unregister_adapter(&dec->adapter);
 
                return result;
        }
@@ -1366,7 +1486,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
 
                dvb_dmxdev_release(&dec->dmxdev);
                dvb_dmx_release(&dec->demux);
-               dvb_unregister_adapter(dec->adapter);
+               dvb_unregister_adapter(&dec->adapter);
 
                return result;
        }
@@ -1379,12 +1499,12 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
                dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
                dvb_dmxdev_release(&dec->dmxdev);
                dvb_dmx_release(&dec->demux);
-               dvb_unregister_adapter(dec->adapter);
+               dvb_unregister_adapter(&dec->adapter);
 
                return result;
        }
 
-       dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx);
+       dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx);
 
        return 0;
 }
@@ -1398,9 +1518,37 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
        dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
        dvb_dmxdev_release(&dec->dmxdev);
        dvb_dmx_release(&dec->demux);
-       dvb_unregister_adapter(dec->adapter);
+       if (dec->fe) {
+               dvb_unregister_frontend(dec->fe);
+               if (dec->fe->ops.release)
+                       dec->fe->ops.release(dec->fe);
+       }
+       dvb_unregister_adapter(&dec->adapter);
+}
+
+static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
+{
+
+       dprintk("%s\n", __FUNCTION__);
+       /* we have to check whether the irq URB is already submitted.
+         * As the irq is submitted after the interface is changed,
+         * this is the best method i figured out.
+         * Any others?*/
+       if (dec->interface == TTUSB_DEC_INTERFACE_IN)
+               usb_kill_urb(dec->irq_urb);
+
+       usb_free_urb(dec->irq_urb);
+
+       usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,
+                          dec->irq_buffer, dec->irq_dma_handle);
+
+       if (dec->rc_input_dev) {
+               input_unregister_device(dec->rc_input_dev);
+               dec->rc_input_dev = NULL;
+       }
 }
 
+
 static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
 {
        int i;
@@ -1410,7 +1558,7 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
        dec->iso_stream_count = 0;
 
        for (i = 0; i < ISO_BUF_COUNT; i++)
-               usb_unlink_urb(dec->iso_urb[i]);
+               usb_kill_urb(dec->iso_urb[i]);
 
        ttusb_dec_free_iso_urbs(dec);
 }
@@ -1429,261 +1577,10 @@ static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
        }
 }
 
-static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
-                                 void *arg)
-{
-       struct ttusb_dec *dec = fe->data;
-
-       dprintk("%s\n", __FUNCTION__);
-
-       switch (cmd) {
-
-       case FE_GET_INFO:
-               dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
-               memcpy(arg, dec->frontend_info,
-                      sizeof (struct dvb_frontend_info));
-               break;
-
-       case FE_READ_STATUS: {
-                       fe_status_t *status = (fe_status_t *)arg;
-                       dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
-                       *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-                                 FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
-                       break;
-               }
-
-       case FE_READ_BER: {
-                       u32 *ber = (u32 *)arg;
-                       dprintk("%s: FE_READ_BER\n", __FUNCTION__);
-                       *ber = 0;
-                       return -ENOSYS;
-                       break;
-               }
-
-       case FE_READ_SIGNAL_STRENGTH: {
-                       dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
-                       *(s32 *)arg = 0xFF;
-                       return -ENOSYS;
-                       break;
-               }
-
-       case FE_READ_SNR:
-               dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
-               *(s32 *)arg = 0;
-               return -ENOSYS;
-               break;
-
-       case FE_READ_UNCORRECTED_BLOCKS:
-               dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
-               *(u32 *)arg = 0;
-               return -ENOSYS;
-               break;
-
-       case FE_SET_FRONTEND: {
-                       struct dvb_frontend_parameters *p =
-                               (struct dvb_frontend_parameters *)arg;
-               u8 b[] = { 0x00, 0x00, 0x00, 0x03,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x01,
-                          0x00, 0x00, 0x00, 0xff,
-                          0x00, 0x00, 0x00, 0xff };
-                       u32 freq;
-
-                       dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
-
-                       dprintk("            frequency->%d\n", p->frequency);
-                       dprintk("            symbol_rate->%d\n",
-                               p->u.qam.symbol_rate);
-                       dprintk("            inversion->%d\n", p->inversion);
-
-                       freq = htonl(p->frequency / 1000);
-                       memcpy(&b[4], &freq, sizeof (u32));
-                       ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
-
-                       break;
-               }
-
-       case FE_GET_FRONTEND:
-               dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
-               break;
-
-       case FE_SLEEP:
-               dprintk("%s: FE_SLEEP\n", __FUNCTION__);
-               return -ENOSYS;
-               break;
-
-       case FE_INIT:
-               dprintk("%s: FE_INIT\n", __FUNCTION__);
-               break;
-
-       default:
-               dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
-               return -EINVAL;
-
-       }
-
-       return 0;
-}
-
-static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe,
-                                         unsigned int cmd, void *arg)
-{
-       struct ttusb_dec *dec = fe->data;
-
-       dprintk("%s\n", __FUNCTION__);
-
-       switch (cmd) {
-
-       case FE_GET_INFO:
-               dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
-               memcpy(arg, dec->frontend_info,
-                      sizeof (struct dvb_frontend_info));
-               break;
-
-       case FE_READ_STATUS: {
-                       fe_status_t *status = (fe_status_t *)arg;
-                       dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
-                       *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-                                 FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
-                       break;
-               }
-
-       case FE_READ_BER: {
-                       u32 *ber = (u32 *)arg;
-                       dprintk("%s: FE_READ_BER\n", __FUNCTION__);
-                       *ber = 0;
-                       return -ENOSYS;
-                       break;
-               }
-
-       case FE_READ_SIGNAL_STRENGTH: {
-                       dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
-                       *(s32 *)arg = 0xFF;
-                       return -ENOSYS;
-                       break;
-               }
-
-       case FE_READ_SNR:
-               dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
-               *(s32 *)arg = 0;
-               return -ENOSYS;
-               break;
-
-       case FE_READ_UNCORRECTED_BLOCKS:
-               dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
-               *(u32 *)arg = 0;
-               return -ENOSYS;
-               break;
-
-       case FE_SET_FRONTEND: {
-                       struct dvb_frontend_parameters *p =
-                               (struct dvb_frontend_parameters *)arg;
-               u8 b[] = { 0x00, 0x00, 0x00, 0x01,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x01,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x00,
-                          0x00, 0x00, 0x00, 0x00 };
-                       u32 freq;
-                       u32 sym_rate;
-                       u32 band;
-               u32 lnb_voltage;
-
-                       dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
-
-                       dprintk("            frequency->%d\n", p->frequency);
-                       dprintk("            symbol_rate->%d\n",
-                               p->u.qam.symbol_rate);
-                       dprintk("            inversion->%d\n", p->inversion);
-
-               freq = htonl(p->frequency * 1000 +
-                      (dec->hi_band ? LOF_HI : LOF_LO));
-                       memcpy(&b[4], &freq, sizeof(u32));
-                       sym_rate = htonl(p->u.qam.symbol_rate);
-                       memcpy(&b[12], &sym_rate, sizeof(u32));
-                       band = htonl(dec->hi_band ? LOF_HI : LOF_LO);
-                       memcpy(&b[24], &band, sizeof(u32));
-               lnb_voltage = htonl(dec->voltage);
-               memcpy(&b[28], &lnb_voltage, sizeof(u32));
-
-                       ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
-
-                       break;
-               }
-
-       case FE_GET_FRONTEND:
-               dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
-               break;
-
-       case FE_SLEEP:
-               dprintk("%s: FE_SLEEP\n", __FUNCTION__);
-               return -ENOSYS;
-               break;
-
-       case FE_INIT:
-               dprintk("%s: FE_INIT\n", __FUNCTION__);
-               break;
-
-       case FE_DISEQC_SEND_MASTER_CMD:
-               dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__);
-               break;
-
-       case FE_DISEQC_SEND_BURST:
-               dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__);
-               break;
-
-       case FE_SET_TONE: {
-                       fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg;
-                       dprintk("%s: FE_SET_TONE\n", __FUNCTION__);
-                       dec->hi_band = (SEC_TONE_ON == tone);
-                       break;
-               }
-
-       case FE_SET_VOLTAGE:
-               dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
-               switch ((fe_sec_voltage_t) arg) {
-               case SEC_VOLTAGE_13:
-                       dec->voltage = 13;
-                       break;
-               case SEC_VOLTAGE_18:
-                       dec->voltage = 18;
-                       break;
-               default:
-                       return -EINVAL;
-                       break;
-               }
-               break;
-
-       default:
-               dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
-               return -EINVAL;
-
-       }
-
-       return 0;
-}
-
-static void ttusb_dec_init_frontend(struct ttusb_dec *dec)
-{
-       dec->i2c_bus.adapter = dec->adapter;
-
-       dvb_register_frontend(dec->frontend_ioctl, &dec->i2c_bus, (void *)dec,
-                             dec->frontend_info);
-}
-
-static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
-{
-       dvb_unregister_frontend(dec->frontend_ioctl, &dec->i2c_bus);
-}
-
 static void ttusb_dec_init_filters(struct ttusb_dec *dec)
 {
        INIT_LIST_HEAD(&dec->filter_info_list);
-       dec->filter_info_list_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&dec->filter_info_list_lock);
 }
 
 static void ttusb_dec_exit_filters(struct ttusb_dec *dec)
@@ -1698,6 +1595,18 @@ static void ttusb_dec_exit_filters(struct ttusb_dec *dec)
        }
 }
 
+static int fe_send_command(struct dvb_frontend* fe, const u8 command,
+                          int param_length, const u8 params[],
+                          int *result_length, u8 cmd_result[])
+{
+       struct ttusb_dec* dec = fe->dvb->priv;
+       return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
+}
+
+static struct ttusbdecfe_config fe_config = {
+       .send_command = fe_send_command
+};
+
 static int ttusb_dec_probe(struct usb_interface *intf,
                           const struct usb_device_id *id)
 {
@@ -1708,38 +1617,62 @@ static int ttusb_dec_probe(struct usb_interface *intf,
 
        udev = interface_to_usbdev(intf);
 
-       if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
+       if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
                printk("%s: couldn't allocate memory.\n", __FUNCTION__);
                return -ENOMEM;
        }
 
        usb_set_intfdata(intf, (void *)dec);
 
-       memset(dec, 0, sizeof(struct ttusb_dec));
-
-       switch (id->idProduct) {
-               case 0x1006:
+       switch (le16_to_cpu(id->idProduct)) {
+       case 0x1006:
                ttusb_dec_set_model(dec, TTUSB_DEC3000S);
-                       break;
+               break;
 
-               case 0x1008:
+       case 0x1008:
                ttusb_dec_set_model(dec, TTUSB_DEC2000T);
                break;
 
        case 0x1009:
                ttusb_dec_set_model(dec, TTUSB_DEC2540T);
-                       break;
+               break;
        }
 
        dec->udev = udev;
 
-       ttusb_dec_init_usb(dec);
+       if (ttusb_dec_init_usb(dec))
+               return 0;
        if (ttusb_dec_init_stb(dec)) {
                ttusb_dec_exit_usb(dec);
                return 0;
        }
        ttusb_dec_init_dvb(dec);
-       ttusb_dec_init_frontend(dec);
+
+       dec->adapter.priv = dec;
+       switch (le16_to_cpu(id->idProduct)) {
+       case 0x1006:
+               dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
+               break;
+
+       case 0x1008:
+       case 0x1009:
+               dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
+               break;
+       }
+
+       if (dec->fe == NULL) {
+               printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
+                      le16_to_cpu(dec->udev->descriptor.idVendor),
+                      le16_to_cpu(dec->udev->descriptor.idProduct));
+       } else {
+               if (dvb_register_frontend(&dec->adapter, dec->fe)) {
+                       printk("budget-ci: Frontend registration failed!\n");
+                       if (dec->fe->ops.release)
+                               dec->fe->ops.release(dec->fe);
+                       dec->fe = NULL;
+               }
+       }
+
        ttusb_dec_init_v_pes(dec);
        ttusb_dec_init_filters(dec);
        ttusb_dec_init_tasklet(dec);
@@ -1748,6 +1681,9 @@ static int ttusb_dec_probe(struct usb_interface *intf,
 
        ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
 
+       if (enable_rc)
+               ttusb_init_rc(dec);
+
        return 0;
 }
 
@@ -1760,11 +1696,12 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
        dprintk("%s\n", __FUNCTION__);
 
        if (dec->active) {
-       ttusb_dec_exit_tasklet(dec);
+               ttusb_dec_exit_tasklet(dec);
                ttusb_dec_exit_filters(dec);
-       ttusb_dec_exit_usb(dec);
-               ttusb_dec_exit_frontend(dec);
-       ttusb_dec_exit_dvb(dec);
+               if(enable_rc)
+                       ttusb_dec_exit_rc(dec);
+               ttusb_dec_exit_usb(dec);
+               ttusb_dec_exit_dvb(dec);
        }
 
        kfree(dec);
@@ -1779,22 +1716,16 @@ static void ttusb_dec_set_model(struct ttusb_dec *dec,
        case TTUSB_DEC2000T:
                dec->model_name = "DEC2000-t";
                dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
-               dec->frontend_info = &dec2000t_frontend_info;
-               dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
                break;
 
        case TTUSB_DEC2540T:
                dec->model_name = "DEC2540-t";
                dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
-               dec->frontend_info = &dec2000t_frontend_info;
-               dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
                break;
 
        case TTUSB_DEC3000S:
                dec->model_name = "DEC3000-s";
                dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
-               dec->frontend_info = &dec3000s_frontend_info;
-               dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
                break;
        }
 }
@@ -1809,9 +1740,9 @@ static struct usb_device_id ttusb_dec_table[] = {
 
 static struct usb_driver ttusb_dec_driver = {
        .name           = "ttusb-dec",
-      .probe           = ttusb_dec_probe,
-      .disconnect      = ttusb_dec_disconnect,
-      .id_table                = ttusb_dec_table,
+       .probe          = ttusb_dec_probe,
+       .disconnect     = ttusb_dec_disconnect,
+       .id_table       = ttusb_dec_table,
 };
 
 static int __init ttusb_dec_init(void)
@@ -1839,8 +1770,3 @@ MODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>");
 MODULE_DESCRIPTION(DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
-
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level");
-MODULE_PARM(output_pva, "i");
-MODULE_PARM_DESC(output_pva, "Output PVA from dvr device");