summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/frontends/stv0299.c
diff options
context:
space:
mode:
authorHolger Waechtler <devnull@localhost>2003-05-05 18:11:06 +0000
committerHolger Waechtler <devnull@localhost>2003-05-05 18:11:06 +0000
commit15ee2f4af37d50903ab258fdb8b679478e7f179c (patch)
tree03fe63b16ab4424acf2b265954ac8f9941e6898d /linux/drivers/media/dvb/frontends/stv0299.c
parent62e5a2a64c25bc9638387ce09388c59fc4f366b1 (diff)
downloadmediapointer-dvb-s2-15ee2f4af37d50903ab258fdb8b679478e7f179c.tar.gz
mediapointer-dvb-s2-15ee2f4af37d50903ab258fdb8b679478e7f179c.tar.bz2
support for SU1278 w/ tua6100 PLL
Diffstat (limited to 'linux/drivers/media/dvb/frontends/stv0299.c')
-rw-r--r--linux/drivers/media/dvb/frontends/stv0299.c331
1 files changed, 213 insertions, 118 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c
index a7aa39da2..4b3bd1b18 100644
--- a/linux/drivers/media/dvb/frontends/stv0299.c
+++ b/linux/drivers/media/dvb/frontends/stv0299.c
@@ -37,7 +37,6 @@
#include <asm/errno.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
@@ -45,14 +44,19 @@
#include "dvb_frontend.h"
#include "dvb_functions.h"
-static int debug = 0;
-#define dprintk if (debug) printk
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
/* frontend types */
#define UNKNOWN_FRONTEND -1
#define PHILIPS_SU1278SH 0
#define ALPS_BSRU6 1
#define LG_TDQF_S001F 2
+#define PHILIPS_SU1278 3
/* Master Clock = 88 MHz */
#define M_CLK (88000000UL)
@@ -79,11 +83,6 @@ struct dvb_frontend_info uni0299_info = {
static
u8 init_tab [] = {
- /* clock registers */
- 0x01, 0x15, /* K = 0, DIRCLK = 0, M = 0x15 */
- 0x02, 0x30, /* STDBY = 0, VCO = 0 (ON), SERCLK = 0, P = 0 */
- /* f_VCO = 4MHz * 4 * (M+1) / (K+1) = 352 MHz */
- 0x03, 0x00, /* auxiliary clock not used */
0x04, 0x7d, /* F22FR = 0x7d */
/* F22 = f_VCO / 128 / 0x7d = 22 kHz */
@@ -95,14 +94,14 @@ u8 init_tab [] = {
0x07, 0x00, /* DAC LSB */
/* DiSEqC registers */
- 0x08, 0x40, /* DiSEqC off */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
0x09, 0x00, /* FIFO */
/* Input/Output configuration register */
0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
/* OP0 ctl = Normal, OP0 val = 1 (18 V) */
/* Nyquist filter = 00, QPSK reverse = 0 */
-
+
/* AGC1 control register */
0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
@@ -110,34 +109,27 @@ u8 init_tab [] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
+
0x11, 0x84,
0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
- 0x13, 0xb6, // alpha_car b:4 a:0 noise est:256ks derot:on
- 0x14, 0x93, // beat carc:0 d:0 e:0xf phase detect algo: 1
+
0x15, 0xc9, // lock detector threshold
- 0x16, 0x1d, /* AGC1 integrator value */
+ 0x16, 0x00,
0x17, 0x00,
- 0x18, 0x14,
- 0x19, 0xf2,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
- 0x1a, 0x11,
-
- 0x1b, 0x9c,
- 0x1c, 0x00,
- 0x1d, 0x00,
- 0x1e, 0x0b,
0x1f, 0x50,
0x20, 0x00,
0x21, 0x00,
0x22, 0x00,
0x23, 0x00,
- 0x24, 0xff,
- 0x25, 0xff,
- 0x26, 0xff,
0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+
0x29, 0x1e, // 1/2 threshold
0x2a, 0x14, // 2/3 threshold
0x2b, 0x0f, // 3/4 threshold
@@ -150,38 +142,6 @@ u8 init_tab [] = {
0x32, 0x19, // viterbi and synchro search
0x33, 0xfc, // rs control
0x34, 0x93, // error control
-
- 0x0b, 0x00,
- 0x27, 0x00,
- 0x2f, 0x00,
- 0x30, 0x00,
- 0x35, 0x00,
- 0x36, 0x00,
- 0x37, 0x00,
- 0x38, 0x00,
- 0x39, 0x00,
- 0x3a, 0x00,
- 0x3b, 0x00,
- 0x3c, 0x00,
- 0x3d, 0x00,
- 0x3e, 0x00,
- 0x3f, 0x00,
- 0x40, 0x00,
- 0x41, 0x00,
- 0x42, 0x00,
- 0x43, 0x00,
- 0x44, 0x00,
- 0x45, 0x00,
- 0x46, 0x00,
- 0x47, 0x00,
- 0x48, 0x00,
- 0x49, 0x00,
- 0x4a, 0x00,
- 0x4b, 0x00,
- 0x4c, 0x00,
- 0x4d, 0x00,
- 0x4e, 0x00,
- 0x4f, 0x00
};
@@ -192,8 +152,6 @@ int stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
u8 buf [] = { reg, data };
struct i2c_msg msg = { addr: 0x68, flags: 0, buf: buf, len: 2 };
- dprintk ("%s\n", __FUNCTION__);
-
ret = i2c->xfer (i2c, &msg, 1);
if (ret != 1)
@@ -213,8 +171,6 @@ u8 stv0299_readreg (struct dvb_i2c_bus *i2c, u8 reg)
struct i2c_msg msg [] = { { addr: 0x68, flags: 0, buf: b0, len: 1 },
{ addr: 0x68, flags: I2C_M_RD, buf: b1, len: 1 } };
- dprintk ("%s\n", __FUNCTION__);
-
ret = i2c->xfer (i2c, msg, 2);
if (ret != 2)
@@ -231,35 +187,31 @@ int stv0299_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len)
struct i2c_msg msg [] = { { addr: 0x68, flags: 0, buf: &reg1, len: 1 },
{ addr: 0x68, flags: I2C_M_RD, buf: b, len: len } };
- dprintk ("%s\n", __FUNCTION__);
-
ret = i2c->xfer (i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
- return ret == 2 ? 0 : -1;
+ return ret == 2 ? 0 : ret;
}
static
-int pll_write (struct dvb_i2c_bus *i2c, u8 data [4], int ftype)
+int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len)
{
int ret;
u8 rpt1 [] = { 0x05, 0xb5 }; /* enable i2c repeater on stv0299 */
- /* TSA5059 i2c-bus address */
- u8 addr = (ftype == PHILIPS_SU1278SH) ? 0x60 : 0x61;
+ u8 rpt2 [] = { 0x05, 0x35 }; /* disable i2c repeater on stv0299 */
struct i2c_msg msg [] = {{ addr: 0x68, flags: 0, buf: rpt1, len: 2 },
- { addr: addr, flags: 0, buf: data, len: 4 }};
-
- dprintk ("%s\n", __FUNCTION__);
+ { addr: addr, flags: 0, buf: data, len: len },
+ { addr: 0x68, flags: 0, buf: rpt2, len: 2 }};
- ret = i2c->xfer (i2c, msg, 2);
+ ret = i2c->xfer (i2c, msg, 3);
- if (ret != 2)
- dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
+ if (ret != 3)
+ printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
- return (ret != 2) ? -1 : 0;
+ return (ret != 3) ? ret : 0;
}
@@ -287,7 +239,7 @@ int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
else
buf[3] = 0x00;
- return pll_write (i2c, buf, ftype);
+ return pll_write (i2c, 0x61, buf, sizeof(buf));
}
/**
@@ -297,10 +249,12 @@ int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
static
int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
{
+ u8 addr = (ftype == PHILIPS_SU1278SH) ? 0x60 : 0x61;
u32 div = freq / 125;
-
u8 buf[4] = { (div >> 8) & 0x7f, div & 0xff, 0x84 };
+ dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype);
+
if (ftype == PHILIPS_SU1278SH)
/* activate f_xtal/f_comp signal output */
/* charge pump current C0/C1 = 00 */
@@ -308,16 +262,144 @@ int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
else
buf[3] = freq > 1530000 ? 0xc0 : 0xc4;
- dprintk ("%s\n", __FUNCTION__);
+ return pll_write (i2c, addr, buf, sizeof(buf));
+}
+
+
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define MIN2(a,b) ((a) < (b) ? (a) : (b))
+#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
+
+static
+int tua6100_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq,
+ int ftype, int srate)
+{
+ u8 reg0 [2] = { 0x00, 0x00 };
+ u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
+ u8 reg2 [3] = { 0x02, 0x00, 0x00 };
+ int _fband;
+ int first_ZF;
+ int R, A, N, P, M;
+ int err;
+
+ first_ZF = (freq) / 1000;
+
+ if (ABS(MIN2(ABS(first_ZF-1190),ABS(first_ZF-1790))) <
+ ABS(MIN3(ABS(first_ZF-1202),ABS(first_ZF-1542),ABS(first_ZF-1890))))
+ _fband = 2;
+ else
+ _fband = 3;
+
+ if (_fband == 2) {
+ if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+ ((first_ZF >= 1430) && (first_ZF < 1950)))
+ reg0[1] = 0x07;
+ else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
+ ((first_ZF >= 1950) && (first_ZF < 2150)))
+ reg0[1] = 0x0B;
+ }
+
+ if(_fband == 3) {
+ if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+ ((first_ZF >= 1455) && (first_ZF < 1950)))
+ reg0[1] = 0x07;
+ else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
+ ((first_ZF >= 1950) && (first_ZF < 2150)))
+ reg0[1] = 0x0B;
+ else if ((first_ZF >= 1420) && (first_ZF < 1455))
+ reg0[1] = 0x0F;
+ }
+
+ if (first_ZF > 1525)
+ reg1[1] |= 0x80;
+ else
+ reg1[1] &= 0x7F;
+
+ if (_fband == 2) {
+ if (first_ZF > 1430) { /* 1430MHZ */
+ reg1[1] &= 0xCF; /* N2 */
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ } else {
+ reg1[1] &= 0xCF; /* N2 */
+ reg1[1] |= 0x20;
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ }
+ }
+
+ if (_fband == 3) {
+ if ((first_ZF >= 1455) &&
+ (first_ZF < 1630)) {
+ reg1[1] &= 0xCF; /* N2 */
+ reg1[1] |= 0x20;
+ reg2[1] &= 0xCF; /* R2 */
+ } else {
+ if (first_ZF < 1455) {
+ reg1[1] &= 0xCF; /* N2 */
+ reg1[1] |= 0x20;
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ } else {
+ if (first_ZF >= 1630) {
+ reg1[1] &= 0xCF; /* N2 */
+ reg2[1] &= 0xCF; /* R2 */
+ reg2[1] |= 0x10;
+ }
+ }
+ }
+ }
+
+ /* set ports, enable P0 for symbol rates > 4Ms/s */
+ if (srate >= 4000000)
+ reg1[1] |= 0x0c;
+ else
+ reg1[1] |= 0x04;
+
+ reg2[1] |= 0x0c;
+
+ R = 64;
+ A = 64;
+ P = 64; //32
+
+ M = (freq * R) / 4; /* in Mhz */
+ N = (M - A * 1000) / (P * 1000);
+
+ reg1[1] |= (N >> 9) & 0x03;
+ reg1[2] = (N >> 1) & 0xff;
+ reg1[3] = (N << 7) & 0x80;
- return pll_write (i2c, buf, ftype);
+ reg2[1] |= (R >> 8) & 0x03;
+ reg2[2] = R & 0xFF; /* R */
+
+ reg1[3] |= A & 0x7f; /* A */
+
+ if (P == 64)
+ reg1[1] |= 0x40; /* Prescaler 64/65 */
+
+ reg0[1] |= 0x03;
+
+ if ((err = pll_write(i2c, 0x60, reg0, sizeof(reg0))))
+ return err;
+
+ if ((err = pll_write(i2c, 0x60, reg1, sizeof(reg1))))
+ return err;
+
+ if ((err = pll_write(i2c, 0x60, reg2, sizeof(reg2))))
+ return err;
+
+ return 0;
}
+
static
-int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
+int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
{
if (ftype == LG_TDQF_S001F)
return sl1935_set_tv_freq(i2c, freq, ftype);
+ else if (ftype == PHILIPS_SU1278)
+ return tua6100_set_tv_freq(i2c, freq, ftype, srate);
else
return tsa5059_set_tv_freq(i2c, freq, ftype);
}
@@ -352,12 +434,18 @@ int stv0299_init (struct dvb_i2c_bus *i2c, int ftype)
dprintk("stv0299: init chip\n");
+ stv0299_writereg (i2c, 0x01, 0x15);
+ stv0299_writereg (i2c, 0x02, ftype == PHILIPS_SU1278 ? 0x00 : 0x30);
+ stv0299_writereg (i2c, 0x03, 0x00);
+
for (i=0; i<sizeof(init_tab); i+=2)
stv0299_writereg (i2c, init_tab[i], init_tab[i+1]);
/* AGC1 reference register setup */
if (ftype == PHILIPS_SU1278SH)
stv0299_writereg (i2c, 0x0f, 0xd2); /* Iagc = Inverse, m1 = 18 */
+ else if (ftype == PHILIPS_SU1278)
+ stv0299_writereg (i2c, 0x0f, 0x94); /* Iagc = Inverse, m1 = 18 */
else
stv0299_writereg (i2c, 0x0f, 0x52); /* Iagc = Normal, m1 = 18 */
@@ -371,8 +459,11 @@ int stv0299_check_inversion (struct dvb_i2c_bus *i2c)
dprintk ("%s\n", __FUNCTION__);
if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) {
- u8 val = stv0299_readreg (i2c, 0x0c);
- return stv0299_writereg (i2c, 0x0c, val ^ 0x01);
+ dvb_delay(30);
+ if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) {
+ u8 val = stv0299_readreg (i2c, 0x0c);
+ return stv0299_writereg (i2c, 0x0c, val ^ 0x01);
+ }
}
return 0;
@@ -525,7 +616,9 @@ int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
{
u8 val;
- dprintk ("%s\n", __FUNCTION__);
+ dprintk("%s: %s\n", __FUNCTION__,
+ tone == SEC_TONE_ON ? "SEC_TONE_ON" :
+ tone == SEC_TONE_OFF ? "SEC_TONE_OFF" : "??");
if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
return -ETIMEDOUT;
@@ -546,19 +639,25 @@ int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
static
int stv0299_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
{
- u8 val;
+ u8 reg0x0c;
- dprintk ("%s\n", __FUNCTION__);
+ dprintk("%s: %s\n", __FUNCTION__,
+ voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+ voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+ reg0x0c = stv0299_readreg (i2c, 0x0c);
- val = stv0299_readreg (i2c, 0x0c);
- val &= 0x0f;
- val |= 0x40; /* LNB power on */
+ /**
+ * H/V switching over OP0, OP1 is LNB power on
+ */
+ reg0x0c &= 0x0f;
+ reg0x0c |= 0x40; /* LNB power on */
switch (voltage) {
case SEC_VOLTAGE_13:
- return stv0299_writereg (i2c, 0x0c, val);
+ return stv0299_writereg (i2c, 0x0c, reg0x0c);
case SEC_VOLTAGE_18:
- return stv0299_writereg (i2c, 0x0c, val | 0x10);
+ return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10);
default:
return -EINVAL;
};
@@ -642,8 +741,6 @@ int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
int tuner_type = (int)fe->data;
struct dvb_i2c_bus *i2c = fe->i2c;
- dprintk ("%s\n", __FUNCTION__);
-
switch (cmd) {
case FE_GET_INFO:
memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info));
@@ -713,15 +810,16 @@ int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
struct dvb_frontend_parameters *p = arg;
- pll_set_tv_freq (i2c, p->frequency, tuner_type);
+ pll_set_tv_freq (i2c, p->frequency, tuner_type,
+ p->u.qpsk.symbol_rate);
+
stv0299_set_FEC (i2c, p->u.qpsk.fec_inner);
stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
- stv0299_check_inversion (i2c);
- /* pll_set_tv_freq (i2c, p->frequency, tuner_type); */
stv0299_writereg (i2c, 0x22, 0x00);
stv0299_writereg (i2c, 0x23, 0x00);
stv0299_readreg (i2c, 0x23);
stv0299_writereg (i2c, 0x12, 0xb9);
+ stv0299_check_inversion (i2c);
/* printk ("%s: tsa5059 status: %x\n", __FUNCTION__, tsa5059_read_status(i2c)); */
break;
@@ -748,20 +846,14 @@ int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
}
case FE_SLEEP:
- stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */
+ stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */
+ stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */
stv0299_writereg (i2c, 0x02, 0x80);
break;
case FE_INIT:
return stv0299_init (i2c, tuner_type);
- case FE_RESET:
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
- stv0299_readreg (i2c, 0x23);
- stv0299_writereg (i2c, 0x12, 0xb9);
- break;
-
case FE_DISEQC_SEND_MASTER_CMD:
return stv0299_send_diseqc_msg (i2c, arg);
@@ -786,33 +878,46 @@ int probe_tuner (struct dvb_i2c_bus *i2c)
{
/* read the status register of TSA5059 */
u8 rpt[] = { 0x05, 0xb5 };
- u8 stat [1];
+ u8 stat [] = { 0 };
int ret;
struct i2c_msg msg1 [] = {{ addr: 0x68, flags: 0, buf: rpt, len: 2 },
{ addr: 0x60, flags: I2C_M_RD, buf: stat, len: 1 }};
struct i2c_msg msg2 [] = {{ addr: 0x68, flags: 0, buf: rpt, len: 2 },
{ addr: 0x61, flags: I2C_M_RD, buf: stat, len: 1 }};
+ struct i2c_msg msg3 [] = {{ addr: 0x68, flags: 0, buf: rpt, len: 2 },
+ { addr: 0x60, flags: 0, buf: stat, len: 1 }};
+ stv0299_writereg (i2c, 0x01, 0x15);
+ stv0299_writereg (i2c, 0x02, 0x30);
+ stv0299_writereg (i2c, 0x03, 0x00);
if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) {
printk ("%s: setup for tuner SU1278/SH\n", __FILE__);
return PHILIPS_SU1278SH;
}
- ret = i2c->xfer(i2c, msg2, 2);
-
- if (ret == 2) {
-if (0) { // if ((stat[0] & 0x3f) == 0) {
+ if ((ret = i2c->xfer(i2c, msg2, 2)) == 2) {
+ //if ((stat[0] & 0x3f) == 0) {
+ if (0) {
printk ("%s: setup for tuner TDQF-S001F\n", __FILE__);
return LG_TDQF_S001F;
- }
- else {
+ } else {
printk ("%s: setup for tuner BSRU6, TDQB-S00x\n",
__FILE__);
return ALPS_BSRU6;
}
}
+ /**
+ * setup i2c timing for SU1278...
+ */
+ stv0299_writereg (i2c, 0x02, 0x00);
+
+ if ((ret = i2c->xfer(i2c, msg3, 2)) == 2) {
+ printk ("%s: setup for tuner Philips SU1278\n", __FILE__);
+ return PHILIPS_SU1278;
+ }
+
printk ("%s: unknown PLL synthesizer (ret == %i), "
"please report to <linuxdvb@linuxtv.org>!!\n",
__FILE__, ret);
@@ -834,13 +939,6 @@ int uni0299_attach (struct dvb_i2c_bus *i2c)
if (id != 0xa1 && id != 0x80)
return -ENODEV;
- /**
- * wake up...
- */
- stv0299_writereg (i2c, 0x01, 0x15);
- stv0299_writereg (i2c, 0x02, 0x30);
- stv0299_writereg (i2c, 0x03, 0x00);
-
if ((tuner_type = probe_tuner(i2c)) < 0)
return -ENODEV;
@@ -877,9 +975,6 @@ void __exit exit_uni0299 (void)
module_init (init_uni0299);
module_exit (exit_uni0299);
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter");
MODULE_LICENSE("GPL");