2003-06-25 10:23:59

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 1/7] Update saa7146 driver core

- fix WRITE_RPS0 and WRITE_RPS1 inlines, fix usage in mxb and budget drivers
- export "saa7146_start_preview" and "saa7146_stop_preview" to allow drivers to start and stop video overlay (necessary for analog module support in the av7110 driver)
- fix i2c implementation: some frontend drivers transfer a huge amount of firmware data (> 30kB), speed up the transmission by busy waiting between byte transfers for bigger transmissions
- change ioctl function in various driver to accept a saa7146 filehandle instead of a saa714 device structure
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/common/saa7146_hlp.c linux-2.5.73.work/drivers/media/common/saa7146_hlp.c
--- linux-2.5.73.bk/drivers/media/common/saa7146_hlp.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/common/saa7146_hlp.c 2003-06-18 14:42:12.000000000 +0200
@@ -935,6 +935,7 @@
static void program_capture_engine(struct saa7146_dev *dev, int planar)
{
struct saa7146_vv *vv = dev->vv_data;
+ int count = 0;

unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/common/saa7146_vbi.c linux-2.5.73.work/drivers/media/common/saa7146_vbi.c
--- linux-2.5.73.bk/drivers/media/common/saa7146_vbi.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/common/saa7146_vbi.c 2003-06-18 14:44:17.000000000 +0200
@@ -9,6 +9,7 @@
u32 *cpu;
dma_addr_t dma_addr;

+ int count = 0;
int i;

DECLARE_WAITQUEUE(wait, current);
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/budget-patch.c linux-2.5.73.work/drivers/media/dvb/ttpci/budget-patch.c
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/budget-patch.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/budget-patch.c 2003-06-19 11:33:02.000000000 +0200
@@ -165,6 +165,7 @@
{
struct budget_patch *budget;
int err;
+ int count = 0;

if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
return -ENOMEM;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/common/saa7146_i2c.c linux-2.5.73.work/drivers/media/common/saa7146_i2c.c
--- linux-2.5.73.bk/drivers/media/common/saa7146_i2c.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/common/saa7146_i2c.c 2003-06-18 13:52:23.000000000 +0200
@@ -181,9 +181,10 @@
/* this functions writes out the data-byte 'dword' to the i2c-device.
it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
failed badly (e.g. address error) */
-static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword)
+static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_delay)
{
u32 status = 0, mc2 = 0;
+ int trial = 0;
int timeout;

/* write out i2c-command */
@@ -224,10 +225,13 @@
/* wait until we get a transfer done or error */
timeout = jiffies + HZ/100 + 1; /* 10ms */
while(1) {
+ /**
+ * first read usually delivers bogus results...
+ */
+ saa7146_i2c_status(dev);
status = saa7146_i2c_status(dev);
- if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
+ if ((status & 0x3) != 1)
break;
- }
if (jiffies > timeout) {
/* this is normal when probing the bus
* (no answer from nonexisistant device...)
@@ -235,6 +239,9 @@
DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n"));
return -EIO;
}
+ if ((++trial < 20) && short_delay)
+ udelay(10);
+ else
my_wait(dev,1);
}
}
@@ -277,6 +284,7 @@
u32* buffer = dev->d_i2c.cpu_addr;
int err = 0;
int address_err = 0;
+ int short_delay = 0;

if (down_interruptible (&dev->i2c_lock))
return -ERESTARTSYS;
@@ -292,6 +300,8 @@
goto out;
}

+ if (count > 3) short_delay = 1;
+
do {
/* reset the i2c-device if necessary */
err = saa7146_i2c_reset(dev);
@@ -302,7 +312,7 @@

/* write out the u32s one after another */
for(i = 0; i < count; i++) {
- err = saa7146_i2c_writeout(dev, &buffer[i] );
+ err = saa7146_i2c_writeout(dev, &buffer[i], short_delay);
if ( 0 != err) {
/* this one is unsatisfying: some i2c slaves on some
dvb cards don't acknowledge correctly, so the saa7146
@@ -357,7 +367,7 @@
if( 0 == dev->revision ) {
u32 zero = 0;
saa7146_i2c_reset(dev);
- if( 0 != saa7146_i2c_writeout(dev, &zero)) {
+ if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
INFO(("revision 0 error. this should never happen.\n"));
}
}
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/common/saa7146_video.c linux-2.5.73.work/drivers/media/common/saa7146_video.c
--- linux-2.5.73.bk/drivers/media/common/saa7146_video.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/common/saa7146_video.c 2003-06-18 13:57:02.000000000 +0200
@@ -220,7 +220,7 @@
}
}

-static int start_preview(struct saa7146_fh *fh)
+int saa7146_start_preview(struct saa7146_fh *fh)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
@@ -266,12 +266,12 @@
return 0;
}

-static int stop_preview(struct saa7146_fh *fh)
+int saa7146_stop_preview(struct saa7146_fh *fh)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;

- DEB_EE(("saa7146.o: stop_preview()\n"));
+ DEB_EE(("saa7146.o: saa7146_stop_preview()\n"));

/* check if overlay is running */
if( 0 == vv->ov_data ) {
@@ -333,8 +333,8 @@
if( vv->ov_data != NULL ) {
if( fh == vv->ov_data->fh) {
spin_lock_irqsave(&dev->slock,flags);
- stop_preview(fh);
- start_preview(fh);
+ saa7146_stop_preview(fh);
+ saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
}
@@ -522,8 +522,8 @@
if( 0 != vv->ov_data ) {
if( fh == vv->ov_data->fh ) {
spin_lock_irqsave(&dev->slock,flags);
- stop_preview(fh);
- start_preview(fh);
+ saa7146_stop_preview(fh);
+ saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
}
@@ -747,12 +747,12 @@

if( 0 != (dev->ext->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
DEB_D(("extension handles ioctl exclusive.\n"));
- result = dev->ext->ext_vv_data->ioctl(dev, cmd, arg);
+ result = dev->ext->ext_vv_data->ioctl(fh, cmd, arg);
return result;
}
if( 0 != (dev->ext->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
DEB_D(("extension handles ioctl before.\n"));
- result = dev->ext->ext_vv_data->ioctl(dev, cmd, arg);
+ result = dev->ext->ext_vv_data->ioctl(fh, cmd, arg);
if( -EAGAIN != result ) {
return result;
}
@@ -968,7 +968,7 @@

if( vv->ov_data != NULL ) {
ov_fh = vv->ov_data->fh;
- stop_preview(ov_fh);
+ saa7146_stop_preview(ov_fh);
restart_overlay = 1;
}

@@ -983,7 +983,7 @@
}

if( 0 != restart_overlay ) {
- start_preview(ov_fh);
+ saa7146_start_preview(ov_fh);
}
up(&dev->lock);

@@ -1013,7 +1013,7 @@
}
}
spin_lock_irqsave(&dev->slock,flags);
- err = start_preview(fh);
+ err = saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
} else {
if( vv->ov_data != NULL ) {
@@ -1022,7 +1022,7 @@
}
}
spin_lock_irqsave(&dev->slock,flags);
- err = stop_preview(fh);
+ err = saa7146_stop_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
return err;
@@ -1287,7 +1287,7 @@
if( 0 != vv->ov_data ) {
if( fh == vv->ov_data->fh ) {
spin_lock_irqsave(&dev->slock,flags);
- stop_preview(fh);
+ saa7146_stop_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
}
@@ -1331,7 +1331,7 @@

if( vv->ov_data != NULL ) {
ov_fh = vv->ov_data->fh;
- stop_preview(ov_fh);
+ saa7146_stop_preview(ov_fh);
restart_overlay = 1;
}

@@ -1343,7 +1343,7 @@

/* restart overlay if it was active before */
if( 0 != restart_overlay ) {
- start_preview(ov_fh);
+ saa7146_start_preview(ov_fh);
}

return ret;
@@ -1360,3 +1360,6 @@
};

EXPORT_SYMBOL_GPL(saa7146_video_uops);
+
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
diff -uNrwB --new-file linux-2.5.73.bk/include/media/saa7146_vv.h linux-2.5.73.work/include/media/saa7146_vv.h
--- linux-2.5.73.bk/include/media/saa7146_vv.h 2003-06-25 09:46:55.000000000 +0200
+++ linux-2.5.73.work/include/media/saa7146_vv.h 2003-06-18 14:43:38.000000000 +0200
@@ -10,12 +10,10 @@
#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */

#define WRITE_RPS0(x) do { \
- static int count = 0; \
dev->d_rps0.cpu_addr[ count++ ] = cpu_to_le32(x); \
} while (0);

#define WRITE_RPS1(x) do { \
- static int count = 0; \
dev->d_rps1.cpu_addr[ count++ ] = cpu_to_le32(x); \
} while (0);

@@ -166,7 +164,7 @@
int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);

struct saa7146_extension_ioctls *ioctls;
- int (*ioctl)(struct saa7146_dev*, unsigned int cmd, void *arg);
+ int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
};

struct saa7146_use_ops {
@@ -201,6 +199,8 @@

/* from saa7146_video.c */
extern struct saa7146_use_ops saa7146_video_uops;
+int saa7146_start_preview(struct saa7146_fh *fh);
+int saa7146_stop_preview(struct saa7146_fh *fh);

/* from saa7146_vbi.c */
extern struct saa7146_use_ops saa7146_vbi_uops;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/budget-av.c linux-2.5.73.work/drivers/media/dvb/ttpci/budget-av.c
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/budget-av.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/budget-av.c 2003-06-18 14:06:00.000000000 +0200
@@ -256,8 +256,9 @@
};


-static int av_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg)
+static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
+ struct saa7146_dev *dev = fh->dev;
struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
/*
struct saa7146_vv *vv = dev->vv_data;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/video/dpc7146.c linux-2.5.73.work/drivers/media/video/dpc7146.c
--- linux-2.5.73.bk/drivers/media/video/dpc7146.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/video/dpc7146.c 2003-06-25 12:16:54.000000000 +0200
@@ -246,8 +246,9 @@
}
#endif

-static int dpc_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg)
+static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
+ struct saa7146_dev *dev = fh->dev;
struct dpc* dpc = (struct dpc*)dev->ext_priv;
/*
struct saa7146_vv *vv = dev->vv_data;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/video/mxb.c linux-2.5.73.work/drivers/media/video/mxb.c
--- linux-2.5.73.bk/drivers/media/video/mxb.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/video/mxb.c 2003-06-25 12:16:38.000000000 +0200
@@ -566,8 +566,9 @@
return 0;
}

-static int mxb_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg)
+static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
+ struct saa7146_dev *dev = fh->dev;
struct mxb* mxb = (struct mxb*)dev->ext_priv;
struct saa7146_vv *vv = dev->vv_data;



2003-06-25 10:25:46

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 2/7] Update dvb core

- indentation fixes in dvb_demux.c
- include cleanup in various files
- simplify dvb/ttpci/Makefile
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_demux.c
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_demux.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_demux.c 2003-06-18 13:59:33.000000000 +0200
@@ -1110,8 +1130,8 @@
return 0;
}

-int
-dvb_dmx_init(struct dvb_demux *dvbdemux)
+
+int dvb_dmx_init(struct dvb_demux *dvbdemux)
{
int i, err;
struct dmx_demux *dmx = &dvbdemux->dmx;
@@ -1181,8 +1207,8 @@
return 0;
}

-int
-dvb_dmx_release(struct dvb_demux *dvbdemux)
+
+int dvb_dmx_release(struct dvb_demux *dvbdemux)
{
struct dmx_demux *dmx = &dvbdemux->dmx;

diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_functions.c linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_functions.c
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_functions.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_functions.c 2003-06-18 13:51:03.000000000 +0200
@@ -1,10 +1,10 @@
#include <linux/version.h>
-#include <linux/string.h>
-#include <linux/smp_lock.h>
-#include <linux/fs.h>
#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/string.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>

diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_functions.h linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_functions.h
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_functions.h 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_functions.h 2003-06-23 12:40:49.000000000 +0200
@@ -1,6 +1,8 @@
#ifndef __DVB_FUNCTIONS_H__
#define __DVB_FUNCTIONS_H__

+#include <linux/version.h>
+
/**
* a sleeping delay function, waits i ms
*

diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvbdev.c linux-2.5.73.work/drivers/media/dvb/dvb-core/dvbdev.c
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvbdev.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvbdev.c 2003-06-18 13:51:03.000000000 +0200
@@ -29,8 +29,6 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/version.h>
-#include <asm/semaphore.h>

#include "dvbdev.h"
#include "dvb_functions.h"
int dvb_generic_open(struct inode *inode, struct file *file)
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvbdev.h linux-2.5.73.work/drivers/media/dvb/dvb-core/dvbdev.h
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvbdev.h 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvbdev.h 2003-06-18 13:51:03.000000000 +0200
@@ -27,8 +27,9 @@
#include <linux/types.h>
#include <linux/poll.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/list.h>
+#include <linux/version.h>
+#include <linux/devfs_fs_kernel.h>

#define DVB_MAJOR 250

diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/Makefile linux-2.5.73.work/drivers/media/dvb/ttpci/Makefile
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/Makefile 2003-06-25 09:41:45.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/Makefile 2003-06-23 12:40:49.000000000 +0200
@@ -3,16 +3,12 @@
# and the AV7110 DVB device driver
#

-dvb-ttpci-budget-objs := budget.o
-dvb-ttpci-budget-av-objs := budget-av.o
-dvb-ttpci-budget-ci-objs := budget-ci.o
-dvb-ttpci-budget-patch-objs := budget-patch.o
dvb-ttpci-objs := av7110.o av7110_ipack.o av7110_ir.o

-obj-$(CONFIG_DVB_BUDGET) += budget-core.o dvb-ttpci-budget.o
-obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o dvb-ttpci-budget-ci.o
-obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o dvb-ttpci-budget-av.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o dvb-ttpci-budget-patch.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o

EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/

2003-06-25 10:25:47

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 3/7] Major dvb_net update

- code review and fix the old race condition in dev->set_multicast_list
- use tq_schedule instead of tq_immediate
- remove card_num and dev_num from struct dvb_net (now obsolete)
- prevent interface from being removed while it is in use
- allow add/remove only for the superuser
- set check-CRC flag on section filter to drop broken packets
- some more debug printfs in filter handling code
- cleaned up and commented packet reception handler
- fix formatting
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_net.c linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_net.c
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_net.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_net.c 2003-06-25 09:50:42.000000000 +0200
@@ -24,22 +24,25 @@
*
*/

-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-
#include <linux/dvb/net.h>
+#include <asm/uaccess.h>

#include "dvb_demux.h"
#include "dvb_net.h"
#include "dvb_functions.h"

+
+#if 1
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+
#define DVB_NET_MULTICAST_MAX 10

struct dvb_net_priv {
+ int in_use;
struct net_device_stats stats;
char name[6];
u16 pid;
@@ -49,10 +52,16 @@
int multi_num;
struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX];
unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
- int mode;
+ int rx_mode;
+#define RX_MODE_UNI 0
+#define RX_MODE_MULTI 1
+#define RX_MODE_ALL_MULTI 2
+#define RX_MODE_PROMISC 3
+ struct work_struct wq;
};

-/*
+
+/**
* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
@@ -60,8 +69,8 @@
* stolen from eth.c out of the linux kernel, hacked for dvb-device
* by Michael Holzt <[email protected]>
*/
-
-unsigned short my_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
+static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
+ struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
@@ -70,8 +79,7 @@
skb_pull(skb,dev->hard_header_len);
eth= skb->mac.ethernet;

