Commit 016b74ef authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] dvb: Update TTUSB DEC driver

From: Michael Hunold <hunold@linuxtv.org>

add support for the DEC3000-s (Alex Woods)

use the hotplug firmware loader for 2.6 kernels instead of compiling the
firmware into the module (Alex Woods)
parent 40c83765
config DVB_TTUSB_DEC config DVB_TTUSB_DEC
tristate "Technotrend/Hauppauge USB DEC2000-T devices" tristate "Technotrend/Hauppauge USB DEC devices"
depends on DVB_CORE && USB && !STANDALONE depends on DVB_CORE && USB && FW_LOADER
help help
Support for external USB adapters designed by Technotrend and Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'DEC2000-T'. produced by Hauppauge, shipped under the brand name 'DEC2000-t'
and 'DEC3000-s'.
Even if these devices have a MPEG decoder built in, they transmit Even if these devices have a MPEG decoder built in, they transmit
only compressed MPEG data over the USB bus, so you need only compressed MPEG data over the USB bus, so you need
an external software decoder to watch TV on your computer. an external software decoder to watch TV on your computer.
Say Y if you own such a device and want to use it. The DEC devices require firmware in order to boot into a mode in
which they are slaves to the PC. See
linux/Documentation/dvb/FIRMWARE for details.
The firmware can be obtained and put into the default
locations as follows:
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 wget http://hauppauge.lightpath.net/de/dec215a.exe
unzip -j dec215a.exe Software/Oem/STB/App/Boot/STB_PC_T.bin unzip -j dec215a.exe Software/Oem/STB/App/Boot/STB_PC_T.bin
mv STB_PC_T.bin /etc/dvb/dec2000t.bin mv STB_PC_T.bin /usr/lib/hotplug/firmware/dec2000t.bin
unzip -j dec215a.exe Software/Oem/STB/App/Boot/STB_PC_S.bin
mv STB_PC_S.bin /usr/lib/hotplug/firmware/dec3000s.bin
Say Y if you own such a device and want to use it.
obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o
obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o dec2000_frontend.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ 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 > $@
...@@ -19,19 +19,137 @@ ...@@ -19,19 +19,137 @@
* *
*/ */
#include <linux/version.h> #include <asm/semaphore.h>
#include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/version.h>
#include <linux/interrupt.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#include <linux/firmware.h>
#endif
#include "ttusb_dec.h" #include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_i2c.h"
#include "dvb_filter.h"
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "dvb_net.h"
static int debug = 0; static int debug = 0;
#define dprintk if (debug) printk #define dprintk if (debug) printk
#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
#define LOF_HI 10600000
#define LOF_LO 9750000
enum ttusb_model {
TTUSB_DEC2000T,
TTUSB_DEC3000S
};
struct ttusb_dec {
enum ttusb_model model;
char *model_name;
char *firmware_name;
/* 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;
struct dvb_frontend_info *frontend_info;
int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
u16 pid[DMX_PES_OTHER];
int hi_band;
/* 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;
u8 v_pes[16 + MAX_AV_PES_LENGTH];
int v_pes_length;
int v_pes_postbytes;
struct list_head urb_frame_list;
struct tasklet_struct urb_tasklet;
spinlock_t urb_frame_list_lock;
int active; /* Loaded successfully */
};
struct urb_frame {
u8 data[ISO_FRAME_SIZE];
int length;
struct list_head urb_frame_list;
};
static struct dvb_frontend_info dec2000t_frontend_info = {
.name = "TechnoTrend/Hauppauge DEC2000-t Frontend",
.type = FE_OFDM,
.frequency_min = 51000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO,
};
static struct dvb_frontend_info dec3000s_frontend_info = {
.name = "TechnoTrend/Hauppauge DEC3000-s Frontend",
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO,
};
static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
int param_length, const u8 params[], int param_length, const u8 params[],
int *result_length, u8 cmd_result[]) int *result_length, u8 cmd_result[])
...@@ -129,22 +247,8 @@ static void ttusb_dec_set_pids(struct ttusb_dec *dec) ...@@ -129,22 +247,8 @@ static void ttusb_dec_set_pids(struct ttusb_dec *dec)
ttusb_dec_av_pes2ts_cb, dec->demux.feed); ttusb_dec_av_pes2ts_cb, dec->demux.feed);
dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
ttusb_dec_av_pes2ts_cb, dec->demux.feed); ttusb_dec_av_pes2ts_cb, dec->demux.feed);
} dec->v_pes_length = 0;
dec->v_pes_postbytes = 0;
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, static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes,
...@@ -194,7 +298,8 @@ static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes, ...@@ -194,7 +298,8 @@ static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes,
&av_pes[12], prebytes); &av_pes[12], prebytes);
dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
dec->v_pes_length + prebytes); dec->v_pes_length + prebytes,
1);
} }
if (av_pes[5] & 0x10) { if (av_pes[5] & 0x10) {
...@@ -239,13 +344,14 @@ static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes, ...@@ -239,13 +344,14 @@ static void ttusb_dec_process_av_pes(struct ttusb_dec * dec, u8 * av_pes,
if (postbytes == 0) if (postbytes == 0)
dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
dec->v_pes_length); dec->v_pes_length, 1);
break; break;
} }
case 0x02: /* MainAudioStream */ case 0x02: /* MainAudioStream */
dvb_filter_pes2ts(&dec->a_pes2ts, &av_pes[8], length - 12); dvb_filter_pes2ts(&dec->a_pes2ts, &av_pes[8], length - 12,
av_pes[5] & 0x10);
break; break;
default: default:
...@@ -379,7 +485,11 @@ static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs) ...@@ -379,7 +485,11 @@ static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)
int i; int i;
for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
struct iso_packet_descriptor *d;
#else
struct usb_iso_packet_descriptor *d; struct usb_iso_packet_descriptor *d;
#endif
u8 *b; u8 *b;
int length; int length;
struct urb_frame *frame; struct urb_frame *frame;
...@@ -432,9 +542,11 @@ static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) ...@@ -432,9 +542,11 @@ static void ttusb_dec_setup_urbs(struct ttusb_dec *dec)
urb->context = dec; urb->context = dec;
urb->complete = ttusb_dec_process_urb; urb->complete = ttusb_dec_process_urb;
urb->pipe = dec->stream_pipe; urb->pipe = dec->stream_pipe;
urb->transfer_flags = URB_ISO_ASAP;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
urb->transfer_flags = URB_ISO_ASAP;
urb->interval = 1; urb->interval = 1;
#else
urb->transfer_flags = USB_ISO_ASAP;
#endif #endif
urb->number_of_packets = FRAMES_PER_ISO_BUF; urb->number_of_packets = FRAMES_PER_ISO_BUF;
urb->transfer_buffer_length = ISO_FRAME_SIZE * urb->transfer_buffer_length = ISO_FRAME_SIZE *
...@@ -502,8 +614,12 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) ...@@ -502,8 +614,12 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
ttusb_dec_setup_urbs(dec); ttusb_dec_setup_urbs(dec);
for (i = 0; i < ISO_BUF_COUNT; i++) { for (i = 0; i < ISO_BUF_COUNT; i++) {
if ((result = usb_submit_urb(dec->iso_urb[i] #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
, GFP_KERNEL))) { if ((result = usb_submit_urb(dec->iso_urb[i],
GFP_ATOMIC))) {
#else
if ((result = usb_submit_urb(dec->iso_urb[i]))) {
#endif
printk("%s: failed urb submission %d: " printk("%s: failed urb submission %d: "
"error %d\n", __FUNCTION__, i, result); "error %d\n", __FUNCTION__, i, result);
...@@ -659,7 +775,11 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) ...@@ -659,7 +775,11 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
for (i = 0; i < ISO_BUF_COUNT; i++) { for (i = 0; i < ISO_BUF_COUNT; i++) {
struct urb *urb; struct urb *urb;
if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {
#else
if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF))) {
#endif
ttusb_dec_free_iso_urbs(dec); ttusb_dec_free_iso_urbs(dec);
return -ENOMEM; return -ENOMEM;
} }
...@@ -711,20 +831,61 @@ static void ttusb_dec_init_usb(struct ttusb_dec *dec) ...@@ -711,20 +831,61 @@ static void ttusb_dec_init_usb(struct ttusb_dec *dec)
ttusb_dec_alloc_iso_urbs(dec); ttusb_dec_alloc_iso_urbs(dec);
} }
#include "dsp_dec2000.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
#include "dsp_dec2000t.h"
#include "dsp_dec3000s.h"
#endif
static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
{ {
int i, j, actual_len, result, size, trans_count; int i, j, actual_len, result, size, trans_count;
u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xc8, 0x61, u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 }; 0x00 };
u8 b1[] = { 0x61 }; u8 b1[] = { 0x61 };
u8 b[ARM_PACKET_SIZE]; u8 b[ARM_PACKET_SIZE];
u32 dsp_length = htonl(sizeof(dsp_dec2000)); u8 *firmware = NULL;
size_t firmware_size = 0;
u32 firmware_csum = 0;
u32 firmware_size_nl;
u32 firmware_csum_nl;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
const struct firmware *fw_entry = NULL;
#endif
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
memcpy(b0, &dsp_length, 4); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
printk(KERN_ERR "%s: Firmware (%s) unavailable.\n",
__FUNCTION__, dec->firmware_name);
return 1;
}
firmware = fw_entry->data;
firmware_size = fw_entry->size;
#endif
switch (dec->model) {
case TTUSB_DEC2000T:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
firmware = &dsp_dec2000t[0];
firmware_size = sizeof(dsp_dec2000t);
#endif
firmware_csum = 0x1bc86100;
break;
case TTUSB_DEC3000S:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
firmware = &dsp_dec3000s[0];
firmware_size = sizeof(dsp_dec3000s);
#endif
firmware_csum = 0x00000000;
break;
}
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);
result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
...@@ -734,8 +895,8 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) ...@@ -734,8 +895,8 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
trans_count = 0; trans_count = 0;
j = 0; j = 0;
for (i = 0; i < sizeof(dsp_dec2000); i += COMMAND_PACKET_SIZE) { for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
size = sizeof(dsp_dec2000) - i; size = firmware_size - i;
if (size > COMMAND_PACKET_SIZE) if (size > COMMAND_PACKET_SIZE)
size = COMMAND_PACKET_SIZE; size = COMMAND_PACKET_SIZE;
...@@ -743,7 +904,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) ...@@ -743,7 +904,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
b[j + 1] = trans_count++; b[j + 1] = trans_count++;
b[j + 2] = 0xf0; b[j + 2] = 0xf0;
b[j + 3] = size; b[j + 3] = size;
memcpy(&b[j + 4], &dsp_dec2000[i], size); memcpy(&b[j + 4], &firmware[i], size);
j += COMMAND_PACKET_SIZE + 4; j += COMMAND_PACKET_SIZE + 4;
...@@ -764,7 +925,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) ...@@ -764,7 +925,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
return result; return result;
} }
static void ttusb_dec_init_stb(struct ttusb_dec *dec) static int ttusb_dec_init_stb(struct ttusb_dec *dec)
{ {
u8 c[COMMAND_PACKET_SIZE]; u8 c[COMMAND_PACKET_SIZE];
int c_length; int c_length;
...@@ -774,9 +935,14 @@ static void ttusb_dec_init_stb(struct ttusb_dec *dec) ...@@ -774,9 +935,14 @@ static void ttusb_dec_init_stb(struct ttusb_dec *dec)
result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
if (!result) if (!result) {
if (c_length != 0x0c || (c_length == 0x0c && c[9] != 0x63)) if (c_length != 0x0c || (c_length == 0x0c && c[9] != 0x63))
ttusb_dec_boot_dsp(dec); return ttusb_dec_boot_dsp(dec);
else
return 0;
}
else
return result;
} }
static int ttusb_dec_init_dvb(struct ttusb_dec *dec) static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
...@@ -785,22 +951,13 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) ...@@ -785,22 +951,13 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
if ((result = dvb_register_adapter(&dec->adapter, "dec2000")) < 0) { if ((result = dvb_register_adapter(&dec->adapter, dec->model_name)) < 0) {
printk("%s: dvb_register_adapter failed: error %d\n", printk("%s: dvb_register_adapter failed: error %d\n",
__FUNCTION__, result); __FUNCTION__, result);
return 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.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
dec->demux.priv = (void *)dec; dec->demux.priv = (void *)dec;
...@@ -814,8 +971,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) ...@@ -814,8 +971,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
result); result);
dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
0);
dvb_unregister_adapter(dec->adapter); dvb_unregister_adapter(dec->adapter);
return result; return result;
...@@ -830,8 +985,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) ...@@ -830,8 +985,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
__FUNCTION__, result); __FUNCTION__, result);
dvb_dmx_release(&dec->demux); dvb_dmx_release(&dec->demux);
dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
0);
dvb_unregister_adapter(dec->adapter); dvb_unregister_adapter(dec->adapter);
return result; return result;
...@@ -846,8 +999,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) ...@@ -846,8 +999,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
dvb_dmxdev_release(&dec->dmxdev); dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux); dvb_dmx_release(&dec->demux);
dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
0);
dvb_unregister_adapter(dec->adapter); dvb_unregister_adapter(dec->adapter);
return result; return result;
...@@ -861,8 +1012,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) ...@@ -861,8 +1012,6 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
dvb_dmxdev_release(&dec->dmxdev); dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux); dvb_dmx_release(&dec->demux);
dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter,
0);
dvb_unregister_adapter(dec->adapter); dvb_unregister_adapter(dec->adapter);
return result; return result;
...@@ -882,7 +1031,6 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) ...@@ -882,7 +1031,6 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
dvb_dmxdev_release(&dec->dmxdev); dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux); dvb_dmx_release(&dec->demux);
dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, 0);
dvb_unregister_adapter(dec->adapter); dvb_unregister_adapter(dec->adapter);
} }
...@@ -914,6 +1062,257 @@ static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) ...@@ -914,6 +1062,257 @@ static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
} }
} }
static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
void *arg)
{
struct ttusb_dec *dec = fe->data;
dprintk("%s\n", __FUNCTION__);
switch (cmd) {
case FE_GET_INFO:
dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
memcpy(arg, dec->frontend_info,
sizeof (struct dvb_frontend_info));
break;
case FE_READ_STATUS: {
fe_status_t *status = (fe_status_t *)arg;
dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
break;
}
case FE_READ_BER: {
u32 *ber = (u32 *)arg;
dprintk("%s: FE_READ_BER\n", __FUNCTION__);
*ber = 0;
return -ENOSYS;
break;
}
case FE_READ_SIGNAL_STRENGTH: {
dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
*(s32 *)arg = 0xFF;
return -ENOSYS;
break;
}
case FE_READ_SNR:
dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
*(s32 *)arg = 0;
return -ENOSYS;
break;
case FE_READ_UNCORRECTED_BLOCKS:
dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
*(u32 *)arg = 0;
return -ENOSYS;
break;
case FE_SET_FRONTEND: {
struct dvb_frontend_parameters *p =
(struct dvb_frontend_parameters *)arg;
u8 b[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff };
u32 freq;
dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
dprintk(" frequency->%d\n", p->frequency);
dprintk(" symbol_rate->%d\n",
p->u.qam.symbol_rate);
dprintk(" inversion->%d\n", p->inversion);
freq = htonl(p->frequency / 1000);
memcpy(&b[4], &freq, sizeof (u32));
ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
break;
}
case FE_GET_FRONTEND:
dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
break;
case FE_SLEEP:
dprintk("%s: FE_SLEEP\n", __FUNCTION__);
return -ENOSYS;
break;
case FE_INIT:
dprintk("%s: FE_INIT\n", __FUNCTION__);
break;
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 ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
void *arg)
{
struct ttusb_dec *dec = fe->data;
dprintk("%s\n", __FUNCTION__);
switch (cmd) {
case FE_GET_INFO:
dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
memcpy(arg, dec->frontend_info,
sizeof (struct dvb_frontend_info));
break;
case FE_READ_STATUS: {
fe_status_t *status = (fe_status_t *)arg;
dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
break;
}
case FE_READ_BER: {
u32 *ber = (u32 *)arg;
dprintk("%s: FE_READ_BER\n", __FUNCTION__);
*ber = 0;
return -ENOSYS;
break;
}
case FE_READ_SIGNAL_STRENGTH: {
dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
*(s32 *)arg = 0xFF;
return -ENOSYS;
break;
}
case FE_READ_SNR:
dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
*(s32 *)arg = 0;
return -ENOSYS;
break;
case FE_READ_UNCORRECTED_BLOCKS:
dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
*(u32 *)arg = 0;
return -ENOSYS;
break;
case FE_SET_FRONTEND: {
struct dvb_frontend_parameters *p =
(struct dvb_frontend_parameters *)arg;
u8 b[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
u32 freq;
u32 sym_rate;
u32 band;
dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
dprintk(" frequency->%d\n", p->frequency);
dprintk(" symbol_rate->%d\n",
p->u.qam.symbol_rate);
dprintk(" inversion->%d\n", p->inversion);
freq = htonl(p->frequency * 1000 + (dec->hi_band ? LOF_HI : LOF_LO));
memcpy(&b[4], &freq, sizeof(u32));
sym_rate = htonl(p->u.qam.symbol_rate);
memcpy(&b[12], &sym_rate, sizeof(u32));
band = htonl(dec->hi_band ? LOF_HI : LOF_LO);
memcpy(&b[24], &band, sizeof(u32));
ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
break;
}
case FE_GET_FRONTEND:
dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
break;
case FE_SLEEP:
dprintk("%s: FE_SLEEP\n", __FUNCTION__);
return -ENOSYS;
break;
case FE_INIT:
dprintk("%s: FE_INIT\n", __FUNCTION__);
break;
case FE_RESET:
dprintk("%s: FE_RESET\n", __FUNCTION__);
break;
case FE_DISEQC_SEND_MASTER_CMD:
dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__);
break;
case FE_DISEQC_SEND_BURST:
dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__);
break;
case FE_SET_TONE: {
fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg;
dprintk("%s: FE_SET_TONE\n", __FUNCTION__);
dec->hi_band = (SEC_TONE_ON == tone);
break;
}
case FE_SET_VOLTAGE:
dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
break;
default:
dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
return -EINVAL;
}
return 0;
}
static void ttusb_dec_init_frontend(struct ttusb_dec *dec)
{
dec->i2c_bus.adapter = dec->adapter;
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);
}
static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
{
dvb_unregister_frontend(dec->frontend_ioctl, &dec->i2c_bus);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum, static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum,
const struct usb_device_id *id) const struct usb_device_id *id)
...@@ -929,19 +1328,6 @@ static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum, ...@@ -929,19 +1328,6 @@ static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum,
printk("%s: couldn't allocate memory.\n", __FUNCTION__); printk("%s: couldn't allocate memory.\n", __FUNCTION__);
return NULL; 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);
ttusb_dec_init_tasklet(dec);
return (void *)dec;
}
#else #else
static int ttusb_dec_probe(struct usb_interface *intf, static int ttusb_dec_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
...@@ -958,22 +1344,47 @@ static int ttusb_dec_probe(struct usb_interface *intf, ...@@ -958,22 +1344,47 @@ static int ttusb_dec_probe(struct usb_interface *intf,
return -ENOMEM; return -ENOMEM;
} }
usb_set_intfdata(intf, (void *)dec);
#endif
memset(dec, 0, sizeof(struct ttusb_dec)); memset(dec, 0, sizeof(struct ttusb_dec));
switch (id->idProduct) {
case 0x1006:
dec->model = TTUSB_DEC3000S;
dec->model_name = "DEC3000-s";
dec->firmware_name = "dec3000s.bin";
break;
case 0x1008:
dec->model = TTUSB_DEC2000T;
dec->model_name = "DEC2000-t";
dec->firmware_name = "dec2000t.bin";
break;
}
dec->udev = udev; dec->udev = udev;
ttusb_dec_init_usb(dec); ttusb_dec_init_usb(dec);
ttusb_dec_init_stb(dec); if (ttusb_dec_init_stb(dec)) {
ttusb_dec_exit_usb(dec);
return 0;
}
ttusb_dec_init_dvb(dec); ttusb_dec_init_dvb(dec);
ttusb_dec_init_frontend(dec);
ttusb_dec_init_v_pes(dec); ttusb_dec_init_v_pes(dec);
ttusb_dec_init_tasklet(dec); ttusb_dec_init_tasklet(dec);
usb_set_intfdata(intf, (void *)dec); dec->active = 1;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
return (void *)dec;
#else
ttusb_dec_set_streaming_interface(dec); ttusb_dec_set_streaming_interface(dec);
return 0; return 0;
}
#endif #endif
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void ttusb_dec_disconnect(struct usb_device *udev, void *data) static void ttusb_dec_disconnect(struct usb_device *udev, void *data)
...@@ -989,17 +1400,20 @@ static void ttusb_dec_disconnect(struct usb_interface *intf) ...@@ -989,17 +1400,20 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
if (dec->active) {
ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_tasklet(dec);
ttusb_dec_exit_usb(dec); ttusb_dec_exit_usb(dec);
ttusb_dec_exit_frontend(dec);
ttusb_dec_exit_dvb(dec); ttusb_dec_exit_dvb(dec);
}
kfree(dec); kfree(dec);
} }
static struct usb_device_id ttusb_dec_table[] = { static struct usb_device_id ttusb_dec_table[] = {
{USB_DEVICE(0x0b48, 0x1006)}, /* Unconfirmed */ {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */
{USB_DEVICE(0x0b48, 0x1007)}, /* Unconfirmed */ /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */
{USB_DEVICE(0x0b48, 0x1008)}, /* DEC 2000 t */ {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */
{} {}
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment