xyzzy@xxxxxxxxxxxxx schrieb:
On Mon, 16 Apr 2007, Mauro Carvalho Chehab wrote:
On Mon, 16 Apr 2007, Marco Gittler wrote:
so i this first enough to put it in and have some more testern for this
device ?
For me, it seems ok now. I'll apply it later at master tree, to allow more
people to test it. This will bring us about 3 weeks for testing and decide
if this is ready for 2.6.22 or not.
This will also give opportunity to other guys to send their comments,
patches and sugestions to improve your driver.
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 Mon Apr 16 12:06:05 2007 +0200
@@ -110,6 +110,7 @@ config DVB_USB_CXUSB
Medion MD95700 hybrid USB2.0 device.
DViCO FusionHDTV (Bluebird) USB2.0 devices
+
ok is done
Random blank line inserted.
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 Mon Apr 16 13:16:17 2007 +0200
[...]
+#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"
Includes should be first <linux/*.h> includes (with <> not ""), then
include "compat.h", then sub-system includes (e.g., "dvb-usb.h"), then your
includes. The <linux/*> then compat.h order is important, the rest not as
much.
i took a look to other drivers and let now some includes out(my include
first , like other drivers , because else the DVB_USB_LOG_PREFIX need
extra handling, and no other did this.
+ int ret = 0, t = 0;
+ u8 r[10];
+ u8 u8buf[len];
[...]
+ memset(r, 0, sizeof(*r));
You don't need to initialize ret or t. It would easier to initialize r (I
don't think you need to anyway, but if you do) with "u8 r[10] = {0};" Instead
of adding an extra call to memset(). Also the memset is wrong, it should
be "memset(r, 0, sizeof(r));" as sizeof(*r) is 1, not 10.
Linux coding style is for one blank line after variables are declared and
before statements start.
The variable sized u8buf[len] array is a C99 feature. Are we allowed to
use this in the kernel? I'm not sure if this is allowed or not.
+ t = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
+ 0x01, 0x0, r, 10, 2000);
You never use t anywhere. You should probably check if usb_con...() failed
and return an error or print something.
ok i made this (hope right , as i saw in the usb log)
static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
[...]
+ request = (addr & 0xff00) >> 8;
+ if (!request)
+ request = 0xb1;
+ value = (addr & 0xff);
+ if (flag & OPERA_READ_MSG) {
+ value |= 0x01;
+static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
[...]
+ if ((tmp = opera1_usb_i2c_msgxfer(d,
+ msg[i].addr,
The Linux I2C subsystem uses 7-bit addresses, while your code is using
8-bit addresses. You should either change opera1_usb_i2c_msgxfer() so it
uses 7-bit addreses, or change opera1_i2c_xfer() so it passes
"msg[i].addr<<1" to opera1_usb_i2c_msgxfer(). This problem keeps comming
up again and again, you can check the list archives to find more
explainations.
opera1_i2c_xfer() would be better if you had this at the first line of
code:
if (!d)
return -ENODEV;
And the got rid of the extra if(d){ ... } part. Note that if d is NULL,
you will crash on the line that does "mutex_lock_interruptible(&d->i2c_mutex)",
which is run _before_ you check if d is null. So the current if(d){ } is
pointless, you will crash before you get there.
+static struct stv0299_config opera1_stv0299_config = {
+ .demod_address = 0xd0,
[...]
+static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ adap->pll_addr = 0xc0;
The addresses are wrong, it should be 0x68 and 0x60. It works because your
i2c code is also wrong, and the mistakes cancel each other out.
i think you mean the last bit for read/write ?
the i2c code is a big unnormal as standard i2c.
so the log from the win... driver shows 2 byte adresses.
ffff8100249ea6c0 2936190441 S Co:010:00 s 40 b1 00d0 0000 0002 2 = 1398
ffff8100249ea6c0 2936191215 C Co:010:00 0 2 >
ffff8100249ea6c0 2936194552 S Ci:010:00 s c0 b1 0001 0000 0001 1 <
ffff8100249ea6c0 2936194724 C Ci:010:00 0 1 = 08
ffff8100249ea6c0 2936198952 S Co:010:00 s 40 b1 00d0 0000 0002 2 = 1495
ffff8100249ea6c0 2936199716 C Co:010:00 0 2 >
ffff8100249ea6c0 2936204424 S Ci:010:00 s c0 b1 0001 0000 0001 1 <
ffff8100249ea6c0 2936204714 C Ci:010:00 0 1 = 08
ffff8100249ea6c0 2936209431 S Co:010:00 s 40 b1 00d0 0000 0002 2 = 05b5
ffff8100249ea6c0 2936210214 C Co:010:00 0 2 >
ffff8100249ea6c0 2936214427 S Ci:010:00 s c0 b1 0001 0000 0001 1 <
ffff8100249ea6c0 2936214715 C Ci:010:00 0 1 = 08
ffff8100249ea6c0 2936218450 S Co:010:00 s 40 b1 00c0 0000 0004 4 = 0874e1e2
the c0 last line here ist the c0 for the stv0299 tuner so the adress
0xc0 ist right i would say.
so the 2nd byte should be the first of the buffer and use only the first
for i2c ?
but does this match with the stv0299 code( then the i2c_transfer part
must be a wrapper for the stv0299 stuff, and another way for the opera
code itself.
but any help to make this code better and more standard i2c conform.
+static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ u8 buf_start[2] = { 0xff, 0x03 };
+ u8 buf_stop[2] = { 0xff, 0x00 };
Declare constant arrays like this as static const.
ic can make it static but static const gives:
opera1.c: In function 'opera1_set_voltage':
opera1.c:154: warning: initialization discards qualifiers from pointer
target type
+static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
[...]
+ memset(rcbuffer, 0, 32);
This memset isn't necessary, you're just going to over-write it with the i2c
command.
ok removed, was from earlier part of the code
i also replaced some registers with readable codes, afaik.
but a better handling for the i2c addr/buf part can be found and the
better named.
Signed-off-by: Marco Gittler <g.marco@xxxxxxxxxx>
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 Tue Apr 17 11:50:13 2007 +0200
@@ -211,3 +211,10 @@ 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 Tue Apr 17 12:36:16 2007 +0200
@@ -0,0 +1,604 @@
+/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
+*
+* Copyright (C) 2006 Mario Hlawitschka (dh1pa@xxxxxxxxx)
+* Copyright (C) 2006 Marco Gittler (g.marco@xxxxxxxxxx)
+*
+* 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 "stv0299.h"
+
+
+#define OPERA_READ_MSG 0
+#define OPERA_WRITE_MSG 1
+#define OPERA_I2C_TUNER 0xd1
+
+#define READ_FX2_REG_REQ 0xBA
+#define READ_MAC_ADDR 0x08
+#define OPERA_WRITE_FX2 0xBB
+#define OPERA_TUNER_REQ 0xB1
+#define REG_SYMBOLRATE_BYTE0 0x1f
+#define REG_SYMBOLRATE_BYTE1 0x20
+#define REG_SYMBOLRATE_BYTE2 0x21
+
+struct opera1_state {
+ u32 last_key_pressed;
+};
+struct opera_rc_keys {
+ u32 keycode;
+ u32 event;
+};
+
+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);
+#if 0
+struct mutex mymutex;
+#endif
+
+static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
+ u8 * data, u16 len, int flags)
+{
+ int ret;
+ u8 r;
+ 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;
+
+#if 0
+ if (mutex_lock_interruptible(&mymutex)) {
+ return -EAGAIN;
+ }
+#endif
+ if (flags == OPERA_WRITE_MSG)
+ memcpy(u8buf, data, len);
+ ret =
+ usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+ value, 0x0, u8buf, len, 2000);
+
+ if (request == OPERA_TUNER_REQ) {
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
+ 0x01, 0x0, &r, 1, 2000)<1 || r!=0x08)
+ return 0;
+ }
+ if (flags == OPERA_READ_MSG)
+ memcpy(data, u8buf, len);
+#if 0
+ mutex_unlock(&mymutex);
+#endif
+ 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) {
+ 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 (!d)
+ return -ENODEV;
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ 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)
+{
+ static u8 command_13v[1]={0x00};
+ static u8 command_18v[1]={0x01};
+ struct i2c_msg msg[] = {
+ {.addr = 0xb600,.flags = 0,.buf = command_13v,.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 = command_18v;
+ }
+ 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, REG_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, REG_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, REG_SYMBOLRATE_BYTE2, (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,
+ REG_SYMBOLRATE_BYTE0, 0x06,
+ REG_SYMBOLRATE_BYTE1, 0x50,
+ REG_SYMBOLRATE_BYTE2, 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)
+{
+ static u8 buf_start[2] = { 0xff, 0x03 };
+ static u8 buf_stop[2] = { 0xff, 0x00 };
+ struct i2c_msg start_tuner[] = {
+ {.addr = 0xb1a6,.buf = onoff ? buf_start : buf_stop,.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}, /*power */
+
+};
+
+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;
+
+ 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])
+{
+ u8 command[] = { READ_MAC_ADDR };
+ opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 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 testval;
+ 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 = 0, fpga_command = 0;
+ memcpy(p, fw->data, fw->size);
+ /* clear fpga ? */
+ opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 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 */
+ 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,
+ }
+ }
+ },
+ }
+ },
+ .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;
+#if 0
+ mutex_init(&mymutex);
+#endif
+ 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@xxxxxxxxx");
+MODULE_AUTHOR("Marco Gittler (c) g.marco@xxxxxxxxxx");
+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 Tue Apr 17 11:55:26 2007 +0200
@@ -0,0 +1,9 @@
+#ifndef _OPERA1_H_
+#define _OPERA1_H_
+
+#define DVB_USB_LOG_PREFIX "opera"
+#include "dvb-usb.h"
+
+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 Mon Apr 16 12:48:58 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);
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb