[linux-dvb] [PATCH] Initial Support for Opera USB2.0 DVB-S Adapter

Patrick Boettcher patrick.boettcher at desy.de
Thu Mar 1 12:00:23 CET 2007


On Sun, 25 Feb 2007, Marco wrote:

> Hi
> 
> Attached is a patch for v4l-dvb , for the Opera DVB-S USB2.0 Adapter.
> It should work for the dvb stuff 100% and for RC-Stuff nearly 100%(slow 
> response to keys some times)
> 3 firmware files are needed which can be found after a search with google (or 
> can i upload these files somwhere ?)
> 
> 
> Signed-of-by: Marci Gittler <g.marco at freenet.de>
> Signed-of-by: Mario Hlawitschka <dh1pa at amsat.org>

Some comment about the driver:

In general you could cleanup the thing a little. There are some strange 
things which should be written differently to make it easier for others to 
read (and also to please kernel people). For buffers you should always u8 
not char.

[..]
+#include "opera1.h"
+
+static u32 last_key_pressed=-1;

You cannot do that, because if you plug two devices at the same time, they 
will both use the same global variable. Things like that have to go into 
a private struct allocated for each device. You can you the size_of_priv 
field in the dvb_usb_device_properties to let the dvb-usb-framework 
allocate it.

+static const char* 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;

you can make this global static.

+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;
+
+int opera1_xilinx_rw(struct usb_device*dev, u8 request, u16 value, u8*data, u16 len,int flags){
+
+	int ret=0,t=0;
+	char r[10];
+	u8 u8buf[len];
+	unsigned int pipe=(flags==1)?usb_rcvctrlpipe(dev,0):usb_sndctrlpipe(dev,0);
+	u8 request_type=(flags==1)?USB_DIR_IN:USB_DIR_OUT;
+
+
+	//if (mutex_lock_interruptible(&mymutex)){
+	//    return -EAGAIN;
+	//}
+
+
+	if (flags==0)
+	    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==1)
+	    memcpy(data,u8buf,len);
+	//mutex_unlock(&mymutex);
+	return ret;
+	
+}

You could use *data here to do the transfer. Use u8 for local buffers. 
Initialize buffers. Make all locally used functions static.

+int opera1_xilinx_read(struct usb_device*dev, u8 request, u16 value, u8*data, u16 len){
+    return opera1_xilinx_rw(dev,request,value,data,len,1);
+}
+int opera1_xilinx_send(struct usb_device*dev, u8 request, u16 value, u8*data, u16 len){
+    return opera1_xilinx_rw(dev,request,value,data,len,0);
+}
+
+/* I2C */
+
+static int opera1_usb_i2c_xfer(struct dvb_usb_device* dev,struct i2c_msg msg[],int num)
+{
+	int i;
+	u8 request;
+	u16 value;
+	//return 0;
+	if (dev==NULL){
+		info ("no usb_device");
+		return -EINVAL;
+	}
+	if (mutex_lock_interruptible(&dev->i2c_mutex) < 0)
+		return -EAGAIN;
+	for (i = 0; i < num; i++) {
+		//READ
+		request=(msg[i].addr&0xff00) >> 8;
+		if (!request)
+			request=0xb1;	
+		value=(msg[i].addr&0xff);
+		if (msg[i].flags & I2C_M_RD){
+			value|=0x01;
+		}
+		if (request==0xa0)
+			value=0xe600;
+		if ((msg[i].flags & I2C_M_RD)) {			
+			opera1_xilinx_read(dev->udev,request,value,msg[i].buf,msg[i].len);
+		}else{//WRITE
+			opera1_xilinx_send(dev->udev,request,value,msg[i].buf,msg[i].len);
+		}
+	}
+	mutex_unlock(&dev->i2c_mutex);
+	return i;
+}

Do not abuse i2c_messages for doing USB-transfer. I2C is dedicated bus 
with a standardized interface (i2c_address, buffer). The I2C Adapter in 
the linux kernel should only be used to represent the real I2C-bus inside 
a device. 

