[linux-dvb] [PATCH] Opera S1- DVB-USB

Marco Gittler g.marco at freenet.de
Sun Apr 15 19:55:09 CEST 2007


sorry missing patch itself is in this post.

Signed-of-by Marco Gittler <g.marco at freenet.de>

Signed-of-by: Mario Hlawitschka <dh1pa at amsat.org>

g.marco at freenet.de schrieb:
> here the corrected patch for the opera dvb s1 usb-box
>
> i hope it is now nicer than last time.
>
> some hints about the code are also welcome.
>
> firmware files can put somewhere here ?
>
> thx
>
> Signed-of-by Marco Gittler <g.marco at freenet.de>
>
> Signed-of-by: Mario Hlawitschka <dh1pa at amsat.org>
>
>
>
> _______________________________________________
> linux-dvb mailing list
> linux-dvb at linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

-------------- next part --------------
diff -r b5be3479f070 linux/drivers/media/dvb/dvb-usb/Kconfig
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig	Sat Apr 14 16:19:13 2007 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig	Fri Mar 02 19:04:20 2007 +0200
@@ -110,6 +110,7 @@ config DVB_USB_CXUSB
 
 	  Medion MD95700 hybrid USB2.0 device.
 	  DViCO FusionHDTV (Bluebird) USB2.0 devices
+
 
 config DVB_USB_M920X
 	tristate "Uli m920x DVB-T USB2.0 support"
@@ -211,3 +212,11 @@ config DVB_USB_DTT200U
 	  The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
 
 	  The WT-220U and its clones are pen-sized.
+
+config DVB_USB_OPERA1
+        tristate "Opera1 DVB-S USB2.0 receiver"
+        depends on DVB_USB
+        select DVB_STV0299 
+	#if !DVB_FE_CUSTOMISE
+        help
+	    Say Y here to support the Opera DVB-S USB2.0 receiver.
diff -r b5be3479f070 linux/drivers/media/dvb/dvb-usb/Makefile
--- a/linux/drivers/media/dvb/dvb-usb/Makefile	Sat Apr 14 16:19:13 2007 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/Makefile	Sun Apr 15 12:08:27 2007 +0200
@@ -51,4 +51,8 @@ dvb-usb-dib0700-objs = dib0700_core.o di
 dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
 obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
 
+dvb-usb-opera-objs = opera1.o
+obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
+
+
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff -r b5be3479f070 linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Sat Apr 14 16:19:13 2007 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Sun Apr 15 11:57:27 2007 +0200
@@ -38,6 +38,7 @@
 #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
 #define USB_VID_UNIWILL				0x1584
 #define USB_VID_WIDEVIEW			0x14aa
+#define USB_VID_OPERA1				0x695C
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
@@ -142,6 +143,8 @@
 #define USB_PID_GENPIX_8PSK_WARM			0x0201
 #define USB_PID_SIGMATEK_DVB_110			0x6610
 #define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
+#define USB_PID_OPERA1_COLD				0x2830
+#define USB_PID_OPERA1_WARM				0x3829
 
 
 #endif
diff -r b5be3479f070 linux/drivers/media/dvb/dvb-usb/opera1.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/dvb-usb/opera1.c	Sun Apr 15 12:05:45 2007 +0200
@@ -0,0 +1,574 @@
+/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
+*
+* Copyright (C) 2006 Mario Hlawitschka (dh1pa at amsat.org)
+* Copyright (C) 2006 Marco Gittler (g.marco at freenet.de)
+*
+*	This program is free software; you can redistribute it and/or modify it
+*	under the terms of the GNU General Public License as published by the Free
+*	Software Foundation, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+#include "opera1.h"
+#include "linux/module.h"
+#include "linux/init.h"
+#include "linux/firmware.h"
+#include "dvb-usb.h"
+#include "dvb-pll.h"
+#include "stv0299.h"
+
+
+#define OPERA_READ_MSG 0
+#define OPERA_WRITE_MSG 1
+#define OPERA_I2C_TUNER 0xd1
+
+#define READ_FX2_REG_REQ  0xBA
+#define OPERA_WRITE_FX2 0xBB
+#define OPERA_TUNER_REQ 0xB1
+
+
+struct opera1_state{
+	u32 last_key_pressed;
+};
+struct opera_rc_keys {
+	u32 keycode;
+	u32 event;
+};
+static const u8* xilinx_init="\x90\x6e\xc5\xfa\x32\xd0\x73\x23\x1e";
+static int opera1_xilinx_load_firmware(struct usb_device *dev, const char *filename);
+
+int dvb_usb_opera1_debug;
+module_param_named(debug,dvb_usb_opera1_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
+//struct mutex mymutex;
+
+static int opera1_xilinx_rw(struct usb_device*dev, u8 request, u16 value, u8*data, u16 len,int flags){
+
+	int ret=0,t=0;
+	u8 r[10];
+	u8 u8buf[len];
+	unsigned int pipe=(flags==OPERA_READ_MSG)?usb_rcvctrlpipe(dev,0):usb_sndctrlpipe(dev,0);
+	u8 request_type=(flags==OPERA_READ_MSG)?USB_DIR_IN:USB_DIR_OUT;
+
+	memset(r,0,10);
+	//if (mutex_lock_interruptible(&mymutex)){
+	//    return -EAGAIN;
+	//}
+
+	if (flags==OPERA_WRITE_MSG)
+	    memcpy(u8buf,data,len);
+	ret=usb_control_msg(dev, pipe,request, request_type| USB_TYPE_VENDOR,value, 0x0 /*index*/, u8buf,len, 2000);
+	//msleep(20);
+	if (request==OPERA_TUNER_REQ){
+		t=usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+		OPERA_TUNER_REQ, USB_DIR_IN|USB_TYPE_VENDOR, 0x01,0x0/*index*/, r, 10, 2000);
+	}
+	if (flags==OPERA_READ_MSG)
+	    memcpy(data,u8buf,len);
+	//mutex_unlock(&mymutex);
+	return ret;
+	
+}
+
+/* I2C */
+
+static int opera1_usb_i2c_msgxfer(struct dvb_usb_device* dev, u16 addr, u8* buf, u16 len, int flag)
+{
+	int ret=0;
+	u8 request;
+	u16 value;
+	
+	if (dev==NULL){
+			info ("no usb_device");
+			return -EINVAL;
+	}
+	if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
+			return -EAGAIN;
+
+	request=(addr&0xff00) >> 8;
+	if (!request)
+		request=0xb1;	
+	value=(addr&0xff);
+	if (flag & OPERA_READ_MSG){
+		value|=0x01;
+	}
+	if (request==0xa0)
+		value=0xe600;
+	ret=opera1_xilinx_rw(dev->udev,request,value,buf,len,flag);
+
+	mutex_unlock(&dev->usb_mutex);
+	return ret;
+}
+
+static int opera1_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i=0,tmp=0;
+	
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (d){
+		for (i=0;i<num;i++){
+			if ((tmp=opera1_usb_i2c_msgxfer(d,
+				 msg[i].addr,msg[i].buf,msg[i].len,
+				 (msg[i].flags==I2C_M_RD?OPERA_READ_MSG:OPERA_WRITE_MSG)))
+				!=msg[i].len){
+					
+					break;
+				}
+				if (dvb_usb_opera1_debug& 0x10)
+					info("sending i2c mesage %d %d",tmp,msg[i].len);
+		}
+	}
+	
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+static u32 opera1_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm opera1_i2c_algo = {
+	.master_xfer   = opera1_i2c_xfer,
+	.functionality = opera1_i2c_func,
+};
+
+static int opera1_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct i2c_msg msg[]={
+		{.addr=0xb600,.flags=0,.buf="\x00",.len=1}, //13 V
+	};
+	struct dvb_usb_adapter* udev_adap=(struct dvb_usb_adapter*)(fe->dvb->priv);
+	if (voltage==SEC_VOLTAGE_18){
+		msg[0].addr=0xb601;
+		msg[0].buf="\x01";	
+	}
+	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio){
+	stv0299_writereg(fe, 0x13, 0x98);
+	stv0299_writereg(fe, 0x14, 0x95);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+
+	return 0;
+
+}
+static u8 opera1_inittab[]={
+	0x00 ,0xa1 ,
+	0x01 ,0x15 ,
+	0x02 ,0x00 ,
+	0x03 ,0x00 ,
+	0x04 ,0x7d ,
+	0x05 ,0x05 ,
+	0x06 ,0x02 ,
+	0x07 ,0x00 ,
+	0x0b, 0x00 ,
+	0x0c ,0x01 ,
+	0x0d ,0x81 ,
+	0x0e ,0x44 ,
+	0x0f ,0x19 ,
+	0x10 ,0x3f ,
+	0x11 ,0x84 ,
+	0x12 ,0xda ,
+	0x13 ,0x98 ,
+	0x14 ,0x95 ,
+	0x15 ,0xc9 ,
+	0x16 ,0xeb ,
+	0x17 ,0x00 ,
+	0x18 ,0x19 ,
+	0x19 ,0x8b ,
+	0x1a ,0x00 ,
+	0x1b ,0x82 ,
+	0x1c,0x7f ,
+	0x1d,0x00 ,
+	0x1e,0x00 ,
+	0x1f,0x06 ,
+	0x20,0x50 ,
+	0x21,0x10 ,
+	0x22,0x00 ,
+	0x23,0x00 ,
+	0x24,0x37 ,
+	0x25,0xbc ,
+	0x26,0x00 ,
+	0x27,0x00 ,
+	0x28,0x00 ,
+	0x29,0x1e ,
+	0x2a,0x14 ,
+	0x2b,0x1f ,
+	0x2c,0x09 ,
+	0x2d,0x0a ,
+	0x2e,0x00 ,
+	0x2f,0x00 ,
+	0x30,0x00, 
+	0x31,0x1f ,
+	0x32,0x19 ,
+	0x33,0xfc ,
+	0x34,0x13,
+	0xff,0xff,
+};
+
+static struct stv0299_config opera1_stv0299_config={
+	.demod_address= 0xd0,
+	.min_delay_ms=100,
+	.mclk=88000000UL,
+	.invert=1,
+	.skip_reinit=0,
+	.lock_output=STV0229_LOCKOUTPUT_0,
+	.volt13_op0_op1=STV0299_VOLT13_OP0,
+	.inittab=opera1_inittab,
+	.set_symbol_rate=opera1_stv0299_set_symbol_rate,
+};
+
+static int opera1_frontend_attach(struct dvb_usb_adapter *d){
+
+	if ((d->fe=dvb_attach(stv0299_attach,&opera1_stv0299_config,&d->dev->i2c_adap))!=NULL){
+		d->fe->ops.set_voltage=opera1_set_voltage;
+		return 0;
+	}
+	info ("not attached stv0299");
+	return -EIO;
+}
+
+static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
+{
+    adap->pll_addr=0xc0;
+    adap->pll_desc=&dvb_pll_opera1;
+    adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+    return 0;
+}
+
+static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int addr=onoff?0xb701:0xb700;
+	u8 val=onoff?0x01:0x00;
+	if (dvb_usb_opera1_debug)
+		info("power %s",onoff?"on":"off");
+	return opera1_usb_i2c_msgxfer(d,addr,&val,1,OPERA_WRITE_MSG);	
+}
+static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+
+	struct i2c_msg start_tuner[]={
+		{.addr=0xb1a6,.buf=onoff?"\xff\x03":"\xff\x00",.len=2},
+	};
+	if (dvb_usb_opera1_debug)
+		info("streaming %s",onoff?"on":"off");
+	i2c_transfer(&adap->dev->i2c_adap,start_tuner,1);
+	return 0;
+}
+static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
+{
+
+	u8 b_pid[3];
+	struct i2c_msg msg[]={
+		{.addr=0xb1a6,.buf=b_pid,.len=3},
+	};
+	if (dvb_usb_opera1_debug)
+		info("pidfilter index: %d pid: %d %s",index,pid,onoff?"on":"off");
+	b_pid[0]=(2*index)+4;
+	b_pid[1]=onoff?(pid&0xff):(0x00);
+	b_pid[2]=onoff?((pid>>8)&0xff):(0x00);
+	i2c_transfer(&adap->dev->i2c_adap,msg,1);
+	return 0;
+}
+static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff){
+	int u=0x04;
+	u8 b_pid[3];
+	struct i2c_msg msg[]={
+		{.addr=0xb1a6,.buf=b_pid,.len=3},
+	};
+	if (dvb_usb_opera1_debug)
+		info("%s hw-pidfilter",onoff?"enable":"disable");
+	for ( ;u<0x7e;u+=2){
+		b_pid[0]=u;
+		b_pid[1]=0;
+		b_pid[2]=0x80;
+		i2c_transfer(&adap->dev->i2c_adap,msg,1);
+	}
+	return 0;
+}
+
+
+static struct dvb_usb_rc_key opera1_rc_keys[]={
+	{0x5f,0xa0,KEY_1},
+	{0x51,0xaf,KEY_2},
+	{0x5d,0xa2,KEY_3},
+	{0x41,0xbe,KEY_4},
+	
+	{0x0b,0xf5,KEY_5},
+	{0x43,0xbd,KEY_6},
+	{0x47,0xb8,KEY_7},
+	{0x49,0xb6,KEY_8},
+	{0x05,0xfa,KEY_9},
+	{0x45,0xba,KEY_0},
+	
+	{0x09,0xf6,KEY_UP},//chanup
+	{0x1b,0xe5,KEY_DOWN},//chandown
+	{0x5d,0xa3,KEY_LEFT},//voldown
+	{0x5f,0xa1,KEY_RIGHT},//volup
+	{0x07,0xf8,KEY_SPACE},//tab
+	{0x1f,0xe1,KEY_ENTER},//play ok
+	{0x1b,0xe4,KEY_Z},//zoom
+	{0x59,0xa6,KEY_M},//mute
+	{0x5b,0xa5,KEY_F},//tv/f
+	{0x19,0xe7,KEY_R},//rec
+	{0x01,0xfe,KEY_S},//Stop
+	{0x03,0xfd,KEY_P},//pause 
+	{0x03,0xfc,KEY_W},//<- ->
+	{0x07,0xf9,KEY_C},//capture
+	{0x47,0xb9,KEY_Q},//exit
+	{0x43,0xbc,KEY_O},//power7
+	
+};
+
+static int opera1_rc_query(struct dvb_usb_device *dev, u32 *event, int *state)
+{
+	struct opera1_state* opst=dev->priv;
+	u8 rcbuffer[32];
+	const u16 startmarker1=0x10ed;
+	const u16 startmarker2=0x11ec;
+	struct i2c_msg read_remote[]={
+	    {.addr=0xb880,.buf=rcbuffer,.flags=I2C_M_RD,.len=32},
+	};
+	int i=0;
+	u32 send_key=0;
+	memset(rcbuffer,0,32);
+	
+	if (i2c_transfer(&dev->i2c_adap,read_remote,1)==1){
+		for (i=0;i<32;i++)
+		{
+			if (rcbuffer[i] )
+				send_key|=1;
+			if (i<31)
+				send_key =send_key << 1;
+		}
+		if (send_key&0x8000)
+			send_key=(send_key<<1)|(send_key>>15&0x01);
+
+		if (send_key==0xffff && opst->last_key_pressed!=0){
+			*state=REMOTE_KEY_REPEAT;
+			*event=opst->last_key_pressed;
+			return 0;
+		}
+		for (;send_key!=0;){
+			if (send_key>>16==startmarker2){
+				break;
+			}else if (send_key>>16==startmarker1){
+				send_key=(send_key&0xfffeffff)|(startmarker1<<16);
+				break;
+			}else
+					send_key>>=1;
+		}
+
+		if (send_key==0)
+			return 0;
+		
+		send_key=(send_key&0xffff)|0x0100;
+		
+		for (i=0;i< ARRAY_SIZE(opera1_rc_keys);i++){
+			if ( (opera1_rc_keys[i].custom*256+opera1_rc_keys[i].data)==(send_key&0xffff))
+			{
+				*state = REMOTE_KEY_PRESSED;
+				*event=opera1_rc_keys[i].event;
+				opst->last_key_pressed=opera1_rc_keys[i].event;
+				break;
+			}
+			opst->last_key_pressed=0;
+		}
+	}else
+		*state = REMOTE_NO_KEY_PRESSED;
+		return 0;
+}
+
+
+/* do not change the order of the ID table */
+static struct usb_device_id opera1_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_CYPRESS,		USB_PID_OPERA1_COLD         ) },
+			{ USB_DEVICE(USB_VID_OPERA1,	USB_PID_OPERA1_WARM         ) },
+		  { }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, opera1_table);
+static int opera1_firmware_download(struct usb_device *udev, const struct firmware *fw)
+{
+	
+	int ret = usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+	const struct firmware *fw1=NULL;
+
+	if(ret==0)
+	{
+		if ((ret = request_firmware(&fw1, "opera1-2.fw", &udev->dev)) != 0) {
+			err("did not find the firmware file. (%s) "
+					"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			"opera1-2.fw",ret);
+			
+		}else{
+			ret = usb_cypress_load_firmware(udev,fw1,CYPRESS_FX2);
+			release_firmware(fw1);
+			if (ret!=0)
+				info("error loading firmware1 %d,%d",-EIO,ret);
+			
+		}
+	}
+	return ret;
+
+}
+static int opera1_read_mac_address (struct dvb_usb_device *d, u8 mac[6]){
+	opera1_xilinx_rw(d->udev,0xb1,0xa0,"\x08",1,OPERA_WRITE_MSG);
+	opera1_xilinx_rw(d->udev,0xb1,0xa1,mac,6,OPERA_READ_MSG);
+	return 0;
+}
+static int opera1_xilinx_load_firmware(struct usb_device *dev, const char *filename)
+{
+	const struct firmware *fw = NULL;
+	u8 *b,*p;
+	int ret = 0,i;
+	u8 dummydata[10],testval;
+	memcpy(dummydata, xilinx_init, 9);
+	info("start downloading fpga firmware");
+
+	if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
+		err("did not find the firmware file. (%s) "
+				"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+		filename);
+		return ret;
+	}else{
+		p = kmalloc(fw->size,GFP_KERNEL);
+		opera1_xilinx_rw(dev,0xbc,0x00,&testval,1,OPERA_READ_MSG);
+		if (p != NULL && testval!=0x67) {
+			
+			u8 reset;
+			memcpy(p,fw->data,fw->size);
+			// clear fpga ?
+			opera1_xilinx_rw(dev,0xbc,0xaa,"\x00",1,OPERA_WRITE_MSG);
+			for(i = 0; p[i] != 0 && i < fw->size; ) {
+				b = (u8 *) p+i;
+				if (
+					opera1_xilinx_rw(dev,OPERA_WRITE_FX2,0x0, b+1, b[0],OPERA_WRITE_MSG) != b[0]
+					) {
+					err("error while transferring firmware");
+					ret = -EINVAL;
+					break;
+				}
+				i = i+ 1 + b[0];
+			}
+			/* restart the CPU */
+			reset = 0;
+			if (ret || (opera1_xilinx_rw(dev,0xa0,0xe600,&reset,1,OPERA_WRITE_MSG)!=1)) {
+				err("could not restart the USB controller CPU.");
+				ret = -EINVAL;
+			}
+			kfree(p);
+		}
+	}
+	if (fw){
+		release_firmware(fw);
+	}
+	return ret;
+}
+
+static struct dvb_usb_device_properties opera1_properties = {	
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "opera1.fw",
+	.download_firmware = opera1_firmware_download,
+	.size_of_priv     = sizeof(struct opera1_state),
+
+	.power_ctrl       = opera1_power_ctrl,
+	.i2c_algo         = &opera1_i2c_algo,
+	
+	.rc_key_map = opera1_rc_keys,
+	.rc_key_map_size= ARRAY_SIZE(opera1_rc_keys),
+	.rc_interval =  200,
+	.rc_query=opera1_rc_query,
+	.read_mac_address=opera1_read_mac_address,
+	.generic_bulk_ctrl_endpoint = 0x00,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.adapter={
+		{
+			.frontend_attach  = opera1_frontend_attach,
+			.streaming_ctrl = opera1_streaming_ctrl,
+			.tuner_attach=opera1_tuner_attach,	
+			.caps=DVB_USB_ADAP_HAS_PID_FILTER |DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter      = opera1_pid_filter,
+			.pid_filter_ctrl=opera1_pid_filter_control,
+			.pid_filter_count = 252,
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,//0x200,
+					}
+				}
+			},
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{	"Opera1 DVB-S USB2.0",
+		{ &opera1_table[0], NULL },
+		{ &opera1_table[1], NULL },
+		},
+	}
+};
+
+
+static int opera1_probe(struct usb_interface *intf,
+								const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	struct usb_device* udev=interface_to_usbdev(intf);
+	
+	if (udev->descriptor.idProduct==USB_PID_OPERA1_WARM && 
+	    udev->descriptor.idVendor==USB_VID_OPERA1 && 
+	    (d==NULL || opera1_xilinx_load_firmware(udev,"opera1-fpga.fw")!=0 )
+	){
+		return -EINVAL;
+	}
+
+	if (dvb_usb_device_init(intf,&opera1_properties,THIS_MODULE,&d) != 0)
+		return -EINVAL;
+	
+	return 0;
+}
+
+static struct usb_driver opera1_driver = {
+	.name		= "opera1",
+	.probe		= opera1_probe,
+	.disconnect 	= dvb_usb_device_exit,
+	.id_table	= opera1_table,
+};
+
+static int  __init opera1_module_init(void)
+{
+	int result=0;
+//	mutex_init(&mymutex);
+	if ((result = usb_register(&opera1_driver))) {
+		err("usb_register failed. Error number %d",result);	
+	}
+	return result;
+}
+
+static void __exit opera1_module_exit(void)
+{
+	usb_deregister(&opera1_driver);
+}
+
+module_init (opera1_module_init);
+module_exit (opera1_module_exit);
+
+MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa at amsat.org");
+MODULE_AUTHOR("Marco Gittler (c) g.marco at freenet.de");
+MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+
diff -r b5be3479f070 linux/drivers/media/dvb/dvb-usb/opera1.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/dvb-usb/opera1.h	Sun Apr 15 11:58:00 2007 +0200
@@ -0,0 +1,7 @@
+#ifndef _OPERA1_H_
+#define _OPERA1_H_
+
+#define DVB_USB_LOG_PREFIX "opera"
+extern int dvb_usb_opera1_debug;
+#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
+#endif
diff -r b5be3479f070 linux/drivers/media/dvb/frontends/dvb-pll.c
--- a/linux/drivers/media/dvb/frontends/dvb-pll.c	Sat Apr 14 16:19:13 2007 -0300
+++ b/linux/drivers/media/dvb/frontends/dvb-pll.c	Sun Apr 15 12:01:47 2007 +0200
@@ -451,6 +451,31 @@ struct dvb_pll_desc dvb_pll_thomson_fe66
 	}
 };
 EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+{
+	if (bandwidth == BANDWIDTH_8_MHZ)
+		buf[2] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_opera1 = {
+	.name  = "Opera Tuner",
+	.min   =  900000,
+	.max   = 2250000,
+	.iffreq= 0,
+	.setbw = opera1_bw,
+	.count = 8,
+	.entries = {
+		{   1064000, 500, 0xe5, 0xc6 },
+		{   1169000, 500, 0xe5, 0xe6 },
+		{	 1299000, 500, 0xe5, 0x24 },
+		{   1444000, 500, 0xe5, 0x44 },
+		{   1606000, 500, 0xe5, 0x64 },
+		{   1777000, 500, 0xe5, 0x84 },
+		{   1941000, 500, 0xe5, 0xa4 },
+		{   2250000, 500, 0xe5, 0xc4 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_opera1);
 
 struct dvb_pll_priv {
 	/* i2c details */
diff -r b5be3479f070 linux/drivers/media/dvb/frontends/dvb-pll.h
--- a/linux/drivers/media/dvb/frontends/dvb-pll.h	Sat Apr 14 16:19:13 2007 -0300
+++ b/linux/drivers/media/dvb/frontends/dvb-pll.h	Sun Apr 15 19:52:10 2007 +0200
@@ -48,6 +48,7 @@ extern struct dvb_pll_desc dvb_pll_phili
 extern struct dvb_pll_desc dvb_pll_philips_td1316;
 
 extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
+extern struct dvb_pll_desc dvb_pll_opera1;
 
 extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 			     u32 freq, int bandwidth);


More information about the linux-dvb mailing list