- if(*eth->h_dest&1)
- {
+ if (*eth->h_dest & 1) {
if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
skb->pkt_type=PACKET_BROADCAST;
else
@@ -83,7 +91,7 @@

rawp = skb->data;

- /*
+ /**
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
@@ -92,31 +100,60 @@
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);

- /*
+ /**
* Real 802.2 LLC
*/
return htons(ETH_P_802_2);
}

-static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int pkt_len)
+
+static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
{
u8 *eth;
struct sk_buff *skb;

- if (pkt_len<13) {
- printk("%s: IP/MPE packet length = %d too small.\n", dev->name, pkt_len);
+ /* note: pkt_len includes a 32bit checksum */
+ if (pkt_len < 16) {
+ printk("%s: IP/MPE packet length = %d too small.\n",
+ dev->name, pkt_len);
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+ return;
+ }
+ if ((pkt[5] & 0xfd) != 0xc1) {
+ /* drop scrambled or broken packets */
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
return;
}
- skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL) {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
- dev->name);
+ if (pkt[5] & 0x02) {
+ //FIXME: handle LLC/SNAP
((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
return;
}
- eth=(u8 *) skb_put(skb, pkt_len+2);
- memcpy(eth+14, (void*)pkt+12, pkt_len-12);
+ if (pkt[7]) {
+ /* FIXME: assemble datagram from multiple sections */
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ return;
+ }
+
+ /* we have 14 byte ethernet header (ip header follows);
+ * 12 byte MPE header; 4 byte checksum; + 2 byte alignment
+ */
+ if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2))) {
+ //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+ ((struct dvb_net_priv *) dev->priv)->stats.rx_dropped++;
+ return;
+ }
+ skb_reserve(skb, 2); /* longword align L3 header */
+ skb->dev = dev;
+
+ /* copy L3 payload */
+ eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14);
+ memcpy(eth + 14, pkt + 12, pkt_len - 12 - 4);

+ /* create ethernet header: */
eth[0]=pkt[0x0b];
eth[1]=pkt[0x0a];
eth[2]=pkt[0x09];
@@ -123,11 +160,13 @@
eth[3]=pkt[0x08];
eth[4]=pkt[0x04];
eth[5]=pkt[0x03];
+
eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;
- eth[12]=0x08; eth[13]=0x00;

- skb->protocol=my_eth_type_trans(skb,dev);
- skb->dev=dev;
+ eth[12] = 0x08; /* ETH_P_IP */
+ eth[13] = 0x00;
+
+ skb->protocol = dvb_net_eth_type_trans(skb, dev);

((struct dvb_net_priv *)dev->priv)->stats.rx_packets++;
((struct dvb_net_priv *)dev->priv)->stats.rx_bytes+=skb->len;
@@ -141,9 +180,11 @@
{
struct net_device *dev=(struct net_device *) filter->priv;

- /* FIXME: this only works if exactly one complete section is
- delivered in buffer1 only */
- dvb_net_sec(dev, buffer1, buffer1_len);
+ /**
+ * we rely on the DVB API definition where exactly one complete
+ * section is delivered in buffer1
+ */
+ dvb_net_sec (dev, (u8*) buffer1, buffer1_len);
return 0;
}

@@ -178,24 +223,27 @@
memset((*secfilter)->filter_mode, 0xff, DMX_MAX_FILTER_SIZE);

(*secfilter)->filter_value[0]=0x3e;
- (*secfilter)->filter_mask[0]=0xff;
-
(*secfilter)->filter_value[3]=mac[5];
- (*secfilter)->filter_mask[3]=mac_mask[5];
(*secfilter)->filter_value[4]=mac[4];
- (*secfilter)->filter_mask[4]=mac_mask[4];
(*secfilter)->filter_value[8]=mac[3];
- (*secfilter)->filter_mask[8]=mac_mask[3];
(*secfilter)->filter_value[9]=mac[2];
- (*secfilter)->filter_mask[9]=mac_mask[2];
-
(*secfilter)->filter_value[10]=mac[1];
- (*secfilter)->filter_mask[10]=mac_mask[1];
(*secfilter)->filter_value[11]=mac[0];
+
+ (*secfilter)->filter_mask[0] = 0xff;
+ (*secfilter)->filter_mask[3] = mac_mask[5];
+ (*secfilter)->filter_mask[4] = mac_mask[4];
+ (*secfilter)->filter_mask[8] = mac_mask[3];
+ (*secfilter)->filter_mask[9] = mac_mask[2];
+ (*secfilter)->filter_mask[10] = mac_mask[1];
(*secfilter)->filter_mask[11]=mac_mask[0];

- printk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n",
+ dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n",
dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n",
+ dev->name, mac_mask[0], mac_mask[1], mac_mask[2],
+ mac_mask[3], mac_mask[4], mac_mask[5]);
+
return 0;
}

@@ -206,46 +254,57 @@
struct dmx_demux *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;

+ dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
+ if (priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
+ printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
+
priv->secfeed=0;
priv->secfilter=0;

+ dprintk("%s: alloc secfeed\n", __FUNCTION__);
ret=demux->allocate_section_feed(demux, &priv->secfeed,
dvb_net_callback);
if (ret<0) {
- printk("%s: could not get section feed\n", dev->name);
+ printk("%s: could not allocate section feed\n", dev->name);
return ret;
}

- ret=priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 0);
+ ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1);
+
if (ret<0) {
printk("%s: could not set section feed\n", dev->name);
- priv->demux->
- release_section_feed(priv->demux, priv->secfeed);
+ priv->demux->release_section_feed(priv->demux, priv->secfeed);
priv->secfeed=0;
return ret;
}
- /* fixme: is this correct? */
- try_module_get(THIS_MODULE);

- if (priv->mode<3)
+ if (priv->rx_mode != RX_MODE_PROMISC) {
+ dprintk("%s: set secfilter\n", __FUNCTION__);
dvb_net_filter_set(dev, &priv->secfilter, mac, mask_normal);
+ }

- switch (priv->mode) {
- case 1:
- for (i=0; i<priv->multi_num; i++)
+ switch (priv->rx_mode) {
+ case RX_MODE_MULTI:
+ for (i = 0; i < priv->multi_num; i++) {
+ dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i);
dvb_net_filter_set(dev, &priv->multi_secfilter[i],
priv->multi_macs[i], mask_normal);
+ }
break;
- case 2:
+ case RX_MODE_ALL_MULTI:
priv->multi_num=1;
- dvb_net_filter_set(dev, &priv->multi_secfilter[0], mac_allmulti, mask_allmulti);
+ dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__);
+ dvb_net_filter_set(dev, &priv->multi_secfilter[0],
+ mac_allmulti, mask_allmulti);
break;
- case 3:
+ case RX_MODE_PROMISC:
priv->multi_num=0;
+ dprintk("%s: set secfilter\n", __FUNCTION__);
dvb_net_filter_set(dev, &priv->secfilter, mac, mask_promisc);
break;
}

+ dprintk("%s: start filtering\n", __FUNCTION__);
priv->secfeed->start_filtering(priv->secfeed);
return 0;
}
@@ -255,89 +315,93 @@
struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
int i;

+ dprintk("%s\n", __FUNCTION__);
if (priv->secfeed) {
- if (priv->secfeed->is_filtering)
+ if (priv->secfeed->is_filtering) {
+ dprintk("%s: stop secfeed\n", __FUNCTION__);
priv->secfeed->stop_filtering(priv->secfeed);
- if (priv->secfilter)
- priv->secfeed->
- release_filter(priv->secfeed,
+ }
+
+ if (priv->secfilter) {
+ dprintk("%s: release secfilter\n", __FUNCTION__);
+ priv->secfeed->release_filter(priv->secfeed,
priv->secfilter);
priv->secfilter=0;
+ }

for (i=0; i<priv->multi_num; i++) {
- if (priv->multi_secfilter[i])
- priv->secfeed->
- release_filter(priv->secfeed,
+ if (priv->multi_secfilter[i]) {
+ dprintk("%s: release multi_filter[%d]\n", __FUNCTION__, i);
+ priv->secfeed->release_filter(priv->secfeed,
priv->multi_secfilter[i]);
priv->multi_secfilter[i]=0;
}
- priv->demux->
- release_section_feed(priv->demux, priv->secfeed);
+ }
+
+ priv->demux->release_section_feed(priv->demux, priv->secfeed);
priv->secfeed=0;
- /* fixme: is this correct? */
- module_put(THIS_MODULE);
} else
printk("%s: no feed to stop\n", dev->name);
}

-static int dvb_add_mc_filter(struct net_device *dev, struct dev_mc_list *mc)
+
+static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc)
{
struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
- int ret;

- if (priv->multi_num >= DVB_NET_MULTICAST_MAX)
+ if (priv->multi_num == DVB_NET_MULTICAST_MAX)
return -ENOMEM;

- ret = memcmp(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);
memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);

priv->multi_num++;
-
- return ret;
+ return 0;
}

-static void dvb_net_set_multi(struct net_device *dev)
+
+static void tq_set_multicast_list (void *data)
{
+ struct net_device *dev = data;
struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
- struct dev_mc_list *mc;
- int mci;
- int update = 0;
+
+ dvb_net_feed_stop(dev);
+
+ priv->rx_mode = RX_MODE_UNI;

if(dev->flags & IFF_PROMISC) {
-// printk("%s: promiscuous mode\n", dev->name);
- if(priv->mode != 3)
- update = 1;
- priv->mode = 3;
- } else if(dev->flags & IFF_ALLMULTI) {
-// printk("%s: allmulti mode\n", dev->name);
- if(priv->mode != 2)
- update = 1;
- priv->mode = 2;
- } else if(dev->mc_count > 0) {
-// printk("%s: set_mc_list, %d entries\n",
-// dev->name, dev->mc_count);
- if(priv->mode != 1)
- update = 1;
- priv->mode = 1;
+ dprintk("%s: promiscuous mode\n", dev->name);
+ priv->rx_mode = RX_MODE_PROMISC;
+ } else if ((dev->flags & IFF_ALLMULTI)) {
+ dprintk("%s: allmulti mode\n", dev->name);
+ priv->rx_mode = RX_MODE_ALL_MULTI;
+ } else if (dev->mc_count) {
+ int mci;
+ struct dev_mc_list *mc;
+
+ dprintk("%s: set_mc_list, %d entries\n",
+ dev->name, dev->mc_count);
+
+ priv->rx_mode = RX_MODE_MULTI;
priv->multi_num = 0;
+
for (mci = 0, mc=dev->mc_list;
mci < dev->mc_count;
- mc=mc->next, mci++)
- if(dvb_add_mc_filter(dev, mc) != 0)
- update = 1;
- } else {
- if(priv->mode != 0)
- update = 1;
- priv->mode = 0;
+ mc = mc->next, mci++) {
+ dvb_set_mc_filter(dev, mc);
+ }
}

- if(netif_running(dev) != 0 && update > 0)
- {
- dvb_net_feed_stop(dev);
dvb_net_feed_start(dev);
}
+
+
+static void dvb_net_set_multicast_list (struct net_device *dev)
+{
+ struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+ schedule_work(&priv->wq);
}

+
static int dvb_net_set_config(struct net_device *dev, struct ifmap *map)
{
if (netif_running(dev))
@@ -348,11 +413,10 @@
static int dvb_net_set_mac(struct net_device *dev, void *p)
{
struct sockaddr *addr=p;
- int update;

- update = memcmp(dev->dev_addr, addr->sa_data, dev->addr_len);
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- if (netif_running(dev) != 0 && update > 0) {
+
+ if (netif_running(dev)) {
dvb_net_feed_stop(dev);
dvb_net_feed_start(dev);
}
@@ -362,6 +427,9 @@

static int dvb_net_open(struct net_device *dev)
{
+ struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+
+ priv->in_use++;
dvb_net_feed_start(dev);
return 0;
}
@@ -366,8 +434,12 @@
return 0;
}

+
static int dvb_net_stop(struct net_device *dev)
{
+ struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+
+ priv->in_use--;
dvb_net_feed_stop(dev);
return 0;
}
@@ -386,16 +459,14 @@
dev->stop = dvb_net_stop;
dev->hard_start_xmit = dvb_net_tx;
dev->get_stats = dvb_net_get_stats;
- dev->set_multicast_list = dvb_net_set_multi;
+ dev->set_multicast_list = dvb_net_set_multicast_list;
dev->set_config = dvb_net_set_config;
dev->set_mac_address = dvb_net_set_mac;
dev->mtu = 4096;
dev->mc_count = 0;
-
- dev->flags |= IFF_NOARP;
dev->hard_header_cache = NULL;

- //SET_MODULE_OWNER(dev);
+ dev->flags |= IFF_NOARP;

return 0;
}
@@ -404,11 +476,13 @@
{
int i;

- for (i=0; i<dvbnet->dev_num; i++)
+ for (i=0; i<DVB_NET_DEVICES_MAX; i++)
if (!dvbnet->state[i])
break;
- if (i==dvbnet->dev_num)
+
+ if (i == DVB_NET_DEVICES_MAX)
return -1;
+
dvbnet->state[i]=1;
return i;
}
@@ -414,8 +488,7 @@
}


-int
-dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
+static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
{
struct net_device *net;
struct dmx_demux *demux;
@@ -423,8 +496,7 @@
int result;
int if_num;

- if_num=get_if(dvbnet);
- if (if_num<0)
+ if ((if_num = get_if(dvbnet)) < 0)
return -EINVAL;

net=&dvbnet->device[if_num];
@@ -435,47 +507,52 @@
net->dma = 0;
net->mem_start = 0;
memcpy(net->name, "dvb0_0", 7);
- net->name[3]=dvbnet->card_num+0x30;
- net->name[5]=if_num+0x30;
+ net->name[3] = dvbnet->dvbdev->adapter->num + '0';
+ net->name[5] = if_num + '0';
+ net->addr_len = 6;
+ memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
net->next = NULL;
net->init = dvb_net_init_dev;
- net->priv = kmalloc(sizeof(struct dvb_net_priv), GFP_KERNEL);
- if (net->priv == NULL)
+
+ if (!(net->priv = kmalloc(sizeof(struct dvb_net_priv), GFP_KERNEL)))
return -ENOMEM;

priv = net->priv;
memset(priv, 0, sizeof(struct dvb_net_priv));
priv->demux = demux;
priv->pid = pid;
- priv->mode = 0;
+ priv->rx_mode = RX_MODE_UNI;
+
+ INIT_WORK(&priv->wq, tq_set_multicast_list, net);

net->base_addr = pid;

if ((result = register_netdev(net)) < 0) {
return result;
}
- /* fixme: is this correct? */
- try_module_get(THIS_MODULE);

return if_num;
}

-int
-dvb_net_remove_if(struct dvb_net *dvbnet, int num)
+
+static int dvb_net_remove_if(struct dvb_net *dvbnet, int num)
{
+ struct dvb_net_priv *priv = dvbnet->device[num].priv;
+
if (!dvbnet->state[num])
return -EINVAL;
+ if (priv->in_use)
+ return -EBUSY;
+
dvb_net_stop(&dvbnet->device[num]);
- kfree(dvbnet->device[num].priv);
+ kfree(priv);
unregister_netdev(&dvbnet->device[num]);
dvbnet->state[num]=0;
- /* fixme: is this correct? */
- module_put(THIS_MODULE);
-
return 0;
}

-int dvb_net_do_ioctl(struct inode *inode, struct file *file,
+
+static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
@@ -490,6 +567,8 @@
struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg;
int result;

+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
result=dvb_net_add_if(dvbnet, dvbnetif->pid);
if (result<0)
return result;
@@ -502,7 +581,7 @@
struct dvb_net_priv *priv_data;
struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg;

- if (dvbnetif->if_num >= dvbnet->dev_num ||
+ if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
!dvbnet->state[dvbnetif->if_num])
return -EFAULT;

@@ -512,7 +591,9 @@
break;
}
case NET_REMOVE_IF:
- return dvb_net_remove_if(dvbnet, (long) parg);
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return dvb_net_remove_if(dvbnet, (int) parg);
default:
return -EINVAL;
}
@@ -542,28 +627,29 @@
.fops = &dvb_net_fops,
};

-void
-dvb_net_release(struct dvb_net *dvbnet)
+
+void dvb_net_release (struct dvb_net *dvbnet)
{
int i;

dvb_unregister_device(dvbnet->dvbdev);
- for (i=0; i<dvbnet->dev_num; i++) {
+
+ for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
if (!dvbnet->state[i])
continue;
dvb_net_remove_if(dvbnet, i);
}
}