+static int opera1_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	if (d)
+		return opera1_usb_i2c_xfer(d,msg,num);
+	return -EINVAL;
+}
+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_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	int freq_add=0;
+	u8 tuner_buf[4];
+	struct dvb_usb_adapter* udev_adap=(struct dvb_usb_adapter*)(fe->dvb->priv);
+	
+	
+	struct i2c_msg tuner_msg = {.addr=0xc0, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+	struct i2c_msg msg[]={
+		{.addr=0xb701,.flags=0,.buf="\x01",.len=1},
+		{.addr=0xb600,.flags=0,.buf="\x00",.len=1},
+	};
+	
+	u8 filter=0;
+
+	// setup PLL filter
+	switch (params->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ: filter = 0;break;
+		case BANDWIDTH_7_MHZ: filter = 0;break;
+		case BANDWIDTH_8_MHZ: filter = 1;break;
+		default:	break; //INVAILD
+	}
+
+	freq_add=params->frequency/500;
+	tuner_buf[0]=(freq_add>>8) & 0xff;
+	tuner_buf[1]=freq_add & 0xff;
+	tuner_buf[2]=(filter==1) ? 0xed:0xe5;//symbolrate 0x500000 :0xed /0x400000 :exe5 ( e1/e5/ed)
+
+	if (freq_add/2<1100) tuner_buf[3]=0xe6;
+	if (freq_add/2>1100) tuner_buf[3]=0x24;
+	if (freq_add/2>1400) tuner_buf[3]=0x64;
+	if (freq_add/2>1666) tuner_buf[3]=0x84;
+	if (freq_add/2>1800) tuner_buf[3]=0xa4;
+	if (freq_add/2>1900) tuner_buf[3]=0xc4;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+	i2c_transfer(&udev_adap->dev->i2c_adap, &tuner_msg, 1);
+	msleep(1);
+	return 0;
+}

It is obvious something is wrong here. msg is an array of two messages but 
you only give 1. 

It would be much better to dvb-pll to program the tuner. If for your tuner 
is not implemented yet it can be easily done. 

To use dvb-pll you need to implement the i2c_adapter of your device properly.

+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;
+}

I'm sure the LNB-controller on your board is already implemented... Please 
use the existing implementation (also you need the i2c-adapter properly 
implemented for that).

+static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio){
+	
+	u8 aclk = 0x98;
+	u8 bclk = 0x95;
+
+	if (srate < 1500000) {
+		aclk = 0xb7;
+		bclk = 0x47;
+	} else if (srate < 3000000) {
+		aclk = 0xb7;
+		bclk = 0x4b;
+	} else if (srate < 7000000) {
+		aclk = 0xb7;
+		bclk = 0x4f;
+	} else if (srate < 14000000) {
+		aclk = 0xb7;
+		bclk = 0x53;
+	} else if (srate < 30000000) {
+		aclk = 0xb6;
+		bclk = 0x53;
+	} else if (srate < 45000000) {
+		aclk = 0xb4;
+		bclk = 0x51;
+	}
+//info ("set symbol rate");
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	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.tuner_ops.set_params=opera1_tuner_set_params;
+		d->fe->ops.set_voltage=opera1_set_voltage;
+		return 0;
+	}
+	info ("not attached stv0299");
+	return -EIO;
+}
+
+int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret=0;
+	struct i2c_msg power_on_mgs[]={
+		{.addr=0xb701,.buf="\x01",.len=1},
+  		{.addr=0xb601,.buf="\x01",.len=1},//set VOLTAGE setzen
+		{.addr=0xb1a6,.buf="\xff\x03",.len=2},
+	};
+
+	if (onoff){
+		opera1_usb_i2c_xfer(d,power_on_mgs,3);
+	}
+	
+	return ret;
+}

If you use an existing lnb-controller-driver it will be done 
automatically.

+static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+
+	struct i2c_msg start_tuner[]={
+		{.addr=0xb1d0,.buf="\x0c\x01",.len=2},
+		{.addr=0xb1a6,.buf="\xff\x00",.len=2},
+	};
+
+	if (!onoff){
+		start_tuner[0].buf[1]=0x03;
+	}
+	i2c_transfer(&adap->dev->i2c_adap,start_tuner,2);
+	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},
+	};
+	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;
+}

For sending firmware specific commands to your device you should use 
specific function for that.


