All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Hunold <hunold@linuxtv.org>
To: akpm@osdl.org, torvalds@osdl.org, linux-kernel@vger.kernel.org
Subject: [PATCH 9/12] Update TTUSB DEC driver
Date: Fri, 19 Dec 2003 13:28:43 +0100	[thread overview]
Message-ID: <1071836923279@convergence.de> (raw)
In-Reply-To: <10718369223748@convergence.de>

DVB: - add support for the DEC3000-s (Alex Woods)
DVB: - use the hotplug firmware loader for 2.6 kernels instead of compiling the firmware into the module (Alex Woods)
diff -uNrwB --new-file linux-2.6.0/drivers/media/dvb/ttusb-dec/Kconfig linux-2.6.0-p/drivers/media/dvb/ttusb-dec/Kconfig
--- linux-2.6.0/drivers/media/dvb/ttusb-dec/Kconfig	2003-12-18 03:58:17.000000000 +0100
+++ linux-2.6.0-p/drivers/media/dvb/ttusb-dec/Kconfig	2003-12-08 16:19:01.000000000 +0100
@@ -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 -uNrwB --new-file linux-2.6.0/drivers/media/dvb/ttusb-dec/Makefile linux-2.6.0-p/drivers/media/dvb/ttusb-dec/Makefile
--- linux-2.6.0/drivers/media/dvb/ttusb-dec/Makefile	2003-12-18 03:58:56.000000000 +0100
+++ linux-2.6.0-p/drivers/media/dvb/ttusb-dec/Makefile	2003-12-08 16:19:01.000000000 +0100
@@ -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 -uNrwB --new-file linux-2.6.0/drivers/media/dvb/ttusb-dec/ttusb_dec.c linux-2.6.0-p/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- linux-2.6.0/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2003-12-18 03:59:37.000000000 +0100
+++ linux-2.6.0-p/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2003-12-10 13:50:16.000000000 +0100
@@ -19,19 +19,137 @@
  *
  */
 
-#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <linux/list.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/spinlock.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_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 @@
 				       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 @@
 				       &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 @@
 
 			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 @@
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 
 	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 @@
 
 	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 @@
 		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 @@
 		       __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 @@
 
 		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 @@
 		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 @@
 	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 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 @@
 		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 @@
 		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 @@
 
 	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 */
 	{}
 };
 


  reply	other threads:[~2003-12-19 12:36 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-12-19 12:28 [PATCH 0/12] LinuxTV.org DVB+V4L fixes Michael Hunold
2003-12-19 12:28 ` [PATCH 1/12] Remove firmware of av7110 driver Michael Hunold
2003-12-19 12:28   ` [PATCH 2/12] Update saa7146 capture core Michael Hunold
2003-12-19 12:28     ` [PATCH 3/12] Add new DVB driver Michael Hunold
2003-12-19 12:28       ` [PATCH 4/12] Update Skystar2 " Michael Hunold
2003-12-19 12:28         ` [PATCH 5/12] Update DVB core Michael Hunold
2003-12-19 12:28           ` [PATCH 6/12] Update DVB frontend drivers Michael Hunold
2003-12-19 12:28             ` [PATCH 7/12] Update av7110 driver Michael Hunold
2003-12-19 12:28               ` [PATCH 8/12] Add firmware loading support to " Michael Hunold
2003-12-19 12:28                 ` Michael Hunold [this message]
2003-12-19 12:28                   ` [PATCH 10/12] Cleanup patch to remove 2.4 crud Michael Hunold
2003-12-19 12:28                     ` [PATCH 11/12] Firmware_class update Michael Hunold
2003-12-19 12:28                       ` [PATCH 12/12] Add DVB documentation Michael Hunold

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=1071836923279@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.