-int
-dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet, struct dmx_demux *dmx)
+
+int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
+ struct dmx_demux *dmx)
{
int i;

dvbnet->demux = dmx;
- dvbnet->dev_num = DVB_NET_DEVICES_MAX;

- for (i=0; i<dvbnet->dev_num; i++)
+ for (i=0; i<DVB_NET_DEVICES_MAX; i++)
dvbnet->state[i] = 0;

dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net,
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_net.h linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_net.h
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_net.h 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_net.h 2003-06-23 12:40:49.000000000 +0200
@@ -35,8 +35,6 @@

struct dvb_net {
struct dvb_device *dvbdev;
- int card_num;
- int dev_num;
struct net_device device[DVB_NET_DEVICES_MAX];
int state[DVB_NET_DEVICES_MAX];
struct dmx_demux *demux;

2003-06-25 10:33:17

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 5/7] Add two new dvb frontend drivers

- Zarlink MT312 satellite channel decoder driver contributed by Andreas Oberritter
- tda10045 DVB-T driver contributed by Andrew de Quincy and Robert Schlalach
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/Kconfig linux-2.5.73.work/drivers/media/dvb/frontends/Kconfig
--- linux-2.5.73.bk/drivers/media/dvb/frontends/Kconfig 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/Kconfig 2003-06-25 09:50:42.000000000 +0200
@@ -93,6 +93,16 @@
DVB adapter simply enable all supported frontends, the
right one will get autodetected.

+config DVB_MT312
+ tristate "Zarlink MT312 Satellite Channel Decoder (QPSK)"
+ depends on DVB_CORE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+ If you don't know what tuner module is soldered on your
+ DVB adapter simply enable all supported frontends, the
+ right one will get autodetected.
+
config DVB_VES1820
tristate "Frontends with external VES1820 demodulator (QAM)"
depends on DVB_CORE
@@ -105,3 +115,12 @@
DVB adapter simply enable all supported frontends, the
right one will get autodetected.

+config DVB_TDA10045H
+ tristate "Frontends with external TDA10045H demodulator (OFDM)"
+ depends on DVB_CORE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ If you don't know what tuner module is soldered on your
+ DVB adapter simply enable all supported frontends, the
+ right one will get autodetected.
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/Makefile linux-2.5.73.work/drivers/media/dvb/frontends/Makefile
--- linux-2.5.73.bk/drivers/media/dvb/frontends/Makefile 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/Makefile 2003-06-25 09:50:42.000000000 +0200
@@ -12,4 +12,6 @@
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o
obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
+obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
+obj-$(CONFIG_DVB_TDA10045H) += tda10045h.o
diff -uNrwB --new-file linux-2.5.73.patch/drivers/media/dvb/frontends/mt312.c linux-2.5.73.work/drivers/media/dvb/frontends/mt312.c
--- linux-2.5.73.patch/drivers/media/dvb/frontends/mt312.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.73.work/drivers/media/dvb/frontends/mt312.c 2003-06-25 10:48:06.000000000 +0200
@@ -0,0 +1,714 @@
+/*
+ Driver for Zarlink MT312 Satellite Channel Decoder
+
+ Copyright (C) 2003 Andreas Oberritter <[email protected]>
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ References:
+ http://products.zarlink.com/product_profiles/MT312.htm
+ http://products.zarlink.com/product_profiles/SL1935.htm
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "mt312.h"
+
+#define I2C_ADDR_MT312 0x0e
+#define I2C_ADDR_SL1935 0x61
+
+#define MT312_DEBUG 0
+
+#define MT312_SYS_CLK 90000000UL /* 90 MHz */
+#define MT312_PLL_CLK 10000000UL /* 10 MHz */
+
+static struct dvb_frontend_info mt312_info = {
+ .name = "Zarlink MT312",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
+ /*.frequency_tolerance = 29500, FIXME: binary compatibility waste? */
+ .symbol_rate_min = MT312_SYS_CLK / 128,
+ .symbol_rate_max = MT312_SYS_CLK / 2,
+ /*.symbol_rate_tolerance = 500, FIXME: binary compatibility waste? 2% */
+ .notifier_delay = 0,
+ .caps =
+ FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_RECOVER |
+ FE_CAN_CLEAN_SETUP | FE_CAN_MUTE_TS
+};
+
+static int mt312_read(struct dvb_i2c_bus *i2c,
+ const enum mt312_reg_addr reg, void *buf,
+ const size_t count)
+{
+ int ret;
+ struct i2c_msg msg[2];
+ u8 regbuf[1] = { reg };
+
+ msg[0].addr = I2C_ADDR_MT312;
+ msg[0].flags = 0;
+ msg[0].buf = regbuf;
+ msg[0].len = 1;
+ msg[1].addr = I2C_ADDR_MT312;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ ret = i2c->xfer(i2c, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
+ return -EREMOTEIO;
+ }
+#ifdef MT312_DEBUG
+ {
+ int i;
+ printk(KERN_INFO "R(%d):", reg & 0x7f);
+ for (i = 0; i < count; i++)
+ printk(" %02x", ((const u8 *) buf)[i]);
+ printk("\n");
+ }
+#endif
+
+ return 0;
+}
+
+static int mt312_write(struct dvb_i2c_bus *i2c,
+ const enum mt312_reg_addr reg, const void *src,
+ const size_t count)
+{
+ int ret;
+ u8 buf[count + 1];
+ struct i2c_msg msg;
+
+#ifdef MT312_DEBUG
+ {
+ int i;
+ printk(KERN_INFO "W(%d):", reg & 0x7f);
+ for (i = 0; i < count; i++)
+ printk(" %02x", ((const u8 *) src)[i]);
+ printk("\n");
+ }
+#endif
+
+ buf[0] = reg;
+ memcpy(&buf[1], src, count);
+
+ msg.addr = I2C_ADDR_MT312;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = count + 1;
+
+ ret = i2c->xfer(i2c, &msg, 1);
+
+ if (ret != 1) {
+ printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static inline int mt312_readreg(struct dvb_i2c_bus *i2c,
+ const enum mt312_reg_addr reg, u8 * val)
+{
+ return mt312_read(i2c, reg, val, 1);
+}
+
+static inline int mt312_writereg(struct dvb_i2c_bus *i2c,
+ const enum mt312_reg_addr reg, const u8 val)
+{
+ return mt312_write(i2c, reg, &val, 1);
+}
+
+static int mt312_pll_write(struct dvb_i2c_bus *i2c, const u8 addr,
+ u8 * buf, const u8 len)
+{
+ int ret;
+ struct i2c_msg msg;
+
+ msg.addr = addr;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = len;
+
+ if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x40)) < 0)
+ return ret;
+
+ if ((ret = i2c->xfer(i2c, &msg, 1)) != 1)
+ printk(KERN_ERR "%s: i/o error (ret == %d)\n", __FUNCTION__, ret);
+
+ if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x00)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static inline u32 mt312_div(u32 a, u32 b)
+{
+ return (a + (b / 2)) / b;
+}
+
+static int sl1935_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr)
+{
+ /* 155 uA, Baseband Path B */
+ u8 buf[4] = { 0x00, 0x00, 0x80, 0x00 };
+
+ u8 exp;
+ u32 ref;
+ u32 div;
+
+ if (sr < 10000000) { /* 1-10 MSym/s: ratio 2 ^ 3 */
+ exp = 3;
+ buf[2] |= 0x40; /* 690 uA */
+ } else if (sr < 15000000) { /* 10-15 MSym/s: ratio 2 ^ 4 */
+ exp = 4;
+ buf[2] |= 0x20; /* 330 uA */
+ } else { /* 15-45 MSym/s: ratio 2 ^ 7 */
+ exp = 7;
+ buf[3] |= 0x08; /* Baseband Path A */
+ }
+
+ div = mt312_div(MT312_PLL_CLK, 1 << exp);
+ ref = mt312_div(freq * 1000, div);
+ mt312_info.frequency_stepsize = mt312_div(div, 1000);
+
+ buf[0] = (ref >> 8) & 0x7f;
+ buf[1] = (ref >> 0) & 0xff;
+ buf[2] |= (exp - 1);
+
+ if (freq < 1550000)
+ buf[3] |= 0x10;
+
+ printk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
+ buf[1], buf[2], buf[3]);
+
+ return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf));
+}
+
+static int mt312_reset(struct dvb_i2c_bus *i2c, const u8 full)
+{
+ return mt312_writereg(i2c, RESET, full ? 0x80 : 0x40);
+}
+
+static int mt312_init(struct dvb_i2c_bus *i2c)
+{
+ int ret;
+ u8 buf[2];
+
+ /* wake up */
+ if ((ret = mt312_writereg(i2c, CONFIG, 0x8c)) < 0)
+ return ret;
+
+ /* wait at least 150 usec */
+ udelay(150);
+
+ /* full reset */
+ if ((ret = mt312_reset(i2c, 1)) < 0)
+ return ret;
+
+ /* SYS_CLK */
+ buf[0] = mt312_div(MT312_SYS_CLK * 2, 1000000);
+
+ /* DISEQC_RATIO */
+ buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
+
+ if ((ret = mt312_write(i2c, SYS_CLK, buf, sizeof(buf))) < 0)
+ return ret;
+
+ if ((ret = mt312_writereg(i2c, SNR_THS_HIGH, 0x32)) < 0)
+ return ret;
+
+ /* TS_SW_LIM */
+ buf[0] = 0x8c;
+ buf[1] = 0x98;
+
+ if ((ret = mt312_write(i2c, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
+ return ret;
+
+ if ((ret = mt312_writereg(i2c, CS_SW_LIM, 0x69)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_send_master_cmd(struct dvb_i2c_bus *i2c,
+ const struct dvb_diseqc_master_cmd *c)
+{
+ int ret;
+ u8 diseqc_mode;
+
+ if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
+ return -EINVAL;
+
+ if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+ return ret;
+
+ if ((ret =
+ mt312_write(i2c, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
+ return ret;
+
+ if ((ret =
+ mt312_writereg(i2c, DISEQC_MODE,
+ (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
+ | 0x04)) < 0)
+ return ret;
+
+ /* set DISEQC_MODE[2:0] to zero if a return message is expected */
+ if (c->msg[0] & 0x02)
+ if ((ret =
+ mt312_writereg(i2c, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_recv_slave_reply(struct dvb_i2c_bus *i2c,
+ struct dvb_diseqc_slave_reply *r)
+{
+ /* TODO */
+ return -EOPNOTSUPP;
+}
+
+static int mt312_send_burst(struct dvb_i2c_bus *i2c, const fe_sec_mini_cmd_t c)
+{
+ const u8 mini_tab[2] = { 0x02, 0x03 };
+
+ int ret;
+ u8 diseqc_mode;
+
+ if (c > SEC_MINI_B)
+ return -EINVAL;
+
+ if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+ return ret;
+
+ if ((ret =
+ mt312_writereg(i2c, DISEQC_MODE,
+ (diseqc_mode & 0x40) | mini_tab[c])) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_set_tone(struct dvb_i2c_bus *i2c, const fe_sec_tone_mode_t t)
+{
+ const u8 tone_tab[2] = { 0x01, 0x00 };
+
+ int ret;
+ u8 diseqc_mode;
+
+ if (t > SEC_TONE_OFF)
+ return -EINVAL;
+
+ if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+ return ret;
+
+ if ((ret =
+ mt312_writereg(i2c, DISEQC_MODE,
+ (diseqc_mode & 0x40) | tone_tab[t])) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_set_voltage(struct dvb_i2c_bus *i2c, const fe_sec_voltage_t v)
+{
+ const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+
+ if (v > SEC_VOLTAGE_OFF)
+ return -EINVAL;
+
+ return mt312_writereg(i2c, DISEQC_MODE, volt_tab[v]);
+}
+
+static int mt312_read_status(struct dvb_i2c_bus *i2c, fe_status_t * s)
+{
+ int ret;
+ u8 status[3];
+
+ *s = 0;
+
+ if ((ret = mt312_read(i2c, QPSK_STAT_H, status, sizeof(status))) < 0)
+ return ret;
+
+ if (status[0] & 0xc0)
+ *s |= FE_HAS_SIGNAL; /* signal noise ratio */
+ if (status[0] & 0x04)
+ *s |= FE_HAS_CARRIER; /* qpsk carrier lock */
+ if (status[2] & 0x02)
+ *s |= FE_HAS_VITERBI; /* viterbi lock */
+ if (status[2] & 0x04)
+ *s |= FE_HAS_SYNC; /* byte align lock */
+ if (status[0] & 0x01)
+ *s |= FE_HAS_LOCK; /* qpsk lock */
+
+ return 0;
+}
+
+static int mt312_read_bercnt(struct dvb_i2c_bus *i2c, u32 * ber)
+{
+ int ret;
+ u8 buf[3];
+
+ if ((ret = mt312_read(i2c, RS_BERCNT_H, buf, 3)) < 0)
+ return ret;
+
+ *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
+
+ return 0;
+}
+
+static int mt312_read_agc(struct dvb_i2c_bus *i2c, u16 * signal_strength)
+{
+ int ret;
+ u8 buf[3];
+ u16 agc;
+ s16 err_db;
+
+ if ((ret = mt312_read(i2c, AGC_H, buf, sizeof(buf))) < 0)
+ return ret;
+
+ agc = (buf[0] << 6) | (buf[1] >> 2);
+ err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6;
+
+ *signal_strength = agc;
+
+ printk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db);
+
+ return 0;
+}
+
+static int mt312_read_snr(struct dvb_i2c_bus *i2c, u16 * snr)
+{
+ int ret;
+ u8 buf[2];
+
+ if ((ret = mt312_read(i2c, M_SNR_H, &buf, sizeof(buf))) < 0)
+ return ret;
+
+ *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
+
+ return 0;
+}
+
+static int mt312_read_ubc(struct dvb_i2c_bus *i2c, u32 * ubc)
+{
+ int ret;
+ u8 buf[2];
+
+ if ((ret = mt312_read(i2c, RS_UBC_H, &buf, sizeof(buf))) < 0)
+ return ret;
+
+ *ubc = (buf[0] << 8) | buf[1];
+
+ return 0;
+}
+
+static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
+ const struct dvb_frontend_parameters *p)
+{
+ int ret;
+ u8 buf[5];
+ u16 sr;
+
+ const u8 fec_tab[10] =
+ { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
+ const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
+
+ if ((p->frequency < mt312_info.frequency_min)
+ || (p->frequency > mt312_info.frequency_max))
+ return -EINVAL;
+
+ if ((p->inversion < INVERSION_OFF)
+ || (p->inversion > INVERSION_AUTO))
+ return -EINVAL;
+
+ if ((p->u.qpsk.symbol_rate < mt312_info.symbol_rate_min)
+ || (p->u.qpsk.symbol_rate > mt312_info.symbol_rate_max))
+ return -EINVAL;
+
+ if ((p->u.qpsk.fec_inner < FEC_NONE)
+ || (p->u.qpsk.fec_inner > FEC_AUTO))
+ return -EINVAL;
+
+ if ((p->u.qpsk.fec_inner == FEC_4_5)
+ || (p->u.qpsk.fec_inner == FEC_8_9))
+ return -EINVAL;
+
+ if ((ret =
+ sl1935_set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0)
+ return ret;
+
+ /* sr = (u16)(sr * 256.0 / 1000000.0) */
+ sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
+
+ /* SYM_RATE */
+ buf[0] = (sr >> 8) & 0x3f;
+ buf[1] = (sr >> 0) & 0xff;
+
+ /* VIT_MODE */
+ buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner];
+
+ /* QPSK_CTRL */
+ buf[3] = 0x40; /* swap I and Q before QPSK demodulation */
+
+ if (p->u.qpsk.symbol_rate < 10000000)
+ buf[3] |= 0x04; /* use afc mode */
+
+ /* GO */
+ buf[4] = 0x01;
+
+ if ((ret = mt312_write(i2c, SYM_RATE_H, buf, sizeof(buf))) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_get_inversion(struct dvb_i2c_bus *i2c,
+ fe_spectral_inversion_t * i)
+{
+ int ret;
+ u8 vit_mode;
+
+ if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0)
+ return ret;
+
+ if (vit_mode & 0x80) /* auto inversion was used */
+ *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+
+ return 0;
+}
+
+static int mt312_get_symbol_rate(struct dvb_i2c_bus *i2c, u32 * sr)
+{
+ int ret;
+ u8 sym_rate_h;
+ u8 dec_ratio;
+ u16 sym_rat_op;
+ u16 monitor;
+ u8 buf[2];
+
+ if ((ret = mt312_readreg(i2c, SYM_RATE_H, &sym_rate_h)) < 0)
+ return ret;
+
+ if (sym_rate_h & 0x80) { /* symbol rate search was used */
+ if ((ret = mt312_writereg(i2c, MON_CTRL, 0x03)) < 0)
+ return ret;
+
+ if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0)
+ return ret;
+
+ monitor = (buf[0] << 8) | buf[1];
+
+ printk(KERN_DEBUG "sr(auto) = %u\n",
+ mt312_div(monitor * 15625, 4));
+ } else {
+ if ((ret = mt312_writereg(i2c, MON_CTRL, 0x05)) < 0)
+ return ret;
+
+ if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0)
+ return ret;
+
+ dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
+
+ if ((ret = mt312_read(i2c, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
+ return ret;
+
+ sym_rat_op = (buf[0] << 8) | buf[1];
+
+ printk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
+ sym_rat_op, dec_ratio);
+ printk(KERN_DEBUG "*sr(manual) = %lu\n",
+ (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+ 2) - dec_ratio);
+ }
+
+ return 0;
+}
+
+static int mt312_get_code_rate(struct dvb_i2c_bus *i2c, fe_code_rate_t * cr)
+{
+ const fe_code_rate_t fec_tab[8] =
+ { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
+ FEC_AUTO,
+ FEC_AUTO
+ };
+
+ int ret;
+ u8 fec_status;
+
+ if ((ret = mt312_readreg(i2c, FEC_STATUS, &fec_status)) < 0)
+ return ret;
+
+ *cr = fec_tab[(fec_status >> 4) & 0x07];
+
+ return 0;
+}
+
+static int mt312_get_frontend(struct dvb_i2c_bus *i2c,
+ struct dvb_frontend_parameters *p)
+{
+ int ret;
+
+ if ((ret = mt312_get_inversion(i2c, &p->inversion)) < 0)
+ return ret;
+
+ if ((ret = mt312_get_symbol_rate(i2c, &p->u.qpsk.symbol_rate)) < 0)
+ return ret;
+
+ if ((ret = mt312_get_code_rate(i2c, &p->u.qpsk.fec_inner)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_sleep(struct dvb_i2c_bus *i2c)
+{
+ int ret;
+ u8 config;
+
+ /* reset all registers to defaults */
+ if ((ret = mt312_reset(i2c, 1)) < 0)
+ return ret;
+
+ if ((ret = mt312_readreg(i2c, CONFIG, &config)) < 0)
+ return ret;
+
+ /* enter standby */
+ if ((ret = mt312_writereg(i2c, CONFIG, config & 0x7f)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mt312_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+ struct dvb_i2c_bus *i2c = fe->i2c;
+
+ switch (cmd) {
+ case FE_GET_INFO:
+ memcpy(arg, &mt312_info, sizeof(struct dvb_frontend_info));
+ break;
+
+ case FE_DISEQC_RESET_OVERLOAD:
+ return -EOPNOTSUPP;
+
+ case FE_DISEQC_SEND_MASTER_CMD:
+ return mt312_send_master_cmd(i2c, arg);
+
+ case FE_DISEQC_RECV_SLAVE_REPLY:
+ if ((long) fe->data == ID_MT312)
+ return mt312_recv_slave_reply(i2c, arg);
+ else
+ return -EOPNOTSUPP;
+
+ case FE_DISEQC_SEND_BURST:
+ return mt312_send_burst(i2c, (fe_sec_mini_cmd_t) arg);
+
+ case FE_SET_TONE:
+ return mt312_set_tone(i2c, (fe_sec_tone_mode_t) arg);
+
+ case FE_SET_VOLTAGE:
+ return mt312_set_voltage(i2c, (fe_sec_voltage_t) arg);
+
+ case FE_ENABLE_HIGH_LNB_VOLTAGE:
+ return -EOPNOTSUPP;
+
+ case FE_READ_STATUS:
+ return mt312_read_status(i2c, arg);
+
+ case FE_READ_BER:
+ return mt312_read_bercnt(i2c, arg);
+
+ case FE_READ_SIGNAL_STRENGTH:
+ return mt312_read_agc(i2c, arg);
+
+ case FE_READ_SNR:
+ return mt312_read_snr(i2c, arg);
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ return mt312_read_ubc(i2c, arg);
+
+ case FE_SET_FRONTEND:
+ return mt312_set_frontend(i2c, arg);
+
+ case FE_GET_FRONTEND:
+ return mt312_get_frontend(i2c, arg);
+
+ case FE_GET_EVENT:
+ return -EOPNOTSUPP;
+
+ case FE_SLEEP:
+ return mt312_sleep(i2c);
+
+ case FE_INIT:
+ return mt312_init(i2c);
+
+ case FE_RESET:
+ return mt312_reset(i2c, 0);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int mt312_attach(struct dvb_i2c_bus *i2c)
+{
+ int ret;
+ u8 id;
+
+ if ((ret = mt312_readreg(i2c, ID, &id)) < 0)
+ return ret;
+
+ if ((id != ID_VP310) && (id != ID_MT312))
+ return -ENODEV;
+
+ return dvb_register_frontend(mt312_ioctl, i2c, (void *) (long) id,
+ &mt312_info);
+}
+
+static void mt312_detach(struct dvb_i2c_bus *i2c)
+{
+ dvb_unregister_frontend(mt312_ioctl, i2c);
+}
+
+static int __init mt312_module_init(void)
+{
+ return dvb_register_i2c_device(THIS_MODULE, mt312_attach, mt312_detach);
+}
+
+static void __exit mt312_module_exit(void)
+{
+ dvb_unregister_i2c_device(mt312_attach);
+}
+
+module_init(mt312_module_init);
+module_exit(mt312_module_exit);
+
+MODULE_DESCRIPTION("MT312 Satellite Channel Decoder Driver");
+MODULE_AUTHOR("Andreas Oberritter <[email protected]>");
+MODULE_LICENSE("GPL");
diff -uNrwB --new-file linux-2.5.73.patch/drivers/media/dvb/frontends/mt312.h linux-2.5.73.work/drivers/media/dvb/frontends/mt312.h
--- linux-2.5.73.patch/drivers/media/dvb/frontends/mt312.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.73.work/drivers/media/dvb/frontends/mt312.h 2003-06-25 10:46:35.000000000 +0200
@@ -0,0 +1,162 @@
+/*
+ Driver for Zarlink MT312 QPSK Frontend
+
+ Copyright (C) 2003 Andreas Oberritter <[email protected]>
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _DVB_FRONTENDS_MT312
+#define _DVB_FRONTENDS_MT312
+
+enum mt312_reg_addr {
+ QPSK_INT_H = 0,
+ QPSK_INT_M = 1,
+ QPSK_INT_L = 2,
+ FEC_INT = 3,
+ QPSK_STAT_H = 4,
+ QPSK_STAT_L = 5,
+ FEC_STATUS = 6,
+ LNB_FREQ_H = 7,
+ LNB_FREQ_L = 8,
+ M_SNR_H = 9,
+ M_SNR_L = 10,
+ VIT_ERRCNT_H = 11,
+ VIT_ERRCNT_M = 12,
+ VIT_ERRCNT_L = 13,
+ RS_BERCNT_H = 14,
+ RS_BERCNT_M = 15,
+ RS_BERCNT_L = 16,
+ RS_UBC_H = 17,
+ RS_UBC_L = 18,
+ SIG_LEVEL = 19,
+ GPP_CTRL = 20,
+ RESET = 21,
+ DISEQC_MODE = 22,
+ SYM_RATE_H = 23,
+ SYM_RATE_L = 24,
+ VIT_MODE = 25,
+ QPSK_CTRL = 26,
+ GO = 27,
+ IE_QPSK_H = 28,
+ IE_QPSK_M = 29,
+ IE_QPSK_L = 30,
+ IE_FEC = 31,
+ QPSK_STAT_EN = 32,
+ FEC_STAT_EN = 33,
+ SYS_CLK = 34,
+ DISEQC_RATIO = 35,
+ DISEQC_INSTR = 36,
+ FR_LIM = 37,
+ FR_OFF = 38,
+ AGC_CTRL = 39,
+ AGC_INIT = 40,
+ AGC_REF = 41,
+ AGC_MAX = 42,
+ AGC_MIN = 43,
+ AGC_LK_TH = 44,
+ TS_AGC_LK_TH = 45,
+ AGC_PWR_SET = 46,
+ QPSK_MISC = 47,
+ SNR_THS_LOW = 48,
+ SNR_THS_HIGH = 49,
+ TS_SW_RATE = 50,
+ TS_SW_LIM_L = 51,
+ TS_SW_LIM_H = 52,
+ CS_SW_RATE_1 = 53,
+ CS_SW_RATE_2 = 54,
+ CS_SW_RATE_3 = 55,
+ CS_SW_RATE_4 = 56,
+ CS_SW_LIM = 57,
+ TS_LPK = 58,
+ TS_LPK_M = 59,
+ TS_LPK_L = 60,
+ CS_KPROP_H = 61,
+ CS_KPROP_L = 62,
+ CS_KINT_H = 63,
+ CS_KINT_L = 64,
+ QPSK_SCALE = 65,
+ TLD_OUTCLK_TH = 66,
+ TLD_INCLK_TH = 67,
+ FLD_TH = 68,
+ PLD_OUTLK3 = 69,
+ PLD_OUTLK2 = 70,
+ PLD_OUTLK1 = 71,
+ PLD_OUTLK0 = 72,
+ PLD_INLK3 = 73,
+ PLD_INLK2 = 74,
+ PLD_INLK1 = 75,
+ PLD_INLK0 = 76,
+ PLD_ACC_TIME = 77,
+ SWEEP_PAR = 78,
+ STARTUP_TIME = 79,
+ LOSSLOCK_TH = 80,
+ FEC_LOCK_TM = 81,
+ LOSSLOCK_TM = 82,
+ VIT_ERRPER_H = 83,
+ VIT_ERRPER_M = 84,
+ VIT_ERRPER_L = 85,
+ VIT_SETUP = 86,
+ VIT_REF0 = 87,
+ VIT_REF1 = 88,
+ VIT_REF2 = 89,
+ VIT_REF3 = 90,
+ VIT_REF4 = 91,
+ VIT_REF5 = 92,
+ VIT_REF6 = 93,
+ VIT_MAXERR = 94,
+ BA_SETUPT = 95,
+ OP_CTRL = 96,
+ FEC_SETUP = 97,
+ PROG_SYNC = 98,
+ AFC_SEAR_TH = 99,
+ CSACC_DIF_TH = 100,
+ QPSK_LK_CT = 101,
+ QPSK_ST_CT = 102,
+ MON_CTRL = 103,
+ QPSK_RESET = 104,
+ QPSK_TST_CT = 105,
+ QPSK_TST_ST = 106,
+ TEST_R = 107,
+ AGC_H = 108,
+ AGC_M = 109,
+ AGC_L = 110,
+ FREQ_ERR1_H = 111,
+ FREQ_ERR1_M = 112,
+ FREQ_ERR1_L = 113,
+ FREQ_ERR2_H = 114,
+ FREQ_ERR2_L = 115,
+ SYM_RAT_OP_H = 116,
+ SYM_RAT_OP_L = 117,
+ DESEQC2_INT = 118,
+ DISEQC2_STAT = 119,
+ DISEQC2_FIFO = 120,
+ DISEQC2_CTRL1 = 121,
+ DISEQC2_CTRL2 = 122,
+ MONITOR_H = 123,
+ MONITOR_L = 124,
+ TEST_MODE = 125,
+ ID = 126,
+ CONFIG = 127
+};
+
+enum mt312_model_id {
+ ID_VP310 = 1,
+ ID_MT312 = 3
+};
+
+#endif /* DVB_FRONTENDS_MT312 */
diff -uNrwB --new-file linux-2.5.73.patch/drivers/media/dvb/frontends/tda10045h.c linux-2.5.73.work/drivers/media/dvb/frontends/tda10045h.c
--- linux-2.5.73.patch/drivers/media/dvb/frontends/tda10045h.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.73.work/drivers/media/dvb/frontends/tda10045h.c 2003-06-25 09:50:42.000000000 +0200
@@ -0,0 +1,1231 @@
+ /*
+ Driver for Philips TDA10045H OFDM Frontend
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+/*
+ This driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
+ windows driver saved as '/usr/lib/DVB/driver/frontends/tda10045h.mc'.
+ You can also pass the complete file name with the module parameter 'tda10045h_firmware'.
+
+ Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
+ be added reasonably painlessly.
+
+ Windows driver URL: http://www.technotrend.de/
+ */
+
+
+#define __KERNEL_SYSCALLS__
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/unistd.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include "dvb_frontend.h"
+#include "dvb_functions.h"
+
+static int tda10045h_debug = 0;
+static char *tda10045h_firmware =
+ "/usr/lib/DVB/driver/frontends/tda10045h.mc";
+
+
+#define TDA10045H_ADDRESS 0x08
+#define TDA10045H_TUNERA_ADDRESS 0x61
+#define TDA10045H_TDM1316L_ADDRESS 0x63
+#define TDA10045H_MC44BC374_ADDRESS 0x65
+
+#define TDA10045H_CHIPID 0x00
+#define TDA10045H_AUTO 0x01
+#define TDA10045H_IN_CONF1 0x02
+#define TDA10045H_IN_CONF2 0x03
+#define TDA10045H_OUT_CONF1 0x04
+#define TDA10045H_OUT_CONF2 0x05
+#define TDA10045H_STATUS_CD 0x06
+#define TDA10045H_CONFC4 0x07
+#define TDA10045H_REG0C 0x0C
+#define TDA10045H_CODE_IN 0x0D
+#define TDA10045H_FWPAGE 0x0E
+#define TDA10045H_SCAN_CPT 0x10
+#define TDA10045H_DSP_CMD 0x11
+#define TDA10045H_DSP_ARG 0x12
+#define TDA10045H_DSP_DATA1 0x13
+#define TDA10045H_DSP_DATA2 0x14
+#define TDA10045H_CONFADC1 0x15
+#define TDA10045H_CONFC1 0x16
+#define TDA10045H_SIGNAL_STRENGTH 0x1a
+#define TDA10045H_SNR 0x1c
+#define TDA10045H_REG1E 0x1e
+#define TDA10045H_REG1F 0x1f
+#define TDA10045H_CBER_MSB 0x21
+#define TDA10045H_CBER_LSB 0x22
+#define TDA10045H_CVBER_LUT 0x23
+#define TDA10045H_VBER_MSB 0x24
+#define TDA10045H_VBER_MID 0x25
+#define TDA10045H_VBER_LSB 0x26
+#define TDA10045H_UNCOR 0x27
+#define TDA10045H_CONFPLL_P 0x2D
+#define TDA10045H_CONFPLL_M_MSB 0x2E
+#define TDA10045H_CONFPLL_M_LSB 0x2F
+#define TDA10045H_CONFPLL_N 0x30
+#define TDA10045H_UNSURW_MSB 0x31
+#define TDA10045H_UNSURW_LSB 0x32
+#define TDA10045H_WREF_MSB 0x33
+#define TDA10045H_WREF_MID 0x34
+#define TDA10045H_WREF_LSB 0x35
+#define TDA10045H_MUXOUT 0x36
+#define TDA10045H_CONFADC2 0x37
+#define TDA10045H_IOFFSET 0x38
+
+
+#define dprintk if (tda10045h_debug) printk
+
+static struct dvb_frontend_info tda10045h_info = {
+ .name = "Philips TDA10045H",
+ .type = FE_OFDM,
+ .frequency_min = 87000000,
+ .frequency_max = 895000000,
+ .frequency_stepsize = 166667,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+};
+
+#pragma pack(1)
+struct tda10045h_state {
+ u8 tuner_address;
+ u8 initialised;
+};
+#pragma pack()
+
+struct fwinfo {
+ int file_size;
+ int fw_offset;
+ int fw_size;
+};
+static struct fwinfo tda10045h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x34cc5,.fw_size = 30555}, /* 2.15a */
+};
+static int tda10045h_fwinfo_count =
+ sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
+
+
+static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+static u8 bandwidth_8mhz[] =
+ { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
+static u8 bandwidth_7mhz[] =
+ { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
+static u8 bandwidth_6mhz[] =
+ { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
+static u8 tuner_data[] = { 0x0b, 0xf5, 0x88, 0xab, 0x00 };
+static int errno;
+
+static
+int tda10045h_write_byte(struct dvb_i2c_bus *i2c, int reg, int data)
+{
+ int ret;
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {.addr = TDA10045H_ADDRESS,.flags = 0,.buf =
+ buf,.len = 2
+ };
+
+ dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
+
+ ret = i2c->xfer(i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ __FUNCTION__, reg, data, ret);
+
+ dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
+ reg, data, ret);
+ return (ret != 1) ? -1 : 0;
+}
+
+static
+int tda10045h_read_byte(struct dvb_i2c_bus *i2c, int reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = { {.addr = TDA10045H_ADDRESS,.flags =
+ 0,.buf = b0,.len = 1},
+ {.addr = TDA10045H_ADDRESS,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ };
+
+ dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
+
+ ret = i2c->xfer(i2c, msg, 2);
+
+ if (ret != 2) {
+ dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
+ ret);
+ return -1;
+ }
+
+ dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
+ reg, b1[0], ret);
+ return b1[0];
+}
+
+static
+int tda10045h_write_mask(struct dvb_i2c_bus *i2c, int reg, int mask,
+ int data)
+{
+ int val;
+ dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
+ mask, data);
+
+ // read a byte and check
+ val = tda10045h_read_byte(i2c, reg);
+ if (val < 0)
+ return val;
+
+ // mask if off
+ val = val & ~mask;
+ val |= data & 0xff;
+
+ // write it out again
+ return tda10045h_write_byte(i2c, reg, val);
+}
+
+static
+int tda10045h_write_buf(struct dvb_i2c_bus *i2c, int reg,
+ unsigned char *buf, int len)
+{
+ int i;
+ int result;
+
+ dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len);
+
+ result = 0;
+ for (i = 0; i < len; i++) {
+ result = tda10045h_write_byte(i2c, reg + i, buf[i]);
+ if (result != 0)
+ break;
+ }
+
+ return result;
+}
+
+static
+int tda10045h_enable_tuner_i2c(struct dvb_i2c_bus *i2c)
+{
+ int result;
+ dprintk("%s\n", __FUNCTION__);
+
+ result = tda10045h_write_mask(i2c, TDA10045H_CONFC4, 2, 2);
+ dvb_delay(1);
+ return result;
+}
+
+static
+int tda10045h_disable_tuner_i2c(struct dvb_i2c_bus *i2c)
+{
+
+ dprintk("%s\n", __FUNCTION__);
+
+ return tda10045h_write_mask(i2c, TDA10045H_CONFC4, 2, 0);
+}
+
+static
+int tda10045h_dsp_command(struct dvb_i2c_bus *i2c, int cmd, int arg)
+{
+ int counter;
+ int data1;
+ int data2;
+
+ dprintk("%s: cmd=0x%x, arg=0x%x\n", __FUNCTION__, cmd, arg);
+
+ // send command and argument
+ if (tda10045h_write_byte(i2c, TDA10045H_DSP_ARG, arg) < 0)
+ return -1;
+ if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, cmd) < 0)
+ return -1;
+
+ // command retry loop
+ counter = 0;
+ while (counter++ < 5) {
+
+ // read in the two data bytes
+ data1 = tda10045h_read_byte(i2c, TDA10045H_DSP_DATA1);
+ data2 = tda10045h_read_byte(i2c, TDA10045H_DSP_DATA2);
+ if ((data1 < 0) || (data2 < 0))
+ return -1;
+
+ // finshed yet?
+ if (data1 == cmd)
+ continue;
+ if (data2 == arg)
+ continue;
+
+ // OK, resend command
+ if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, cmd) < 0)
+ return -1;
+ }
+
+ // OK, did it work?
+ if (data1 != cmd)
+ return -1;
+ if (data2 != arg)
+ return -1;
+
+ // success
+ return 0;
+}
+
+
+static
+int tda10045h_init(struct dvb_i2c_bus *i2c)
+{
+ int fw_pos;
+ int tx_size;
+ int counter;
+ u8 fw_buf[65];
+ struct i2c_msg fw_msg = {.addr = TDA10045H_ADDRESS,.flags =
+ 0,.buf = fw_buf,.len = 0
+ };
+ struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0
+ };
+ unsigned char *firmware = NULL;
+ int filesize;
+ int fw_size = 0;
+ int fd;
+ int data1;
+ int fwinfo_idx;
+ mm_segment_t fs = get_fs();
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // Load the firmware
+ set_fs(get_ds());
+ fd = open(tda10045h_firmware, 0, 0);
+ if (fd < 0) {
+ printk("%s: Unable to open firmware %s\n", __FUNCTION__,
+ tda10045h_firmware);
+ return -EIO;
+ }
+ filesize = lseek(fd, 0L, 2);
+ if (filesize <= 0) {
+ printk("%s: Firmware %s is empty\n", __FUNCTION__,
+ tda10045h_firmware);
+ sys_close(fd);
+ return -EIO;
+ }
+ // find extraction parameters
+ for (fwinfo_idx = 0; fwinfo_idx < tda10045h_fwinfo_count;
+ fwinfo_idx++) {
+ if (tda10045h_fwinfo[fwinfo_idx].file_size == filesize)
+ break;
+ }
+ if (fwinfo_idx >= tda10045h_fwinfo_count) {
+ printk("%s: Unsupported firmware %s\n", __FUNCTION__,
+ tda10045h_firmware);
+ sys_close(fd);
+ return -EIO;
+ }
+ fw_size = tda10045h_fwinfo[fwinfo_idx].fw_size;
+
+ // allocate buffer for it
+ firmware = vmalloc(fw_size);
+ if (firmware == NULL) {
+ printk("%s: Out of memory loading firmware\n",
+ __FUNCTION__);
+ sys_close(fd);
+ return -EIO;
+ }
+ // read it!
+ lseek(fd, tda10045h_fwinfo[fwinfo_idx].fw_offset, 0);
+ if (read(fd, firmware, fw_size) != fw_size) {
+ printk("%s: Failed to read firmware\n", __FUNCTION__);
+ vfree(firmware);
+ sys_close(fd);
+ return -EIO;
+ }
+ sys_close(fd);
+ set_fs(fs);
+
+ // Disable the MC44BC374C
+ tda10045h_enable_tuner_i2c(i2c);
+ tuner_msg.addr = TDA10045H_MC44BC374_ADDRESS;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+ i2c->xfer(i2c, &tuner_msg, 1);
+ }
+ tda10045h_disable_tuner_i2c(i2c);
+
+ // setup for firmware upload
+ tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P, bandwidth_8mhz,
+ sizeof(bandwidth_8mhz));
+ tda10045h_write_byte(i2c, TDA10045H_IOFFSET, 0);
+ dvb_delay(500);
+
+ // do the firmware upload
+ tda10045h_write_byte(i2c, TDA10045H_FWPAGE, 0);
+ fw_pos = 0;
+ while (fw_pos != fw_size) {
+ // work out how much to send this time
+ tx_size = fw_size - fw_pos;
+ if (tx_size > 64) {
+ tx_size = 64;
+ }
+ // send the chunk
+ fw_buf[0] = TDA10045H_CODE_IN;
+ memcpy(fw_buf + 1, firmware + fw_pos, tx_size);
+ fw_msg.len = tx_size + 1;
+ if (i2c->xfer(i2c, &fw_msg, 1) != 1) {
+ vfree(firmware);
+ return -EIO;
+ }
+ fw_pos += tx_size;
+
+ dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, fw_pos);
+ }
+ dvb_delay(100);
+ vfree(firmware);
+
+ // Initialise the DSP and check upload was OK
+ tda10045h_write_mask(i2c, TDA10045H_CONFC4, 0x10, 0);
+ tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, 0x67);
+ if ((tda10045h_read_byte(i2c, TDA10045H_DSP_DATA1) != 0x67) ||
+ (tda10045h_read_byte(i2c, TDA10045H_DSP_DATA2) != 0x2c)) {
+ printk("%s: firmware upload failed!\n", __FUNCTION__);
+ return -EIO;
+ }
+ // tda setup
+ tda10045h_write_byte(i2c, TDA10045H_CONFADC1, 0x2e);
+ tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x40, 0);
+ tda10045h_write_mask(i2c, TDA10045H_CONFC4, 0x20, 0);
+ tda10045h_write_mask(i2c, TDA10045H_VBER_MSB, 0xe0, 0xa0);
+ tda10045h_write_byte(i2c, TDA10045H_REG1F, 0);
+ tda10045h_write_byte(i2c, TDA10045H_REG1E, 0);
+ tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x80, 0x80);
+
+ // DSP init
+ tda10045h_write_mask(i2c, TDA10045H_CONFC4, 0x10, 0);
+ if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, 0x61) < 0)
+ return -1;
+
+ // command retry loop
+ counter = 0;
+ while (counter++ < 5) {
+
+ // read in the data byte
+ data1 = tda10045h_read_byte(i2c, TDA10045H_DSP_DATA1);
+ if (data1 < 0)
+ return data1;
+
+ // finshed yet?
+ if (data1 & 1)
+ continue;
+
+ // OK, resend command
+ if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, 0x61) < 0)
+ return -1;
+ }
+ tda10045h_write_byte(i2c, TDA10045H_DSP_DATA1, 0x01);
+ tda10045h_write_byte(i2c, TDA10045H_DSP_DATA2, 0x0e);
+ tda10045h_dsp_command(i2c, 0x69, 0);
+ tda10045h_write_byte(i2c, TDA10045H_DSP_DATA2, 0x01);
+ tda10045h_dsp_command(i2c, 0x69, 1);
+ tda10045h_write_byte(i2c, TDA10045H_DSP_DATA2, 0x03);
+ tda10045h_dsp_command(i2c, 0x69, 2);
+
+ // tda setup
+ tda10045h_write_mask(i2c, TDA10045H_CONFADC2, 0x20, 0x20);
+ tda10045h_write_mask(i2c, TDA10045H_CONFADC1, 0x80, 0);
+ tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x10, 0);
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 0x10, 0x10);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF2, 0xC0, 0x0);
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 8, 0);
+
+ // done
+ return 0;
+}
+
+static
+int tda10045h_encode_fec(int fec)
+{
+ // convert known FEC values
+ switch (fec) {
+ case FEC_1_2:
+ return 0;
+ case FEC_2_3:
+ return 1;
+ case FEC_3_4:
+ return 2;
+ case FEC_5_6:
+ return 3;
+ case FEC_7_8:
+ return 4;
+ }
+
+ // unsupported
+ return -EINVAL;
+}
+
+static
+int tda10045h_decode_fec(int tdafec)
+{
+ // convert known FEC values
+ switch (tdafec) {
+ case 0:
+ return FEC_1_2;
+ case 1:
+ return FEC_2_3;
+ case 2:
+ return FEC_3_4;
+ case 3:
+ return FEC_5_6;
+ case 4:
+ return FEC_7_8;
+ }
+
+ // unsupported
+ return -1;
+}
+
+static
+int tda10045h_set_frequency(struct dvb_i2c_bus *i2c,
+ struct tda10045h_state *tda_state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ int counter, counter2;
+ u8 tuner_buf[5];
+ u8 v1, v2, v3;
+ struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf =
+ tuner_buf,.len = sizeof(tuner_buf)
+ };
+ int tuner_frequency;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // setup the frequency buffer
+ switch (tda_state->tuner_address) {
+ case TDA10045H_TUNERA_ADDRESS:
+
+ // setup tuner buffer
+ tuner_frequency =
+ (((fe_params->frequency / 1000) * 6) + 217502) / 1000;
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0x88;
+ if (fe_params->frequency < 550000000) {
+ tuner_buf[3] = 0xab;
+ } else {
+ tuner_buf[3] = 0xeb;
+ }
+
+ // tune it
+ tda10045h_enable_tuner_i2c(i2c);
+ tuner_msg.addr = tda_state->tuner_address;
+ tuner_msg.len = 4;
+ i2c->xfer(i2c, &tuner_msg, 1);
+
+ // wait for it to finish
+ tuner_msg.len = 1;
+ tuner_msg.flags = I2C_M_RD;
+ counter = 0;
+ counter2 = 0;
+ while (counter++ < 100) {
+ if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+ if (tuner_buf[0] & 0x40) {
+ counter2++;
+ } else {
+ counter2 = 0;
+ }
+ }
+
+ if (counter2 > 10) {
+ break;
+ }
+ }
+ tda10045h_disable_tuner_i2c(i2c);
+ break;
+
+ case TDA10045H_TDM1316L_ADDRESS:
+ // determine settings
+ tuner_frequency = fe_params->frequency + 36167000;
+ if (tuner_frequency < 87000000) {
+ return -EINVAL;
+ } else if (tuner_frequency < 130000000) {
+ v1 = 1;
+ v2 = 3;
+ } else if (tuner_frequency < 160000000) {
+ v1 = 1;
+ v2 = 5;
+ } else if (tuner_frequency < 200000000) {
+ v1 = 1;
+ v2 = 6;
+ } else if (tuner_frequency < 290000000) {
+ v1 = 2;
+ v2 = 3;
+ } else if (tuner_frequency < 420000000) {
+ v1 = 2;
+ v2 = 5;
+ } else if (tuner_frequency < 480000000) {
+ v1 = 2;
+ v2 = 6;
+ } else if (tuner_frequency < 620000000) {
+ v1 = 4;
+ v2 = 3;
+ } else if (tuner_frequency < 830000000) {
+ v1 = 4;
+ v2 = 5;
+ } else if (tuner_frequency < 895000000) {
+ v1 = 4;
+ v2 = 7;
+ } else {
+ return -EINVAL;
+ }
+
+ // work out v3
+ switch (fe_params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ: // FIXME: IS THIS CORRECT???????
+ if (fe_params->frequency <= 300000000) {
+ v3 = 0;
+ } else {
+ v3 = 1;
+ }
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ v3 = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ v3 = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate tuner parameters
+ tuner_frequency =
+ (((fe_params->frequency / 1000) * 6) + 217502) / 1000;
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (3 << 5) | (v3 << 3) | v1;
+ tuner_buf[4] = 0x85;
+
+ // tune it
+ tda10045h_enable_tuner_i2c(i2c);
+ tuner_msg.addr = tda_state->tuner_address;
+ tuner_msg.len = 5;
+ if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+ return -EIO;
+ }
+ dvb_delay(50);
+ tuner_buf[3] = (v2 << 5) | (v3 << 3) | v1;
+ if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+ return -EIO;
+ }
+ dvb_delay(1);
+ tda10045h_disable_tuner_i2c(i2c);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dprintk("%s: success\n", __FUNCTION__);
+
+ // done
+ return 0;
+}
+
+static
+int tda10045h_set_fe(struct dvb_i2c_bus *i2c,
+ struct tda10045h_state *tda_state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // set frequency
+ tmp = tda10045h_set_frequency(i2c, tda_state, fe_params);
+ if (tmp < 0)
+ return tmp;
+
+ // hardcoded to use auto as much as possible
+ fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
+ fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+ fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+
+ // Set standard params.. or put them to auto
+ if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
+ (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
+ (fe_params->u.ofdm.constellation == QAM_AUTO) ||
+ (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 1, 1); // enable auto
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x03, 0); // turn off constellation bits
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x60, 0); // turn off hierarchy bits
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF2, 0x3f, 0); // turn off FEC bits
+ } else {
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 1, 0); // disable auto
+
+ // set HP FEC
+ tmp = tda10045h_encode_fec(fe_params->u.ofdm.code_rate_HP);
+ if (tmp < 0)
+ return tmp;
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF2, 7, tmp);
+
+ // set LP FEC
+ if (fe_params->u.ofdm.code_rate_LP != FEC_NONE) {
+ tmp =
+ tda10045h_encode_fec(fe_params->u.ofdm.
+ code_rate_LP);
+ if (tmp < 0)
+ return tmp;
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF2,
+ 0x38, tmp << 3);
+ }
+ // set constellation
+ switch (fe_params->u.ofdm.constellation) {
+ case QPSK:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 3, 0);
+ break;
+
+ case QAM_16:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 3, 1);
+ break;
+
+ case QAM_64:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 3, 2);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set hierarchy
+ switch (fe_params->u.ofdm.hierarchy_information) {
+ case HIERARCHY_NONE:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 0x60, 0 << 5);
+ break;
+
+ case HIERARCHY_1:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 0x60, 1 << 5);
+ break;
+
+ case HIERARCHY_2:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 0x60, 2 << 5);
+ break;
+
+ case HIERARCHY_4:
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+ 0x60, 3 << 5);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ // set bandwidth
+ switch (fe_params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda10045h_write_byte(i2c, TDA10045H_REG0C, 0x14);
+ tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P,
+ bandwidth_6mhz,
+ sizeof(bandwidth_6mhz));
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda10045h_write_byte(i2c, TDA10045H_REG0C, 0x80);
+ tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P,
+ bandwidth_7mhz,
+ sizeof(bandwidth_7mhz));
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda10045h_write_byte(i2c, TDA10045H_REG0C, 0x14);
+ tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P,
+ bandwidth_8mhz,
+ sizeof(bandwidth_8mhz));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set inversion
+ switch (fe_params->inversion) {
+ case INVERSION_OFF:
+ tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x20, 0);
+ break;
+
+ case INVERSION_ON:
+ tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x20, 0x20);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set guard interval
+ switch (fe_params->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+ 0 << 2);
+ break;
+
+ case GUARD_INTERVAL_1_16:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+ 1 << 2);
+ break;
+
+ case GUARD_INTERVAL_1_8:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+ 2 << 2);
+ break;
+
+ case GUARD_INTERVAL_1_4:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+ 3 << 2);
+ break;
+
+ case GUARD_INTERVAL_AUTO:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 2);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+ 0 << 2);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set transmission mode
+ switch (fe_params->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 4, 0);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x10,
+ 0 << 4);
+ break;
+
+ case TRANSMISSION_MODE_8K:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 4, 0);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x10,
+ 1 << 4);
+ break;
+
+ case TRANSMISSION_MODE_AUTO:
+ tda10045h_write_mask(i2c, TDA10045H_AUTO, 4, 4);
+ tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x10, 0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // reset DSP
+ tda10045h_write_mask(i2c, TDA10045H_CONFC4, 8, 8);
+ tda10045h_write_mask(i2c, TDA10045H_CONFC4, 8, 0);
+ dvb_delay(10);
+
+ // done
+ return 0;
+}
+
+
+static
+int tda10045h_get_fe(struct dvb_i2c_bus *i2c,
+ struct dvb_frontend_parameters *fe_params)
+{
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // inversion status
+ fe_params->inversion = INVERSION_OFF;
+ if (tda10045h_read_byte(i2c, TDA10045H_CONFC1) & 0x20) {
+ fe_params->inversion = INVERSION_ON;
+ }
+ // bandwidth
+ switch (tda10045h_read_byte(i2c, TDA10045H_WREF_LSB)) {
+ case 0x14:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ break;
+ case 0xdb:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ break;
+ case 0x4f:
+ fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ break;
+ }
+
+ // FEC
+ fe_params->u.ofdm.code_rate_HP =
+ tda10045h_decode_fec(tda10045h_read_byte
+ (i2c, TDA10045H_OUT_CONF2) & 7);
+ fe_params->u.ofdm.code_rate_LP =
+ tda10045h_decode_fec((tda10045h_read_byte
+ (i2c, TDA10045H_OUT_CONF2) >> 3) & 7);
+
+ // constellation
+ switch (tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 3) {
+ case 0:
+ fe_params->u.ofdm.constellation = QPSK;
+ break;
+ case 1:
+ fe_params->u.ofdm.constellation = QAM_16;
+ break;
+ case 2:
+ fe_params->u.ofdm.constellation = QAM_64;
+ break;
+ }
+
+ // transmission mode
+ fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ if (tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 0x10) {
+ fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ }
+ // guard interval
+ switch ((tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 0x0c) >>
+ 2) {
+ case 0:
+ fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ // hierarchy
+ switch ((tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 0x60) >>
+ 5) {
+ case 0:
+ fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ break;
+ case 1:
+ fe_params->u.ofdm.hierarchy_information = HIERARCHY_1;
+ break;
+ case 2:
+ fe_params->u.ofdm.hierarchy_information = HIERARCHY_2;
+ break;
+ case 3:
+ fe_params->u.ofdm.hierarchy_information = HIERARCHY_4;
+ break;
+ }
+
+ // done
+ return 0;
+}
+
+
+static
+int tda10045h_read_status(struct dvb_i2c_bus *i2c, fe_status_t * fe_status)
+{
+ int status;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read status
+ status = tda10045h_read_byte(i2c, TDA10045H_STATUS_CD);
+ if (status == -1) {
+ return -EIO;
+ }
+ // decode
+ *fe_status = 0;
+ if (status == 0x2f) {
+ *fe_status =
+ FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+ }
+ // FIXME: decode statuses better
+
+ dprintk("%s: ------------------ raw_status=0x%x\n", __FUNCTION__, status);
+
+ // success
+ dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status);
+ return 0;
+}
+
+static
+int tda10045h_read_signal_strength(struct dvb_i2c_bus *i2c, u16 * signal)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read it
+ tmp = tda10045h_read_byte(i2c, TDA10045H_SIGNAL_STRENGTH);
+
+ if (tmp < 0)
+ return -EIO;
+
+ // done
+ *signal = (tmp << 8) | tmp;
+ dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal);
+ return 0;
+}
+
+
+static
+int tda10045h_read_snr(struct dvb_i2c_bus *i2c, u16 * snr)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read it
+ tmp = tda10045h_read_byte(i2c, TDA10045H_SNR);
+ if (tmp < 0)
+ return -EIO;
+ // FIXME: calculate this properly
+
+ // done
+ *snr = ~((tmp << 8) | tmp);
+ dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
+ return 0;
+}
+
+static
+int tda10045h_read_ucblocks(struct dvb_i2c_bus *i2c, u32 * ucblocks)
+{
+ int tmp;
+ int tmp2;
+ int counter;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read the UCBLOCKS and reset
+ counter = 0;
+ tmp = tda10045h_read_byte(i2c, TDA10045H_UNCOR);
+ if (tmp < 0)
+ return -EIO;
+ tmp &= 0x7f;
+ while (counter++ < 5) {
+ tda10045h_write_mask(i2c, TDA10045H_UNCOR, 0x80, 0);
+ tda10045h_write_mask(i2c, TDA10045H_UNCOR, 0x80, 0);
+ tda10045h_write_mask(i2c, TDA10045H_UNCOR, 0x80, 0);
+
+ tmp2 = tda10045h_read_byte(i2c, TDA10045H_UNCOR);
+ if (tmp2 < 0)
+ return -EIO;
+ tmp2 &= 0x7f;
+ if ((tmp2 < tmp) || (tmp2 == 0))
+ break;
+ }
+ // FIXME: calculate this properly
+
+ // done
+ if (tmp != 0x7f) {
+ *ucblocks = tmp;
+ } else {
+ *ucblocks = 0xffffffff;
+ }
+ dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
+ return 0;
+}
+
+static
+int tda10045h_read_vber(struct dvb_i2c_bus *i2c, u32 * vber)
+{
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read it in
+ *vber = 0;
+ *vber |= tda10045h_read_byte(i2c, TDA10045H_VBER_LSB);
+ *vber |= tda10045h_read_byte(i2c, TDA10045H_VBER_MID) << 8;
+ *vber |=
+ (tda10045h_read_byte(i2c, TDA10045H_VBER_MSB) & 0x0f) << 16;
+
+ // reset counter
+ tda10045h_read_byte(i2c, TDA10045H_CVBER_LUT);
+ // FIXME: calculate this properly
+
+ // done
+ dprintk("%s: vber=0x%x\n", __FUNCTION__, *vber);
+ return 0;
+}
+
+static
+int tda10045h_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+ int status;
+ struct dvb_i2c_bus *i2c = fe->i2c;
+ struct tda10045h_state *tda_state = (struct tda10045h_state *) &(fe->data);
+
+ dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd);
+
+ switch (cmd) {
+ case FE_GET_INFO:
+ memcpy(arg, &tda10045h_info,
+ sizeof(struct dvb_frontend_info));
+ break;
+
+ case FE_READ_STATUS:
+ return tda10045h_read_status(i2c, (fe_status_t *) arg);
+
+ case FE_READ_BER:
+ return tda10045h_read_vber(i2c, (u32 *) arg);
+
+ case FE_READ_SIGNAL_STRENGTH:
+ return tda10045h_read_signal_strength(i2c, (u16 *) arg);
+
+ case FE_READ_SNR:
+ return tda10045h_read_snr(i2c, (u16 *) arg);
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ return tda10045h_read_ucblocks(i2c, (u32 *) arg);
+
+ case FE_SET_FRONTEND:
+ return tda10045h_set_fe(i2c, tda_state,
+ (struct dvb_frontend_parameters
+ *) arg);
+
+ case FE_GET_FRONTEND:
+ return tda10045h_get_fe(i2c,
+ (struct dvb_frontend_parameters
+ *) arg);
+
+ case FE_SLEEP:
+ break;
+
+ case FE_INIT:
+ // don't bother reinitialising
+ if (tda_state->initialised)
+ return 0;
+
+ // OK, perform initialisation
+ status = tda10045h_init(i2c);
+ if (status == 0)
+ tda_state->initialised = 1;
+ return status;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+
+static
+int tda10045h_attach(struct dvb_i2c_bus *i2c)
+{
+ int tuner_address = -1;
+ struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0
+ };
+ struct tda10045h_state tda_state;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // supported frontend?
+ if (tda10045h_read_byte(i2c, TDA10045H_CHIPID) != 0x25)
+ return -ENODEV;
+
+ // supported tuner?
+ tda10045h_enable_tuner_i2c(i2c);
+ tuner_msg.addr = TDA10045H_TUNERA_ADDRESS;
+ tuner_msg.buf = tuner_data;
+ tuner_msg.len = 4;
+ if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+ tuner_address = TDA10045H_TUNERA_ADDRESS;
+ printk("tda10045h: Detected, tuner type A.\n");
+ } else {
+ tuner_msg.addr = TDA10045H_TDM1316L_ADDRESS;
+ tuner_msg.buf = tuner_data;
+ tuner_msg.len = 5;
+ if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+ tuner_address = TDA10045H_TDM1316L_ADDRESS;
+ printk
+ ("tda10045h: Detected Philips TDM1316L tuner.\n");
+ }
+ }
+ tda10045h_disable_tuner_i2c(i2c);
+
+ // did we find a tuner?
+ if (tuner_address == -1) {
+ printk("tda10045h: Detected, but with unknown tuner.\n");
+ return -ENODEV;
+ }
+ // create state
+ tda_state.tuner_address = tuner_address;
+ tda_state.initialised = 0;
+
+ // register
+ dvb_register_frontend(tda10045h_ioctl, i2c, (void *)(*((u32*) &tda_state)),
+ &tda10045h_info);
+
+ // success
+ return 0;
+}
+
+
+static
+void tda10045h_detach(struct dvb_i2c_bus *i2c)
+{
+ dprintk("%s\n", __FUNCTION__);
+
+ dvb_unregister_frontend(tda10045h_ioctl, i2c);
+}
+
+
+static
+int __init init_tda10045h(void)
+{
+ return dvb_register_i2c_device(THIS_MODULE, tda10045h_attach,
+ tda10045h_detach);
+}
+
+
+static
+void __exit exit_tda10045h(void)
+{
+ dvb_unregister_i2c_device(tda10045h_attach);
+}
+
+module_init(init_tda10045h);
+module_exit(exit_tda10045h);
+
+MODULE_DESCRIPTION("Philips TDA10045H DVB-T Frontend");
+MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(tda10045h_debug, "i");
+MODULE_PARM_DESC(tda10045h_debug, "enable verbose debug messages");
+
+MODULE_PARM(tda10045h_firmware, "s");
+MODULE_PARM_DESC(tda10045h_firmware, "where to find the firmware file");

2003-06-25 10:34:42

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 7/7] Update dvb av7110 driver

- Fix to 'Sharing SDRAM between TT re-insertion and OSD...' - OSD didn't get the maximum available memory in one piece; needs new firmware version 0x2616
- Improved performance when setting palette with full 256 color OSD
- read MAC from EEPROM if available, contributed by Michael Glaum <[email protected]>
- add some MODULE_PARM_DESC for modinfo
- add support for the "analog module" available for DVB-C cards: the saa7113 is initialized and some more v4l2 ioctls are available. you can use "xawtv" now to switch between "dvb" and "analog" input. when you are one the "analog" input, you can tune in analog channels.
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/av7110.c linux-2.5.73.work/drivers/media/dvb/ttpci/av7110.c
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/av7110.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/av7110.c 2003-06-23 12:40:49.000000000 +0200
@@ -86,6 +86,7 @@
#define DEB_EE(x)
#endif

+#include "ttpci-eeprom.h"
#include "av7110.h"
#include "av7110_ipack.h"

@@ -110,7 +112,8 @@

int av7110_num = 0;

-#define FW_CI_LL_SUPPORT(arm_app) (((arm_app) >> 16) & 0x8000)
+#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
+#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF)

/****************************************************************************
* DEBI functions
@@ -1089,7 +1092,7 @@
u32 stat;
#endif

- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));

if (!av7110->arm_ready) {
DEB_D(("arm not ready.\n"));
@@ -1166,7 +1169,7 @@
{
int ret;

- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));

if (!av7110->arm_ready) {
DEB_D(("arm not ready.\n"));
@@ -1190,7 +1193,7 @@
u16 buf[num+2];
int i, ret;

- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));

buf[0]=(( type << 8 ) | com);
buf[1]=num;
@@ -1332,7 +1335,7 @@

static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data)
{
- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));

return outcom(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
}
@@ -1659,6 +1662,24 @@
color, ((blend>>4)&0x0f));
}

+static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last)
+{
+ int i;
+ int length = last - first + 1;
+
+ if (length * 4 > DATA_BUFF3_SIZE)
+ return -1;
+
+ for (i=0; i<length; i++) {
+ u32 blend = (colors[i] & 0xF0000000) >> 4;
+ u32 yuv = blend ? RGB2YUV(colors[i] & 0xFF, (colors[i] >> 8) & 0xFF, (colors[i] >> 16) & 0xFF) | blend : 0;
+ yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); // TODO kls2003-06-15: not sure if this is endian-proof
+ wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i*4, yuv, 4);
+ }
+ return outcom(av7110, COMTYPE_OSD, Set_Palette, 4,
+ av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], first, last);
+}
+
static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, int x1, int y1, int inc, u8 *data)
{
uint w, h, bpp, bpl, size, lpb, bnum, brest;
@@ -1721,6 +1742,9 @@
return 0;
case OSD_SetPalette:
{
+ if (FW_VERSION(av7110->arm_app) >= 0x2618)
+ OSDSetPalette(av7110, (u32 *)dc->data, dc->color, dc->x0);
+ else {
int i, len=dc->x0-dc->color+1;
u8 *colors=(u8 *)dc->data;

@@ -1728,6 +1752,7 @@
OSDSetColor(av7110, dc->color+i,
colors[i*4] , colors[i*4+1],
colors[i*4+2], colors[i*4+3]);
+ }
return 0;
}
case OSD_SetTrans:
@@ -2087,28 +2112,28 @@

static inline void TestMode(struct av7110 *av7110, int mode)
{
- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));
outcom(av7110, COMTYPE_ENCODER, SetTestMode, 1, mode);
}

static inline void VidMode(struct av7110 *av7110, int mode)
{
- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));
outcom(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
}


-static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
+static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg)
{
- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));
return outcom(av7110, 0x80, 0x02, 4,
(com>>16), (com&0xffff),
(arg>>16), (arg&0xffff));
}

-static inline int audcom(struct av7110 *av7110, u32 com)
+static int inline audcom(struct av7110 *av7110, u32 com)
{
- DEB_EE(("av7110: %p\n",av7110));
+// DEB_EE(("av7110: %p\n",av7110));
return outcom(av7110, 0x80, 0x03, 4,
(com>>16), (com&0xffff));
}
@@ -2583,38 +2608,274 @@
* V4L SECTION
****************************************************************************/

-int av7110_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg)
+static struct v4l2_input inputs[2] = {
+ { 0, "DVB", V4L2_INPUT_TYPE_CAMERA, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 1, "ANALOG", V4L2_INPUT_TYPE_TUNER, 2, 1, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+};
+
+/* taken from ves1820.c */
+static int ves1820_writereg(struct saa7146_dev *dev, u8 reg, u8 data)
{
+ u8 addr = 0x09;
+ u8 buf[] = { 0x00, reg, data };
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
+
+ DEB_EE(("av7710: dev: %p\n",dev));
+
+ if( 1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
+{
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
+
+ DEB_EE(("av7710: dev: %p\n",dev));
+
+ if( 1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * set up the downconverter frequency divisor for a
+ * reference clock comparision frequency of 62.5 kHz.
+ */
+static int tuner_set_tv_freq (struct saa7146_dev *dev, u32 freq)
+{
+ u32 div;
+ u8 config;
+ u8 buf [4];
+
+ DEB_EE(("av7710: freq: 0x%08x\n",freq));
+
+ /* magic number: 56. tuning with the frequency given by v4l2
+ is always off by 56*62.5 kHz...*/
+ div = freq + 56;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x8e;
+
+ if (freq < 16*168.25 )
+ config = 0xa0;
+ else if (freq < 16*447.25)
+ config = 0x90;
+ else
+ config = 0x30;
+ config &= ~0x02;
+
+ buf[3] = config;
+
+ return tuner_write (dev, 0x61, buf);
+}
+
+static struct saa7146_standard analog_standard[];
+static struct saa7146_standard dvb_standard[];
+static struct saa7146_standard standard[];
+
+int av7110_dvb_c_switch(struct saa7146_fh *fh)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ u16 buf[3] = { ((COMTYPE_AUDIODAC << 8) + ADSwitch), 1, 1 };
+
+ u8 band = 0;
+ int source, sync;
+ struct saa7146_fh *ov_fh = NULL;
+ int restart_overlay = 0;
+
+ DEB_EE(("av7110: %p\n",av7110));
+
+ if( vv->ov_data != NULL ) {
+ ov_fh = vv->ov_data->fh;
+ saa7146_stop_preview(ov_fh);
+ restart_overlay = 1;
+ }
+
+ if( 0 != av7110->current_input ) {
+ buf[2] = 0;
+ band = 0x68; /* analog band */
+ source = SAA7146_HPS_SOURCE_PORT_B;
+ sync = SAA7146_HPS_SYNC_PORT_B;
+ memcpy(standard,analog_standard,sizeof(struct saa7146_standard)*2);
+ } else {
+ buf[2] = 1;
+ band = 0x28; /* digital band */
+ source = SAA7146_HPS_SOURCE_PORT_A;
+ sync = SAA7146_HPS_SYNC_PORT_A;
+ memcpy(standard,dvb_standard,sizeof(struct saa7146_standard)*2);
+ }
+
+ /* hmm, this does not do anything!? */
+ if (OutCommand(av7110, buf, 3)) {
+ printk("ADSwitch error\n");
+ }
+
+ if( 0 != ves1820_writereg(dev, 0x0f, band )) {
+ printk("setting band in demodulator failed.\n");
+ }
+ saa7146_set_hps_source_and_sync(dev, source, sync);
+
+ /* restart overlay if it was active before */
+ if( 0 != restart_overlay ) {
+ saa7146_start_preview(ov_fh);
+ }
+
+ return 0;
+}
+
+int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
DEB_EE(("saa7146_dev: %p\n",dev));

switch(cmd) {
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
+
+ if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) {
+ return -EINVAL;
+ }
+
+ memset(t,0,sizeof(*t));
+ strcpy(t->name, "Television");
+
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+ t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
+ t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
+ /* FIXME: add the real signal strength here */
+ t->signal = 0xffff;
+ t->afc = 0;
+ /* fixme: real autodetection here */
+ t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ DEB_EE(("VIDIOC_S_TUNER: %d\n", t->index));
+
+ if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) {
+ return -EINVAL;
+ }
+
+
+ switch(t->audmode) {
+ case V4L2_TUNER_MODE_STEREO: {
+ DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
+ break;
+ }
+ case V4L2_TUNER_MODE_LANG1: {
+ DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
+ break;
+ }
+ case V4L2_TUNER_MODE_LANG2: {
+ DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
+ break;
+ }
+ default: { /* case V4L2_TUNER_MODE_MONO: {*/
+ DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
+ break;
+ }
+ }
+
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency));
+
+ if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) {
+ return -EINVAL;
+ }
+
+ memset(f,0,sizeof(*f));
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = av7110->current_freq;
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n",f->frequency));
+
+ if( 0 == av7110->has_analog_tuner || av7110->current_input != 1 ) {
+ return -EINVAL;
+ }
+
+ if (V4L2_TUNER_ANALOG_TV != f->type)
+ return -EINVAL;
+
+ /* tune in desired frequency */
+ tuner_set_tv_freq(dev, f->frequency);
+ av7110->current_freq = f->frequency;
+
+ return 0;
+ }
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;

+ DEB_EE(("VIDIOC_ENUMINPUT: %d\n", i->index));
+
+ if( 0 != av7110->has_analog_tuner ) {
+ if( i->index < 0 || i->index >= 2) {
+ return -EINVAL;
+ }
+ } else {
if( i->index != 0 ) {
return -EINVAL;
}
+ }

- memset(i,0,sizeof(*i));
- i->index = 0;
- strcpy(i->name, "DVB");
- i->type = V4L2_INPUT_TYPE_CAMERA;
- i->audioset = 1;
+ memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));

return 0;
}
case VIDIOC_G_INPUT:
{
int *input = (int *)arg;
- *input = 0;
+ *input = av7110->current_input;
+ DEB_EE(("VIDIOC_G_INPUT: %d\n", *input));
return 0;
}
case VIDIOC_S_INPUT:
{
+ int input = *(int *)arg;
+
+ DEB_EE(("VIDIOC_S_INPUT: %d\n", input));
+
+ if( 0 == av7110->has_analog_tuner ) {
return 0;
}
+
+ if( input < 0 || input >= 2) {
+ return -EINVAL;
+ }
+
+ /* fixme: switch inputs here */
+ av7110->current_input = input;
+ return av7110_dvb_c_switch(fh);
+ }
default:
+ printk("no such ioctl\n");
return -ENOIOCTLCMD;
}
return 0;
@@ -4006,7 +4267,6 @@
#endif
// }