+static struct dvb_usb_rc_key opera1_rc_keys[]={
+	{0x5f,0xa0,KEY_1},
+	{0x50,0xae,KEY_2},
+	{0x5d,0xa2,KEY_3},
+	{0x41,0xbe,KEY_4},
+	
+	{0x0a,0xf4,KEY_5},
+	{0x42,0xbc,KEY_6},
+	{0x47,0xb8,KEY_7},
+	{0x49,0xb6,KEY_8},
+	{0x05,0xfa,KEY_9},
+	{0x45,0xba,KEY_0},
+	
+	{0x09,0xf6,KEY_UP},//chanup
+	{0x1a,0xe4,KEY_DOWN},//chandown
+	{0x5c,0xa2,KEY_LEFT},//voldown
+	{0x5e,0xa0,KEY_RIGHT},//volup
+	{0x07,0xf8,KEY_SPACE},//tab
+	{0x1e,0xe0,KEY_ENTER},//play ok
+	{0x1b,0xe4,KEY_Z},//zoom
+	{0x59,0xa6,KEY_M},//mute
+	{0x5a,0xa4,KEY_F},//tv/f
+	{0x18,0xe6,KEY_R},//rec
+	{0x01,0xfe,KEY_S},//Stop
+	{0x02,0xfc,KEY_P},//pause 
+	{0x03,0xfc,KEY_W},//<- ->
+	{0x06,0xf8,KEY_C},//capture
+	{0x46,0xb8,KEY_Q},//exit
+	{0x43,0xbc,KEY_O},//power7
+	
+};
+
+static int opera1_rc_query(struct dvb_usb_device *dev, u32 *event, int *state)
+{
+	// u8* search="0000000100000000010101000101000";
+	/**
+	startmarker 0001000011101101 or 0001000111101100
+	
+	*/
+	u8 rcbuffer[32];
+	const u8 startmarker1[16]="\x0\x0\x0\x1\x0\x0\x0\x0\x1\x1\x1\x0\x1\x1\x0\x1";
+	const u8 startmarker2[16]="\x0\x0\x0\x1\x0\x0\x0\x1\x1\x1\x1\x0\x1\x1\x0\x0";
+	struct i2c_msg read_remote[]={
+	    {.addr=0xb880,.buf=rcbuffer,.flags=I2C_M_RD,.len=32},
+	};
+	int i=0,b=0;
+	u32 send_key=0;
+	memset(rcbuffer,0,32);
+	
+	if (i2c_transfer(&dev->i2c_adap,read_remote,1)==1){
+		if (memcmp(rcbuffer,"\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1",32)==0 && last_key_pressed!=-1){
+			*state=REMOTE_KEY_REPEAT;
+			*event=last_key_pressed;
+			return 0;
+		}
+		/*for (b=0;b<32;b++){
+			if (rcbuffer[b])
+				printk("1");
+			else
+				printk("0");
+		}
+		printk("\n");*/
+		for (b=0;b<32;b++){
+			if (b+16<32){
+				if (memcmp(rcbuffer+b,startmarker1,16)==0 || memcmp(rcbuffer+b,startmarker2,16)==0){
+					/*for (c=b+16;c<32;c++){
+						if (rcbuffer[c])
+							printk("1");
+						else
+							printk("0");
+
+					}
+					printk("\n");*/
+					break;
+				}
+			}
+		}
+		
+		//if ((b+15+16)==31)//only vaild sequences
+			
+		for (i=b+16;i<32 && i<b+15+16;i++)
+		{
+			if (rcbuffer[i] /*&& (i-b-2)!=6*/)
+				send_key|=1;
+			send_key =send_key << 1;
+		}
+		//printk("key code :%x\n",send_key);
+		if (send_key==0)
+		    return 0;
+		printk("key code :%x\n",send_key);
+
+		for (i=0;i< ARRAY_SIZE(opera1_rc_keys);i++){
+			if (	
+							send_key!=0x7efe &&
+							(send_key&0xff )==opera1_rc_keys[i].data && 
+							((send_key&0xff00) >>8)==opera1_rc_keys[i].custom
+				)
+			{
+				*state = REMOTE_KEY_PRESSED;
+				*event=opera1_rc_keys[i].event;
+				last_key_pressed=opera1_rc_keys[i].event;
+				break;
+			}
+			last_key_pressed=-1;
+		}
+	}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_WARM,	USB_PID_OPERA1_WARM         ) },
+/* 01 *//*{ USB_DEVICE(USB_VID_CYPRESS,		USB_PID_OPERA1_COLD2         ) },
+		  { USB_DEVICE(USB_VID_OPERA1_WARM,	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_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");
+
+	opera1_xilinx_send(dev,0xb1,0xa0,dummydata,9);
+	opera1_xilinx_send(dev,0xb1,0xa0,dummydata,1);
+	opera1_xilinx_read(dev,0xb1,0xa1,dummydata,1);
+	opera1_xilinx_send(dev,0xbc,0xaa,"\x00",1);
+	opera1_xilinx_send(dev,0xbc,0x00,&testval,1);
+	opera1_xilinx_send(dev,0xbc,0x00,&testval,1);
+	opera1_xilinx_send(dev,0xbc,0x00,&testval,1);
+	opera1_xilinx_send(dev,0xbc,0x00,&testval,1);
+
+	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);
+		if (p != NULL) {
+			u8 reset;
+			memcpy(p,fw->data,fw->size);
+			for(i = 0; p[i] != 0 && i < fw->size; ) {
+				b = (u8 *) p+i;
+				if (
+					opera1_xilinx_send(dev,OPERA_WRITE_FX2,0x0, b+1, b[0]) != b[0]
+					) {
+					err("error while transferring firmware");
+					ret = -EINVAL;
+					break;
+				}
+				i = i+ 1 + b[0];
+			}
+			/* restart the CPU */
+			reset = 0;
+			if (ret || (opera1_xilinx_send(dev,0xa0,0xe600,&reset,1)!=1)) {
+				err("could not restart the USB controller CPU.");
+				ret = -EINVAL;
+			}
+			kfree(p);
+		}
+	}
+	if (fw){
+		release_firmware(fw);
+	}
+	info("done downloading fpga firmware");
+	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     = 0,
+
+	.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,
+	
+	.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,
+			
+			.caps=DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+			.pid_filter      = opera1_pid_filter,
+			.pid_filter_count = 252,
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 0x200,
+					}
+				}
+			},
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{	"Opera1 DVB-S USB2.0",
+		{ &opera1_table[0], NULL },
+		{ &opera1_table[1], NULL },
+		},
+	/*	{	"Opera1 DVB-S USB2.0 wrong product ID",
+		{ &opera1_table[2], NULL },
+		{ &opera1_table[3], 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_WARM && 
+	    (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 42b9d09cff15 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	Sat Feb 24 14:02:20 2007 +0100
@@ -0,0 +1,38 @@
+#ifndef _OPERA1_H_
+#define _OPERA1_H_
+
+
+#define DVB_USB_LOG_PREFIX "opera"
+#include "dvb-usb.h"
+#include "dvb_frontend.h"
+#include <linux/version.h>
+extern int dvb_usb_opera1_debug;
+#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
+
+struct opera_rc_keys {
+	u32 keycode;
+	u32 event;
+};
+///Send Querys
+
+#define QUERY_RC 0x01
+#define WAIT_FOR_COMPLETE 0x02
+
+///Register on Cypress
+
+#define READ_FX2_REG_REQ  0xBA
+#define OPERA_WRITE_FX2 0xBB
+
+#define OPERA_TUNER_REQ 0xB1
+#define OPERA_TUNER1_REQ 0xb6
+#define OPERA_TUNER2_REQ 0xb7
+#define OPERA_REMOTE 0xB8
+#define OPERA_TUNER4_REQ 0xbb
+#define OPERA_TUNER5_REQ 0xbc
+
+#define USB_VID_OPERA1_WARM                     0x695C /*do we have such a thing?*/
+#define USB_PID_OPERA1_COLD                     0x2830
+#define USB_PID_OPERA1_COLD2                     0x8613
+#define USB_PID_OPERA1_WARM                     0x3829 /*do we have such a thing?*/
+
+#endif

It would be nice if someone with this device can review the driver also. 
Maybe there are other things which can be simplified..

HTH,
Patrick.



More information about the linux-dvb mailing list