[PATCH 1/1] Add two drivers for USB based DVB-T adapters

From: LinuxTV.org CVS maintainer (hunold@convergence.de)
Date: Tue Jul 15 2003 - 12:12:53 EST


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

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Jul 15 2003 - 22:00:58 EST