- av7110->dvb_net.card_num=av7110->dvb_adapter->num;
dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);

return 0;
@@ -4061,6 +4321,10 @@
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
+ { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
+ { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
+ { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
{ 0, 0 }
};

@@ -4114,6 +4378,8 @@
return -ENOMEM;
}

+ ttpci_eeprom_parse_mac(av7110->i2c_bus);
+
saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
saa7146_write(dev, BCS_CTRL, 0x80400040);

@@ -4186,9 +4452,9 @@
bootarm(av7110);
firmversion(av7110);

- if ((av7110->arm_app&0xffff)<0x2501)
+ if (FW_VERSION(av7110->arm_app)<0x2501)
printk ("av7110: Warning, firmware version 0x%04x is too old. "
- "System might be unstable!\n", av7110->arm_app&0xffff);
+ "System might be unstable!\n", FW_VERSION(av7110->arm_app));

kernel_thread(arm_thread, (void *) av7110, 0);

@@ -4199,6 +4465,8 @@
VidMode(av7110, vidmode);

/* remaining inits according to card and frontend type */
+ av7110->has_analog_tuner = 0;
+ av7110->current_input = 0;
if (i2c_writereg(av7110, 0x20, 0x00, 0x00)==1) {
printk ("av7110(%d): Crystal audio DAC detected\n",
av7110->dvb_adapter->num);
@@ -4225,6 +4493,31 @@
msp_writereg(av7110, 0x12, 0x000a, 0x0220); // SCART 1 source
msp_writereg(av7110, 0x12, 0x0007, 0x7f00); // SCART 1 volume
msp_writereg(av7110, 0x12, 0x000d, 0x4800); // prescale SCART
+
+ if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
+ INFO(("saa7113 not accessible.\n"));
+ } else {
+ av7110->has_analog_tuner = 1;
+ /* init the saa7113 */
+ i2c_writereg(av7110, 0x48, 0x02, 0xd0); i2c_writereg(av7110, 0x48, 0x03, 0x23); i2c_writereg(av7110, 0x48, 0x04, 0x00);
+ i2c_writereg(av7110, 0x48, 0x05, 0x00); i2c_writereg(av7110, 0x48, 0x06, 0xe9); i2c_writereg(av7110, 0x48, 0x07, 0x0d);
+ i2c_writereg(av7110, 0x48, 0x08, 0x98); i2c_writereg(av7110, 0x48, 0x09, 0x02); i2c_writereg(av7110, 0x48, 0x0a, 0x80);
+ i2c_writereg(av7110, 0x48, 0x0b, 0x40); i2c_writereg(av7110, 0x48, 0x0c, 0x40); i2c_writereg(av7110, 0x48, 0x0d, 0x00);
+ i2c_writereg(av7110, 0x48, 0x0e, 0x01); i2c_writereg(av7110, 0x48, 0x0f, 0x7c); i2c_writereg(av7110, 0x48, 0x10, 0x48);
+ i2c_writereg(av7110, 0x48, 0x11, 0x0c); i2c_writereg(av7110, 0x48, 0x12, 0x8b); i2c_writereg(av7110, 0x48, 0x13, 0x10);
+ i2c_writereg(av7110, 0x48, 0x14, 0x00); i2c_writereg(av7110, 0x48, 0x15, 0x00); i2c_writereg(av7110, 0x48, 0x16, 0x00);
+ i2c_writereg(av7110, 0x48, 0x17, 0x00); i2c_writereg(av7110, 0x48, 0x18, 0x00); i2c_writereg(av7110, 0x48, 0x19, 0x00);
+ i2c_writereg(av7110, 0x48, 0x1a, 0x00); i2c_writereg(av7110, 0x48, 0x1b, 0x00); i2c_writereg(av7110, 0x48, 0x1c, 0x00);
+ i2c_writereg(av7110, 0x48, 0x1d, 0x00); i2c_writereg(av7110, 0x48, 0x1e, 0x00);
+ }
+
+ memcpy(standard,dvb_standard,sizeof(struct saa7146_standard)*2);
+ /* set dd1 stream a & b */
+ saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+ saa7146_write(dev, DD1_INIT, 0x0200700);
+ saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+
} else if (dev->pci->subsystem_vendor == 0x110a) {
printk("av7110(%d): DVB-C w/o analog module detected\n",
av7110->dvb_adapter->num);
@@ -4330,6 +4623,16 @@
{ "NTSC", V4L2_STD_NTSC, 0x10, 244, 480, 0x40, 708, 709, 480, 640 },
};

+static struct saa7146_standard analog_standard[] = {
+ { "PAL", V4L2_STD_PAL, 0x18, 288, 576, 0x08, 708, 709, 576, 768 },
+ { "NTSC", V4L2_STD_NTSC, 0x10, 244, 480, 0x40, 708, 709, 480, 640 },
+};
+
+static struct saa7146_standard dvb_standard[] = {
+ { "PAL", V4L2_STD_PAL, 0x14, 288, 576, 0x4a, 708, 709, 576, 768 },
+ { "NTSC", V4L2_STD_NTSC, 0x10, 244, 480, 0x40, 708, 709, 480, 640 },
+};
+
static struct saa7146_extension av7110_extension;

#define MAKE_AV7110_INFO(x_var,x_name) \
@@ -4390,7 +4693,7 @@
static struct saa7146_ext_vv av7110_vv_data = {
.inputs = 1,
.audios = 1,
- .capabilities = 0,
+ .capabilities = V4L2_CAP_TUNER,
.flags = SAA7146_EXT_SWAP_ODD_EVEN,

.stds = &standard[0],
@@ -4442,7 +4745,11 @@

MODULE_PARM(av7110_debug,"i");
MODULE_PARM(vidmode,"i");
+MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
MODULE_PARM(pids_off,"i");
+MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");
MODULE_PARM(adac,"i");
+MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
MODULE_PARM(hw_sections, "i");
+MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");

diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/av7110.h linux-2.5.73.work/drivers/media/dvb/ttpci/av7110.h
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/av7110.h 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/av7110.h 2003-06-17 09:29:10.000000000 +0200
@@ -153,7 +153,8 @@
BlitBmp,
ReleaseBmp,
SetWTrans,
- SetWNoTrans
+ SetWNoTrans,
+ Set_Palette
};

enum av7110_pid_command {
@@ -405,6 +406,11 @@
struct dvb_i2c_bus *i2c_bus;
char *card_name;

+ /* support for analog module of dvb-c */
+ int has_analog_tuner;
+ int current_input;
+ u32 current_freq;
+
struct tasklet_struct debi_tasklet;
struct tasklet_struct gpio_tasklet;

@@ -572,6 +578,9 @@
#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE)
#define DATA_BUFF2_SIZE 0x0800

+#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE)
+#define DATA_BUFF3_SIZE 0x0400
+
#define Reserved (DPRAM_BASE + 0x1E00)
#define Reserved_SIZE 0x1C0

diff -uNrwB --new-file linux-2.5.73.patch/drivers/media/dvb/ttpci/ttpci-eeprom.c linux-2.5.73.work/drivers/media/dvb/ttpci/ttpci-eeprom.c
--- linux-2.5.73.patch/drivers/media/dvb/ttpci/ttpci-eeprom.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/ttpci-eeprom.c 2003-06-25 10:57:21.000000000 +0200
@@ -0,0 +1,118 @@
+/*
+ Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM,
+ decode it and store it in the associated adapter struct for
+ use by dvb_net.c
+
+ This code was tested on TT-Budget/WinTV-NOVA-CI PCI boards with
+ Atmel and ST Microelectronics EEPROMs.
+
+ This card appear to have the 24C16 write protect held to ground,
+ thus permitting normal read/write operation. Theoretically it
+ would be possible to write routines to burn a different (encoded)
+ MAC address into the EEPROM.
+
+ Robert Schlabbach GMX
+ Michael Glaum KVH Industries
+ Holger Waechtler Convergence
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <asm/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "dvb_i2c.h"
+#include "dvb_functions.h"
+
+#if 1
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+
+static int ttpci_eeprom_read_encodedMAC(struct dvb_i2c_bus *i2c, u8 * encodedMAC)
+{
+ int ret;
+ u8 b0[] = { 0xd4 };
+
+ struct i2c_msg msg[] = {
+ {.addr = 0x50,.flags = 0,.buf = b0,.len = 1},
+ {.addr = 0x50,.flags = I2C_M_RD,.buf = encodedMAC,.len = 6}
+ };
+
+ dprintk("%s\n", __FUNCTION__);
+
+ ret = i2c->xfer(i2c, msg, 2);
+
+ if (ret != 2) /* Assume EEPROM isn't there */
+ return (-ENODEV);
+
+ return 0;
+}
+
+static void decodeMAC(u8 * decodedMAC, const u8 * encodedMAC)
+{
+ u8 ormask0[3] = { 0x54, 0x7B, 0x9E };
+ u8 ormask1[3] = { 0xD3, 0xF1, 0x23 };
+ u8 low;
+ u8 high;
+ u8 shift;
+ int i;
+
+ decodedMAC[0] = 0x00;
+ decodedMAC[1] = 0xD0;
+ decodedMAC[2] = 0x5C;
+
+ for (i = 0; i < 3; i++) {
+ low = encodedMAC[2 * i] ^ ormask0[i];
+ high = encodedMAC[2 * i + 1] ^ ormask1[i];
+ shift = (high >> 6) & 0x3;
+
+ decodedMAC[5 - i] = ((high << 8) | low) >> shift;
+ }
+
+}
+
+
+int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c)
+{
+ int ret;
+ u8 encodedMAC[6];
+ u8 decodedMAC[6];
+
+ ret = ttpci_eeprom_read_encodedMAC(i2c, encodedMAC);
+
+ if (ret != 0) { /* Will only be -ENODEV */
+ dprintk("Couldn't read from EEPROM: not there?\n");
+ memset(i2c->adapter->proposed_mac, 0, 6);
+ return ret;
+ }
+
+ decodeMAC(decodedMAC, encodedMAC);
+ memcpy(i2c->adapter->proposed_mac, decodedMAC, 6);
+
+ dprintk("%s adapter %i has MAC addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ i2c->adapter->name, i2c->adapter->num,
+ decodedMAC[0], decodedMAC[1], decodedMAC[2],
+ decodedMAC[3], decodedMAC[4], decodedMAC[5]);
+ dprintk("encoded MAC was %02x:%02x:%02x:%02x:%02x:%02x\n",
+ encodedMAC[0], encodedMAC[1], encodedMAC[2],
+ encodedMAC[3], encodedMAC[4], encodedMAC[5]);
+ return 0;
+}
diff -uNrwB --new-file linux-2.5.73.patch/drivers/media/dvb/ttpci/ttpci-eeprom.h linux-2.5.73.work/drivers/media/dvb/ttpci/ttpci-eeprom.h
--- linux-2.5.73.patch/drivers/media/dvb/ttpci/ttpci-eeprom.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/ttpci-eeprom.h 2003-06-25 10:55:33.000000000 +0200
@@ -0,0 +1,32 @@
+/*
+ Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM,
+ decode it and store it in associated adapter net device
+
+ Robert Schlabbach GMX
+ Michael Glaum KVH Industries
+ Holger Waechtler Convergence
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __TTPCI_EEPROM_H__
+#define __TTPCI_EEPROM_H__
+
+#include "dvb_i2c.h"
+
+extern int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c);
+
+#endif
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvbdev.h linux-2.5.73.work/drivers/media/dvb/dvb-core/dvbdev.h
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvbdev.h 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvbdev.h 2003-06-25 12:24:18.000000000 +0200
@@ -48,6 +48,7 @@
struct list_head list_head;
struct list_head device_list;
const char *name;
+ u8 proposed_mac [6];
};



2003-06-25 10:26:51

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 4/7] Update various dvb frontend drivers

- grundig_29504-401.c: fix charge pump and band switch setting bug, catched by Robert Schlabbach <[email protected]>
- grundig_29504-401.c: pass apply_frontend_param() return value to upper layers
- grundig_29504-401.c: try to make a more specific detection mechanism
- grundig_29504-491.c:remove bogus out-of-range check, FEC table index is limited to 0...7 due to &= ~0x03 anyway...
- nxt6000.c: Patch by Paul Andreassen: Add Support for Comtech DVBT-6k07 (PLL IC: SP5730)
- ves1820.c: use Robert Schlabbach's suggestions for CLKCONF (0x03) and CARCONF (0x04)
- alps_bsrv2.c: don't enable voltage on init + inversion bugfix
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_frontend.c linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_frontend.c
--- linux-2.5.73.bk/drivers/media/dvb/dvb-core/dvb_frontend.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/dvb-core/dvb_frontend.c 2003-06-23 12:40:49.000000000 +0200
@@ -263,8 +263,14 @@
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;

+ up(&fe->sem);
+
ret = wait_event_interruptible (events->wait_queue,
events->eventw != events->eventr);
+
+ if (down_interruptible (&fe->sem))
+ return -ERESTARTSYS;
+
if (ret < 0)
return ret;
}
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/alps_bsrv2.c linux-2.5.73.work/drivers/media/dvb/frontends/alps_bsrv2.c
--- linux-2.5.73.bk/drivers/media/dvb/frontends/alps_bsrv2.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/alps_bsrv2.c 2003-06-25 09:50:42.000000000 +0200
@@ -55,7 +55,7 @@
0x01, 0xA4, 0x35, 0x81, 0x2A, 0x0d, 0x55, 0xC4,
0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7F, 0x00,
0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x31, 0xb0, 0x14, 0x00, 0xDC, 0x20,
+ 0x80, 0x00, 0x31, 0xb0, 0x14, 0x00, 0xDC, 0x00,
0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
@@ -158,6 +158,11 @@
{
u8 val;

+ /*
+ * inversion on/off are interchanged because i and q seem to
+ * be swapped on the hardware
+ */
+
switch (inversion) {
case INVERSION_OFF:
val = 0xc0;
@@ -166,13 +171,16 @@
val = 0x80;
break;
case INVERSION_AUTO:
- val = 0x40;
+ val = 0x00;
break;
default:
return -EINVAL;
}

