linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] Add two drivers for USB based DVB-T adapters
@ 2003-07-15 17:12 Michael Hunold
  2003-07-15 21:20 ` Greg KH
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Hunold @ 2003-07-15 17:12 UTC (permalink / raw)
  To: linux-kernel

This is part 17 of the patchset I send earlier. I guess the message was
eaten by the list server because of the size. I removed the data for the
firmware bootloader, so here it comes again.
[DVB] - add two new usb dvb drivers:
        - dvb-ttusb-budget.c for Technotrend/Hauppauge Nova-USB devices (Thanks to Holger Waechtler <holger@convergence.de> and elix Domke <tmbinc@gmx.net>)
	- dvb-ttusb-dec.c for Technotrend/Hauppauge USB DEC2000-T devices (Thanks to Alex Woods <linux-dvb@giblets.org>)
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/Kconfig linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/Kconfig
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/Kconfig	2003-06-21 17:43:27.000000000 +0200
@@ -0,0 +1,11 @@
+config DVB_TTUSB_BUDGET
+	tristate "Technotrend/Hauppauge Nova-USB devices"
+	depends on DVB_CORE && USB
+	help
+	  Support for external USB adapters designed by Technotrend and
+	  produced by Hauppauge, shipped under the brand name 'Nova-USB'.
+
+          These devices don't have a MPEG decoder built in, so you need
+	  an external software decoder to watch TV.	  
+
+	  Say Y if you own such a device and want to use it.
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/Makefile linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/Makefile
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/Makefile	2003-04-30 12:07:36.000000000 +0200
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2003-07-15 09:38:04.000000000 +0200
@@ -0,0 +1,1271 @@
+/*
+ * TTUSB DVB driver
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@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 the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ */
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/errno.h>
+#include <asm/semaphore.h>
+
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+
+#include "dvb_functions.h"
+
+/*
+  TTUSB_HWSECTIONS:
+    the DSP supports filtering in hardware, however, since the "muxstream"
+    is a bit braindead (no matching channel masks or no matching filter mask),
+    we won't support this - yet. it doesn't event support negative filters,
+    so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just
+    parse TS data. USB bandwith will be a problem when having large
+    datastreams, especially for dvb-net, but hey, that's not my problem.
+	
+  TTUSB_DISEQC, TTUSB_TONE:
+    let the STC do the diseqc/tone stuff. this isn't supported at least with
+    my TTUSB, so let it undef'd unless you want to implement another
+    frontend. never tested.
+		
+  DEBUG:
+    define it to > 3 for really hardcore debugging. you probably don't want
+    this unless the device doesn't load at all. > 2 for bandwidth statistics.
+*/
+
+static int debug = 0;
+
+#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0)
+
+#define ISO_BUF_COUNT      4
+#define FRAMES_PER_ISO_BUF 4
+#define ISO_FRAME_SIZE     912
+#define TTUSB_MAXCHANNEL   32
+#ifdef TTUSB_HWSECTIONS
+#define TTUSB_MAXFILTER    16	/* ??? */
+#endif
+
+#define TTUSB_BUDGET_NAME "ttusb_stc_fw"
+
+/**
+ *  since we're casting (struct ttusb*) <-> (struct dvb_demux*) around
+ *  the dvb_demux field must be the first in struct!!
+ */
+struct ttusb {
+	struct dvb_demux dvb_demux;
+	struct dmxdev dmxdev;
+	struct dvb_net dvbnet;
+
+	/* our semaphore, for channel allocation/deallocation */
+	struct semaphore sem;
+	/* and one for USB access. */
+	struct semaphore semusb;
+
+	struct dvb_adapter *adapter;
+	struct usb_device *dev;
+
+	int disconnecting;
+	int iso_streaming;
+
+	unsigned int bulk_out_pipe;
+	unsigned int bulk_in_pipe;
+	unsigned int isoc_in_pipe;
+
+	void *iso_buffer;
+	dma_addr_t iso_dma_handle;
+
+	struct urb *iso_urb[ISO_BUF_COUNT];
+
+	int running_feed_count;
+	int last_channel;
+	int last_filter;
+
+	u8 c;			/* transaction counter, wraps around...  */
+	fe_sec_tone_mode_t tone;
+	fe_sec_voltage_t voltage;
+
+	int mux_state;		// 0..2 - MuxSyncWord, 3 - nMuxPacks,    4 - muxpack
+	u8 mux_npacks;
+	u8 muxpack[256 + 8];
+	int muxpack_ptr, muxpack_len;
+
+	int insync;
+
+	u16 cc;			/* MuxCounter - will increment on EVERY MUX PACKET */
+	/* (including stuffing. yes. really.) */
+
+	u8 last_result[32];
+
+	struct ttusb_channel {
+		struct ttusb *ttusb;
+		struct dvb_demux_feed *dvbdmxfeed;
+
+		int active;
+		int id;
+		int pid;
+		int type;	/* 1 - TS, 2 - Filter */
+#ifdef TTUSB_HWSECTIONS
+		int filterstate[TTUSB_MAXFILTER];	/* 0: not busy, 1: busy */
+#endif
+	} channel[TTUSB_MAXCHANNEL];
+#if 0
+	devfs_handle_t stc_devfs_handle;
+#endif
+};
+
+/* ugly workaround ... don't know why it's neccessary to read */
+/* all result codes. */
+
+#define DEBUG 0
+static int ttusb_cmd(struct ttusb *ttusb,
+	      const u8 * data, int len, int needresult)
+{
+	int actual_len;
+	int err;
+#if DEBUG >= 3
+	int i;
+
+	printk(">");
+	for (i = 0; i < len; ++i)
+		printk(" %02x", data[i]);
+	printk("\n");
+#endif
+
+	if (down_interruptible(&ttusb->semusb) < 0)
+		return -EAGAIN;
+
+	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
+			   (u8 *) data, len, &actual_len, HZ);
+	if (err != 0) {
+		dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
+			__FUNCTION__, err);
+		up(&ttusb->semusb);
+		return err;
+	}
+	if (actual_len != len) {
+		dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__,
+			actual_len, len);
+		up(&ttusb->semusb);
+		return -1;
+	}
+
+	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe,
+			   ttusb->last_result, 32, &actual_len, HZ);
+
+	if (err != 0) {
+		printk("%s: failed, receive error %d\n", __FUNCTION__,
+		       err);
+		up(&ttusb->semusb);
+		return err;
+	}
+#if DEBUG >= 3
+	actual_len = ttusb->last_result[3] + 4;
+	printk("<");
+	for (i = 0; i < actual_len; ++i)
+		printk(" %02x", ttusb->last_result[i]);
+	printk("\n");
+#endif
+	if (!needresult)
+		up(&ttusb->semusb);
+	return 0;
+}
+
+static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
+{
+	memcpy(data, ttusb->last_result, len);
+	up(&ttusb->semusb);
+	return 0;
+}
+
+static int ttusb_i2c_msg(struct ttusb *ttusb,
+		  u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf,
+		  u8 rcv_len)
+{
+	u8 b[0x28];
+	u8 id = ++ttusb->c;
+	int i, err;
+
+	if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7)
+		return -EINVAL;
+
+	b[0] = 0xaa;
+	b[1] = id;
+	b[2] = 0x31;
+	b[3] = snd_len + 3;
+	b[4] = addr << 1;
+	b[5] = snd_len;
+	b[6] = rcv_len;
+
+	for (i = 0; i < snd_len; i++)
+		b[7 + i] = snd_buf[i];
+
+	err = ttusb_cmd(ttusb, b, snd_len + 7, 1);
+
+	if (err)
+		return -EREMOTEIO;
+
+	err = ttusb_result(ttusb, b, 0x20);
+
+	if (rcv_len > 0) {
+
+		if (err || b[0] != 0x55 || b[1] != id) {
+			dprintk
+			    ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ",
+			     __FUNCTION__, err, id);
+			return -EREMOTEIO;
+		}
+
+		for (i = 0; i < rcv_len; i++)
+			rcv_buf[i] = b[7 + i];
+	}
+
+	return rcv_len;
+}
+
+static int ttusb_i2c_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg msg[],
+		   int num)
+{
+	struct ttusb *ttusb = i2c->data;
+	int i = 0;
+	int inc;
+
+	if (down_interruptible(&ttusb->sem) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+		int err;
+
+		if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) {
+			addr = msg[i].addr;
+			snd_buf = msg[i].buf;
+			snd_len = msg[i].len;
+			rcv_buf = msg[i + 1].buf;
+			rcv_len = msg[i + 1].len;
+			inc = 2;
+		} else {
+			addr = msg[i].addr;
+			snd_buf = msg[i].buf;
+			snd_len = msg[i].len;
+			rcv_buf = NULL;
+			rcv_len = 0;
+			inc = 1;
+		}
+
+		err = ttusb_i2c_msg(ttusb, addr,
+				    snd_buf, snd_len, rcv_buf, rcv_len);
+
+		if (err < rcv_len) {
+			printk("%s: i == %i\n", __FUNCTION__, i);
+			break;
+		}
+
+		i += inc;
+	}
+
+	up(&ttusb->sem);
+	return i;
+}
+
+#include "dvb-ttusb-dspbootcode.h"
+
+static int ttusb_boot_dsp(struct ttusb *ttusb)
+{
+	int i, err;
+	u8 b[40];
+
+	/* BootBlock */
+	b[0] = 0xaa;
+	b[2] = 0x13;
+	b[3] = 28;
+
+	/* upload dsp code in 32 byte steps (36 didn't work for me ...) */
+	/* 32 is max packet size, no messages should be splitted. */
+	for (i = 0; i < sizeof(dsp_bootcode); i += 28) {
+		memcpy(&b[4], &dsp_bootcode[i], 28);
+
+		b[1] = ++ttusb->c;
+
+		err = ttusb_cmd(ttusb, b, 32, 0);
+		if (err)
+			goto done;
+	}
+
+	/* last block ... */
+	b[1] = ++ttusb->c;
+	b[2] = 0x13;
+	b[3] = 0;
+
+	err = ttusb_cmd(ttusb, b, 4, 0);
+	if (err)
+		goto done;
+
+	/* BootEnd */
+	b[1] = ++ttusb->c;
+	b[2] = 0x14;
+	b[3] = 0;
+
+	err = ttusb_cmd(ttusb, b, 4, 0);
+
+      done:
+	if (err) {
+		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
+			__FUNCTION__, err);
+	}
+
+	return err;
+}
+
+static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type,
+		      int pid)
+{
+	int err;
+	/* SetChannel */
+	u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type,
+		(pid >> 8) & 0xff, pid & 0xff
+	};
+
+	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
+	return err;
+}
+
+static int ttusb_del_channel(struct ttusb *ttusb, int channel_id)
+{
+	int err;
+	/* DelChannel */
+	u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id };
+
+	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
+	return err;
+}
+
+#ifdef TTUSB_HWSECTIONS
+static int ttusb_set_filter(struct ttusb *ttusb, int filter_id,
+		     int associated_chan, u8 filter[8], u8 mask[8])
+{
+	int err;
+	/* SetFilter */
+	u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan,
+		filter[0], filter[1], filter[2], filter[3],
+		filter[4], filter[5], filter[6], filter[7],
+		filter[8], filter[9], filter[10], filter[11],
+		mask[0], mask[1], mask[2], mask[3],
+		mask[4], mask[5], mask[6], mask[7],
+		mask[8], mask[9], mask[10], mask[11]
+	};
+
+	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
+	return err;
+}
+
+static int ttusb_del_filter(struct ttusb *ttusb, int filter_id)
+{
+	int err;
+	/* DelFilter */
+	u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id };
+
+	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
+	return err;
+}
+#endif
+
+static int ttusb_init_controller(struct ttusb *ttusb)
+{
+	u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 };
+	u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 };
+	u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 };
+	/* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */
+	u8 b3[] =
+	    { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e };
+	u8 b4[] =
+	    { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e };
+
+	u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 };
+	u8 get_dsp_version[0x20] =
+	    { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 };
+	int err;
+
+	/* reset board */
+	if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0)))
+		return err;
+
+	/* reset board (again?) */
+	if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0)))
+		return err;
+
+	ttusb_boot_dsp(ttusb);
+
+	/* set i2c bit rate */
+	if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0)))
+		return err;
+
+	if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1)))
+		return err;
+
+	err = ttusb_result(ttusb, b4, sizeof(b4));
+
+	if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1)))
+		return err;
+
+	if ((err = ttusb_result(ttusb, get_version, sizeof(get_version))))
+		return err;
+
+	dprintk("%s: stc-version: %c%c%c%c%c\n", __FUNCTION__,
+		get_version[4], get_version[5], get_version[6],
+		get_version[7], get_version[8]);
+
+	if (memcmp(get_version + 4, "V 0.0", 5) &&
+	    memcmp(get_version + 4, "V 1.1", 5)) {
+		printk
+		    ("%s: unknown STC version %c%c%c%c%c, please report!\n",
+		     __FUNCTION__, get_version[4], get_version[5],
+		     get_version[6], get_version[7], get_version[8]);
+	}
+
+	err =
+	    ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1);
+	if (err)
+		return err;
+
+	err =
+	    ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version));
+	if (err)
+		return err;
+	printk("%s: dsp-version: %c%c%c\n", __FUNCTION__,
+	       get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]);
+	return 0;
+}
+
+#ifdef TTUSB_DISEQC
+static int ttusb_send_diseqc(struct ttusb *ttusb,
+		      const struct dvb_diseqc_master_cmd *cmd)
+{
+	u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
+
+	int err;
+
+	b[3] = 4 + 2 + cmd->msg_len;
+	b[4] = 0xFF;		/* send diseqc master, not burst */
+	b[5] = cmd->msg_len;
+
+	memcpy(b + 5, cmd->msg, cmd->msg_len);
+
+	/* Diseqc */
+	if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) {
+		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
+			__FUNCTION__, err);
+	}
+
+	return err;
+}
+#endif
+
+static int ttusb_update_lnb(struct ttusb *ttusb)
+{
+	u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
+		ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1,
+		ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1
+	};
+	int err;
+
+	/* SetLNB */
+	if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) {
+		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
+			__FUNCTION__, err);
+	}
+
+	return err;
+}
+
+static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage)
+{
+	ttusb->voltage = voltage;
+	return ttusb_update_lnb(ttusb);
+}
+
+#ifdef TTUSB_TONE
+static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone)
+{
+	ttusb->tone = tone;
+	return ttusb_update_lnb(ttusb);
+}
+#endif
+
+static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	struct ttusb *ttusb = fe->i2c->data;
+
+	switch (cmd) {
+	case FE_SET_VOLTAGE:
+		return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg);
+#ifdef TTUSB_TONE
+	case FE_SET_TONE:
+		return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg);
+#endif
+#ifdef TTUSB_DISEQC
+	case FE_DISEQC_SEND_MASTER_CMD:
+		return ttusb_send_diseqc(ttusb,
+					 (struct dvb_diseqc_master_cmd *)
+					 arg);
+#endif
+	default:
+		return -EOPNOTSUPP;
+	};
+}
+
+#if 0
+static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
+{
+	u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq };
+	int err, actual_len;
+
+	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
+	if (err) {
+		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
+			__FUNCTION__, err);
+	}
+}
+#endif
+
+/*****************************************************************************/
+
+#ifdef TTUSB_HWSECTIONS
+static void ttusb_handle_ts_data(struct ttusb_channel *channel,
+				 const u8 * data, int len);
+static void ttusb_handle_sec_data(struct ttusb_channel *channel,
+				  const u8 * data, int len);
+#endif
+
+int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid;
+
+static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
+			   int len)
+{
+	u16 csum = 0, cc;
+	int i;
+	for (i = 0; i < len; i += 2)
+		csum ^= le16_to_cpup((u16 *) (muxpack + i));
+	if (csum) {
+		printk("%s: muxpack with incorrect checksum, ignoring\n",
+		       __FUNCTION__);
+		numinvalid++;
+		return;
+	}
+
+	cc = (muxpack[len - 4] << 8) | muxpack[len - 3];
+	cc &= 0x7FFF;
+	if (cc != ttusb->cc)
+		printk("%s: cc discontinuity (%d frames missing)\n",
+		       __FUNCTION__, (cc - ttusb->cc) & 0x7FFF);
+	ttusb->cc = (cc + 1) & 0x7FFF;
+	if (muxpack[0] & 0x80) {
+#ifdef TTUSB_HWSECTIONS
+		/* section data */
+		int pusi = muxpack[0] & 0x40;
+		int channel = muxpack[0] & 0x1F;
+		int payload = muxpack[1];
+		const u8 *data = muxpack + 2;
+		/* check offset flag */
+		if (muxpack[0] & 0x20)
+			data++;
+
+		ttusb_handle_sec_data(ttusb->channel + channel, data,
+				      payload);
+		data += payload;
+
+		if ((!!(ttusb->muxpack[0] & 0x20)) ^
+		    !!(ttusb->muxpack[1] & 1))
+			data++;
+#warning TODO: pusi
+		printk("cc: %04x\n", (data[0] << 8) | data[1]);
+#endif
+		numsec++;
+	} else if (muxpack[0] == 0x47) {
+#ifdef TTUSB_HWSECTIONS
+		/* we have TS data here! */
+		int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2];
+		int channel;
+		for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel)
+			if (ttusb->channel[channel].active
+			    && (pid == ttusb->channel[channel].pid))
+				ttusb_handle_ts_data(ttusb->channel +
+						     channel, muxpack,
+						     188);
+#endif
+		numts++;
+		dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1);
+	} else if (muxpack[0] != 0) {
+		numinvalid++;
+		printk("illegal muxpack type %02x\n", muxpack[0]);
+	} else
+		numstuff++;
+}
+
+static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
+{
+	int maxwork = 1024;
+	while (len) {
+		if (!(maxwork--)) {
+			printk("%s: too much work\n", __FUNCTION__);
+			break;
+		}
+
+		switch (ttusb->mux_state) {
+		case 0:
+		case 1:
+		case 2:
+			len--;
+			if (*data++ == 0xAA)
+				++ttusb->mux_state;
+			else {
+				ttusb->mux_state = 0;
+#if DEBUG > 3
+				if (ttusb->insync)
+					printk("%02x ", data[-1]);
+#else
+				if (ttusb->insync) {
+					printk("%s: lost sync.\n",
+					       __FUNCTION__);
+					ttusb->insync = 0;
+				}
+#endif
+			}
+			break;
+		case 3:
+			ttusb->insync = 1;
+			len--;
+			ttusb->mux_npacks = *data++;
+			++ttusb->mux_state;
+			ttusb->muxpack_ptr = 0;
+			/* maximum bytes, until we know the length */
+			ttusb->muxpack_len = 2;
+			break;
+		case 4:
+			{
+				int avail;
+				avail = len;
+				if (avail >
+				    (ttusb->muxpack_len -
+				     ttusb->muxpack_ptr))
+					avail =
+					    ttusb->muxpack_len -
+					    ttusb->muxpack_ptr;
+				memcpy(ttusb->muxpack + ttusb->muxpack_ptr,
+				       data, avail);
+				ttusb->muxpack_ptr += avail;
+				if (ttusb->muxpack_ptr > 264)
+					BUG();
+				data += avail;
+				len -= avail;
+				/* determine length */
+				if (ttusb->muxpack_ptr == 2) {
+					if (ttusb->muxpack[0] & 0x80) {
+						ttusb->muxpack_len =
+						    ttusb->muxpack[1] + 2;
+						if (ttusb->
+						    muxpack[0] & 0x20)
+							ttusb->
+							    muxpack_len++;
+						if ((!!
+						     (ttusb->
+						      muxpack[0] & 0x20)) ^
+						    !!(ttusb->
+						       muxpack[1] & 1))
+							ttusb->
+							    muxpack_len++;
+						ttusb->muxpack_len += 4;
+					} else if (ttusb->muxpack[0] ==
+						   0x47)
+						ttusb->muxpack_len =
+						    188 + 4;
+					else if (ttusb->muxpack[0] == 0x00)
+						ttusb->muxpack_len =
+						    ttusb->muxpack[1] + 2 +
+						    4;
+					else {
+						dprintk
+						    ("%s: invalid state: first byte is %x\n",
+						     __FUNCTION__,
+						     ttusb->muxpack[0]);
+						ttusb->mux_state = 0;
+					}
+				}
+
+			/**
+			 * if length is valid and we reached the end:
+			 * goto next muxpack
+			 */
+				if ((ttusb->muxpack_ptr >= 2) &&
+				    (ttusb->muxpack_ptr ==
+				     ttusb->muxpack_len)) {
+					ttusb_process_muxpack(ttusb,
+							      ttusb->
+							      muxpack,
+							      ttusb->
+							      muxpack_ptr);
+					ttusb->muxpack_ptr = 0;
+					/* maximum bytes, until we know the length */
+					ttusb->muxpack_len = 2;
+
+				/**
+				 * no muxpacks left?
+				 * return to search-sync state
+				 */
+					if (!ttusb->mux_npacks--) {
+						ttusb->mux_state = 0;
+						break;
+					}
+				}
+				break;
+			}
+		default:
+			BUG();
+			break;
+		}
+	}
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void ttusb_iso_irq(struct urb *urb)
+#else
+static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs)
+#endif
+{
+	struct ttusb *ttusb = urb->context;
+
+	if (!ttusb->iso_streaming)
+		return;
+
+#if 0
+	printk("%s: status %d, errcount == %d, length == %i\n",
+	       __FUNCTION__,
+	       urb->status, urb->error_count, urb->actual_length);
+#endif
+
+	if (!urb->status) {
+		int i;
+		for (i = 0; i < urb->number_of_packets; ++i) {
+			struct usb_iso_packet_descriptor *d;
+			u8 *data;
+			int len;
+			numpkt++;
+			if ((jiffies - lastj) >= HZ) {
+#if DEBUG > 2
+				printk
+				    ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n",
+				     numpkt * HZ / (jiffies - lastj),
+				     numts, numstuff, numsec, numinvalid,
+				     numts + numstuff + numsec +
+				     numinvalid);
+#endif
+				numts = numstuff = numsec = numinvalid = 0;
+				lastj = jiffies;
+				numpkt = 0;
+			}
+			d = &urb->iso_frame_desc[i];
+			data = urb->transfer_buffer + d->offset;
+			len = d->actual_length;
+			d->actual_length = 0;
+			d->status = 0;
+			ttusb_process_frame(ttusb, data, len);
+		}
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	usb_submit_urb(urb, GFP_KERNEL);
+#endif
+}
+
+static void ttusb_free_iso_urbs(struct ttusb *ttusb)
+{
+	int i;
+
+	for (i = 0; i < ISO_BUF_COUNT; i++)
+		if (ttusb->iso_urb[i])
+			usb_free_urb(ttusb->iso_urb[i]);
+
+	pci_free_consistent(NULL,
+			    ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF *
+			    ISO_BUF_COUNT, ttusb->iso_buffer,
+			    ttusb->iso_dma_handle);
+}
+
+static int ttusb_alloc_iso_urbs(struct ttusb *ttusb)
+{
+	int i;
+
+	ttusb->iso_buffer = pci_alloc_consistent(NULL,
+						 ISO_FRAME_SIZE *
+						 FRAMES_PER_ISO_BUF *
+						 ISO_BUF_COUNT,
+						 &ttusb->iso_dma_handle);
+
+	memset(ttusb->iso_buffer, 0,
+	       ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT);
+
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		struct urb *urb;
+
+		if (!
+		    (urb =
+		     usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) {
+			ttusb_free_iso_urbs(ttusb);
+			return -ENOMEM;
+		}
+
+		ttusb->iso_urb[i] = urb;
+	}
+
+	return 0;
+}
+
+static void ttusb_stop_iso_xfer(struct ttusb *ttusb)
+{
+	int i;
+
+	for (i = 0; i < ISO_BUF_COUNT; i++)
+		usb_unlink_urb(ttusb->iso_urb[i]);
+
+	ttusb->iso_streaming = 0;
+}
+
+static int ttusb_start_iso_xfer(struct ttusb *ttusb)
+{
+	int i, j, err, buffer_offset = 0;
+
+	if (ttusb->iso_streaming) {
+		printk("%s: iso xfer already running!\n", __FUNCTION__);
+		return 0;
+	}
+
+	ttusb->insync = 0;
+	ttusb->mux_state = 0;
+
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		int frame_offset = 0;
+		struct urb *urb = ttusb->iso_urb[i];
+
+		urb->dev = ttusb->dev;
+		urb->context = ttusb;
+		urb->complete = ttusb_iso_irq;
+		urb->pipe = ttusb->isoc_in_pipe;
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->number_of_packets = FRAMES_PER_ISO_BUF;
+		urb->transfer_buffer_length =
+		    ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
+		urb->transfer_buffer = ttusb->iso_buffer + buffer_offset;
+		buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
+
+		for (j = 0; j < FRAMES_PER_ISO_BUF; j++) {
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = ISO_FRAME_SIZE;
+			frame_offset += ISO_FRAME_SIZE;
+		}
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		int next = (i + 1) % ISO_BUF_COUNT;
+		ttusb->iso_urb[i]->next = ttusb->iso_urb[next];
+	}
+#endif
+
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_KERNEL))) {
+			ttusb_stop_iso_xfer(ttusb);
+			printk
+			    ("%s: failed urb submission (%i: err = %i)!\n",
+			     __FUNCTION__, i, err);
+			return err;
+		}
+	}
+
+	ttusb->iso_streaming = 1;
+
+	return 0;
+}
+
+#ifdef TTUSB_HWSECTIONS
+static void ttusb_handle_ts_data(struct ttusb_channel *channel, const u8 * data,
+			  int len)
+{
+	struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
+
+	dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0);
+}
+
+static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data,
+			   int len)
+{
+//      struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
+#error TODO: handle ugly stuff
+//      dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0);
+}
+#endif
+
+static struct ttusb_channel *ttusb_channel_allocate(struct ttusb *ttusb)
+{
+	int i;
+
+	if (down_interruptible(&ttusb->sem))
+		return NULL;
+
+	/* lock! */
+	for (i = 0; i < TTUSB_MAXCHANNEL; ++i) {
+		if (!ttusb->channel[i].active) {
+			ttusb->channel[i].active = 1;
+			up(&ttusb->sem);
+			return ttusb->channel + i;
+		}
+	}
+
+	up(&ttusb->sem);
+
+	return NULL;
+}
+
+static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
+	struct ttusb_channel *channel;
+
+	printk("ttusb_start_feed\n");
+
+	switch (dvbdmxfeed->type) {
+	case DMX_TYPE_TS:
+		break;
+	case DMX_TYPE_SEC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (dvbdmxfeed->type == DMX_TYPE_TS) {
+		switch (dvbdmxfeed->pes_type) {
+		case DMX_TS_PES_VIDEO:
+		case DMX_TS_PES_AUDIO:
+		case DMX_TS_PES_TELETEXT:
+		case DMX_TS_PES_PCR:
+		case DMX_TS_PES_OTHER:
+			channel = ttusb_channel_allocate(ttusb);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		channel = ttusb_channel_allocate(ttusb);
+	}
+
+	if (!channel)
+		return -EBUSY;
+
+	dvbdmxfeed->priv = channel;
+	channel->dvbdmxfeed = dvbdmxfeed;
+
+	channel->pid = dvbdmxfeed->pid;
+
+#ifdef TTUSB_HWSECTIONS
+	if (dvbdmxfeed->type == DMX_TYPE_TS) {
+		channel->type = 1;
+	} else if (dvbdmxfeed->type == DMX_TYPE_SEC) {
+		channel->type = 2;
+#error TODO: allocate filters
+	}
+#else
+	channel->type = 1;
+#endif
+
+	ttusb_set_channel(ttusb, channel->id, channel->type, channel->pid);
+
+	if (0 == ttusb->running_feed_count++)
+		ttusb_start_iso_xfer(ttusb);
+
+	return 0;
+}
+
+static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct ttusb_channel *channel =
+	    (struct ttusb_channel *) dvbdmxfeed->priv;
+	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
+
+	ttusb_del_channel(channel->ttusb, channel->id);
+
+	if (--ttusb->running_feed_count == 0)
+		ttusb_stop_iso_xfer(ttusb);
+
+	channel->active = 0;
+
+	return 0;
+}
+
+static int ttusb_setup_interfaces(struct ttusb *ttusb)
+{
+	usb_set_configuration(ttusb->dev, 1);
+	usb_set_interface(ttusb->dev, 1, 1);
+
+	ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1);
+	ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1);
+	ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2);
+
+	return 0;
+}
+
+#if 0
+static u8 stc_firmware[8192];
+
+static int stc_open(struct inode *inode, struct file *file)
+{
+	struct ttusb *ttusb = file->private_data;
+	int addr;
+
+	for (addr = 0; addr < 8192; addr += 16) {
+		u8 snd_buf[2] = { addr >> 8, addr & 0xFF };
+		ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr,
+			      16);
+	}
+
+	return 0;
+}
+
+static ssize_t stc_read(struct file *file, char *buf, size_t count,
+		 loff_t * offset)
+{
+	int tc = count;
+
+	if ((tc + *offset) > 8192)
+		tc = 8192 - *offset;
+
+	if (tc < 0)
+		return 0;
+
+	copy_to_user(buf, stc_firmware + *offset, tc);
+
+	*offset += tc;
+
+	return tc;
+}
+
+static int stc_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations stc_fops = {
+	.owner = THIS_MODULE,
+	.read = stc_read,
+	.open = stc_open,
+	.release = stc_release,
+};
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void *ttusb_probe(struct usb_device *udev, unsigned int ifnum,
+		  const struct usb_device_id *id)
+{
+	struct ttusb *ttusb;
+	int result, channel;
+
+	if (ifnum != 0)
+		return NULL;
+
+	dprintk("%s: TTUSB DVB connected\n", __FUNCTION__);
+
+	if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL)))
+		return NULL;
+
+#else
+static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct ttusb *ttusb;
+	int result, channel;
+
+	dprintk("%s: TTUSB DVB connected\n", __FUNCTION__);
+
+	udev = interface_to_usbdev(intf);
+
+	if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL)))
+		return -ENOMEM;
+
+#endif
+
+	memset(ttusb, 0, sizeof(struct ttusb));
+
+	for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) {
+		ttusb->channel[channel].id = channel;
+		ttusb->channel[channel].ttusb = ttusb;
+	}
+
+	ttusb->dev = udev;
+	ttusb->c = 0;
+	ttusb->mux_state = 0;
+	sema_init(&ttusb->sem, 0);
+	sema_init(&ttusb->semusb, 1);
+
+	ttusb_setup_interfaces(ttusb);
+
+	ttusb_alloc_iso_urbs(ttusb);
+	if (ttusb_init_controller(ttusb))
+		printk("ttusb_init_controller: error\n");
+
+	up(&ttusb->sem);
+
+	dvb_register_adapter(&ttusb->adapter,
+			     "Technotrend/Hauppauge Nova-USB");
+
+	dvb_register_i2c_bus(ttusb_i2c_xfer, ttusb, ttusb->adapter, 0);
+	dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
+				ttusb);
+
+	memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
+
+	ttusb->dvb_demux.dmx.capabilities =
+	    DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	ttusb->dvb_demux.priv = 0;
+#ifdef TTUSB_HWSECTIONS
+	ttusb->dvb_demux.filternum = TTUSB_MAXFILTER;
+#else
+	ttusb->dvb_demux.filternum = 32;
+#endif
+	ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL;
+	ttusb->dvb_demux.start_feed = ttusb_start_feed;
+	ttusb->dvb_demux.stop_feed = ttusb_stop_feed;
+	ttusb->dvb_demux.write_to_decoder = 0;
+
+	if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) {
+		printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n",
+		       result);
+		goto err;
+	}
+//FIXME dmxdev (nur WAS?)
+	ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum;
+	ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx;
+	ttusb->dmxdev.capabilities = 0;
+
+	if ((result = dvb_dmxdev_init(&ttusb->dmxdev, ttusb->adapter)) < 0) {
+		printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
+		       result);
+		dvb_dmx_release(&ttusb->dvb_demux);
+		goto err;
+	}
+
+	if (dvb_net_init
+	    (ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
+		printk("ttusb_dvb: dvb_net_init failed!\n");
+	}
+
+      err:
+#if 0
+	ttusb->stc_devfs_handle =
+	    devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME,
+			   DEVFS_FL_DEFAULT, 0, 192,
+			   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
+			   | S_IROTH | S_IWOTH, &stc_fops, ttusb);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	return (void *) ttusb;
+#else
+	usb_set_intfdata(intf, (void *) ttusb);
+
+	return 0;
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void ttusb_disconnect(struct usb_device *udev, void *data)
+{
+	struct ttusb *ttusb = data;
+#else
+static void ttusb_disconnect(struct usb_interface *intf)
+{
+	struct ttusb *ttusb = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+#endif
+
+	ttusb->disconnecting = 1;
+
+	ttusb_stop_iso_xfer(ttusb);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69))
+#undef devfs_remove
+#define devfs_remove(x)	devfs_unregister(ttusb->stc_devfs_handle);
+#endif
+#if 0
+	devfs_remove(TTUSB_BUDGET_NAME);
+#endif
+	ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx);
+	dvb_net_release(&ttusb->dvbnet);
+	dvb_dmxdev_release(&ttusb->dmxdev);
+	dvb_dmx_release(&ttusb->dvb_demux);
+
+	dvb_unregister_i2c_bus(ttusb_i2c_xfer, ttusb->adapter, 0);
+	dvb_unregister_adapter(ttusb->adapter);
+
+	ttusb_free_iso_urbs(ttusb);
+
+	kfree(ttusb);
+
+	dprintk("%s: TTUSB DVB disconnected\n", __FUNCTION__);
+}
+
+static struct usb_device_id ttusb_table[] = {
+	{USB_DEVICE(0xb48, 0x1003)},
+	{USB_DEVICE(0xb48, 0x1004)},	/* to be confirmed ????  */
+	{USB_DEVICE(0xb48, 0x1005)},	/* to be confirmed ????  */
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, ttusb_table);
+
+static struct usb_driver ttusb_driver = {
+      .name 		= "Technotrend/Hauppauge USB-Nova",
+      .probe 		= ttusb_probe,
+      .disconnect 	= ttusb_disconnect,
+      .id_table 	= ttusb_table,
+};
+
+static int __init ttusb_init(void)
+{
+	int err;
+
+	if ((err = usb_register(&ttusb_driver)) < 0) {
+		printk("%s: usb_register failed! Error number %d",
+		       __FILE__, err);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void __exit ttusb_exit(void)
+{
+	usb_deregister(&ttusb_driver);
+}
+
+module_init(ttusb_init);
+module_exit(ttusb_exit);
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug or not");
+
+MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
+MODULE_DESCRIPTION("TTUSB DVB Driver");
+MODULE_LICENSE("GPL");
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h	2003-07-15 09:39:13.000000000 +0200
@@ -0,0 +1,9 @@
+
+#include <asm/types.h>
+
+u8 dsp_bootcode [] __initdata = {
+	0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00, 
+ // firmware bootloader missing, this won't work!
+	0x07, 0xef, 0xf4, 0x95, 0xf4, 0x95, 0x00, 0x00, 
+};
+
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/Kconfig linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/Kconfig
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/Kconfig	2003-06-24 02:06:18.000000000 +0200
@@ -0,0 +1,24 @@
+config DVB_TTUSB_DEC
+	tristate "Technotrend/Hauppauge USB DEC2000-T devices"
+	depends on DVB_CORE && USB
+	help
+	  Support for external USB adapters designed by Technotrend and
+	  produced by Hauppauge, shipped under the brand name 'DEC2000-T'.
+
+          Even if these devices have a MPEG decoder built in, they transmit
+	  only compressed MPEG data over the USB bus, so you need
+	  an external software decoder to watch TV on your computer.	  
+
+	  Say Y if you own such a device and want to use it.
+
+config DVB_TTUSB_DEC_FIRMWARE_FILE
+	string "Full pathname of dec2000t.bin firmware file"
+	depends on DVB_TTUSB_DEC
+	default "/etc/dvb/dec2000t.bin"
+	help
+	  The DEC2000-T requires a firmware in order to boot into a mode in
+	  which it is a slave to the PC.  The firmware file can obtained as
+	  follows:
+	    wget http://hauppauge.lightpath.net/de/dec215a.exe
+	    unzip -j dec215a.exe Software/Oem/STB/App/Boot/STB_PC_T.bin
+	    mv STB_PC_T.bin /etc/dvb/dec2000t.bin
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/Makefile linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/Makefile
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/Makefile	2003-06-24 02:06:18.000000000 +0200
@@ -0,0 +1,11 @@
+
+obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o dec2000_frontend.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+
+host-progs	:= fdump
+
+$(obj)/ttusb_dec.o: $(obj)/dsp_dec2000.h
+
+$(obj)/dsp_dec2000.h: $(patsubst "%", %, $(CONFIG_DVB_TTUSB_DEC_FIRMWARE_FILE)) $(obj)/fdump
+	$(obj)/fdump $< dsp_dec2000 > $@
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/dec2000_frontend.c linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/dec2000_frontend.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/dec2000_frontend.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/dec2000_frontend.c	2003-07-14 11:56:39.000000000 +0200
@@ -0,0 +1,180 @@
+/*
+ * TTUSB DEC-2000-t Frontend
+ *
+ * Copyright (C) 2003 Alex Woods <linux-dvb@giblets.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "dvb_functions.h"
+
+static int debug = 0;
+
+#define dprintk	if (debug) printk
+
+static struct dvb_frontend_info dec2000_frontend_info = {
+	name:			"TechnoTrend/Hauppauge DEC-2000-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 int dec2000_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
+				  void *arg)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+
+	case FE_GET_INFO:
+		dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
+		memcpy(arg, &dec2000_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;
+			struct i2c_msg msg = { addr: 0x71, flags: 0, len:20 };
+
+			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 (int));
+			msg.buf = b;
+			fe->i2c->xfer(fe->i2c, &msg, 1);
+
+			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_RESET:
+		dprintk("%s: FE_RESET\n", __FUNCTION__);
+		break;
+
+	default:
+		dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
+		return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+static int dec2000_frontend_attach(struct dvb_i2c_bus *i2c)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	dvb_register_frontend(dec2000_frontend_ioctl, i2c, NULL,
+			      &dec2000_frontend_info);
+
+	return 0;
+}
+
+static void dec2000_frontend_detach(struct dvb_i2c_bus *i2c)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	dvb_unregister_frontend(dec2000_frontend_ioctl, i2c);
+}
+
+static int __init dec2000_frontend_init(void)
+{
+	return dvb_register_i2c_device(THIS_MODULE, dec2000_frontend_attach,
+				       dec2000_frontend_detach);
+}
+
+static void __exit dec2000_frontend_exit(void)
+{
+	dvb_unregister_i2c_device(dec2000_frontend_attach);
+}
+
+module_init(dec2000_frontend_init);
+module_exit(dec2000_frontend_exit);
+
+MODULE_DESCRIPTION("TechnoTrend/Hauppauge DEC-2000-t Frontend");
+MODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
+
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/fdump.c linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/fdump.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/fdump.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/fdump.c	2003-06-24 02:06:18.000000000 +0200
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+int main (int argc, char **argv)
+{
+	unsigned char buf[8];
+	unsigned int i, count, bytes = 0;
+	int fd;
+
+	if (argc != 3) {
+		fprintf (stderr, "\n\tusage: %s <ucode.bin> <array_name>\n\n",
+			 argv[0]);
+		return -1;
+	}
+
+	fd = open (argv[1], O_RDONLY);
+
+	printf ("\n#include <asm/types.h>\n\nu8 %s [] __initdata = {",
+		argv[2]);
+
+	while ((count = read (fd, buf, 8)) > 0) {
+		printf ("\n\t");
+		for (i=0;i<count;i++, bytes++)
+			printf ("0x%02x, ", buf[i]);
+	}
+
+	printf ("\n};\n\n");
+	close (fd);
+
+	return 0;
+}
+
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/ttusb_dec.c linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/ttusb_dec.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2003-07-14 11:56:39.000000000 +0200
@@ -0,0 +1,991 @@
+/*
+ * TTUSB DEC Driver
+ *
+ * Copyright (C) 2003 Alex Woods <linux-dvb@giblets.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "ttusb_dec.h"
+#include "dvb_frontend.h"
+
+static int debug = 0;
+
+#define dprintk	if (debug) printk
+
+static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
+				  int param_length, const u8 params[],
+				  int *result_length, u8 cmd_result[])
+{
+	int result, actual_len, i;
+	u8 b[COMMAND_PACKET_SIZE + 4];
+	u8 c[COMMAND_PACKET_SIZE + 4];
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if ((result = down_interruptible(&dec->usb_sem))) {
+		printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
+		return result;
+	}
+
+	b[0] = 0xaa;
+	b[1] = ++dec->trans_count;
+	b[2] = command;
+	b[3] = param_length;
+
+	if (params)
+		memcpy(&b[4], params, param_length);
+
+	if (debug) {
+		printk("%s: command: ", __FUNCTION__);
+		for (i = 0; i < param_length + 4; i++)
+			printk("0x%02X ", b[i]);
+		printk("\n");
+	}
+
+	result = usb_bulk_msg(dec->udev, dec->command_pipe, b, sizeof(b),
+			      &actual_len, HZ);
+
+	if (result) {
+		printk("%s: command bulk message failed: error %d\n",
+		       __FUNCTION__, result);
+		up(&dec->usb_sem);
+		return result;
+	}
+
+	result = usb_bulk_msg(dec->udev, dec->result_pipe, c, sizeof(c),
+			      &actual_len, HZ);
+
+	if (result) {
+		printk("%s: result bulk message failed: error %d\n",
+		       __FUNCTION__, result);
+		up(&dec->usb_sem);
+		return result;
+	} else {
+		if (debug) {
+			printk("%s: result: ", __FUNCTION__);
+			for (i = 0; i < actual_len; i++)
+				printk("0x%02X ", c[i]);
+			printk("\n");
+		}
+
+		if (result_length)
+			*result_length = c[3];
+		if (cmd_result && c[3] > 0)
+			memcpy(cmd_result, &c[4], c[3]);
+
+		up(&dec->usb_sem);
+
+		return 0;
+	}
+}
+
+static int ttusb_dec_av_pes2ts_cb(void *priv, unsigned char *data)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)priv;
+
+	dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK);
+
+	return 0;
+}
+
+static void ttusb_dec_set_pids(struct ttusb_dec *dec)
+{
+	u8 b[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+		   0xff, 0xff };
+
+	u16 pcr = htons(dec->pid[DMX_PES_PCR]);
+	u16 audio = htons(dec->pid[DMX_PES_AUDIO]);
+	u16 video = htons(dec->pid[DMX_PES_VIDEO]);
+
+	dprintk("%s\n", __FUNCTION__);
+
+	memcpy(&b[0], &pcr, 2);
+	memcpy(&b[2], &audio, 2);
+	memcpy(&b[4], &video, 2);
+
+	ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
+
+	if (!down_interruptible(&dec->pes2ts_sem)) {
+		dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
+				       ttusb_dec_av_pes2ts_cb, dec->demux.feed);
+		dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
+				       ttusb_dec_av_pes2ts_cb, dec->demux.feed);
+
+		up(&dec->pes2ts_sem);
+	}
+}
+
+static int ttusb_dec_i2c_master_xfer(struct dvb_i2c_bus *i2c,
+				     const struct i2c_msg msgs[], int num)
+{
+	int result, i;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	for (i = 0; i < num; i++)
+		if ((result = ttusb_dec_send_command(i2c->data, msgs[i].addr,
+						     msgs[i].len, msgs[i].buf,
+						     NULL, NULL)))
+			return result;
+
+	return 0;
+}
+
+static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes,
+				     int length)
+{
+	int i;
+	u16 csum = 0;
+	u8 c;
+
+	if (length < 16) {
+		printk("%s: packet too short.\n", __FUNCTION__);
+		return;
+	}
+
+	for (i = 0; i < length; i += 2) {
+		csum ^= le16_to_cpup((u16 *)(av_pes + i));
+		c = av_pes[i];
+		av_pes[i] = av_pes[i + 1];
+		av_pes[i + 1] = c;
+	}
+
+	if (csum) {
+		printk("%s: checksum failed.\n", __FUNCTION__);
+		return;
+	}
+
+	if (length > 8 + MAX_AV_PES_LENGTH + 4) {
+		printk("%s: packet too long.\n", __FUNCTION__);
+		return;
+	}
+
+	if (!(av_pes[0] == 'A' && av_pes[1] == 'V')) {
+		printk("%s: invalid AV_PES packet.\n", __FUNCTION__);
+		return;
+	}
+
+	switch (av_pes[2]) {
+
+	case 0x01: {		/* VideoStream */
+			int prebytes = av_pes[5] & 0x03;
+			int postbytes = (av_pes[5] & 0x0c) >> 2;
+			u16 v_pes_payload_length;
+
+			if (dec->v_pes_postbytes > 0 &&
+			    dec->v_pes_postbytes == prebytes) {
+				memcpy(&dec->v_pes[dec->v_pes_length],
+				       &av_pes[12], prebytes);
+
+				if (!down_interruptible(&dec->pes2ts_sem)) {
+					dvb_filter_pes2ts(&dec->v_pes2ts,
+							  dec->v_pes,
+							  dec->v_pes_length +
+							  prebytes);
+
+					up(&dec->pes2ts_sem);
+				}
+			}
+
+			if (av_pes[5] & 0x10) {
+				dec->v_pes[7] = 0x80;
+				dec->v_pes[8] = 0x05;
+
+				dec->v_pes[9] = 0x21 |
+						((av_pes[8] & 0xc0) >> 5);
+				dec->v_pes[10] = ((av_pes[8] & 0x3f) << 2) |
+						 ((av_pes[9] & 0xc0) >> 6);
+				dec->v_pes[11] = 0x01 |
+						 ((av_pes[9] & 0x3f) << 2) |
+						 ((av_pes[10] & 0x80) >> 6);
+				dec->v_pes[12] = ((av_pes[10] & 0x7f) << 1) |
+						 ((av_pes[11] & 0xc0) >> 7);
+				dec->v_pes[13] = 0x01 |
+						 ((av_pes[11] & 0x7f) << 1);
+
+				memcpy(&dec->v_pes[14], &av_pes[12 + prebytes],
+				       length - 16 - prebytes);
+				dec->v_pes_length = 14 + length - 16 - prebytes;
+			} else {
+				dec->v_pes[7] = 0x00;
+				dec->v_pes[8] = 0x00;
+
+				memcpy(&dec->v_pes[9], &av_pes[8], length - 12);
+				dec->v_pes_length = 9 + length - 12;
+			}
+
+			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;
+
+			v_pes_payload_length = htons(dec->v_pes_length - 6 +
+						     postbytes);
+			memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
+
+			if (postbytes == 0) {
+				if (!down_interruptible(&dec->pes2ts_sem)) {
+					dvb_filter_pes2ts(&dec->v_pes2ts,
+							  dec->v_pes,
+							  dec->v_pes_length);
+
+					up(&dec->pes2ts_sem);
+				}
+			}
+
+			break;
+		}
+
+	case 0x02:		/* MainAudioStream */
+		dvb_filter_pes2ts(&dec->a_pes2ts, &av_pes[8], length - 12);
+		break;
+
+	default:
+		printk("%s: unknown AV_PES type: %02x.\n", __FUNCTION__,
+		       av_pes[2]);
+		break;
+
+	}
+}
+
+static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b,
+					int length)
+{
+	while (length) {
+		switch (dec->av_pes_state) {
+
+		case 0:
+		case 1:
+		case 3:
+			if (*b++ == 0xaa) {
+				dec->av_pes_state++;
+				if (dec->av_pes_state == 4)
+					dec->av_pes_length = 0;
+			} else {
+				dec->av_pes_state = 0;
+			}
+
+			length--;
+			break;
+
+		case 2:
+			if (*b++ == 0x00) {
+				dec->av_pes_state++;
+			} else {
+				dec->av_pes_state = 0;
+			}
+
+			length--;
+			break;
+
+		case 4:
+			dec->av_pes[dec->av_pes_length++] = *b++;
+
+			if (dec->av_pes_length == 8) {
+				dec->av_pes_state++;
+				dec->av_pes_payload_length = le16_to_cpup(
+						(u16 *)(dec->av_pes + 6));
+			}
+
+			length--;
+			break;
+
+		case 5: {
+				int remainder = dec->av_pes_payload_length +
+						8 - dec->av_pes_length;
+
+				if (length >= remainder) {
+					memcpy(dec->av_pes + dec->av_pes_length,
+					       b, remainder);
+					dec->av_pes_length += remainder;
+					b += remainder;
+					length -= remainder;
+					dec->av_pes_state++;
+				} else {
+					memcpy(&dec->av_pes[dec->av_pes_length],
+					       b, length);
+					dec->av_pes_length += length;
+					length = 0;
+				}
+
+				break;
+			}
+
+		case 6:
+			dec->av_pes[dec->av_pes_length++] = *b++;
+
+			if (dec->av_pes_length ==
+			    8 + dec->av_pes_payload_length + 4) {
+				ttusb_dec_process_av_pes(dec, dec->av_pes,
+							 dec->av_pes_length);
+				dec->av_pes_state = 0;
+			}
+
+			length--;
+			break;
+
+		default:
+			printk("%s: illegal packet state encountered.\n",
+			       __FUNCTION__);
+			dec->av_pes_state = 0;
+
+		}
+
+	}
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void ttusb_dec_process_urb(struct urb *urb)
+#else
+static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)
+#endif
+{
+	struct ttusb_dec *dec = urb->context;
+
+	if (!urb->status) {
+		int i;
+
+		for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {
+			struct usb_iso_packet_descriptor *d;
+			u8 *b;
+			int length;
+
+			d = &urb->iso_frame_desc[i];
+			b = urb->transfer_buffer + d->offset;
+			length = d->actual_length;
+
+			ttusb_dec_process_urb_frame(dec, b, length);
+		}
+	} else {
+		 /* -ENOENT is expected when unlinking urbs */
+		if (urb->status != -ENOENT)
+			dprintk("%s: urb error: %d\n", __FUNCTION__,
+				urb->status);
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	if (dec->iso_stream_count)
+		usb_submit_urb(urb, GFP_KERNEL);
+#endif
+}
+
+static void ttusb_dec_setup_urbs(struct ttusb_dec *dec)
+{
+	int i, j, buffer_offset = 0;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		int frame_offset = 0;
+		struct urb *urb = dec->iso_urb[i];
+
+		urb->dev = dec->udev;
+		urb->context = dec;
+		urb->complete = ttusb_dec_process_urb;
+		urb->pipe = dec->stream_pipe;
+		urb->transfer_flags = URB_ISO_ASAP;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		urb->interval = 1;
+#endif
+		urb->number_of_packets = FRAMES_PER_ISO_BUF;
+		urb->transfer_buffer_length = ISO_FRAME_SIZE *
+					      FRAMES_PER_ISO_BUF;
+		urb->transfer_buffer = dec->iso_buffer + buffer_offset;
+		buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
+
+		for (j = 0; j < FRAMES_PER_ISO_BUF; j++) {
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = ISO_FRAME_SIZE;
+			frame_offset += ISO_FRAME_SIZE;
+		}
+	}
+}
+
+static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
+{
+	int i;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if (down_interruptible(&dec->iso_sem))
+		return;
+
+	dec->iso_stream_count--;
+
+	if (!dec->iso_stream_count) {
+		u8 b0[] = { 0x00 };
+
+		for (i = 0; i < ISO_BUF_COUNT; i++)
+			usb_unlink_urb(dec->iso_urb[i]);
+
+		ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL);
+	}
+
+	up(&dec->iso_sem);
+}
+
+/* Setting the interface of the DEC tends to take down the USB communications
+ * for a short period, so it's important not to call this function just before
+ * trying to talk to it.
+ */
+static void ttusb_dec_set_streaming_interface(struct ttusb_dec *dec)
+{
+	if (!dec->interface) {
+		usb_set_interface(dec->udev, 0, 8);
+		dec->interface = 8;
+	}
+}
+
+static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
+{
+	int i, result;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if (down_interruptible(&dec->iso_sem))
+		return -EAGAIN;
+
+	if (!dec->iso_stream_count) {
+		u8 b0[] = { 0x05 };
+
+		ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL);
+
+		ttusb_dec_setup_urbs(dec);
+
+		for (i = 0; i < ISO_BUF_COUNT; i++) {
+			if ((result = usb_submit_urb(dec->iso_urb[i]
+						    , GFP_KERNEL))) {
+				printk("%s: failed urb submission %d: "
+				       "error %d\n", __FUNCTION__, i, result);
+
+				while (i) {
+					usb_unlink_urb(dec->iso_urb[i - 1]);
+					i--;
+				}
+
+				up(&dec->iso_sem);
+				return result;
+			}
+		}
+
+		dec->av_pes_state = 0;
+		dec->v_pes_postbytes = 0;
+	}
+
+	dec->iso_stream_count++;
+
+	up(&dec->iso_sem);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	ttusb_dec_set_streaming_interface(dec);
+#endif
+
+	return 0;
+}
+
+static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ttusb_dec *dec = dvbdmx->priv;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if (!dvbdmx->dmx.frontend)
+		return -EINVAL;
+
+	dprintk("  pid: 0x%04X\n", dvbdmxfeed->pid);
+
+	switch (dvbdmxfeed->type) {
+
+	case DMX_TYPE_TS:
+		dprintk("  type: DMX_TYPE_TS\n");
+		break;
+
+	case DMX_TYPE_SEC:
+		dprintk("  type: DMX_TYPE_SEC\n");
+		break;
+
+	default:
+		dprintk("  type: unknown (%d)\n", dvbdmxfeed->type);
+		return -EINVAL;
+
+	}
+
+	dprintk("  ts_type:");
+
+	if (dvbdmxfeed->ts_type & TS_DECODER)
+		dprintk(" TS_DECODER");
+
+	if (dvbdmxfeed->ts_type & TS_PACKET)
+		dprintk(" TS_PACKET");
+
+	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
+		dprintk(" TS_PAYLOAD_ONLY");
+
+	dprintk("\n");
+
+	switch (dvbdmxfeed->pes_type) {
+
+	case DMX_TS_PES_VIDEO:
+		dprintk("  pes_type: DMX_TS_PES_VIDEO\n");
+		dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
+		dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid;
+		ttusb_dec_set_pids(dec);
+		break;
+
+	case DMX_TS_PES_AUDIO:
+		dprintk("  pes_type: DMX_TS_PES_AUDIO\n");
+		dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid;
+		ttusb_dec_set_pids(dec);
+		break;
+
+	case DMX_TS_PES_TELETEXT:
+		dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
+		dprintk("  pes_type: DMX_TS_PES_TELETEXT\n");
+		break;
+
+	case DMX_TS_PES_PCR:
+		dprintk("  pes_type: DMX_TS_PES_PCR\n");
+		dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
+		ttusb_dec_set_pids(dec);
+		break;
+
+	case DMX_TS_PES_OTHER:
+		dprintk("  pes_type: DMX_TS_PES_OTHER\n");
+		break;
+
+	default:
+		dprintk("  pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
+		return -EINVAL;
+
+	}
+
+	ttusb_dec_start_iso_xfer(dec);
+
+	return 0;
+}
+
+static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	ttusb_dec_stop_iso_xfer(dec);
+
+	return 0;
+}
+
+static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec)
+{
+	int i;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	for (i = 0; i < ISO_BUF_COUNT; i++)
+		if (dec->iso_urb[i])
+			usb_free_urb(dec->iso_urb[i]);
+
+	pci_free_consistent(NULL,
+			    ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF *
+					      ISO_BUF_COUNT),
+			    dec->iso_buffer, dec->iso_dma_handle);
+}
+
+static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
+{
+	int i;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	dec->iso_buffer = pci_alloc_consistent(NULL,
+					       ISO_FRAME_SIZE *
+					       (FRAMES_PER_ISO_BUF *
+						ISO_BUF_COUNT),
+				 	       &dec->iso_dma_handle);
+
+	memset(dec->iso_buffer, 0,
+	       sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)));
+
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		struct urb *urb;
+
+		if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) {
+			ttusb_dec_free_iso_urbs(dec);
+			return -ENOMEM;
+		}
+
+		dec->iso_urb[i] = urb;
+	}
+
+	ttusb_dec_setup_urbs(dec);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	for (i = 0; i < ISO_BUF_COUNT; i++) {
+		int next = (i + 1) % ISO_BUF_COUNT;
+		dec->iso_urb[i]->next = dec->iso_urb[next];
+	}
+#endif
+
+	return 0;
+}
+
+static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	dec->v_pes[0] = 0x00;
+	dec->v_pes[1] = 0x00;
+	dec->v_pes[2] = 0x01;
+	dec->v_pes[3] = 0xe0;
+}
+
+static void ttusb_dec_init_usb(struct ttusb_dec *dec)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	sema_init(&dec->usb_sem, 1);
+	sema_init(&dec->iso_sem, 1);
+
+	dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
+	dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
+	dec->stream_pipe = usb_rcvisocpipe(dec->udev, STREAM_PIPE);
+
+	ttusb_dec_alloc_iso_urbs(dec);
+}
+
+#include "dsp_dec2000.h"
+
+static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
+{
+	int i, j, actual_len, result, size, trans_count;
+	u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xc8, 0x61,
+		    0x00 };
+	u8 b1[] = { 0x61 };
+	u8 b[ARM_PACKET_SIZE];
+	u32 dsp_length = htonl(sizeof(dsp_dec2000));
+
+	dprintk("%s\n", __FUNCTION__);
+
+	memcpy(b0, &dsp_length, 4);
+
+	result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
+
+	if (result)
+		return result;
+
+	trans_count = 0;
+	j = 0;
+
+	for (i = 0; i < sizeof(dsp_dec2000); i += COMMAND_PACKET_SIZE) {
+		size = sizeof(dsp_dec2000) - i;
+		if (size > COMMAND_PACKET_SIZE)
+			size = COMMAND_PACKET_SIZE;
+
+		b[j + 0] = 0xaa;
+		b[j + 1] = trans_count++;
+		b[j + 2] = 0xf0;
+		b[j + 3] = size;
+		memcpy(&b[j + 4], &dsp_dec2000[i], size);
+
+		j += COMMAND_PACKET_SIZE + 4;
+
+		if (j >= ARM_PACKET_SIZE) {
+			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
+					      ARM_PACKET_SIZE, &actual_len,
+					      HZ / 10);
+			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);
+		}
+	}
+
+	result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
+
+	return result;
+}
+
+static void ttusb_dec_init_stb(struct ttusb_dec *dec)
+{
+	u8 c[COMMAND_PACKET_SIZE];
+	int c_length;
+	int result;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
+
+	if (!result)
+		if (c_length != 0x0c || (c_length == 0x0c && c[9] != 0x63))
+			ttusb_dec_boot_dsp(dec);
+}
+
+static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
+{
+	int result;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if ((result = dvb_register_adapter(&dec->adapter, "dec2000")) < 0) {
+		printk("%s: dvb_register_adapter failed: error %d\n",
+		       __FUNCTION__, result);
+
+		return result;
+	}
+
+	if (!(dec->i2c_bus = dvb_register_i2c_bus(ttusb_dec_i2c_master_xfer,
+						  dec, dec->adapter, 0))) {
+		printk("%s: dvb_register_i2c_bus failed\n", __FUNCTION__);
+
+		dvb_unregister_adapter(dec->adapter);
+
+		return -ENOMEM;
+	}
+
+	dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+
+	dec->demux.priv = (void *)dec;
+	dec->demux.filternum = 31;
+	dec->demux.feednum = 31;
+	dec->demux.start_feed = ttusb_dec_start_feed;
+	dec->demux.stop_feed = ttusb_dec_stop_feed;
+	dec->demux.write_to_decoder = NULL;
+
+	if ((result = dvb_dmx_init(&dec->demux)) < 0) {
+		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+		       result);
+
+		dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
+				       0);
+		dvb_unregister_adapter(dec->adapter);
+
+		return result;
+	}
+
+	dec->dmxdev.filternum = 32;
+	dec->dmxdev.demux = &dec->demux.dmx;
+	dec->dmxdev.capabilities = 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_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
+				       0);
+		dvb_unregister_adapter(dec->adapter);
+
+		return result;
+	}
+
+	dec->frontend.source = DMX_FRONTEND_0;
+
+	if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx,
+						  &dec->frontend)) < 0) {
+		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+		       result);
+
+		dvb_dmxdev_release(&dec->dmxdev);
+		dvb_dmx_release(&dec->demux);
+		dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
+				       0);
+		dvb_unregister_adapter(dec->adapter);
+
+		return result;
+	}
+
+	if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx,
+						      &dec->frontend)) < 0) {
+		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+		       result);
+
+		dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
+		dvb_dmxdev_release(&dec->dmxdev);
+		dvb_dmx_release(&dec->demux);
+		dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
+				       0);
+		dvb_unregister_adapter(dec->adapter);
+
+		return result;
+	}
+
+	sema_init(&dec->pes2ts_sem, 1);
+
+	dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx);
+
+	return 0;
+}
+
+static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	dvb_net_release(&dec->dvb_net);
+	dec->demux.dmx.close(&dec->demux.dmx);
+	dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
+	dvb_dmxdev_release(&dec->dmxdev);
+	dvb_dmx_release(&dec->demux);
+	dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, 0);
+	dvb_unregister_adapter(dec->adapter);
+}
+
+static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
+{
+	int i;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	dec->iso_stream_count = 0;
+
+	for (i = 0; i < ISO_BUF_COUNT; i++)
+		usb_unlink_urb(dec->iso_urb[i]);
+
+	ttusb_dec_free_iso_urbs(dec);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum,
+			     const struct usb_device_id *id)
+{
+	struct ttusb_dec *dec;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	if (ifnum != 0)
+		return NULL;
+
+	if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
+		printk("%s: couldn't allocate memory.\n", __FUNCTION__);
+		return NULL;
+	}
+
+	memset(dec, 0, sizeof(struct ttusb_dec));
+
+	dec->udev = udev;
+
+	ttusb_dec_init_usb(dec);
+	ttusb_dec_init_stb(dec);
+	ttusb_dec_init_dvb(dec);
+	ttusb_dec_init_v_pes(dec);
+
+	return (void *)dec;
+}
+#else
+static int ttusb_dec_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct ttusb_dec *dec;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	udev = interface_to_usbdev(intf);
+
+	if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
+		printk("%s: couldn't allocate memory.\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	memset(dec, 0, sizeof(struct ttusb_dec));
+
+	dec->udev = udev;
+
+	ttusb_dec_init_usb(dec);
+	ttusb_dec_init_stb(dec);
+	ttusb_dec_init_dvb(dec);
+	ttusb_dec_init_v_pes(dec);
+
+	usb_set_intfdata(intf, (void *)dec);
+	ttusb_dec_set_streaming_interface(dec);
+
+	return 0;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static void ttusb_dec_disconnect(struct usb_device *udev, void *data)
+{
+	struct ttusb_dec *dec = data;
+#else
+static void ttusb_dec_disconnect(struct usb_interface *intf)
+{
+	struct ttusb_dec *dec = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+#endif
+
+	dprintk("%s\n", __FUNCTION__);
+
+	ttusb_dec_exit_usb(dec);
+	ttusb_dec_exit_dvb(dec);
+
+	kfree(dec);
+}
+
+static struct usb_device_id ttusb_dec_table[] = {
+	{USB_DEVICE(0x0b48, 0x1006)},	/* Unconfirmed */
+	{USB_DEVICE(0x0b48, 0x1007)},	/* Unconfirmed */
+	{USB_DEVICE(0x0b48, 0x1008)},	/* DEC 2000 t */
+	{}
+};
+
+static struct usb_driver ttusb_dec_driver = {
+      name:		DRIVER_NAME,
+      probe:		ttusb_dec_probe,
+      disconnect:	ttusb_dec_disconnect,
+      id_table:		ttusb_dec_table,
+};
+
+static int __init ttusb_dec_init(void)
+{
+	int result;
+
+	if ((result = usb_register(&ttusb_dec_driver)) < 0) {
+		printk("%s: initialisation failed: error %d.\n", __FUNCTION__,
+		       result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit ttusb_dec_exit(void)
+{
+	usb_deregister(&ttusb_dec_driver);
+}
+
+module_init(ttusb_dec_init);
+module_exit(ttusb_dec_exit);
+
+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");
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/ttusb_dec.h linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/ttusb_dec.h
--- linux-2.6.0-test1.work/drivers/media/dvb/ttusb-dec/ttusb_dec.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttusb-dec/ttusb_dec.h	2003-07-14 11:56:39.000000000 +0200
@@ -0,0 +1,87 @@
+/*
+ * TTUSB DEC Driver
+ *
+ * Copyright (C) 2003 Alex Woods <linux-dvb@giblets.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _TTUSB_DEC_H
+#define _TTUSB_DEC_H
+
+#include "asm/semaphore.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_i2c.h"
+#include "dvb_net.h"
+
+#define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"
+
+#define COMMAND_PIPE		0x03
+#define RESULT_PIPE		0x84
+#define STREAM_PIPE		0x88
+
+#define COMMAND_PACKET_SIZE	0x3c
+#define ARM_PACKET_SIZE		0x1000
+
+#define ISO_BUF_COUNT		0x04
+#define FRAMES_PER_ISO_BUF	0x04
+#define ISO_FRAME_SIZE		0x0380
+
+#define	MAX_AV_PES_LENGTH	6144
+
+struct ttusb_dec {
+	/* DVB bits */
+	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;
+
+	u16			pid[DMX_PES_OTHER];
+
+	/* USB bits */
+	struct usb_device	*udev;
+	u8			trans_count;
+	unsigned int		command_pipe;
+	unsigned int		result_pipe;
+	unsigned int		stream_pipe;
+	int			interface;
+	struct semaphore	usb_sem;
+
+	void			*iso_buffer;
+	dma_addr_t		iso_dma_handle;
+	struct urb		*iso_urb[ISO_BUF_COUNT];
+	int			iso_stream_count;
+	struct semaphore	iso_sem;
+
+	u8			av_pes[MAX_AV_PES_LENGTH + 4];
+	int			av_pes_state;
+	int			av_pes_length;
+	int			av_pes_payload_length;
+
+	struct dvb_filter_pes2ts	a_pes2ts;
+	struct dvb_filter_pes2ts	v_pes2ts;
+	struct semaphore		pes2ts_sem;
+
+	u8			v_pes[16 + MAX_AV_PES_LENGTH];
+	int			v_pes_length;
+	int			v_pes_postbytes;
+};
+
+#endif


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2003-07-18  6:09 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-15 17:12 [PATCH 1/1] Add two drivers for USB based DVB-T adapters Michael Hunold
2003-07-15 21:20 ` Greg KH
2003-07-18  6:24   ` Michael Hunold

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).