From c79b339f92921fe73ac32ac2ae49a5b549dfc1f2 Mon Sep 17 00:00:00 2001
From: Antti Palosaari <crope@iki.fi>
Date: Wed, 23 May 2012 10:06:09 -0300
Subject: [PATCH] [media] dvb_usb_v2: copy current dvb_usb as a starting point

Use current implementation as a starting point for the new one.

[mchehab@redhat.com: remove the new files from the build system,
 as the symbols there conflict with the existing ones]
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
 drivers/media/dvb/dvb-usb/dvb_usb.h          | 485 +++++++++++++++++++
 drivers/media/dvb/dvb-usb/dvb_usb_common.h   |  52 ++
 drivers/media/dvb/dvb-usb/dvb_usb_dvb.c      | 289 +++++++++++
 drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 146 ++++++
 drivers/media/dvb/dvb-usb/dvb_usb_i2c.c      |  43 ++
 drivers/media/dvb/dvb-usb/dvb_usb_init.c     | 304 ++++++++++++
 drivers/media/dvb/dvb-usb/dvb_usb_remote.c   | 391 +++++++++++++++
 drivers/media/dvb/dvb-usb/dvb_usb_urb.c      | 121 +++++
 drivers/media/dvb/dvb-usb/usb_urb.c          | 254 ++++++++++
 9 files changed, 2085 insertions(+)
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb.h
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_common.h
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_dvb.c
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_firmware.c
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_i2c.c
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_init.c
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_remote.c
 create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_urb.c
 create mode 100644 drivers/media/dvb/dvb-usb/usb_urb.c

diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h
new file mode 100644
index 0000000000000..95caac116e8e8
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb.h
@@ -0,0 +1,485 @@
+/* dvb-usb.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * the headerfile, all dvb-usb-drivers have to include.
+ *
+ * TODO: clean-up the structures for unused fields and update the comments
+ */
+#ifndef DVB_USB_H
+#define DVB_USB_H
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <media/rc-core.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+
+#include "dvb-pll.h"
+
+#include "dvb-usb-ids.h"
+
+/* debug */
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var,level,args...) \
+	    do { if ((var & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l,func) {\
+	int loop_; \
+	for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
+	func("\n");\
+}
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define debug_dump(b,l,func)
+
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+
+#endif
+
+/* generic log methods - taken from usb.h */
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
+#endif
+
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/**
+ * struct dvb_usb_device_description - name and its according USB IDs
+ * @name: real name of the box, regardless which DVB USB device class is in use
+ * @cold_ids: array of struct usb_device_id which describe the device in
+ *  pre-firmware state
+ * @warm_ids: array of struct usb_device_id which describe the device in
+ *  post-firmware state
+ *
+ * Each DVB USB device class can have one or more actual devices, this struct
+ * assigns a name to it.
+ */
+struct dvb_usb_device_description {
+	const char *name;
+
+#define DVB_USB_ID_MAX_NUM 15
+	struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
+	struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
+};
+
+static inline u8 rc5_custom(struct rc_map_table *key)
+{
+	return (key->scancode >> 8) & 0xff;
+}
+
+static inline u8 rc5_data(struct rc_map_table *key)
+{
+	return key->scancode & 0xff;
+}
+
+static inline u16 rc5_scan(struct rc_map_table *key)
+{
+	return key->scancode & 0xffff;
+}
+
+struct dvb_usb_device;
+struct dvb_usb_adapter;
+struct usb_data_stream;
+
+/**
+ * Properties of USB streaming - TODO this structure should be somewhere else
+ * describes the kind of USB transfer used for data-streaming.
+ *  (BULK or ISOC)
+ */
+struct usb_data_stream_properties {
+#define USB_BULK  1
+#define USB_ISOC  2
+	int type;
+	int count;
+	int endpoint;
+
+	union {
+		struct {
+			int buffersize; /* per URB */
+		} bulk;
+		struct {
+			int framesperurb;
+			int framesize;
+			int interval;
+		} isoc;
+	} u;
+};
+
+/**
+ * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
+ *    A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
+ * @caps: capabilities of the DVB USB device.
+ * @pid_filter_count: number of PID filter position in the optional hardware
+ *  PID-filter.
+ * @num_frontends: number of frontends of the DVB USB adapter.
+ * @frontend_ctrl: called to power on/off active frontend.
+ * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
+ *  device (not URB submitting/killing).
+ * @pid_filter_ctrl: called to en/disable the PID filter, if any.
+ * @pid_filter: called to set/unset a PID for filtering.
+ * @frontend_attach: called to attach the possible frontends (fill fe-field
+ *  of struct dvb_usb_device).
+ * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
+ *  pll_desc and pll_init_buf of struct dvb_usb_device).
+ * @stream: configuration of the USB streaming
+ */
+struct dvb_usb_adapter_fe_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER               0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
+#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS         0x08
+#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD         0x10
+	int caps;
+	int pid_filter_count;
+
+	int (*streaming_ctrl)  (struct dvb_usb_adapter *, int);
+	int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+	int (*pid_filter)      (struct dvb_usb_adapter *, int, u16, int);
+
+	int (*frontend_attach) (struct dvb_usb_adapter *);
+	int (*tuner_attach)    (struct dvb_usb_adapter *);
+
+	struct usb_data_stream_properties stream;
+
+	int size_of_priv;
+};
+
+#define MAX_NO_OF_FE_PER_ADAP 3
+struct dvb_usb_adapter_properties {
+	int size_of_priv;
+
+	int (*frontend_ctrl)   (struct dvb_frontend *, int);
+	int (*fe_ioctl_override) (struct dvb_frontend *,
+				  unsigned int, void *, unsigned int);
+
+	int num_frontends;
+	struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
+};
+
+/**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
+ *  remote control handling).
+ * @rc_map_size: number of items in @rc_map_table.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED      0x00
+#define REMOTE_KEY_PRESSED         0x01
+#define REMOTE_KEY_REPEAT          0x02
+	struct rc_map_table  *rc_map_table;
+	int rc_map_size;
+	int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+	int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @allowed_protos: protocol(s) supported by the driver
+ * @driver_type: Used to point if a device supports raw mode
+ * @change_protocol: callback to change protocol
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+	char *rc_codes;
+	u64 protocol;
+	u64 allowed_protos;
+	enum rc_driver_type driver_type;
+	int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+	char *module_name;
+	int (*rc_query) (struct dvb_usb_device *d);
+	int rc_interval;
+	bool bulk_mode;				/* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ *		       based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+	DVB_RC_LEGACY,
+	DVB_RC_CORE,
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
+ *  download.
+ * @firmware: name of the firmware file.
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ *  DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+ *  so do the warm initialization right after it
+ *
+ * @size_of_priv: how many bytes shall be allocated for the private field
+ *  of struct dvb_usb_device.
+ *
+ * @power_ctrl: called to enable/disable power of the device.
+ * @read_mac_address: called to read the MAC address of the device.
+ * @identify_state: called to determine the state (cold or warm), when it
+ *  is not distinguishable by the USB IDs.
+ *
+ * @rc: remote controller properties
+ *
+ * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
+ *
+ * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
+ *  endpoint which received control messages with bulk transfers. When this
+ *  is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
+ *  helper functions.
+ *
+ * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
+ *  endpoint for responses to control messages sent with bulk transfers via
+ *  the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
+ *  instead of the generic_bulk_ctrl_endpoint when reading usb responses in
+ *  the dvb_usb_generic_rw helper function.
+ *
+ * @num_device_descs: number of struct dvb_usb_device_description in @devices
+ * @devices: array of struct dvb_usb_device_description compatibles with these
+ *  properties.
+ */
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
+
+#define DVB_USB_IS_AN_I2C_ADAPTER            0x01
+	int caps;
+
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135  1
+#define CYPRESS_AN2235  2
+#define CYPRESS_FX2     3
+	int        usb_ctrl;
+	int        (*download_firmware) (struct usb_device *, const struct firmware *);
+	const char *firmware;
+	int        no_reconnect;
+
+	int size_of_priv;
+
+	int num_adapters;
+	struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+	int (*power_ctrl)       (struct dvb_usb_device *, int);
+	int (*read_mac_address) (struct dvb_usb_device *, u8 []);
+	int (*identify_state)   (struct usb_device *, struct dvb_usb_device_properties *,
+			struct dvb_usb_device_description **, int *);
+
+	struct {
+		enum dvb_usb_mode mode;	/* Drivers shouldn't touch on it */
+		struct dvb_rc_legacy legacy;
+		struct dvb_rc core;
+	} rc;
+
+	struct i2c_algorithm *i2c_algo;
+
+	int generic_bulk_ctrl_endpoint;
+	int generic_bulk_ctrl_endpoint_response;
+
+	int num_device_descs;
+	struct dvb_usb_device_description devices[12];
+};
+
+/**
+ * struct usb_data_stream - generic object of an USB stream
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list.
+ *
+ * @urbs_initialized: number of URBs initialized.
+ * @urbs_submitted: number of URBs submitted.
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+	struct usb_device                 *udev;
+	struct usb_data_stream_properties  props;
+
+#define USB_STATE_INIT    0x00
+#define USB_STATE_URB_BUF 0x01
+	int state;
+
+	void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+	struct urb    *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+	int            buf_num;
+	unsigned long  buf_size;
+	u8            *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+	dma_addr_t     dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+	int urbs_initialized;
+	int urbs_submitted;
+
+	void *user_priv;
+};
+
+/**
+ * struct dvb_usb_adapter - a DVB adapter on a USB device
+ * @id: index of this adapter (starting with 0).
+ *
+ * @feedcount: number of reqested feeds (used for streaming-activation)
+ * @pid_filtering: is hardware pid_filtering used or not.
+ *
+ * @pll_addr: I2C address of the tuner for programming
+ * @pll_init: array containing the initialization buffer
+ * @pll_desc: pointer to the appropriate struct dvb_pll_desc
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
+ *
+ * @dvb_adap: device's dvb_adapter.
+ * @dmxdev: device's dmxdev.
+ * @demux: device's software demuxer.
+ * @dvb_net: device's dvb_net interfaces.
+ * @dvb_frontend: device's frontend.
+ * @max_feed_count: how many feeds can be handled simultaneously by this
+ *  device
+ *
+ * @fe_init:  rerouted frontend-init (wakeup) function.
+ * @fe_sleep: rerouted frontend-sleep function.
+ *
+ * @stream: the usb data stream.
+ */
+struct dvb_usb_fe_adapter {
+	struct dvb_frontend *fe;
+
+	int (*fe_init)  (struct dvb_frontend *);
+	int (*fe_sleep) (struct dvb_frontend *);
+
+	struct usb_data_stream stream;
+
+	int pid_filtering;
+	int max_feed_count;
+
+	void *priv;
+};
+
+struct dvb_usb_adapter {
+	struct dvb_usb_device *dev;
+	struct dvb_usb_adapter_properties props;
+
+#define DVB_USB_ADAP_STATE_INIT 0x000
+#define DVB_USB_ADAP_STATE_DVB  0x001
+	int state;
+
+	u8  id;
+
+	int feedcount;
+
+	/* dvb */
+	struct dvb_adapter   dvb_adap;
+	struct dmxdev        dmxdev;
+	struct dvb_demux     demux;
+	struct dvb_net       dvb_net;
+
+	struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
+	int active_fe;
+	int num_frontends_initialized;
+
+	void *priv;
+};
+
+/**
+ * struct dvb_usb_device - object of a DVB USB device
+ * @props: copy of the struct dvb_usb_properties this device belongs to.
+ * @desc: pointer to the device's struct dvb_usb_device_description.
+ * @state: initialization and runtime state of the device.
+ *
+ * @powered: indicated whether the device is power or not.
+ *  Powered is in/decremented for each call to modify the state.
+ * @udev: pointer to the device's struct usb_device.
+ *
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
+ *
+ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
+ *
+ * @rc_dev: rc device for the remote control (rc-core mode)
+ * @input_dev: input device for the remote control (legacy mode)
+ * @rc_query_work: struct work_struct frequent rc queries
+ * @last_event: last triggered event
+ * @last_state: last state (no, pressed, repeat)
+ * @owner: owner of the dvb_adapter
+ * @priv: private data of the actual driver (allocate by dvb-usb, size defined
+ *  in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+	struct dvb_usb_device_properties props;
+	struct dvb_usb_device_description *desc;
+
+	struct usb_device *udev;
+
+#define DVB_USB_STATE_INIT        0x000
+#define DVB_USB_STATE_I2C         0x001
+#define DVB_USB_STATE_DVB         0x002
+#define DVB_USB_STATE_REMOTE      0x004
+	int state;
+
+	int powered;
+
+	/* locking */
+	struct mutex usb_mutex;
+
+	/* i2c */
+	struct mutex i2c_mutex;
+	struct i2c_adapter i2c_adap;
+
+	int                    num_adapters_initialized;
+	struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+	/* remote control */
+	struct rc_dev *rc_dev;
+	struct input_dev *input_dev;
+	char rc_phys[64];
+	struct delayed_work rc_query_work;
+	u32 last_event;
+	int last_state;
+
+	struct module *owner;
+
+	void *priv;
+};
+
+extern int dvb_usbv2_device_init(struct usb_interface *,
+			       struct dvb_usb_device_properties *,
+			       struct module *, struct dvb_usb_device **,
+			       short *adapter_nums);
+extern void dvb_usbv2_device_exit(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
+extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+/* commonly used remote control parsing */
+extern int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
+
+/* commonly used firmware download types and function */
+struct hexline {
+	u8 len;
+	u32 addr;
+	u8 type;
+	u8 data[255];
+	u8 chk;
+};
+extern int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
+extern int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
+
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h
new file mode 100644
index 0000000000000..29df53999a9c6
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h
@@ -0,0 +1,52 @@
+/* dvb-usb-common.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * a header file containing prototypes and types for internal use of the dvb-usb-lib
+ */
+#ifndef DVB_USB_COMMON_H
+#define DVB_USB_COMMON_H
+
+#define DVB_USB_LOG_PREFIX "dvb_usb"
+#include "dvb_usb.h"
+
+extern int dvb_usb_debug;
+extern int dvb_usb_disable_rc_polling;
+
+#define deb_info(args...)  dprintk(dvb_usb_debug,0x001,args)
+#define deb_xfer(args...)  dprintk(dvb_usb_debug,0x002,args)
+#define deb_pll(args...)   dprintk(dvb_usb_debug,0x004,args)
+#define deb_ts(args...)    dprintk(dvb_usb_debug,0x008,args)
+#define deb_err(args...)   dprintk(dvb_usb_debug,0x010,args)
+#define deb_rc(args...)    dprintk(dvb_usb_debug,0x020,args)
+#define deb_fw(args...)    dprintk(dvb_usb_debug,0x040,args)
+#define deb_mem(args...)   dprintk(dvb_usb_debug,0x080,args)
+#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
+
+/* commonly used  methods */
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
+
+extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff);
+
+extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
+extern int usb_urb_exit(struct usb_data_stream *stream);
+extern int usb_urb_submit(struct usb_data_stream *stream);
+extern int usb_urb_kill(struct usb_data_stream *stream);
+
+extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
+
+extern int dvb_usb_i2c_init(struct dvb_usb_device *);
+extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap,
+				    short *adapter_nums);
+extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
+
+extern int dvb_usb_remote_init(struct dvb_usb_device *);
+extern int dvb_usb_remote_exit(struct dvb_usb_device *);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c
new file mode 100644
index 0000000000000..59cc26cb24c50
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c
@@ -0,0 +1,289 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb_usb_common.h"
+
+/* does the complete input transfer handling */
+static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+	struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+	int newfeedcount, ret;
+
+	if (adap == NULL)
+		return -ENODEV;
+
+	if ((adap->active_fe < 0) ||
+	    (adap->active_fe >= adap->num_frontends_initialized)) {
+		return -EINVAL;
+	}
+
+	newfeedcount = adap->feedcount + (onoff ? 1 : -1);
+
+	/* stop feed before setting a new pid if there will be no pid anymore */
+	if (newfeedcount == 0) {
+		deb_ts("stop feeding\n");
+		usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
+
+		if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+			ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
+			if (ret < 0) {
+				err("error while stopping stream.");
+				return ret;
+			}
+		}
+	}
+
+	adap->feedcount = newfeedcount;
+
+	/* activate the pid on the device specific pid_filter */
+	deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
+		adap->fe_adap[adap->active_fe].pid_filtering ?
+		"yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
+		dvbdmxfeed->index, onoff ? "on" : "off");
+	if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+		adap->fe_adap[adap->active_fe].pid_filtering &&
+		adap->props.fe[adap->active_fe].pid_filter != NULL)
+		adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
+
+	/* start the feed if this was the first feed and there is still a feed
+	 * for reception.
+	 */
+	if (adap->feedcount == onoff && adap->feedcount > 0) {
+		deb_ts("submitting all URBs\n");
+		usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
+
+		deb_ts("controlling pid parser\n");
+		if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+			adap->props.fe[adap->active_fe].caps &
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+			adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
+			ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
+				adap->fe_adap[adap->active_fe].pid_filtering);
+			if (ret < 0) {
+				err("could not handle pid_parser");
+				return ret;
+			}
+		}
+		deb_ts("start feeding\n");
+		if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+			ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
+			if (ret < 0) {
+				err("error while enabling fifo.");
+				return ret;
+			}
+		}
+
+	}
+	return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+	return dvb_usb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+	return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
+{
+	int i;
+	int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
+				       adap->dev->owner, &adap->dev->udev->dev,
+				       adapter_nums);
+
+	if (ret < 0) {
+		deb_info("dvb_register_adapter failed: error %d", ret);
+		goto err;
+	}
+	adap->dvb_adap.priv = adap;
+	adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override;
+
+	if (adap->dev->props.read_mac_address) {
+		if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
+			info("MAC address: %pM",adap->dvb_adap.proposed_mac);
+		else
+			err("MAC address reading failed.");
+	}
+
+
+	adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	adap->demux.priv             = adap;
+
+	adap->demux.filternum        = 0;
+	for (i = 0; i < adap->props.num_frontends; i++) {
+		if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
+			adap->demux.filternum = adap->fe_adap[i].max_feed_count;
+	}
+	adap->demux.feednum          = adap->demux.filternum;
+	adap->demux.start_feed       = dvb_usb_start_feed;
+	adap->demux.stop_feed        = dvb_usb_stop_feed;
+	adap->demux.write_to_decoder = NULL;
+	if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
+		err("dvb_dmx_init failed: error %d",ret);
+		goto err_dmx;
+	}
+
+	adap->dmxdev.filternum       = adap->demux.filternum;
+	adap->dmxdev.demux           = &adap->demux.dmx;
+	adap->dmxdev.capabilities    = 0;
+	if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
+		err("dvb_dmxdev_init failed: error %d",ret);
+		goto err_dmx_dev;
+	}
+
+	if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
+						&adap->demux.dmx)) < 0) {
+		err("dvb_net_init failed: error %d",ret);
+		goto err_net_init;
+	}
+
+	adap->state |= DVB_USB_ADAP_STATE_DVB;
+	return 0;
+
+err_net_init:
+	dvb_dmxdev_release(&adap->dmxdev);
+err_dmx_dev:
+	dvb_dmx_release(&adap->demux);
+err_dmx:
+	dvb_unregister_adapter(&adap->dvb_adap);
+err:
+	return ret;
+}
+
+int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+	if (adap->state & DVB_USB_ADAP_STATE_DVB) {
+		deb_info("unregistering DVB part\n");
+		dvb_net_release(&adap->dvb_net);
+		adap->demux.dmx.close(&adap->demux.dmx);
+		dvb_dmxdev_release(&adap->dmxdev);
+		dvb_dmx_release(&adap->demux);
+		dvb_unregister_adapter(&adap->dvb_adap);
+		adap->state &= ~DVB_USB_ADAP_STATE_DVB;
+	}
+	return 0;
+}
+
+static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	int ret = (adap->props.frontend_ctrl) ?
+		adap->props.frontend_ctrl(fe, onoff) : 0;
+
+	if (ret < 0) {
+		err("frontend_ctrl request failed");
+		return ret;
+	}
+	if (onoff)
+		adap->active_fe = fe->id;
+
+	return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	dvb_usb_device_power_ctrl(adap->dev, 1);
+
+	dvb_usb_set_active_fe(fe, 1);
+
+	if (adap->fe_adap[fe->id].fe_init)
+		adap->fe_adap[fe->id].fe_init(fe);
+
+	return 0;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	if (adap->fe_adap[fe->id].fe_sleep)
+		adap->fe_adap[fe->id].fe_sleep(fe);
+
+	dvb_usb_set_active_fe(fe, 0);
+
+	return dvb_usb_device_power_ctrl(adap->dev, 0);
+}
+
+int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+	int ret, i;
+
+	/* register all given adapter frontends */
+	for (i = 0; i < adap->props.num_frontends; i++) {
+
+		if (adap->props.fe[i].frontend_attach == NULL) {
+			err("strange: '%s' #%d,%d "
+			    "doesn't want to attach a frontend.",
+			    adap->dev->desc->name, adap->id, i);
+
+			return 0;
+		}
+
+		ret = adap->props.fe[i].frontend_attach(adap);
+		if (ret || adap->fe_adap[i].fe == NULL) {
+			/* only print error when there is no FE at all */
+			if (i == 0)
+				err("no frontend was attached by '%s'",
+					adap->dev->desc->name);
+
+			return 0;
+		}
+
+		adap->fe_adap[i].fe->id = i;
+
+		/* re-assign sleep and wakeup functions */
+		adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
+		adap->fe_adap[i].fe->ops.init  = dvb_usb_fe_wakeup;
+		adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
+		adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
+
+		if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
+			err("Frontend %d registration failed.", i);
+			dvb_frontend_detach(adap->fe_adap[i].fe);
+			adap->fe_adap[i].fe = NULL;
+			/* In error case, do not try register more FEs,
+			 * still leaving already registered FEs alive. */
+			if (i == 0)
+				return -ENODEV;
+			else
+				return 0;
+		}
+
+		/* only attach the tuner if the demod is there */
+		if (adap->props.fe[i].tuner_attach != NULL)
+			adap->props.fe[i].tuner_attach(adap);
+
+		adap->num_frontends_initialized++;
+	}
+
+	return 0;
+}
+
+int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+	int i = adap->num_frontends_initialized - 1;
+
+	/* unregister all given adapter frontends */
+	for (; i >= 0; i--) {
+		if (adap->fe_adap[i].fe != NULL) {
+			dvb_unregister_frontend(adap->fe_adap[i].fe);
+			dvb_frontend_detach(adap->fe_adap[i].fe);
+		}
+	}
+	adap->num_frontends_initialized = 0;
+
+	return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c
new file mode 100644
index 0000000000000..20f2ed782dd70
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c
@@ -0,0 +1,146 @@
+/* dvb-usb-firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
+ *
+ * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
+ */
+#include "dvb_usb_common.h"
+
+#include <linux/usb.h>
+
+struct usb_cypress_controller {
+	int id;
+	const char *name;       /* name of the usb controller */
+	u16 cpu_cs_register;    /* needs to be restarted, when the firmware has been downloaded. */
+};
+
+static struct usb_cypress_controller cypress[] = {
+	{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
+	{ .id = CYPRESS_AN2135,  .name = "Cypress AN2135",  .cpu_cs_register = 0x7f92 },
+	{ .id = CYPRESS_AN2235,  .name = "Cypress AN2235",  .cpu_cs_register = 0x7f92 },
+	{ .id = CYPRESS_FX2,     .name = "Cypress FX2",     .cpu_cs_register = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
+{
+	return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
+}
+
+int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
+{
+	struct hexline hx;
+	u8 reset;
+	int ret,pos=0;
+
+	/* stop the CPU */
+	reset = 1;
+	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+		err("could not stop the USB controller CPU.");
+
+	while ((ret = dvb_usbv2_get_hexline(fw,&hx,&pos)) > 0) {
+		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+		ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+
+		if (ret != hx.len) {
+			err("error while transferring firmware "
+				"(transferred size: %d, block size: %d)",
+				ret,hx.len);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	if (ret < 0) {
+		err("firmware download failed at %d with %d",pos,ret);
+		return ret;
+	}
+
+	if (ret == 0) {
+		/* restart the CPU */
+		reset = 0;
+		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+			err("could not restart the USB controller CPU.");
+			ret = -EINVAL;
+		}
+	} else
+		ret = -EIO;
+
+	return ret;
+}
+EXPORT_SYMBOL(usbv2_cypress_load_firmware);
+
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
+{
+	int ret;
+	const struct firmware *fw = NULL;
+
+	if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			props->firmware,ret);
+		return ret;
+	}
+
+	info("downloading firmware from file '%s'",props->firmware);
+
+	switch (props->usb_ctrl) {
+		case CYPRESS_AN2135:
+		case CYPRESS_AN2235:
+		case CYPRESS_FX2:
+			ret = usbv2_cypress_load_firmware(udev, fw, props->usb_ctrl);
+			break;
+		case DEVICE_SPECIFIC:
+			if (props->download_firmware)
+				ret = props->download_firmware(udev,fw);
+			else {
+				err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
+				ret = -EINVAL;
+			}
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	release_firmware(fw);
+	return ret;
+}
+
+int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
+			       int *pos)
+{
+	u8 *b = (u8 *) &fw->data[*pos];
+	int data_offs = 4;
+	if (*pos >= fw->size)
+		return 0;
+
+	memset(hx,0,sizeof(struct hexline));
+
+	hx->len  = b[0];
+
+	if ((*pos + hx->len + 4) >= fw->size)
+		return -EINVAL;
+
+	hx->addr = b[1] | (b[2] << 8);
+	hx->type = b[3];
+
+	if (hx->type == 0x04) {
+		/* b[4] and b[5] are the Extended linear address record data field */
+		hx->addr |= (b[4] << 24) | (b[5] << 16);
+/*		hx->len -= 2;
+		data_offs += 2; */
+	}
+	memcpy(hx->data,&b[data_offs],hx->len);
+	hx->chk = b[hx->len + data_offs];
+
+	*pos += hx->len + 5;
+
+	return *pos;
+}
+EXPORT_SYMBOL(dvb_usbv2_get_hexline);
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c
new file mode 100644
index 0000000000000..273f4892da013
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c
@@ -0,0 +1,43 @@
+/* dvb-usb-i2c.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for (de-)initializing an I2C adapter.
+ */
+#include "dvb_usb_common.h"
+
+int dvb_usb_i2c_init(struct dvb_usb_device *d)
+{
+	int ret = 0;
+
+	if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
+		return 0;
+
+	if (d->props.i2c_algo == NULL) {
+		err("no i2c algorithm specified");
+		return -EINVAL;
+	}
+
+	strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
+	d->i2c_adap.algo      = d->props.i2c_algo;
+	d->i2c_adap.algo_data = NULL;
+	d->i2c_adap.dev.parent = &d->udev->dev;
+
+	i2c_set_adapdata(&d->i2c_adap, d);
+
+	if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
+		err("could not add i2c adapter");
+
+	d->state |= DVB_USB_STATE_I2C;
+
+	return ret;
+}
+
+int dvb_usb_i2c_exit(struct dvb_usb_device *d)
+{
+	if (d->state & DVB_USB_STATE_I2C)
+		i2c_del_adapter(&d->i2c_adap);
+	d->state &= ~DVB_USB_STATE_I2C;
+	return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c
new file mode 100644
index 0000000000000..4ae30451eb9e4
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c
@@ -0,0 +1,304 @@
+/*
+ * DVB USB library - provides a generic interface for a DVB USB device driver.
+ *
+ * dvb-usb-init.c
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	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 the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dvb_usb_common.h"
+
+/* debug */
+int dvb_usb_debug;
+module_param_named(debug, dvb_usb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256  (or-able))." DVB_USB_DEBUG_STATUS);
+
+int dvb_usb_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
+
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
+MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+
+static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
+{
+	struct dvb_usb_adapter *adap;
+	int ret, n, o;
+
+	for (n = 0; n < d->props.num_adapters; n++) {
+		adap = &d->adapter[n];
+		adap->dev = d;
+		adap->id  = n;
+
+		memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
+
+	for (o = 0; o < adap->props.num_frontends; o++) {
+		struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
+		/* speed - when running at FULL speed we need a HW PID filter */
+		if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+			err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
+			return -ENODEV;
+		}
+
+		if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+			(props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+			info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
+			adap->fe_adap[o].pid_filtering  = 1;
+			adap->fe_adap[o].max_feed_count = props->pid_filter_count;
+		} else {
+			info("will pass the complete MPEG2 transport stream to the software demuxer.");
+			adap->fe_adap[o].pid_filtering  = 0;
+			adap->fe_adap[o].max_feed_count = 255;
+		}
+
+		if (!adap->fe_adap[o].pid_filtering &&
+			dvb_usb_force_pid_filter_usage &&
+			props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+			info("pid filter enabled by module option.");
+			adap->fe_adap[o].pid_filtering  = 1;
+			adap->fe_adap[o].max_feed_count = props->pid_filter_count;
+		}
+
+		if (props->size_of_priv > 0) {
+			adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
+			if (adap->fe_adap[o].priv == NULL) {
+				err("no memory for priv for adapter %d fe %d.", n, o);
+				return -ENOMEM;
+			}
+		}
+	}
+
+		if (adap->props.size_of_priv > 0) {
+			adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
+			if (adap->priv == NULL) {
+				err("no memory for priv for adapter %d.", n);
+				return -ENOMEM;
+			}
+		}
+
+		if ((ret = dvb_usb_adapter_stream_init(adap)) ||
+			(ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) ||
+			(ret = dvb_usb_adapter_frontend_init(adap))) {
+			return ret;
+		}
+
+		/* use exclusive FE lock if there is multiple shared FEs */
+		if (adap->fe_adap[1].fe)
+			adap->dvb_adap.mfe_shared = 1;
+
+		d->num_adapters_initialized++;
+		d->state |= DVB_USB_STATE_DVB;
+	}
+
+	/*
+	 * when reloading the driver w/o replugging the device
+	 * sometimes a timeout occures, this helps
+	 */
+	if (d->props.generic_bulk_ctrl_endpoint != 0) {
+		usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+		usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	}
+
+	return 0;
+}
+
+static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
+{
+	int n;
+
+	for (n = 0; n < d->num_adapters_initialized; n++) {
+		dvb_usb_adapter_frontend_exit(&d->adapter[n]);
+		dvb_usb_adapter_dvb_exit(&d->adapter[n]);
+		dvb_usb_adapter_stream_exit(&d->adapter[n]);
+		kfree(d->adapter[n].priv);
+	}
+	d->num_adapters_initialized = 0;
+	d->state &= ~DVB_USB_STATE_DVB;
+	return 0;
+}
+
+
+/* general initialization functions */
+static int dvb_usb_exit(struct dvb_usb_device *d)
+{
+	deb_info("state before exiting everything: %x\n", d->state);
+	dvb_usb_remote_exit(d);
+	dvb_usb_adapter_exit(d);
+	dvb_usb_i2c_exit(d);
+	deb_info("state should be zero now: %x\n", d->state);
+	d->state = DVB_USB_STATE_INIT;
+	kfree(d->priv);
+	kfree(d);
+	return 0;
+}
+
+static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
+{
+	int ret = 0;
+
+	mutex_init(&d->usb_mutex);
+	mutex_init(&d->i2c_mutex);
+
+	d->state = DVB_USB_STATE_INIT;
+
+	if (d->props.size_of_priv > 0) {
+		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
+		if (d->priv == NULL) {
+			err("no memory for priv in 'struct dvb_usb_device'");
+			return -ENOMEM;
+		}
+	}
+
+	/* check the capabilities and set appropriate variables */
+	dvb_usb_device_power_ctrl(d, 1);
+
+	if ((ret = dvb_usb_i2c_init(d)) ||
+		(ret = dvb_usb_adapter_init(d, adapter_nums))) {
+		dvb_usb_exit(d);
+		return ret;
+	}
+
+	if ((ret = dvb_usb_remote_init(d)))
+		err("could not initialize remote control.");
+
+	dvb_usb_device_power_ctrl(d, 0);
+
+	return 0;
+}
+
+/* determine the name and the state of the just found USB device */
+static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
+{
+	int i, j;
+	struct dvb_usb_device_description *desc = NULL;
+
+	*cold = -1;
+
+	for (i = 0; i < props->num_device_descs; i++) {
+
+		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
+			deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+			if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
+				props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+				*cold = 1;
+				desc = &props->devices[i];
+				break;
+			}
+		}
+
+		if (desc != NULL)
+			break;
+
+		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
+			deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+			if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+				props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+				*cold = 0;
+				desc = &props->devices[i];
+				break;
+			}
+		}
+	}
+
+	if (desc != NULL && props->identify_state != NULL)
+		props->identify_state(udev, props, &desc, cold);
+
+	return desc;
+}
+
+int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	if (onoff)
+		d->powered++;
+	else
+		d->powered--;
+
+	if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
+		deb_info("power control: %d\n", onoff);
+		if (d->props.power_ctrl)
+			return d->props.power_ctrl(d, onoff);
+	}
+	return 0;
+}
+
+/*
+ * USB
+ */
+int dvb_usbv2_device_init(struct usb_interface *intf,
+			struct dvb_usb_device_properties *props,
+			struct module *owner, struct dvb_usb_device **du,
+			short *adapter_nums)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct dvb_usb_device *d = NULL;
+	struct dvb_usb_device_description *desc = NULL;
+
+	int ret = -ENOMEM, cold = 0;
+
+	if (du != NULL)
+		*du = NULL;
+
+	if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
+		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
+		return -ENODEV;
+	}
+
+	if (cold) {
+		info("found a '%s' in cold state, will try to load a firmware", desc->name);
+		ret = dvb_usb_download_firmware(udev, props);
+		if (!props->no_reconnect || ret != 0)
+			return ret;
+	}
+
+	info("found a '%s' in warm state.", desc->name);
+	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
+	if (d == NULL) {
+		err("no memory for 'struct dvb_usb_device'");
+		return -ENOMEM;
+	}
+
+	d->udev = udev;
+	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
+	d->desc = desc;
+	d->owner = owner;
+
+	usb_set_intfdata(intf, d);
+
+	if (du != NULL)
+		*du = d;
+
+	ret = dvb_usb_init(d, adapter_nums);
+
+	if (ret == 0)
+		info("%s successfully initialized and connected.", desc->name);
+	else
+		info("%s error while loading driver (%d)", desc->name, ret);
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_device_init);
+
+void dvb_usbv2_device_exit(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	const char *name = "generic DVB-USB module";
+
+	usb_set_intfdata(intf, NULL);
+	if (d != NULL && d->desc != NULL) {
+		name = d->desc->name;
+		dvb_usb_exit(d);
+	}
+	info("%s successfully deinitialized and disconnected.", name);
+
+}
+EXPORT_SYMBOL(dvb_usbv2_device_exit);
+
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c
new file mode 100644
index 0000000000000..1c6bef62473fc
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c
@@ -0,0 +1,391 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the input-device and for handling remote-control-queries.
+ */
+#include "dvb_usb_common.h"
+#include <linux/usb/input.h>
+
+static unsigned int
+legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
+				struct rc_map_table *keymap,
+				unsigned int keymap_size)
+{
+	unsigned int index;
+	unsigned int scancode;
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+		index = ke->index;
+	} else {
+		if (input_scancode_to_scalar(ke, &scancode))
+			return keymap_size;
+
+		/* See if we can match the raw key code. */
+		for (index = 0; index < keymap_size; index++)
+			if (keymap[index].scancode == scancode)
+				break;
+
+		/* See if there is an unused hole in the map */
+		if (index >= keymap_size) {
+			for (index = 0; index < keymap_size; index++) {
+				if (keymap[index].keycode == KEY_RESERVED ||
+				    keymap[index].keycode == KEY_UNKNOWN) {
+					break;
+				}
+			}
+		}
+	}
+
+	return index;
+}
+
+static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
+				     struct input_keymap_entry *ke)
+{
+	struct dvb_usb_device *d = input_get_drvdata(dev);
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+	unsigned int index;
+
+	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
+	if (index >= keymap_size)
+		return -EINVAL;
+
+	ke->keycode = keymap[index].keycode;
+	if (ke->keycode == KEY_UNKNOWN)
+		ke->keycode = KEY_RESERVED;
+	ke->len = sizeof(keymap[index].scancode);
+	memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
+	ke->index = index;
+
+	return 0;
+}
+
+static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
+				     const struct input_keymap_entry *ke,
+				     unsigned int *old_keycode)
+{
+	struct dvb_usb_device *d = input_get_drvdata(dev);
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+	unsigned int index;
+
+	index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
+	/*
+	 * FIXME: Currently, it is not possible to increase the size of
+	 * scancode table. For it to happen, one possibility
+	 * would be to allocate a table with key_map_size + 1,
+	 * copying data, appending the new key on it, and freeing
+	 * the old one - or maybe just allocating some spare space
+	 */
+	if (index >= keymap_size)
+		return -EINVAL;
+
+	*old_keycode = keymap[index].keycode;
+	keymap->keycode = ke->keycode;
+	__set_bit(ke->keycode, dev->keybit);
+
+	if (*old_keycode != KEY_RESERVED) {
+		__clear_bit(*old_keycode, dev->keybit);
+		for (index = 0; index < keymap_size; index++) {
+			if (keymap[index].keycode == *old_keycode) {
+				__set_bit(*old_keycode, dev->keybit);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d =
+		container_of(work, struct dvb_usb_device, rc_query_work.work);
+	u32 event;
+	int state;
+
+	/* TODO: need a lock here.  We can simply skip checking for the remote control
+	   if we're busy. */
+
+	/* when the parameter has been set to 1 via sysfs while the driver was running */
+	if (dvb_usb_disable_rc_polling)
+		return;
+
+	if (d->props.rc.legacy.rc_query(d,&event,&state)) {
+		err("error while querying for an remote control event.");
+		goto schedule;
+	}
+
+
+	switch (state) {
+		case REMOTE_NO_KEY_PRESSED:
+			break;
+		case REMOTE_KEY_PRESSED:
+			deb_rc("key pressed\n");
+			d->last_event = event;
+		case REMOTE_KEY_REPEAT:
+			deb_rc("key repeated\n");
+			input_event(d->input_dev, EV_KEY, event, 1);
+			input_sync(d->input_dev);
+			input_event(d->input_dev, EV_KEY, d->last_event, 0);
+			input_sync(d->input_dev);
+			break;
+		default:
+			break;
+	}
+
+/* improved repeat handling ???
+	switch (state) {
+		case REMOTE_NO_KEY_PRESSED:
+			deb_rc("NO KEY PRESSED\n");
+			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+				deb_rc("releasing event %d\n",d->last_event);
+				input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
+				input_sync(d->rc_input_dev);
+			}
+			d->last_state = REMOTE_NO_KEY_PRESSED;
+			d->last_event = 0;
+			break;
+		case REMOTE_KEY_PRESSED:
+			deb_rc("KEY PRESSED\n");
+			deb_rc("pressing event %d\n",event);
+
+			input_event(d->rc_input_dev, EV_KEY, event, 1);
+			input_sync(d->rc_input_dev);
+
+			d->last_event = event;
+			d->last_state = REMOTE_KEY_PRESSED;
+			break;
+		case REMOTE_KEY_REPEAT:
+			deb_rc("KEY_REPEAT\n");
+			if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+				deb_rc("repeating event %d\n",d->last_event);
+				input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);
+				input_sync(d->rc_input_dev);
+				d->last_state = REMOTE_KEY_REPEAT;
+			}
+		default:
+			break;
+	}
+*/
+
+schedule:
+	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
+}
+
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+	int i, err, rc_interval;
+	struct input_dev *input_dev;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	input_dev->name = "IR-receiver inside an USB DVB receiver";
+	input_dev->phys = d->rc_phys;
+	usb_to_input_id(d->udev, &input_dev->id);
+	input_dev->dev.parent = &d->udev->dev;
+	d->input_dev = input_dev;
+	d->rc_dev = NULL;
+
+	input_dev->getkeycode = legacy_dvb_usb_getkeycode;
+	input_dev->setkeycode = legacy_dvb_usb_setkeycode;
+
+	/* set the bits for the keys */
+	deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
+	for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+		deb_rc("setting bit for event %d item %d\n",
+			d->props.rc.legacy.rc_map_table[i].keycode, i);
+		set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
+	}
+
+	/* setting these two values to non-zero, we have to manage key repeats */
+	input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
+	input_dev->rep[REP_DELAY]  = d->props.rc.legacy.rc_interval + 150;
+
+	input_set_drvdata(input_dev, d);
+
+	err = input_register_device(input_dev);
+	if (err)
+		input_free_device(input_dev);
+
+	rc_interval = d->props.rc.legacy.rc_interval;
+
+	INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
+
+	info("schedule remote query interval to %d msecs.", rc_interval);
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(rc_interval));
+
+	d->state |= DVB_USB_STATE_REMOTE;
+
+	return err;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d =
+		container_of(work, struct dvb_usb_device, rc_query_work.work);
+	int err;
+
+	/* TODO: need a lock here.  We can simply skip checking for the remote control
+	   if we're busy. */
+
+	/* when the parameter has been set to 1 via sysfs while the
+	 * driver was running, or when bulk mode is enabled after IR init
+	 */
+	if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
+		return;
+
+	err = d->props.rc.core.rc_query(d);
+	if (err)
+		err("error %d while querying for an remote control event.", err);
+
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(d->props.rc.core.rc_interval));
+}
+
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+	int err, rc_interval;
+	struct rc_dev *dev;
+
+	dev = rc_allocate_device();
+	if (!dev)
+		return -ENOMEM;
+
+	dev->driver_name = d->props.rc.core.module_name;
+	dev->map_name = d->props.rc.core.rc_codes;
+	dev->change_protocol = d->props.rc.core.change_protocol;
+	dev->allowed_protos = d->props.rc.core.allowed_protos;
+	dev->driver_type = d->props.rc.core.driver_type;
+	usb_to_input_id(d->udev, &dev->input_id);
+	dev->input_name = "IR-receiver inside an USB DVB receiver";
+	dev->input_phys = d->rc_phys;
+	dev->dev.parent = &d->udev->dev;
+	dev->priv = d;
+
+	err = rc_register_device(dev);
+	if (err < 0) {
+		rc_free_device(dev);
+		return err;
+	}
+
+	d->input_dev = NULL;
+	d->rc_dev = dev;
+
+	if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
+		return 0;
+
+	/* Polling mode - initialize a work queue for handling it */
+	INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
+
+	rc_interval = d->props.rc.core.rc_interval;
+
+	info("schedule remote query interval to %d msecs.", rc_interval);
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(rc_interval));
+
+	return 0;
+}
+
+int dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+	int err;
+
+	if (dvb_usb_disable_rc_polling)
+		return 0;
+
+	if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
+		d->props.rc.mode = DVB_RC_LEGACY;
+	else if (d->props.rc.core.rc_codes)
+		d->props.rc.mode = DVB_RC_CORE;
+	else
+		return 0;
+
+	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+	/* Start the remote-control polling. */
+	if (d->props.rc.legacy.rc_interval < 40)
+		d->props.rc.legacy.rc_interval = 100; /* default */
+
+	if (d->props.rc.mode == DVB_RC_LEGACY)
+		err = legacy_dvb_usb_remote_init(d);
+	else
+		err = rc_core_dvb_usb_remote_init(d);
+	if (err)
+		return err;
+
+	d->state |= DVB_USB_STATE_REMOTE;
+
+	return 0;
+}
+
+int dvb_usb_remote_exit(struct dvb_usb_device *d)
+{
+	if (d->state & DVB_USB_STATE_REMOTE) {
+		cancel_delayed_work_sync(&d->rc_query_work);
+		if (d->props.rc.mode == DVB_RC_LEGACY)
+			input_unregister_device(d->input_dev);
+		else
+			rc_unregister_device(d->rc_dev);
+	}
+	d->state &= ~DVB_USB_STATE_REMOTE;
+	return 0;
+}
+
+#define DVB_USB_RC_NEC_EMPTY           0x00
+#define DVB_USB_RC_NEC_KEY_PRESSED     0x01
+#define DVB_USB_RC_NEC_KEY_REPEATED    0x02
+int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *d,
+		u8 keybuf[5], u32 *event, int *state)
+{
+	int i;
+	struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+	switch (keybuf[0]) {
+		case DVB_USB_RC_NEC_EMPTY:
+			break;
+		case DVB_USB_RC_NEC_KEY_PRESSED:
+			if ((u8) ~keybuf[1] != keybuf[2] ||
+				(u8) ~keybuf[3] != keybuf[4]) {
+				deb_err("remote control checksum failed.\n");
+				break;
+			}
+			/* See if we can match the raw key code. */
+			for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+				if (rc5_custom(&keymap[i]) == keybuf[1] &&
+					rc5_data(&keymap[i]) == keybuf[3]) {
+					*event = keymap[i].keycode;
+					*state = REMOTE_KEY_PRESSED;
+					return 0;
+				}
+			deb_err("key mapping failed - no appropriate key found in keymapping\n");
+			break;
+		case DVB_USB_RC_NEC_KEY_REPEATED:
+			*state = REMOTE_KEY_REPEAT;
+			break;
+		default:
+			deb_err("unknown type of remote status: %d\n",keybuf[0]);
+			break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dvb_usbv2_nec_rc_key_to_event);
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c
new file mode 100644
index 0000000000000..c4b7845373e28
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c
@@ -0,0 +1,121 @@
+/* dvb-usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * USB and URB stuff.
+ */
+#include "dvb_usb_common.h"
+
+int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+	u16 rlen, int delay_ms)
+{
+	int actlen,ret = -ENOMEM;
+
+	if (!d || wbuf == NULL || wlen == 0)
+		return -EINVAL;
+
+	if (d->props.generic_bulk_ctrl_endpoint == 0) {
+		err("endpoint for generic control not specified.");
+		return -EINVAL;
+	}
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	deb_xfer(">>> ");
+	debug_dump(wbuf,wlen,deb_xfer);
+
+	ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
+			d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
+			2000);
+
+	if (ret)
+		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
+	else
+		ret = actlen != wlen ? -1 : 0;
+
+	/* an answer is expected, and no error before */
+	if (!ret && rbuf && rlen) {
+		if (delay_ms)
+			msleep(delay_ms);
+
+		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
+				d->props.generic_bulk_ctrl_endpoint_response ?
+				d->props.generic_bulk_ctrl_endpoint_response :
+				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
+				2000);
+
+		if (ret)
+			err("recv bulk message failed: %d",ret);
+		else {
+			deb_xfer("<<< ");
+			debug_dump(rbuf,actlen,deb_xfer);
+		}
+	}
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_rw);
+
+int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+	return dvb_usbv2_generic_rw(d,buf,len,NULL,0,0);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_write);
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter(&adap->demux, buffer, length);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter_204(&adap->demux, buffer, length);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
+				      u8 *buffer, size_t length)
+{
+	struct dvb_usb_adapter *adap = stream->user_priv;
+	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+		dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
+}
+
+int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+	int i, ret = 0;
+	for (i = 0; i < adap->props.num_frontends; i++) {
+
+		adap->fe_adap[i].stream.udev      = adap->dev->udev;
+		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
+			adap->fe_adap[i].stream.complete =
+				dvb_usb_data_complete_204;
+		else
+		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
+			adap->fe_adap[i].stream.complete =
+				dvb_usb_data_complete_raw;
+		else
+		adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
+		adap->fe_adap[i].stream.user_priv = adap;
+		ret = usb_urb_init(&adap->fe_adap[i].stream,
+				   &adap->props.fe[i].stream);
+		if (ret < 0)
+			break;
+	}
+	return ret;
+}
+
+int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+	int i;
+	for (i = 0; i < adap->props.num_frontends; i++)
+		usb_urb_exit(&adap->fe_adap[i].stream);
+	return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c
new file mode 100644
index 0000000000000..bf1915367cb92
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/usb_urb.c
@@ -0,0 +1,254 @@
+/* usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * BULK and ISOC USB data transfers in a generic way.
+ * Can be used for DVB-only and also, that's the plan, for
+ * Hybrid USB devices (analog and DVB).
+ */
+#include "dvb_usb_common.h"
+
+/* URB stuff for streaming */
+static void usb_urb_complete(struct urb *urb)
+{
+	struct usb_data_stream *stream = urb->context;
+	int ptype = usb_pipetype(urb->pipe);
+	int i;
+	u8 *b;
+
+	deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
+		ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
+		urb->status,urb->actual_length,urb->transfer_buffer_length,
+		urb->number_of_packets,urb->error_count);
+
+	switch (urb->status) {
+		case 0:         /* success */
+		case -ETIMEDOUT:    /* NAK */
+			break;
+		case -ECONNRESET:   /* kill */
+		case -ENOENT:
+		case -ESHUTDOWN:
+			return;
+		default:        /* error */
+			deb_ts("urb completition error %d.\n", urb->status);
+			break;
+	}
+
+	b = (u8 *) urb->transfer_buffer;
+	switch (ptype) {
+		case PIPE_ISOCHRONOUS:
+			for (i = 0; i < urb->number_of_packets; i++) {
+
+				if (urb->iso_frame_desc[i].status != 0)
+					deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
+				else if (urb->iso_frame_desc[i].actual_length > 0)
+					stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length);
+
+				urb->iso_frame_desc[i].status = 0;
+				urb->iso_frame_desc[i].actual_length = 0;
+			}
+			debug_dump(b,20,deb_uxfer);
+			break;
+		case PIPE_BULK:
+			if (urb->actual_length > 0)
+				stream->complete(stream, b, urb->actual_length);
+			break;
+		default:
+			err("unknown endpoint type in completition handler.");
+			return;
+	}
+	usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+int usb_urb_kill(struct usb_data_stream *stream)
+{
+	int i;
+	for (i = 0; i < stream->urbs_submitted; i++) {
+		deb_ts("killing URB no. %d.\n",i);
+
+		/* stop the URB */
+		usb_kill_urb(stream->urb_list[i]);
+	}
+	stream->urbs_submitted = 0;
+	return 0;
+}
+
+int usb_urb_submit(struct usb_data_stream *stream)
+{
+	int i,ret;
+	for (i = 0; i < stream->urbs_initialized; i++) {
+		deb_ts("submitting URB no. %d\n",i);
+		if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
+			err("could not submit URB no. %d - get them all back",i);
+			usb_urb_kill(stream);
+			return ret;
+		}
+		stream->urbs_submitted++;
+	}
+	return 0;
+}
+
+static int usb_free_stream_buffers(struct usb_data_stream *stream)
+{
+	if (stream->state & USB_STATE_URB_BUF) {
+		while (stream->buf_num) {
+			stream->buf_num--;
+			deb_mem("freeing buffer %d\n",stream->buf_num);
+			usb_free_coherent(stream->udev, stream->buf_size,
+					  stream->buf_list[stream->buf_num],
+					  stream->dma_addr[stream->buf_num]);
+		}
+	}
+
+	stream->state &= ~USB_STATE_URB_BUF;
+
+	return 0;
+}
+
+static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
+{
+	stream->buf_num = 0;
+	stream->buf_size = size;
+
+	deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
+
+	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
+		deb_mem("allocating buffer %d\n",stream->buf_num);
+		if (( stream->buf_list[stream->buf_num] =
+					usb_alloc_coherent(stream->udev, size, GFP_ATOMIC,
+					&stream->dma_addr[stream->buf_num]) ) == NULL) {
+			deb_mem("not enough memory for urb-buffer allocation.\n");
+			usb_free_stream_buffers(stream);
+			return -ENOMEM;
+		}
+		deb_mem("buffer %d: %p (dma: %Lu)\n",
+			stream->buf_num,
+stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
+		memset(stream->buf_list[stream->buf_num],0,size);
+		stream->state |= USB_STATE_URB_BUF;
+	}
+	deb_mem("allocation successful\n");
+
+	return 0;
+}
+
+static int usb_bulk_urb_init(struct usb_data_stream *stream)
+{
+	int i, j;
+
+	if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
+					stream->props.u.bulk.buffersize)) < 0)
+		return i;
+
+	/* allocate the URBs */
+	for (i = 0; i < stream->props.count; i++) {
+		stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!stream->urb_list[i]) {
+			deb_mem("not enough memory for urb_alloc_urb!.\n");
+			for (j = 0; j < i; j++)
+				usb_free_urb(stream->urb_list[j]);
+			return -ENOMEM;
+		}
+		usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
+				usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
+				stream->buf_list[i],
+				stream->props.u.bulk.buffersize,
+				usb_urb_complete, stream);
+
+		stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
+		stream->urbs_initialized++;
+	}
+	return 0;
+}
+
+static int usb_isoc_urb_init(struct usb_data_stream *stream)
+{
+	int i,j;
+
+	if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
+					stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
+		return i;
+
+	/* allocate the URBs */
+	for (i = 0; i < stream->props.count; i++) {
+		struct urb *urb;
+		int frame_offset = 0;
+
+		stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC);
+		if (!stream->urb_list[i]) {
+			deb_mem("not enough memory for urb_alloc_urb!\n");
+			for (j = 0; j < i; j++)
+				usb_free_urb(stream->urb_list[j]);
+			return -ENOMEM;
+		}
+
+		urb = stream->urb_list[i];
+
+		urb->dev = stream->udev;
+		urb->context = stream;
+		urb->complete = usb_urb_complete;
+		urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = stream->props.u.isoc.interval;
+		urb->number_of_packets = stream->props.u.isoc.framesperurb;
+		urb->transfer_buffer_length = stream->buf_size;
+		urb->transfer_buffer = stream->buf_list[i];
+		urb->transfer_dma = stream->dma_addr[i];
+
+		for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
+			frame_offset += stream->props.u.isoc.framesize;
+		}
+
+		stream->urbs_initialized++;
+	}
+	return 0;
+}
+
+int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
+{
+	if (stream == NULL || props == NULL)
+		return -EINVAL;
+
+	memcpy(&stream->props, props, sizeof(*props));
+
+	usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
+
+	if (stream->complete == NULL) {
+		err("there is no data callback - this doesn't make sense.");
+		return -EINVAL;
+	}
+
+	switch (stream->props.type) {
+		case USB_BULK:
+			return usb_bulk_urb_init(stream);
+		case USB_ISOC:
+			return usb_isoc_urb_init(stream);
+		default:
+			err("unknown URB-type for data transfer.");
+			return -EINVAL;
+	}
+}
+
+int usb_urb_exit(struct usb_data_stream *stream)
+{
+	int i;
+
+	usb_urb_kill(stream);
+
+	for (i = 0; i < stream->urbs_initialized; i++) {
+		if (stream->urb_list[i] != NULL) {
+			deb_mem("freeing URB no. %d.\n",i);
+			/* free the URBs */
+			usb_free_urb(stream->urb_list[i]);
+		}
+	}
+	stream->urbs_initialized = 0;
+
+	usb_free_stream_buffers(stream);
+	return 0;
+}
-- 
2.30.2