- return ves1893_writereg (i2c, 0x0c, (init_1893_tab[0x0c] & 0x3f) | val);
+ /* needs to be saved for FE_GET_FRONTEND */
+ init_1893_tab[0x0c] = (init_1893_tab[0x0c] & 0x3f) | val;
+
+ return ves1893_writereg (i2c, 0x0c, init_1893_tab[0x0c]);
}


@@ -383,8 +391,14 @@
afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;

p->frequency -= afc;
+
+ /*
+ * inversion indicator is only valid
+ * if auto inversion was used
+ */
+ if (!(init_1893_tab[0x0c] & 0x80))
p->inversion = (ves1893_readreg (i2c, 0x0f) & 2) ?
- INVERSION_ON : INVERSION_OFF;
+ INVERSION_OFF : INVERSION_ON;
p->u.qpsk.fec_inner = ves1893_get_fec (i2c);
/* XXX FIXME: timing offset !! */
break;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/grundig_29504-401.c linux-2.5.73.work/drivers/media/dvb/frontends/grundig_29504-401.c
--- linux-2.5.73.bk/drivers/media/dvb/frontends/grundig_29504-401.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/grundig_29504-401.c 2003-06-18 14:03:14.000000000 +0200
@@ -37,15 +37,15 @@


struct dvb_frontend_info grundig_29504_401_info = {
- .name = "Grundig 29504-401",
- .type = FE_OFDM,
-/* .frequency_min = ???,*/
-/* .frequency_max = ???,*/
- .frequency_stepsize = 166666,
-/* .frequency_tolerance = ???,*/
-/* .symbol_rate_tolerance = ???,*/
- .notifier_delay = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ name: "Grundig 29504-401",
+ type: FE_OFDM,
+/* frequency_min: ???,*/
+/* frequency_max: ???,*/
+ frequency_stepsize: 166666,
+/* frequency_tolerance: ???,*/
+/* symbol_rate_tolerance: ???,*/
+ notifier_delay: 0,
+ caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
FE_CAN_MUTE_TS /*| FE_CAN_CLEAN_SETUP*/
@@ -109,15 +109,15 @@
div = (36125000 + freq) / 166666;
cfg = 0x88;

- cpump = div < 175000000 ? 2 : div < 390000000 ? 1 :
- div < 470000000 ? 2 : div < 750000000 ? 1 : 3;
+ cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 :
+ freq < 470000000 ? 2 : freq < 750000000 ? 1 : 3;

- band_select = div < 175000000 ? 0x0e : div < 470000000 ? 0x05 : 0x03;
+ band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03;

buf [0] = (div >> 8) & 0x7f;
buf [1] = div & 0xff;
buf [2] = ((div >> 10) & 0x60) | cfg;
- buf [3] = cpump | band_select;
+ buf [3] = (cpump << 6) | band_select;

return tsa5060_write (i2c, buf);
}
@@ -267,12 +268,12 @@
}


-static void reset_and_configure (struct dvb_i2c_bus *i2c)
+static int reset_and_configure (struct dvb_i2c_bus *i2c)
{
u8 buf [] = { 0x06 };
struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };

- i2c->xfer (i2c, &msg, 1);
+ return (i2c->xfer (i2c, &msg, 1) == 1) ? 0 : -ENODEV;
}


@@ -391,7 +392,7 @@
struct dvb_frontend_parameters *p = arg;

tsa5060_set_tv_freq (i2c, p->frequency);
- apply_frontend_param (i2c, p);
+ return apply_frontend_param (i2c, p);
}
case FE_GET_FRONTEND:
/* we could correct the frequency here, but...
@@ -417,25 +418,61 @@

static int l64781_attach (struct dvb_i2c_bus *i2c)
{
+ u8 reg0x3e;
u8 b0 [] = { 0x1a };
u8 b1 [] = { 0x00 };
struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
{ .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };

- if (i2c->xfer (i2c, msg, 2) == 2) /* probably an EEPROM... */
+ /**
+ * the L64781 won't show up before we send the reset_and_configure()
+ * broadcast. If nothing responds there is no L64781 on the bus...
+ */
+ if (reset_and_configure(i2c) < 0) {
+ dprintk("no response on reset_and_configure() broadcast, bailing out...\n");
return -ENODEV;
+ }

- reset_and_configure (i2c);
-
- if (i2c->xfer (i2c, msg, 2) != 2) /* nothing... */
+ /* The chip always responds to reads */
+ if (i2c->xfer(i2c, msg, 2) != 2) {
+ dprintk("no response to read on I2C bus\n");
return -ENODEV;
+ }
+
+ /* Save current register contents for bailout */
+ reg0x3e = l64781_readreg(i2c, 0x3e);

- if (b1[0] != 0xa1)
+ /* Reading the POWER_DOWN register always returns 0 */
+ if (reg0x3e != 0) {
+ dprintk("Device doesn't look like L64781\n");
return -ENODEV;
+ }
+
+ /* Turn the chip off */
+ l64781_writereg (i2c, 0x3e, 0x5a);
+
+ /* Responds to all reads with 0 */
+ if (l64781_readreg(i2c, 0x1a) != 0) {
+ dprintk("Read 1 returned unexpcted value\n");
+ goto bailout;
+ }
+
+ /* Turn the chip on */
+ l64781_writereg (i2c, 0x3e, 0xa5);
+
+ /* Responds with register default value */
+ if (l64781_readreg(i2c, 0x1a) != 0xa1) {
+ dprintk("Read 2 returned unexpcted value\n");
+ goto bailout;
+ }

dvb_register_frontend (grundig_29504_401_ioctl, i2c, NULL,
&grundig_29504_401_info);
return 0;
+
+ bailout:
+ l64781_writereg (i2c, 0x3e, reg0x3e); /* restore reg 0x3e */
+ return -ENODEV;
}


diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/grundig_29504-491.c linux-2.5.73.work/drivers/media/dvb/frontends/grundig_29504-491.c
--- linux-2.5.73.bk/drivers/media/dvb/frontends/grundig_29504-491.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/grundig_29504-491.c 2003-06-25 09:50:42.000000000 +0200
@@ -179,10 +179,7 @@
static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 };

- index = tda8083_readreg (i2c, 0x0e) & 0x3;
-
- if (index > 7)
- return FEC_NONE;
+ index = tda8083_readreg(i2c, 0x0e) & 0x07;

return fec_tab [index];
}
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/nxt6000.c linux-2.5.73.work/drivers/media/dvb/frontends/nxt6000.c
--- linux-2.5.73.bk/drivers/media/dvb/frontends/nxt6000.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/nxt6000.c 2003-06-18 09:32:40.000000000 +0200
@@ -6,8 +6,10 @@

Alps TDME7 (Tuner: MITEL SP5659)
Alps TDED4 (Tuner: TI ALP510, external Nxt6000)
+ Comtech DVBT-6k07 (PLL IC: SP5730)

Copyright (C) 2002-2003 Florian Schirmer <[email protected]>
+ Copyright (C) 2003 Paul Andreassen <[email protected]>

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
@@ -78,6 +80,7 @@

#define TUNER_TYPE_ALP510 0
#define TUNER_TYPE_SP5659 1
+#define TUNER_TYPE_SP5730 2

#define FE2NXT(fe) ((struct nxt6000_config *)&(fe->data))
#define FREQ2DIV(freq) ((freq + 36166667) / 166667)
@@ -212,6 +215,39 @@

}

+static int sp5730_set_tv_freq(struct dvb_frontend *fe, u32 freq)
+{
+
+ u8 buf[4];
+ struct nxt6000_config *nxt = FE2NXT(fe);
+
+ buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
+ buf[1] = FREQ2DIV(freq) & 0xFF;
+ buf[2] = 0x93;
+
+ if ((freq >= 51000000) && (freq < 132100000))
+ buf[3] = 0x05;
+ else if ((freq >= 132100000) && (freq < 143000000))
+ buf[3] = 0x45;
+ else if ((freq >= 146000000) && (freq < 349100000))
+ buf[3] = 0x06;
+ else if ((freq >= 349100000) && (freq < 397100000))
+ buf[3] = 0x46;
+ else if ((freq >= 397100000) && (freq < 426000000))
+ buf[3] = 0x86;
+ else if ((freq >= 430000000) && (freq < 659100000))
+ buf[3] = 0x03;
+ else if ((freq >= 659100000) && (freq < 759100000))
+ buf[3] = 0x43;
+ else if ((freq >= 759100000) && (freq < 858000000))
+ buf[3] = 0x83;
+ else
+ return -EINVAL;
+
+ return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
+
+}
+
static void nxt6000_reset(struct dvb_frontend *fe)
{

@@ -756,6 +792,13 @@

break;

+ case TUNER_TYPE_SP5730:
+
+ if ((result = sp5730_set_tv_freq(fe, param->frequency)) < 0)
+ return result;
+
+ break;
+
default:

return -EFAULT;
@@ -816,6 +859,14 @@

dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt.tuner_addr);

+ } else if (pll_write(i2c, demod_addr_tbl[addr_nr], 0xC0, NULL, 0) == 0) {
+
+ nxt.tuner_addr = 0xC0;
+ nxt.tuner_type = TUNER_TYPE_SP5730;
+ nxt.clock_inversion = 0;
+
+ dprintk("nxt6000: detected SP5730 tuner at 0x%02X\n", nxt.tuner_addr);
+
} else {

printk("nxt6000: unable to detect tuner\n");
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/frontends/ves1820.c linux-2.5.73.work/drivers/media/dvb/frontends/ves1820.c
--- linux-2.5.73.bk/drivers/media/dvb/frontends/ves1820.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/frontends/ves1820.c 2003-06-20 08:48:36.000000000 +0200
@@ -95,7 +95,7 @@

static u8 ves1820_inittab [] =
{
- 0x69, 0x6A, 0x9B, 0x0A, 0x52, 0x46, 0x26, 0x1A,
+ 0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A,
0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x28,
0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
@@ -109,7 +109,7 @@
{
u8 addr = GET_DEMOD_ADDR(fe->data);
u8 buf[] = { 0x00, reg, data };
- struct i2c_msg msg = { addr: addr, .flags = 0, .buf = buf, .len = 3 };
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
struct dvb_i2c_bus *i2c = fe->i2c;
int ret;

@@ -130,8 +130,8 @@
u8 b0 [] = { 0x00, reg };
u8 b1 [] = { 0 };
u8 addr = GET_DEMOD_ADDR(fe->data);
- struct i2c_msg msg [] = { { addr: addr, .flags = 0, .buf = b0, .len = 2 },
- { addr: addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+ struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 },
+ { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
struct dvb_i2c_bus *i2c = fe->i2c;
int ret;

@@ -147,7 +147,7 @@
static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4])
{
int ret;
- struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = 4 };
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };

ret = i2c->xfer (i2c, &msg, 1);


2003-06-25 10:26:54

by Michael Hunold

[permalink] [raw]
Subject: [PATCH 6/7] Update dvb budget driver

- follow changes in dvb_net, use new eeprom parse code to properly detect the mac
- add new subvendor/subystem id pair
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/budget-core.c linux-2.5.73.work/drivers/media/dvb/ttpci/budget-core.c
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/budget-core.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/budget-core.c 2003-06-23 12:40:50.000000000 +0200
@@ -1,4 +1,5 @@
#include "budget.h"
+#include "ttpci-eeprom.h"

int budget_debug = 0;

@@ -165,7 +166,6 @@
if (ret < 0)
return ret;

- budget->dvb_net.card_num = budget->dvb_adapter->num;
dvb_net_init(budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);

return 0;
@@ -222,7 +222,7 @@
get recognized before the main driver is loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);

- saa7146_i2c_adapter_prepare(dev, NULL, SAA7146_I2C_BUS_BIT_RATE_3200);
+ saa7146_i2c_adapter_prepare(dev, NULL, SAA7146_I2C_BUS_BIT_RATE_120);

budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev,
budget->dvb_adapter, 0);
@@ -232,6 +232,8 @@
return -ENOMEM;
}

+ ttpci_eeprom_parse_mac(budget->i2c_bus);
+
if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) {
ret = -ENOMEM;
goto err;
diff -uNrwB --new-file linux-2.5.73.bk/drivers/media/dvb/ttpci/budget.c linux-2.5.73.work/drivers/media/dvb/ttpci/budget.c
--- linux-2.5.73.bk/drivers/media/dvb/ttpci/budget.c 2003-06-25 09:46:54.000000000 +0200
+++ linux-2.5.73.work/drivers/media/dvb/ttpci/budget.c 2003-06-18 13:51:03.000000000 +0200
@@ -192,6 +192,7 @@
MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
/* Uncomment for Budget Patch */
/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
@@ -202,6 +203,7 @@
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
+ MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
{
.vendor = 0,