From: Michael Hunold 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) 25-akpm/drivers/media/dvb/ttusb-dec/Kconfig | 28 - 25-akpm/drivers/media/dvb/ttusb-dec/Makefile | 10 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c | 560 ++++++++++++++++++++---- 3 files changed, 503 insertions(+), 95 deletions(-) diff -puN drivers/media/dvb/ttusb-dec/Kconfig~dvb-09-ttusb-dec-update drivers/media/dvb/ttusb-dec/Kconfig --- 25/drivers/media/dvb/ttusb-dec/Kconfig~dvb-09-ttusb-dec-update Fri Dec 19 14:55:07 2003 +++ 25-akpm/drivers/media/dvb/ttusb-dec/Kconfig Fri Dec 19 14:55:07 2003 @@ -1,24 +1,26 @@ config DVB_TTUSB_DEC - tristate "Technotrend/Hauppauge USB DEC2000-T devices" - depends on DVB_CORE && USB && !STANDALONE + tristate "Technotrend/Hauppauge USB DEC devices" + depends on DVB_CORE && USB && FW_LOADER help 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 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. + 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 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. diff -puN drivers/media/dvb/ttusb-dec/Makefile~dvb-09-ttusb-dec-update drivers/media/dvb/ttusb-dec/Makefile --- 25/drivers/media/dvb/ttusb-dec/Makefile~dvb-09-ttusb-dec-update Fri Dec 19 14:55:07 2003 +++ 25-akpm/drivers/media/dvb/ttusb-dec/Makefile Fri Dec 19 14:55:07 2003 @@ -1,11 +1,3 @@ - -obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o dec2000_frontend.o +obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.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 -puN drivers/media/dvb/ttusb-dec/ttusb_dec.c~dvb-09-ttusb-dec-update drivers/media/dvb/ttusb-dec/ttusb_dec.c --- 25/drivers/media/dvb/ttusb-dec/ttusb_dec.c~dvb-09-ttusb-dec-update Fri Dec 19 14:55:07 2003 +++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c Fri Dec 19 14:55:07 2003 @@ -19,19 +19,137 @@ * */ -#include +#include +#include #include #include #include +#include #include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include +#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_net.h" static int debug = 0; #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, int param_length, const u8 params[], int *result_length, u8 cmd_result[]) @@ -129,22 +247,8 @@ static void ttusb_dec_set_pids(struct tt 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); -} - -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; + dec->v_pes_length = 0; + dec->v_pes_postbytes = 0; } 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(str &av_pes[12], prebytes); 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) { @@ -239,13 +344,14 @@ static void ttusb_dec_process_av_pes(str if (postbytes == 0) dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length); + dec->v_pes_length, 1); break; } 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; default: @@ -379,7 +485,11 @@ static void ttusb_dec_process_urb(struct int 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; +#endif u8 *b; int length; struct urb_frame *frame; @@ -432,9 +542,11 @@ static void ttusb_dec_setup_urbs(struct 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->transfer_flags = URB_ISO_ASAP; urb->interval = 1; +#else + urb->transfer_flags = USB_ISO_ASAP; #endif urb->number_of_packets = FRAMES_PER_ISO_BUF; urb->transfer_buffer_length = ISO_FRAME_SIZE * @@ -502,8 +614,12 @@ static int ttusb_dec_start_iso_xfer(stru ttusb_dec_setup_urbs(dec); for (i = 0; i < ISO_BUF_COUNT; i++) { - if ((result = usb_submit_urb(dec->iso_urb[i] - , GFP_KERNEL))) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + 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: " "error %d\n", __FUNCTION__, i, result); @@ -659,7 +775,11 @@ static int ttusb_dec_alloc_iso_urbs(stru for (i = 0; i < ISO_BUF_COUNT; i++) { 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); return -ENOMEM; } @@ -711,20 +831,61 @@ static void ttusb_dec_init_usb(struct tt 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) { 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 }; u8 b1[] = { 0x61 }; 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__); - 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); @@ -734,8 +895,8 @@ static int ttusb_dec_boot_dsp(struct ttu trans_count = 0; j = 0; - for (i = 0; i < sizeof(dsp_dec2000); i += COMMAND_PACKET_SIZE) { - size = sizeof(dsp_dec2000) - i; + for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { + size = firmware_size - i; if (size > COMMAND_PACKET_SIZE) size = COMMAND_PACKET_SIZE; @@ -743,7 +904,7 @@ static int ttusb_dec_boot_dsp(struct ttu b[j + 1] = trans_count++; b[j + 2] = 0xf0; b[j + 3] = size; - memcpy(&b[j + 4], &dsp_dec2000[i], size); + memcpy(&b[j + 4], &firmware[i], size); j += COMMAND_PACKET_SIZE + 4; @@ -764,7 +925,7 @@ static int ttusb_dec_boot_dsp(struct ttu 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]; int c_length; @@ -774,9 +935,14 @@ static void ttusb_dec_init_stb(struct tt 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)) - 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) @@ -785,22 +951,13 @@ static int ttusb_dec_init_dvb(struct ttu 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", __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; @@ -814,8 +971,6 @@ static int ttusb_dec_init_dvb(struct ttu 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; @@ -830,8 +985,6 @@ static int ttusb_dec_init_dvb(struct ttu __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; @@ -846,8 +999,6 @@ static int ttusb_dec_init_dvb(struct ttu 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; @@ -861,8 +1012,6 @@ static int ttusb_dec_init_dvb(struct ttu 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; @@ -882,7 +1031,6 @@ static void ttusb_dec_exit_dvb(struct tt 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); } @@ -914,6 +1062,257 @@ static void ttusb_dec_exit_tasklet(struc } } +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) static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) @@ -929,19 +1328,6 @@ static void *ttusb_dec_probe(struct usb_ 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); - ttusb_dec_init_tasklet(dec); - - return (void *)dec; -} #else static int ttusb_dec_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -958,22 +1344,47 @@ static int ttusb_dec_probe(struct usb_in return -ENOMEM; } + usb_set_intfdata(intf, (void *)dec); +#endif + 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; 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_frontend(dec); ttusb_dec_init_v_pes(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); return 0; -} #endif +} #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) static void ttusb_dec_disconnect(struct usb_device *udev, void *data) @@ -989,17 +1400,20 @@ static void ttusb_dec_disconnect(struct dprintk("%s\n", __FUNCTION__); + if (dec->active) { ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_usb(dec); + ttusb_dec_exit_frontend(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 */ + {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ + /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ + {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ {} }; _