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

Marco Gittler g.marco at freenet.de
Thu Mar 1 23:22:51 CET 2007



Am Donnerstag, 1. März 2007 schrieb Patrick Boettcher:
> 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.
ok done
>
> +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;
>
done 
> 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.
this causes some usb-ehci controllers to die while sending, so i did copy 
that, but can be removed after successfull test 
>
> +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.
ok did it
>
> +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.
ok the 2nd was too few in the array 1 is enough
>
> 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.
if i'd know how i would do that
>
> 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).
which ? i searched the whole v4l-dvb stuff , and did not find any controller 
that used 2byte addresses , that makes ist hard to use other stuff for this, 
but if you say ist already done , i would change it to the other 
>
> +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.
like i saw for stv0299 the set_symbolrate MUST be implementet bec. there is no 
one in. also here the stuff with the 2 byte address
>
> +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.
which one do you mean ?
>
>
> +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..
ok the remote stuff ist not of good quality, but i found no better way until 
today , because it will not read simple data and then use ist ( it receives 
errors and bitshifts in data)

so i'd liek to out any comments and and make ist better quality
>
> HTH,
> Patrick.





More information about the linux-dvb mailing list