From: Michael Hunold <hunold@linuxtv.org>
To: torvalds@osdl.org, akpm@osdl.org, linux-kernel@vger.kernel.org,
hunold@linuxtv.org
Subject: [PATCH 5/5] TTUSB DVB driver update
Date: Sun, 18 Jan 2004 13:35:42 -0500 [thread overview]
Message-ID: <10744509281247@convergence.de> (raw)
In-Reply-To: <10744509243070@convergence.de>
- [DVB] TTUSB-DEC update by Alex Woods:
- fix USB timeout bug under 2.6
- change some variable names to make it clearer what we are dealing with (PVA).
- support DEC2540-t and add info on it to the ttusb-dec docs.
- add model number returned from DEC2540-t firmware.
- add a module option to get the raw AVPES packets from the dvr device.
- send audio packets to their filter rather than the videos.
- handle the new empty packets that appear with the 2.16 firmware.
- extra error checks.
- handle the new firmwares that change the devices' USB IDs.
- tidy up the STB initialisation process a little.
- apply Hans-Frieder Vogt's patch for calculating firmware CRCs.
- [DVB] make TTUSB budget card depend on USB subsystem
diff -uraNbBw xx-linux-2.6.1-mm4/drivers/media/dvb/ttusb-budget/Kconfig linux-2.6.1-mm4.patched/drivers/media/dvb/ttusb-budget/Kconfig
--- xx-linux-2.6.1-mm4/drivers/media/dvb/ttusb-budget/Kconfig 2004-01-16 19:48:22.000000000 +0100
+++ linux-2.6.1-mm4.patched/drivers/media/dvb/ttusb-budget/Kconfig 2004-01-09 20:27:29.000000000 +0100
@@ -1,6 +1,6 @@
config DVB_TTUSB_BUDGET
tristate "Technotrend/Hauppauge Nova-USB devices"
- depends on DVB_CORE
+ 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'.
diff -urabBw xx-linux-2.6.1-mm4/drivers/media/dvb/ttusb-dec/ttusb_dec.c linux-2.6.1-mm4.usb/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- xx-linux-2.6.1-mm4/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-01-16 19:48:22.000000000 +0100
+++ linux-2.6.1-mm4.usb/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-01-18 15:32:39.000000000 +0100
@@ -20,9 +20,9 @@
*/
#include <asm/semaphore.h>
+#include <linux/crc32.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -39,6 +39,7 @@
#include "dvb_net.h"
static int debug = 0;
+static int output_pva = 0;
#define dprintk if (debug) printk
@@ -46,34 +47,44 @@
#define COMMAND_PIPE 0x03
#define RESULT_PIPE 0x84
-#define STREAM_PIPE 0x88
+#define IN_PIPE 0x88
+#define OUT_PIPE 0x07
#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 ISO_FRAME_SIZE 0x03FF
-#define MAX_AV_PES_LENGTH 6144
+#define MAX_PVA_LENGTH 6144
#define LOF_HI 10600000
#define LOF_LO 9750000
enum ttusb_dec_model {
TTUSB_DEC2000T,
+ TTUSB_DEC2540T,
TTUSB_DEC3000S
};
enum ttusb_dec_packet_type {
- PACKET_AV_PES,
- PACKET_SECTION
+ TTUSB_DEC_PACKET_PVA,
+ TTUSB_DEC_PACKET_SECTION,
+ TTUSB_DEC_PACKET_EMPTY
+};
+
+enum ttusb_dec_interface {
+ TTUSB_DEC_INTERFACE_INITIAL,
+ TTUSB_DEC_INTERFACE_IN,
+ TTUSB_DEC_INTERFACE_OUT
};
struct ttusb_dec {
enum ttusb_dec_model model;
char *model_name;
char *firmware_name;
+ int can_playback;
/* DVB bits */
struct dvb_adapter *adapter;
@@ -93,8 +104,9 @@
u8 trans_count;
unsigned int command_pipe;
unsigned int result_pipe;
- unsigned int stream_pipe;
- int interface;
+ unsigned int in_pipe;
+ unsigned int out_pipe;
+ enum ttusb_dec_interface interface;
struct semaphore usb_sem;
void *iso_buffer;
@@ -103,19 +115,20 @@
int iso_stream_count;
struct semaphore iso_sem;
- u8 packet[MAX_AV_PES_LENGTH + 4];
+ u8 packet[MAX_PVA_LENGTH + 4];
enum ttusb_dec_packet_type packet_type;
int packet_state;
int packet_length;
int packet_payload_length;
+ u16 next_packet_id;
- int av_pes_stream_count;
+ int pva_stream_count;
int filter_stream_count;
struct dvb_filter_pes2ts a_pes2ts;
struct dvb_filter_pes2ts v_pes2ts;
- u8 v_pes[16 + MAX_AV_PES_LENGTH];
+ u8 v_pes[16 + MAX_PVA_LENGTH];
int v_pes_length;
int v_pes_postbytes;
@@ -123,6 +136,8 @@
struct tasklet_struct urb_tasklet;
spinlock_t urb_frame_list_lock;
+ struct dvb_demux_filter *audio_filter;
+ struct dvb_demux_filter *video_filter;
struct list_head filter_info_list;
spinlock_t filter_info_list_lock;
@@ -167,6 +182,22 @@
FE_CAN_HIERARCHY_AUTO,
};
+static void ttusb_dec_set_model(struct ttusb_dec *dec,
+ enum ttusb_dec_model model);
+
+static u16 crc16(u16 crc, const u8 *buf, size_t len)
+{
+ u16 tmp;
+
+ while (len--) {
+ crc ^= *buf++;
+ crc ^= (u8)crc >> 4;
+ tmp = (u8)crc;
+ crc ^= (tmp ^ (tmp << 1)) << 4;
+ }
+ return crc;
+}
+
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[])
@@ -234,11 +265,57 @@
}
}
-static int ttusb_dec_av_pes2ts_cb(void *priv, unsigned char *data)
+static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
+ unsigned int *model, unsigned int *version)
+{
+ u8 c[COMMAND_PACKET_SIZE];
+ int c_length;
+ int result;
+ unsigned int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
+ if (result)
+ return result;
+
+ if (c_length >= 0x0c) {
+ if (mode != NULL) {
+ memcpy(&tmp, c, 4);
+ *mode = ntohl(tmp);
+ }
+ if (model != NULL) {
+ memcpy(&tmp, &c[4], 4);
+ *model = ntohl(tmp);
+ }
+ if (version != NULL) {
+ memcpy(&tmp, &c[8], 4);
+ *version = ntohl(tmp);
+ }
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)priv;
+ struct ttusb_dec *dec = (struct ttusb_dec *)priv;
- dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK);
+ dec->audio_filter->feed->cb.ts(data, 188, 0, 0,
+ &dec->audio_filter->feed->feed.ts,
+ DMX_OK);
+
+ return 0;
+}
+
+static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
+{
+ struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+
+ dec->video_filter->feed->cb.ts(data, 188, 0, 0,
+ &dec->video_filter->feed->feed.ts,
+ DMX_OK);
return 0;
}
@@ -262,64 +339,69 @@
ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
- ttusb_dec_av_pes2ts_cb, dec->demux.feed);
+ ttusb_dec_audio_pes2ts_cb, dec);
dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
- ttusb_dec_av_pes2ts_cb, dec->demux.feed);
+ ttusb_dec_video_pes2ts_cb, dec);
dec->v_pes_length = 0;
dec->v_pes_postbytes = 0;
}
-static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes,
- int length)
+static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
{
if (length < 8) {
printk("%s: packet too short - discarding\n", __FUNCTION__);
return;
}
- if (length > 8 + MAX_AV_PES_LENGTH) {
+ if (length > 8 + MAX_PVA_LENGTH) {
printk("%s: packet too long - discarding\n", __FUNCTION__);
return;
}
- switch (av_pes[2]) {
+ switch (pva[2]) {
case 0x01: { /* VideoStream */
- int prebytes = av_pes[5] & 0x03;
- int postbytes = (av_pes[5] & 0x0c) >> 2;
+ int prebytes = pva[5] & 0x03;
+ int postbytes = (pva[5] & 0x0c) >> 2;
u16 v_pes_payload_length;
+ if (output_pva) {
+ dec->video_filter->feed->cb.ts(pva, length, 0, 0,
+ &dec->video_filter->feed->feed.ts, DMX_OK);
+ return;
+ }
+
if (dec->v_pes_postbytes > 0 &&
dec->v_pes_postbytes == prebytes) {
memcpy(&dec->v_pes[dec->v_pes_length],
- &av_pes[12], prebytes);
+ &pva[12], prebytes);
dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
dec->v_pes_length + prebytes, 1);
}
- if (av_pes[5] & 0x10) {
+ if (pva[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[9] = 0x21 | ((pva[8] & 0xc0) >> 5);
+ dec->v_pes[10] = ((pva[8] & 0x3f) << 2) |
+ ((pva[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);
+ ((pva[9] & 0x3f) << 2) |
+ ((pva[10] & 0x80) >> 6);
+ dec->v_pes[12] = ((pva[10] & 0x7f) << 1) |
+ ((pva[11] & 0xc0) >> 7);
+ dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1);
- memcpy(&dec->v_pes[14], &av_pes[12 + prebytes],
+ memcpy(&dec->v_pes[14], &pva[12 + prebytes],
length - 12 - prebytes);
dec->v_pes_length = 14 + length - 12 - prebytes;
} else {
dec->v_pes[7] = 0x00;
dec->v_pes[8] = 0x00;
- memcpy(&dec->v_pes[9], &av_pes[8], length - 8);
+ memcpy(&dec->v_pes[9], &pva[8], length - 8);
dec->v_pes_length = 9 + length - 8;
}
@@ -344,13 +426,19 @@
}
case 0x02: /* MainAudioStream */
- dvb_filter_pes2ts(&dec->a_pes2ts, &av_pes[8], length - 8,
- av_pes[5] & 0x10);
+ if (output_pva) {
+ dec->audio_filter->feed->cb.ts(pva, length, 0, 0,
+ &dec->audio_filter->feed->feed.ts, DMX_OK);
+ return;
+ }
+
+ dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8,
+ pva[5] & 0x10);
break;
default:
- printk("%s: unknown AV_PES type: %02x.\n", __FUNCTION__,
- av_pes[2]);
+ printk("%s: unknown PVA type: %02x.\n", __FUNCTION__,
+ pva[2]);
break;
}
}
@@ -385,6 +473,7 @@
{
int i;
u16 csum = 0;
+ u16 packet_id;
if (dec->packet_length % 2) {
printk("%s: odd sized packet - discarding\n", __FUNCTION__);
@@ -399,18 +488,34 @@
return;
}
+ packet_id = dec->packet[dec->packet_length - 4] << 8;
+ packet_id += dec->packet[dec->packet_length - 3];
+
+ if ((packet_id != dec->next_packet_id) && dec->next_packet_id) {
+ printk("%s: warning: lost packets between %u and %u\n",
+ __FUNCTION__, dec->next_packet_id - 1, packet_id);
+ }
+
+ if (packet_id == 0xffff)
+ dec->next_packet_id = 0x8000;
+ else
+ dec->next_packet_id = packet_id + 1;
+
switch (dec->packet_type) {
- case PACKET_AV_PES:
- if (dec->av_pes_stream_count)
- ttusb_dec_process_av_pes(dec, dec->packet,
+ case TTUSB_DEC_PACKET_PVA:
+ if (dec->pva_stream_count)
+ ttusb_dec_process_pva(dec, dec->packet,
dec->packet_payload_length);
break;
- case PACKET_SECTION:
+ case TTUSB_DEC_PACKET_SECTION:
if (dec->filter_stream_count)
ttusb_dec_process_filter(dec, dec->packet,
dec->packet_payload_length);
break;
+
+ case TTUSB_DEC_PACKET_EMPTY:
+ break;
}
}
@@ -459,15 +564,25 @@
case 4:
dec->packet[dec->packet_length++] = *b++;
- if (dec->packet_length == 3) {
+ if (dec->packet_length == 2) {
if (dec->packet[0] == 'A' &&
dec->packet[1] == 'V') {
- dec->packet_type = PACKET_AV_PES;
+ dec->packet_type =
+ TTUSB_DEC_PACKET_PVA;
dec->packet_state++;
} else if (dec->packet[0] == 'S') {
- dec->packet_type = PACKET_SECTION;
+ dec->packet_type =
+ TTUSB_DEC_PACKET_SECTION;
dec->packet_state++;
+ } else if (dec->packet[0] == 0x00) {
+ dec->packet_type =
+ TTUSB_DEC_PACKET_EMPTY;
+ dec->packet_payload_length = 2;
+ dec->packet_state = 7;
} else {
+ printk("%s: unknown packet type: "
+ "%02x%02x\n", __FUNCTION__,
+ dec->packet[0], dec->packet[1]);
dec->packet_state = 0;
}
}
@@ -478,13 +593,14 @@
case 5:
dec->packet[dec->packet_length++] = *b++;
- if (dec->packet_type == PACKET_AV_PES &&
+ if (dec->packet_type == TTUSB_DEC_PACKET_PVA &&
dec->packet_length == 8) {
dec->packet_state++;
dec->packet_payload_length = 8 +
(dec->packet[6] << 8) +
dec->packet[7];
- } else if (dec->packet_type == PACKET_SECTION &&
+ } else if (dec->packet_type ==
+ TTUSB_DEC_PACKET_SECTION &&
dec->packet_length == 5) {
dec->packet_state++;
dec->packet_payload_length = 5 +
@@ -521,7 +637,7 @@
dec->packet[dec->packet_length++] = *b++;
- if (dec->packet_type == PACKET_SECTION &&
+ if (dec->packet_type == TTUSB_DEC_PACKET_SECTION &&
dec->packet_payload_length % 2)
tail++;
@@ -627,10 +742,9 @@
urb->dev = dec->udev;
urb->context = dec;
urb->complete = ttusb_dec_process_urb;
- urb->pipe = dec->stream_pipe;
+ urb->pipe = dec->in_pipe;
urb->transfer_flags = URB_ISO_ASAP;
urb->interval = 1;
-
urb->number_of_packets = FRAMES_PER_ISO_BUF;
urb->transfer_buffer_length = ISO_FRAME_SIZE *
FRAMES_PER_ISO_BUF;
@@ -668,12 +782,36 @@
* 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)
+static int ttusb_dec_set_interface(struct ttusb_dec *dec,
+ enum ttusb_dec_interface interface)
{
- if (!dec->interface) {
- usb_set_interface(dec->udev, 0, 8);
- dec->interface = 8;
+ int result = 0;
+ u8 b[] = { 0x05 };
+
+ if (interface != dec->interface) {
+ switch (interface) {
+ case TTUSB_DEC_INTERFACE_INITIAL:
+ result = usb_set_interface(dec->udev, 0, 0);
+ break;
+ case TTUSB_DEC_INTERFACE_IN:
+ result = ttusb_dec_send_command(dec, 0x80, sizeof(b),
+ b, NULL, NULL);
+ if (result)
+ return result;
+ result = usb_set_interface(dec->udev, 0, 7);
+ break;
+ case TTUSB_DEC_INTERFACE_OUT:
+ result = usb_set_interface(dec->udev, 0, 1);
+ break;
+ }
+
+ if (result)
+ return result;
+
+ dec->interface = interface;
}
+
+ return 0;
}
static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
@@ -688,6 +826,10 @@
if (!dec->iso_stream_count) {
ttusb_dec_setup_urbs(dec);
+ dec->packet_state = 0;
+ dec->v_pes_postbytes = 0;
+ dec->next_packet_id = 0;
+
for (i = 0; i < ISO_BUF_COUNT; i++) {
if ((result = usb_submit_urb(dec->iso_urb[i],
GFP_ATOMIC))) {
@@ -703,9 +845,6 @@
return result;
}
}
-
- dec->packet_state = 0;
- dec->v_pes_postbytes = 0;
}
dec->iso_stream_count++;
@@ -720,6 +859,7 @@
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct ttusb_dec *dec = dvbdmx->priv;
u8 b0[] = { 0x05 };
+ int result = 0;
dprintk("%s\n", __FUNCTION__);
@@ -742,12 +882,14 @@
dprintk(" pes_type: DMX_TS_PES_VIDEO\n");
dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid;
+ dec->video_filter = dvbdmxfeed->filter;
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;
+ dec->audio_filter = dvbdmxfeed->filter;
ttusb_dec_set_pids(dec);
break;
@@ -772,12 +914,12 @@
}
- ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL);
-
- dec->av_pes_stream_count++;
- ttusb_dec_start_iso_xfer(dec);
+ result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL);
+ if (result)
+ return result;
- return 0;
+ dec->pva_stream_count++;
+ return ttusb_dec_start_iso_xfer(dec);
}
static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed)
@@ -827,9 +969,7 @@
dvbdmxfeed->priv = finfo;
dec->filter_stream_count++;
- ttusb_dec_start_iso_xfer(dec);
-
- return 0;
+ return ttusb_dec_start_iso_xfer(dec);
}
return -EAGAIN;
@@ -872,7 +1012,7 @@
ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL);
- dec->av_pes_stream_count--;
+ dec->pva_stream_count--;
ttusb_dec_stop_iso_xfer(dec);
@@ -991,7 +1131,8 @@
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);
+ dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
+ dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
ttusb_dec_alloc_iso_urbs(dec);
}
@@ -1001,14 +1142,16 @@
int i, j, actual_len, result, size, trans_count;
u8 b0[] = { 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00 };
+ 0x61, 0x00 };
u8 b1[] = { 0x61 };
u8 b[ARM_PACKET_SIZE];
+ char idstring[21];
u8 *firmware = NULL;
size_t firmware_size = 0;
- u32 firmware_csum = 0;
+ u16 firmware_csum = 0;
+ u16 firmware_csum_ns;
u32 firmware_size_nl;
- u32 firmware_csum_nl;
+ u32 crc32_csum, crc32_check, tmp;
const struct firmware *fw_entry = NULL;
dprintk("%s\n", __FUNCTION__);
@@ -1022,20 +1165,33 @@
firmware = fw_entry->data;
firmware_size = fw_entry->size;
- switch (dec->model) {
- case TTUSB_DEC2000T:
- firmware_csum = 0x1bc86100;
- break;
-
- case TTUSB_DEC3000S:
- firmware_csum = 0x00000000;
- break;
- }
+ if (firmware_size < 60) {
+ printk("%s: firmware size too small for DSP code (%u < 60).\n",
+ __FUNCTION__, firmware_size);
+ return -1;
+ }
+
+ /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
+ at offset 56 of file, so use it to check if the firmware file is
+ valid. */
+ crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
+ memcpy(&tmp, &firmware[56], 4);
+ crc32_check = htonl(tmp);
+ if (crc32_csum != crc32_check) {
+ printk("%s: crc32 check of DSP code failed (calculated "
+ "0x%08x != 0x%08x in file), file invalid.\n",
+ __FUNCTION__, crc32_csum, crc32_check);
+ return -1;
+ }
+ memcpy(idstring, &firmware[36], 20);
+ idstring[20] = '\0';
+ printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
firmware_size_nl = htonl(firmware_size);
memcpy(b0, &firmware_size_nl, 4);
- firmware_csum_nl = htonl(firmware_csum);
- memcpy(&b0[6], &firmware_csum_nl, 4);
+ firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0;
+ firmware_csum_ns = htons(firmware_csum);
+ memcpy(&b0[6], &firmware_csum_ns, 2);
result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
@@ -1077,20 +1233,56 @@
static int ttusb_dec_init_stb(struct ttusb_dec *dec)
{
- u8 c[COMMAND_PACKET_SIZE];
- int c_length;
int result;
+ unsigned int mode, model, version;
dprintk("%s\n", __FUNCTION__);
- result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
+ result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);
if (!result) {
- if (c_length != 0x0c || (c_length == 0x0c && c[9] != 0x63))
- return ttusb_dec_boot_dsp(dec);
+ if (!mode) {
+ if (version == 0xABCDEFAB)
+ printk(KERN_INFO "ttusb_dec: no version "
+ "info in Firmware\n");
+ else
+ printk(KERN_INFO "ttusb_dec: Firmware "
+ "%x.%02x%c%c\n",
+ version >> 24, (version >> 16) & 0xff,
+ (version >> 8) & 0xff, version & 0xff);
+
+ result = ttusb_dec_boot_dsp(dec);
+ if (result)
+ return result;
else
+ return 1;
+ } else {
+ /* We can't trust the USB IDs that some firmwares
+ give the box */
+ switch (model) {
+ case 0x00070008:
+ ttusb_dec_set_model(dec, TTUSB_DEC3000S);
+ break;
+ case 0x00070009:
+ ttusb_dec_set_model(dec, TTUSB_DEC2000T);
+ break;
+ case 0x00070011:
+ ttusb_dec_set_model(dec, TTUSB_DEC2540T);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown model returned "
+ "by firmware (%08x) - please report\n",
+ __FUNCTION__, model);
+ return -1;
+ break;
+ }
+
+ if (version >= 0x01770000)
+ dec->can_playback = 1;
+
return 0;
}
+ }
else
return result;
}
@@ -1101,7 +1293,8 @@
dprintk("%s\n", __FUNCTION__);
- if ((result = dvb_register_adapter(&dec->adapter, dec->model_name)) < 0) {
+ if ((result = dvb_register_adapter(&dec->adapter,
+ dec->model_name)) < 0) {
printk("%s: dvb_register_adapter failed: error %d\n",
__FUNCTION__, result);
@@ -1449,18 +1638,6 @@
{
dec->i2c_bus.adapter = dec->adapter;
- switch (dec->model) {
- case TTUSB_DEC2000T:
- dec->frontend_info = &dec2000t_frontend_info;
- dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
- break;
-
- case TTUSB_DEC3000S:
- dec->frontend_info = &dec3000s_frontend_info;
- dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
- break;
- }
-
dvb_register_frontend(dec->frontend_ioctl, &dec->i2c_bus, (void *)dec,
dec->frontend_info);
}
@@ -1509,15 +1686,15 @@
switch (id->idProduct) {
case 0x1006:
- dec->model = TTUSB_DEC3000S;
- dec->model_name = "DEC3000-s";
- dec->firmware_name = "dvb-ttusb-dec-3000s-2.15a.fw";
+ ttusb_dec_set_model(dec, TTUSB_DEC3000S);
break;
case 0x1008:
- dec->model = TTUSB_DEC2000T;
- dec->model_name = "DEC2000-t";
- dec->firmware_name = "dvb-ttusb-dec-2000t-2.15a.fw";
+ ttusb_dec_set_model(dec, TTUSB_DEC2000T);
+ break;
+
+ case 0x1009:
+ ttusb_dec_set_model(dec, TTUSB_DEC2540T);
break;
}
@@ -1536,7 +1713,7 @@
dec->active = 1;
- ttusb_dec_set_streaming_interface(dec);
+ ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
return 0;
}
@@ -1560,15 +1737,45 @@
kfree(dec);
}
+static void ttusb_dec_set_model(struct ttusb_dec *dec,
+ enum ttusb_dec_model model)
+{
+ dec->model = model;
+
+ switch (model) {
+ case TTUSB_DEC2000T:
+ dec->model_name = "DEC2000-t";
+ dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
+ dec->frontend_info = &dec2000t_frontend_info;
+ dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
+ break;
+
+ case TTUSB_DEC2540T:
+ dec->model_name = "DEC2540-t";
+ dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
+ dec->frontend_info = &dec2000t_frontend_info;
+ dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
+ break;
+
+ case TTUSB_DEC3000S:
+ dec->model_name = "DEC3000-s";
+ dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
+ dec->frontend_info = &dec3000s_frontend_info;
+ dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
+ break;
+ }
+}
+
static struct usb_device_id ttusb_dec_table[] = {
{USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */
/*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */
{USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */
+ {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */
{}
};
static struct usb_driver ttusb_dec_driver = {
- .name = DRIVER_NAME,
+ .name = "ttusb-dec",
.probe = ttusb_dec_probe,
.disconnect = ttusb_dec_disconnect,
.id_table = ttusb_dec_table,
@@ -1602,3 +1809,5 @@
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug level");
+MODULE_PARM(output_pva, "i");
+MODULE_PARM_DESC(output_pva, "Output PVA from dvr device");
prev parent reply other threads:[~2004-01-18 18:43 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-01-18 18:35 [PATCH 0/5] LinuxTV.org DVB update Michael Hunold
2004-01-18 18:35 ` [PATCH 1/5] Update DVB documentation Michael Hunold
2004-01-18 18:35 ` [PATCH 2/5] Update saa7146 driver Michael Hunold
2004-01-18 18:35 ` [PATCH 3/5] Update DVB core Michael Hunold
2004-01-18 18:35 ` [PATCH 4/5] av7110 DVB driver splitup Michael Hunold
2004-01-18 18:35 ` Michael Hunold [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=10744509281247@convergence.de \
--to=hunold@linuxtv.org \
--cc=akpm@osdl.org \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.