[DVB] - fix WRITE_RPS0 and WRITE_RPS1 inlines, fix usage in mxb and budget drivers
[DVB] - 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)
[DVB] - 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
[DVB] - 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;
[DVB] - code review and fix the old race condition in dev->set_multicast_list
[DVB] - use tq_schedule instead of tq_immediate
[DVB] - remove card_num and dev_num from struct dvb_net (now obsolete)
[DVB] - prevent interface from being removed while it is in use
[DVB] - allow add/remove only for the superuser
[DVB] - set check-CRC flag on section filter to drop broken packets
[DVB] - some more debug printfs in filter handling code
[DVB] - cleaned up and commented packet reception handler
[DVB] - 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;
[DVB] - indentation fixes in dvb_demux.c
[DVB] - include cleanup in various files
[DVB] - 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/
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/Kconfig linux-2.6.0-test1.patch/drivers/media/dvb/Kconfig
--- linux-2.6.0-test1.work/drivers/media/dvb/Kconfig 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/Kconfig 2003-07-15 09:46:20.000000000 +0200
@@ -33,9 +33,19 @@
source "drivers/media/dvb/frontends/Kconfig"
comment "Supported SAA7146 based PCI Adapters"
- depends on DVB
+ depends on DVB && PCI
source "drivers/media/dvb/ttpci/Kconfig"
+comment "Supported USB Adapters"
+ depends on DVB && USB
+
+source "drivers/media/dvb/ttusb-budget/Kconfig"
+source "drivers/media/dvb/ttusb-dec/Kconfig"
+
+comment "Supported FlexCopII (B2C2) Adapters"
+ depends on DVB && PCI
+source "drivers/media/dvb/b2c2/Kconfig"
+
endmenu
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/Makefile linux-2.6.0-test1.patch/drivers/media/dvb/Makefile
--- linux-2.6.0-test1.work/drivers/media/dvb/Makefile 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/Makefile 2003-07-15 09:45:41.000000000 +0200
@@ -2,4 +2,5 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ # ttusb-budget/
+obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/
+
[DVB] - Zarlink MT312 satellite channel decoder driver contributed by Andreas Oberritter
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
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,5 @@
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
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 */
Send to Linus only. (138kB bzip2 compressed)
[DVB] - 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
[DVB] - Improved performance when setting palette with full 256 color OSD
[DVB] - read MAC from EEPROM if available, contributed by Michael Glaum <[email protected]>
[DVB] - add some MODULE_PARM_DESC for modinfo
[DVB] - 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,120 @@
+/*
+ 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;
+}
+
+EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
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];
};
[DVB] - follow changes in dvb_net, use new eeprom parse code to properly detect the mac
[DVB] - 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,
[V4L] - separate all EXPORT_SYMBOL stuff to saa7146_ksyms.c
[V4L] - properly stop capturing when no more buffers are available (missing register upload)
[V4L] - make extension data a per-device member, not a per-extension member, so that every device
can have it's own private data (necessary for DVB drivers which handle more than one device)
[V4L] - implement field based capturing, ie. capturing fields to different capture buffers
[V4L] - change default old of capture fields for ALTERNATE mode (comply with bttv)
[V4L] - follow these changes in various analog saa7146 based cards drivers (mxb.c and dpc7146.c)
[DVB] - follow these changes in various saa7146 based budget card drivers
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/Makefile linux-2.6.0-test1.patch/drivers/media/common/Makefile
--- linux-2.6.0-test1.work/drivers/media/common/Makefile 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/Makefile 2003-07-01 13:34:48.000000000 +0200
@@ -1,5 +1,5 @@
saa7146-objs := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o saa7146_vv.o
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_core.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_core.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_core.c 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_core.c 2003-07-07 13:28:54.000000000 +0200
@@ -373,6 +372,9 @@
dev->module = THIS_MODULE;
init_waitqueue_head(&dev->i2c_wq);
+ /* set some default values */
+ saa7146_write(dev, BCS_CTRL, 0x80400040);
+
if( 0 != ext->probe) {
if( 0 != ext->probe(dev) ) {
DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
@@ -391,9 +393,6 @@
list_add_tail(&dev->item,&saa7146_devices);
saa7146_num++;
- /* set some default values */
- saa7146_write(dev, BCS_CTRL, 0x80400040);
-
err = 0;
goto out;
attach_error:
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_fops.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_fops.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_fops.c 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_fops.c 2003-07-07 13:28:54.000000000 +0200
@@ -106,10 +106,21 @@
// fixme: fix this for vflip != 0
saa7146_write(dev, PROT_ADDR1, 0);
+ saa7146_write(dev, MC2, (MASK_02|MASK_18));
+
/* write the address of the rps-program */
saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
/* turn on rps */
saa7146_write(dev, MC1, (MASK_12 | MASK_28));
+
+/*
+ printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
+ printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
+ printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
+ printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
+ printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1));
+ printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
+*/
}
del_timer(&q->timeout);
}
@@ -374,7 +385,7 @@
.minor = -1,
};
-int saa7146_vv_init(struct saa7146_dev* dev)
+int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
{
struct saa7146_vv *vv = kmalloc (sizeof(struct saa7146_vv),GFP_KERNEL);
if( NULL == vv ) {
@@ -385,6 +396,11 @@
DEB_EE(("dev:%p\n",dev));
+ /* save per-device extension data (one extension can
+ handle different devices that might need different
+ configuration data) */
+ dev->ext_vv_data = ext_vv;
+
vv->video_minor = -1;
vv->vbi_minor = -1;
@@ -475,13 +491,6 @@
module_init(saa7146_vv_init_module);
module_exit(saa7146_vv_cleanup_module);
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
-
MODULE_AUTHOR("Michael Hunold <[email protected]>");
MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
MODULE_LICENSE("GPL");
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_hlp.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_hlp.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_hlp.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_hlp.c 2003-07-14 11:56:37.000000000 +0200
@@ -242,7 +242,9 @@
if( 2*out_y >= in_y) {
lpi = 1;
}
- } else if (field == V4L2_FIELD_TOP || field == V4L2_FIELD_BOTTOM) {
+ } else if (field == V4L2_FIELD_TOP
+ || field == V4L2_FIELD_ALTERNATE
+ || field == V4L2_FIELD_BOTTOM) {
if( 4*out_y >= in_y ) {
lpi = 1;
}
@@ -468,9 +470,7 @@
*clip_format &= 0xfffffff7;
if (V4L2_FIELD_HAS_BOTH(field)) {
*clip_format |= 0x00000008;
- } else if (field == V4L2_FIELD_TOP) {
- *clip_format |= 0x00000000;
- } else if (field == V4L2_FIELD_BOTTOM) {
+ } else {
*clip_format |= 0x00000000;
}
}
@@ -593,6 +593,10 @@
}
if (V4L2_FIELD_HAS_BOTH(field)) {
+ } else if (field == V4L2_FIELD_ALTERNATE) {
+ /* fixme */
+ vdma1.base_odd = vdma1.prot_addr;
+ vdma1.pitch /= 2;
} else if (field == V4L2_FIELD_TOP) {
vdma1.base_odd = vdma1.prot_addr;
vdma1.pitch /= 2;
@@ -706,7 +710,7 @@
/* calculate starting address */
where = (which-1)*0x18;
- if( 0 != (dev->ext->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
+ if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
saa7146_write(dev, where, vdma->base_even);
saa7146_write(dev, where+0x04, vdma->base_odd);
} else {
@@ -760,6 +764,16 @@
}
if (V4L2_FIELD_HAS_BOTH(field)) {
+ } else if (field == V4L2_FIELD_ALTERNATE) {
+ /* fixme */
+ if ( vv->last_field == V4L2_FIELD_TOP ) {
+ vdma1.base_odd = vdma1.prot_addr;
+ vdma1.pitch /= 2;
+ } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
+ vdma1.base_odd = vdma1.base_even;
+ vdma1.base_even = vdma1.prot_addr;
+ vdma1.pitch /= 2;
+ }
} else if (field == V4L2_FIELD_TOP) {
vdma1.base_odd = vdma1.prot_addr;
vdma1.pitch /= 2;
@@ -896,6 +910,14 @@
}
if (V4L2_FIELD_HAS_BOTH(field)) {
+ } else if (field == V4L2_FIELD_ALTERNATE) {
+ /* fixme */
+ vdma1.base_odd = vdma1.prot_addr;
+ vdma1.pitch /= 2;
+ vdma2.base_odd = vdma2.prot_addr;
+ vdma2.pitch /= 2;
+ vdma3.base_odd = vdma3.prot_addr;
+ vdma3.pitch /= 2;
} else if (field == V4L2_FIELD_TOP) {
vdma1.base_odd = vdma1.prot_addr;
vdma1.pitch /= 2;
@@ -940,17 +962,17 @@
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;
- if( 0 != (dev->ext->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
+ if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
unsigned long tmp = e_wait;
e_wait = o_wait;
o_wait = tmp;
}
- /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 0 is not set*/
- WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
+ /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
+ WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
- /* set bit 0 */
+ /* set rps register 0 */
WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));
WRITE_RPS0(MASK_27 | MASK_11);
@@ -971,8 +993,14 @@
}
/* wait for o_fid_a/b / e_fid_a/b toggle */
+ if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
+ WRITE_RPS0(CMD_PAUSE | o_wait);
WRITE_RPS0(CMD_PAUSE | e_wait);
+ } else if ( vv->last_field == V4L2_FIELD_TOP ) {
WRITE_RPS0(CMD_PAUSE | o_wait);
+ } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
+ WRITE_RPS0(CMD_PAUSE | e_wait);
+ }
/* turn off video-dma1 */
WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
@@ -1000,13 +1028,39 @@
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
{
struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_vv *vv = dev->vv_data;
+ u32 vdma1_prot_addr;
DEB_CAP(("buf:%p, next:%p\n",buf,next));
+/*
+ printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
+ printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
+ printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
+ printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
+ printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1));
+ printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
+ printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));
+*/
+
+ vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
+ if( 0 == vdma1_prot_addr ) {
+ /* clear out beginning of streaming bit (rps register 0)*/
+ DEB_CAP(("forcing sync to new frame\n"));
+ saa7146_write(dev, MC2, MASK_27 );
+ }
+
saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
saa7146_set_output_format(dev, sfmt->trans);
saa7146_disable_clipping(dev);
+ if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
+ } else if ( vv->last_field == V4L2_FIELD_TOP ) {
+ vv->last_field = V4L2_FIELD_BOTTOM;
+ } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
+ vv->last_field = V4L2_FIELD_TOP;
+ }
+
if( 0 != IS_PLANAR(sfmt->trans)) {
calculate_video_dma_grab_planar(dev, buf);
program_capture_engine(dev,1);
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_i2c.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_i2c.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_i2c.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_i2c.c 2003-06-18 14:20:44.000000000 +0200
@@ -407,8 +407,13 @@
if( NULL != i2c_adapter ) {
memset(i2c_adapter,0,sizeof(struct i2c_adapter));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+ strcpy(i2c_adapter->name, dev->name);
+ i2c_adapter->data = dev;
+#else
strcpy(i2c_adapter->dev.name, dev->name);
i2c_set_adapdata(i2c_adapter,dev);
+#endif
i2c_adapter->algo = &saa7146_algo;
i2c_adapter->algo_data = NULL;
i2c_adapter->id = I2C_ALGO_SAA7146;
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_vbi.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_vbi.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_vbi.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_vbi.c 2003-07-01 13:34:48.000000000 +0200
@@ -444,5 +444,3 @@
.irq_done = vbi_irq_done,
.read = vbi_read,
};
-
-EXPORT_SYMBOL_GPL(saa7146_vbi_uops);
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_video.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_video.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_video.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_video.c 2003-07-10 11:19:39.000000000 +0200
@@ -137,6 +137,7 @@
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_ALTERNATE:
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
@@ -186,11 +187,18 @@
: V4L2_FIELD_BOTTOM;
}
switch (field) {
+ case V4L2_FIELD_ALTERNATE: {
+ vv->last_field = V4L2_FIELD_TOP;
+ maxh = maxh / 2;
+ break;
+ }
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
+ vv->last_field = V4L2_FIELD_INTERLACED;
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
+ vv->last_field = V4L2_FIELD_INTERLACED;
break;
default: {
DEB_D(("no known field mode '%d'.\n",field));
@@ -561,7 +569,7 @@
m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/4))%PAGE_SIZE;
- printk("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2);
+ DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
break;
}
case 16: {
@@ -571,7 +579,7 @@
m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/2))%PAGE_SIZE;
- printk("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2);
+ DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
break;
}
default: {
@@ -674,7 +682,7 @@
spin_lock_irqsave(&dev->slock,flags);
- /* clear out beginning of streaming bit */
+ /* clear out beginning of streaming bit (rps register 0)*/
saa7146_write(dev, MC2, MASK_27 );
/* enable rps0 irqs */
@@ -740,19 +748,19 @@
struct videobuf_queue *q;
/* check if extension handles the command */
- for(ee = 0; dev->ext->ext_vv_data->ioctls[ee].flags != 0; ee++) {
- if( cmd == dev->ext->ext_vv_data->ioctls[ee].cmd )
+ for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) {
+ if( cmd == dev->ext_vv_data->ioctls[ee].cmd )
break;
}
- if( 0 != (dev->ext->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
+ if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
DEB_D(("extension handles ioctl exclusive.\n"));
- result = dev->ext->ext_vv_data->ioctl(fh, cmd, arg);
+ result = dev->ext_vv_data->ioctl(fh, cmd, arg);
return result;
}
- if( 0 != (dev->ext->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
+ if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
DEB_D(("extension handles ioctl before.\n"));
- result = dev->ext->ext_vv_data->ioctl(fh, cmd, arg);
+ result = dev->ext_vv_data->ioctl(fh, cmd, arg);
if( -EAGAIN != result ) {
return result;
}
@@ -793,7 +801,7 @@
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
- cap->capabilities |= dev->ext->ext_vv_data->capabilities;
+ cap->capabilities |= dev->ext_vv_data->capabilities;
return 0;
}
case VIDIOC_G_FBUF:
@@ -942,9 +950,10 @@
struct v4l2_standard *e = arg;
if (e->index < 0 )
return -EINVAL;
- if( e->index < dev->ext->ext_vv_data->num_stds ) {
+ if( e->index < dev->ext_vv_data->num_stds ) {
DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index));
- return v4l2_video_std_construct(e, dev->ext->ext_vv_data->stds[e->index].id, dev->ext->ext_vv_data->stds[e->index].name);
+ v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
+ return 0;
}
return -EINVAL;
}
@@ -972,13 +981,13 @@
restart_overlay = 1;
}
- for(i = 0; i < dev->ext->ext_vv_data->num_stds; i++)
- if (*id & dev->ext->ext_vv_data->stds[i].id)
+ for(i = 0; i < dev->ext_vv_data->num_stds; i++)
+ if (*id & dev->ext_vv_data->stds[i].id)
break;
- if (i != dev->ext->ext_vv_data->num_stds) {
- vv->standard = &dev->ext->ext_vv_data->stds[i];
- if( NULL != dev->ext->ext_vv_data->std_callback )
- dev->ext->ext_vv_data->std_callback(dev, vv->standard);
+ if (i != dev->ext_vv_data->num_stds) {
+ vv->standard = &dev->ext_vv_data->stds[i];
+ if( NULL != dev->ext_vv_data->std_callback )
+ dev->ext_vv_data->std_callback(dev, vv->standard);
found = 1;
}
@@ -1000,7 +1009,7 @@
int on = *(int *)arg;
int err = 0;
- if( NULL == vv->ov_fmt ) {
+ if( NULL == vv->ov_fmt && on != 0 ) {
DEB_D(("VIDIOC_OVERLAY: no framebuffer informations. call S_FBUF first!\n"));
return -EAGAIN;
}
@@ -1036,12 +1045,18 @@
return videobuf_querybuf(q,arg);
}
case VIDIOC_QBUF: {
- DEB_D(("VIDIOC_QBUF \n"));
- return videobuf_qbuf(file,q,arg);
+ struct v4l2_buffer *b = arg;
+ int ret = 0;
+ ret = videobuf_qbuf(file,q,b);
+ DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,b->index));
+ return ret;
}
case VIDIOC_DQBUF: {
- DEB_D(("VIDIOC_DQBUF \n"));
- return videobuf_dqbuf(file,q,arg);
+ struct v4l2_buffer *b = arg;
+ int ret = 0;
+ ret = videobuf_dqbuf(file,q,b);
+ DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,b->index));
+ return ret;
}
case VIDIOC_STREAMON: {
DEB_D(("VIDIOC_STREAMON \n"));
@@ -1075,7 +1090,7 @@
q = &fh->video_q;
down(&q->lock);
- err = videobuf_mmap_setup(file,q,gbuffers,gbufsize);
+ err = videobuf_mmap_setup(file,q,gbuffers,gbufsize); // ,V4L2_MEMORY_MMAP);
if (err < 0) {
up(&q->lock);
return err;
@@ -1250,7 +1265,7 @@
vv->video_q.dev = dev;
/* set some default values */
- vv->standard = &dev->ext->ext_vv_data->stds[0];
+ vv->standard = &dev->ext_vv_data->stds[0];
/* FIXME: what's this? */
vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
@@ -1358,8 +1373,3 @@
.capture_begin = video_begin,
.capture_end = video_end,
};
-
-EXPORT_SYMBOL_GPL(saa7146_video_uops);
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/common/saa7146_vv_ksyms.c linux-2.6.0-test1.patch/drivers/media/common/saa7146_vv_ksyms.c
--- linux-2.6.0-test1.work/drivers/media/common/saa7146_vv_ksyms.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/common/saa7146_vv_ksyms.c 2003-07-01 13:34:48.000000000 +0200
@@ -0,0 +1,15 @@
+#include <linux/module.h>
+#include <media/saa7146_vv.h>
+
+EXPORT_SYMBOL_GPL(saa7146_vbi_uops);
+EXPORT_SYMBOL_GPL(saa7146_video_uops);
+
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
+
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
+EXPORT_SYMBOL_GPL(saa7146_register_device);
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
+
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget-av.c linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget-av.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget-av.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget-av.c 2003-07-07 13:28:54.000000000 +0200
@@ -170,6 +170,7 @@
return err;
}
+static struct saa7146_ext_vv vv_data;
static int budget_av_attach (struct saa7146_dev* dev,
struct saa7146_pci_extension_data *info)
@@ -207,16 +208,22 @@
dvb_delay(500);
if ((err = saa7113_init (budget_av))) {
- budget_av_detach(dev);
+ /* fixme: proper cleanup here */
+ ERR(("cannot init saa7113.\n"));
+ return err;
+ }
+
+ if ( 0 != saa7146_vv_init(dev,&vv_data)) {
+ /* fixme: proper cleanup here */
+ ERR(("cannot init vv subsystem.\n"));
return err;
}
- saa7146_vv_init(dev);
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1",
VFL_TYPE_GRABBER)))
{
+ /* fixme: proper cleanup here */
ERR(("cannot register capture v4l2 device.\n"));
- budget_av_detach(dev);
return err;
}
@@ -300,11 +307,19 @@
}
static struct saa7146_standard standard[] = {
- { "PAL", V4L2_STD_PAL, SAA7146_PAL_VALUES },
- { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES },
+ {
+ .name = "PAL", .id = V4L2_STD_PAL,
+ .v_offset = 0x17, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }, {
+ .name = "NTSC", .id = V4L2_STD_NTSC,
+ .v_offset = 0x16, .v_field = 240, .v_calc = 480,
+ .h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1,
+ .v_max_out = 480, .h_max_out = 640,
+ }
};
-
static struct saa7146_ext_vv vv_data = {
.inputs = 2,
.capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
@@ -339,8 +354,6 @@
.attach = budget_av_attach,
.detach = budget_av_detach,
- .ext_vv_data = &vv_data,
-
.irq_mask = MASK_10,
.irq_func = ttpci_budget_irq10_handler,
};
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget-ci.c linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget-ci.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget-ci.c 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget-ci.c 2003-07-07 13:28:54.000000000 +0200
@@ -371,7 +377,6 @@
static struct saa7146_extension budget_extension = {
.name = "budget_ci dvb\0",
.flags = 0,
- .ext_vv_data = NULL,
.module = THIS_MODULE,
.pci_tbl = &pci_tbl[0],
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget-patch.c linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget-patch.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget-patch.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget-patch.c 2003-07-07 13:28:54.000000000 +0200
@@ -264,7 +264,6 @@
static struct saa7146_extension budget_extension = {
.name = "budget_patch dvb\0",
.flags = 0,
- .ext_vv_data = NULL,
.module = THIS_MODULE,
.pci_tbl = pci_tbl,
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget.c linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttpci/budget.c 2003-07-15 10:59:50.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/budget.c 2003-07-07 13:28:54.000000000 +0200
@@ -215,7 +215,6 @@
static struct saa7146_extension budget_extension = {
.name = "budget dvb\0",
.flags = 0,
- .ext_vv_data = NULL,
.module = THIS_MODULE,
.pci_tbl = pci_tbl,
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/dpc7146.c linux-2.6.0-test1.patch/drivers/media/video/dpc7146.c
--- linux-2.6.0-test1.work/drivers/media/video/dpc7146.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/video/dpc7146.c 2003-07-15 09:57:59.000000000 +0200
@@ -173,6 +173,8 @@
return 0;
}
+static struct saa7146_ext_vv vv_data;
+
/* this function only gets called when the probing was successful */
static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
@@ -183,7 +185,7 @@
/* checking for i2c-devices can be omitted here, because we
already did this in "dpc_vl42_probe" */
- saa7146_vv_init(dev);
+ saa7146_vv_init(dev,&vv_data);
if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
@@ -308,23 +310,32 @@
}
static struct saa7146_standard standard[] = {
- { "PAL-BG", V4L2_STD_PAL_BG, SAA7146_PAL_VALUES },
- { "PAL-I", V4L2_STD_PAL_I, SAA7146_PAL_VALUES },
- { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES },
- { "SECAM", V4L2_STD_SECAM, SAA7146_SECAM_VALUES },
+ {
+ .name = "PAL", .id = V4L2_STD_PAL,
+ .v_offset = 0x17, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }, {
+ .name = "NTSC", .id = V4L2_STD_NTSC,
+ .v_offset = 0x16, .v_field = 240, .v_calc = 480,
+ .h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1,
+ .v_max_out = 480, .h_max_out = 640,
+ }, {
+ .name = "SECAM", .id = V4L2_STD_SECAM,
+ .v_offset = 0x14, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }
};
-static
-struct saa7146_extension extension;
+static struct saa7146_extension extension;
-static
-struct saa7146_pci_extension_data dpc = {
+static struct saa7146_pci_extension_data dpc = {
.ext_priv = "Multimedia eXtension Board",
.ext = &extension,
};
-static
-struct pci_device_id pci_tbl[] = {
+static struct pci_device_id pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
@@ -338,8 +349,7 @@
MODULE_DEVICE_TABLE(pci, pci_tbl);
-static
-struct saa7146_ext_vv vv_data = {
+static struct saa7146_ext_vv vv_data = {
.inputs = DPC_INPUTS,
.capabilities = V4L2_CAP_VBI_CAPTURE,
.stds = &standard[0],
@@ -349,14 +359,12 @@
.ioctl = dpc_ioctl,
};
-static
-struct saa7146_extension extension = {
+static struct saa7146_extension extension = {
.name = "dpc7146 demonstration board",
.flags = SAA7146_USE_I2C_IRQ,
.pci_tbl = &pci_tbl[0],
.module = THIS_MODULE,
- .ext_vv_data = &vv_data,
.probe = dpc_probe,
.attach = dpc_attach,
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/mxb.c linux-2.6.0-test1.patch/drivers/media/video/mxb.c
--- linux-2.6.0-test1.work/drivers/media/video/mxb.c 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/video/mxb.c 2003-07-15 09:57:50.000000000 +0200
@@ -81,7 +81,7 @@
enum { TUNER, AUX1, AUX3, AUX3_YC };
static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
- { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 1, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
@@ -101,8 +101,8 @@
/* this array holds the information of the audio source (mxb_audios),
which has to be switched corresponding to the video source (mxb_channels) */
-static int video_audio_connect[MXB_AUDIOS] =
- { 0, 1, 2, 3, 3 };
+static int video_audio_connect[MXB_INPUTS] =
+ { 0, 1, 3, 3 };
/* these are the necessary input-output-pins for bringing one audio source
(see above) to the CD-output */
@@ -173,8 +173,7 @@
int cur_mute; /* current mute status */
};
-static
-struct saa7146_extension extension;
+static struct saa7146_extension extension;
static int mxb_vbi_bypass(struct saa7146_dev* dev)
{
@@ -431,10 +430,11 @@
polling method ... */
extension.flags &= ~SAA7146_USE_I2C_IRQ;
for(i = 1;;i++) {
- msg.len = mxb_saa7740_init[i].length;
- if (msg.len == -1U) {
+ if( -1 == mxb_saa7740_init[i].length ) {
break;
}
+
+ msg.len = mxb_saa7740_init[i].length;
msg.buf = &mxb_saa7740_init[i].data[0];
if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
DEB_D(("failed to initialize 'sound arena module'.\n"));
@@ -472,6 +472,8 @@
}
*/
+static struct saa7146_ext_vv vv_data;
+
/* this function only gets called when the probing was successful */
static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
@@ -482,7 +484,7 @@
/* checking for i2c-devices can be omitted here, because we
already did this in "mxb_vl42_probe" */
- saa7146_vv_init(dev);
+ saa7146_vv_init(dev,&vv_data);
if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
@@ -1003,20 +1005,35 @@
}
static struct saa7146_standard standard[] = {
- { "PAL-BG", V4L2_STD_PAL_BG, SAA7146_PAL_VALUES },
- { "PAL-I", V4L2_STD_PAL_I, SAA7146_PAL_VALUES },
- { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES },
- { "SECAM", V4L2_STD_SECAM, SAA7146_SECAM_VALUES },
+ {
+ .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
+ .v_offset = 0x17, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }, {
+ .name = "PAL-I", .id = V4L2_STD_PAL_I,
+ .v_offset = 0x17, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }, {
+ .name = "NTSC", .id = V4L2_STD_NTSC,
+ .v_offset = 0x16, .v_field = 240, .v_calc = 480,
+ .h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1,
+ .v_max_out = 480, .h_max_out = 640,
+ }, {
+ .name = "SECAM", .id = V4L2_STD_SECAM,
+ .v_offset = 0x14, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }
};
-static
-struct saa7146_pci_extension_data mxb = {
+static struct saa7146_pci_extension_data mxb = {
.ext_priv = "Multimedia eXtension Board",
.ext = &extension,
};
-static
-struct pci_device_id pci_tbl[] = {
+static struct pci_device_id pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
@@ -1030,8 +1047,7 @@
MODULE_DEVICE_TABLE(pci, pci_tbl);
-static
-struct saa7146_ext_vv vv_data = {
+static struct saa7146_ext_vv vv_data = {
.inputs = MXB_INPUTS,
.capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
.stds = &standard[0],
@@ -1041,14 +1057,12 @@
.ioctl = mxb_ioctl,
};
-static
-struct saa7146_extension extension = {
+static struct saa7146_extension extension = {
.name = MXB_IDENTIFIER,
.flags = SAA7146_USE_I2C_IRQ,
.pci_tbl = &pci_tbl[0],
.module = THIS_MODULE,
- .ext_vv_data = &vv_data,
.probe = mxb_probe,
.attach = mxb_attach,
diff -uNrwB --new-file linux-2.6.0-test1.work/include/media/saa7146.h linux-2.6.0-test1.patch/include/media/saa7146.h
--- linux-2.6.0-test1.work/include/media/saa7146.h 2003-07-15 09:43:07.000000000 +0200
+++ linux-2.6.0-test1.patch/include/media/saa7146.h 2003-07-07 13:28:54.000000000 +0200
@@ -89,8 +89,6 @@
#define SAA7146_USE_I2C_IRQ 0x1
int flags;
- struct saa7146_ext_vv *ext_vv_data;
-
/* pairs of subvendor and subdevice ids for
supported devices, last entry 0xffff, 0xfff */
struct module *module;
@@ -134,6 +132,7 @@
/* extension handling */
struct saa7146_extension *ext; /* indicates if handled by extension */
void *ext_priv; /* pointer for extension private use (most likely some private data) */
+ struct saa7146_ext_vv *ext_vv_data;
/* per device video/vbi informations (if available) */
struct saa7146_vv *vv_data;
diff -uNrwB --new-file linux-2.6.0-test1.work/include/media/saa7146_vv.h linux-2.6.0-test1.patch/include/media/saa7146_vv.h
--- linux-2.6.0-test1.work/include/media/saa7146_vv.h 2003-07-15 10:59:26.000000000 +0200
+++ linux-2.6.0-test1.patch/include/media/saa7146_vv.h 2003-07-07 13:28:55.000000000 +0200
@@ -39,13 +39,13 @@
char *name;
v4l2_std_id id;
- int v_offset;
- int v_field;
- int v_calc;
-
- int h_offset;
- int h_pixels;
- int h_calc;
+ int v_offset; /* number of lines of vertical offset before processing */
+ int v_field; /* number of lines in a field for HPS to process */
+ int v_calc; /* number of vertical active lines */
+
+ int h_offset; /* horizontal offset of processing window */
+ int h_pixels; /* number of horizontal pixels to process */
+ int h_calc; /* number of horizontal active pixels */
int v_max_out;
int h_max_out;
@@ -120,6 +120,7 @@
/* video capture */
struct saa7146_dmaqueue video_q;
struct saa7146_fh *streaming;
+ enum v4l2_field last_field;
/* common: fixme? shouldn't this be in saa7146_fh?
(this leads to a more complicated question: shall the driver
@@ -186,7 +187,7 @@
void saa7146_buffer_timeout(unsigned long data);
void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf);
-int saa7146_vv_init(struct saa7146_dev* dev);
+int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv);
int saa7146_vv_release(struct saa7146_dev* dev);
@@ -215,35 +216,6 @@
#define SAA7146_HPS_SYNC_PORT_A 0x00
#define SAA7146_HPS_SYNC_PORT_B 0x01
-/* number of vertical active lines */
-#define V_ACTIVE_LINES_PAL 576
-#define V_ACTIVE_LINES_NTSC 480
-#define V_ACTIVE_LINES_SECAM 576
-
-/* number of lines in a field for HPS to process */
-#define V_FIELD_PAL 288
-#define V_FIELD_NTSC 240
-#define V_FIELD_SECAM 288
-
-/* number of lines of vertical offset before processing */
-#define V_OFFSET_PAL 0x17
-#define V_OFFSET_NTSC 0x16
-#define V_OFFSET_SECAM 0x14
-
-/* number of horizontal pixels to process */
-#define H_PIXELS_PAL 680
-#define H_PIXELS_NTSC 708
-#define H_PIXELS_SECAM 720
-
-/* horizontal offset of processing window */
-#define H_OFFSET_PAL 0x14
-#define H_OFFSET_NTSC 0x06
-#define H_OFFSET_SECAM 0x14
-
-#define SAA7146_PAL_VALUES V_OFFSET_PAL, V_FIELD_PAL, V_ACTIVE_LINES_PAL, H_OFFSET_PAL, H_PIXELS_PAL, H_PIXELS_PAL+1, V_ACTIVE_LINES_PAL, 768
-#define SAA7146_NTSC_VALUES V_OFFSET_NTSC, V_FIELD_NTSC, V_ACTIVE_LINES_NTSC, H_OFFSET_NTSC, H_PIXELS_NTSC, H_PIXELS_NTSC+1, V_ACTIVE_LINES_NTSC, 640
-#define SAA7146_SECAM_VALUES V_OFFSET_SECAM, V_FIELD_SECAM, V_ACTIVE_LINES_SECAM, H_OFFSET_SECAM, H_PIXELS_SECAM, H_PIXELS_SECAM+1, V_ACTIVE_LINES_SECAM, 768
-
/* some memory sizes */
#define SAA7146_CLIPPING_MEM (14*PAGE_SIZE)
[DVB] - grundig_29504-401.c: fix charge pump and band switch setting bug, catched by Robert Schlabbach <[email protected]>
[DVB] - grundig_29504-401.c: pass apply_frontend_param() return value to upper layers
[DVB] - grundig_29504-401.c: try to make a more specific detection mechanism
[DVB] - grundig_29504-491.c:remove bogus out-of-range check, FEC table index is limited to 0...7 due to &= ~0x03 anyway...
[DVB] - nxt6000.c: Patch by Paul Andreassen: Add Support for Comtech DVBT-6k07 (PLL IC: SP5730)
[DVB] - ves1820.c: use Robert Schlabbach's suggestions for CLKCONF (0x03) and CARCONF (0x04)
[DVB] - 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);
[DVB] - In alps_tdlb7.c read SP8870 status reg to clear pending irqs in FE_SET_FRONTEND, as suggested by Ragnar Sundblad to avoid frontend hang-ups.
[DVB] - the vp310 support in mt312.c support should be configured to 90Mhz, too. skystar2 driver with bugfixed master_xfer() should probably work now.
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/frontends/alps_tdlb7.c linux-2.6.0-test1.patch/drivers/media/dvb/frontends/alps_tdlb7.c
--- linux-2.6.0-test1.work/drivers/media/dvb/frontends/alps_tdlb7.c 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/frontends/alps_tdlb7.c 2003-07-14 11:56:37.000000000 +0200
@@ -349,6 +349,9 @@
sp5659_set_tv_freq (i2c, p->frequency);
+ // read status reg in order to clear pending irqs
+ sp8870_readreg(i2c, 0x200);
+
// sample rate correction bit [23..17]
sp8870_writereg(i2c,0x0319,0x000A);
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/frontends/mt312.c linux-2.6.0-test1.patch/drivers/media/dvb/frontends/mt312.c
--- linux-2.6.0-test1.work/drivers/media/dvb/frontends/mt312.c 2003-07-15 10:59:46.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/frontends/mt312.c 2003-06-27 00:04:06.000000000 +0200
@@ -34,6 +34,7 @@
#define I2C_ADDR_MT312 0x0e
#define I2C_ADDR_SL1935 0x61
+#define I2C_ADDR_TSA5059 0x61
#define MT312_DEBUG 0
@@ -207,12 +208,32 @@
return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf));
}
+static int tsa5059_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr)
+{
+ u8 buf[4];
+
+ u32 ref = mt312_div(freq, 125);
+
+ buf[0] = (ref >> 8) & 0x7f;
+ buf[1] = (ref >> 0) & 0xff;
+ buf[2] = 0x84 | ((ref >> 10) & 0x60);
+ buf[3] = 0x80;
+
+ if (freq < 1550000)
+ buf[3] |= 0x02;
+
+ 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_TSA5059, 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)
+static int mt312_init(struct dvb_i2c_bus *i2c, const long id)
{
int ret;
u8 buf[2];
@@ -240,6 +261,9 @@
if ((ret = mt312_writereg(i2c, SNR_THS_HIGH, 0x32)) < 0)
return ret;
+ if ((ret = mt312_writereg(i2c, OP_CTRL, 0x53)) < 0)
+ return ret;
+
/* TS_SW_LIM */
buf[0] = 0x8c;
buf[1] = 0x98;
@@ -427,7 +451,8 @@
}
static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
- const struct dvb_frontend_parameters *p)
+ const struct dvb_frontend_parameters *p,
+ const long id)
{
int ret;
u8 buf[5];
@@ -437,6 +462,8 @@
{ 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
+ int (*set_tv_freq)(struct dvb_i2c_bus *i2c, u32 freq, u32 sr);
+
if ((p->frequency < mt312_info.frequency_min)
|| (p->frequency > mt312_info.frequency_max))
return -EINVAL;
@@ -457,8 +484,18 @@
|| (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)
+ switch (id) {
+ case ID_VP310:
+ set_tv_freq = tsa5059_set_tv_freq;
+ break;
+ case ID_MT312:
+ set_tv_freq = sl1935_set_tv_freq;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0)
return ret;
/* sr = (u16)(sr * 256.0 / 1000000.0) */
@@ -552,9 +589,7 @@
{
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
- };
+ FEC_AUTO, FEC_AUTO };
int ret;
u8 fec_status;
@@ -652,7 +687,7 @@
return mt312_read_ubc(i2c, arg);
case FE_SET_FRONTEND:
- return mt312_set_frontend(i2c, arg);
+ return mt312_set_frontend(i2c, arg, (long) fe->data);
case FE_GET_FRONTEND:
return mt312_get_frontend(i2c, arg);
@@ -664,7 +699,7 @@
return mt312_sleep(i2c);
case FE_INIT:
- return mt312_init(i2c);
+ return mt312_init(i2c, (long) fe->data);
case FE_RESET:
return mt312_reset(i2c, 0);
[V4L] - add drivers for the Orion and Gemini frame grabber cards, based on the saa7146. For details, see http://www.hexium.hu/. Thanks to Michael Hunold <[email protected]>.
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/Kconfig linux-2.6.0-test1.patch/drivers/media/video/Kconfig
--- linux-2.6.0-test1.work/drivers/media/video/Kconfig 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/video/Kconfig 2003-06-25 11:02:24.000000000 +0200
@@ -257,5 +257,30 @@
whenever you want). If you want to compile it as a module, say M
here and read <file:Documentation/modules.txt>.
+config VIDEO_HEXIUM_ORION
+ tristate "Hexium HV-PCI6 and Orion frame grabber"
+ depends on VIDEO_DEV && PCI
+ ---help---
+ This is a video4linux driver for the Hexium HV-PCI6 and
+ Orion frame grabber cards by Hexium.
+
+ This driver is available as a module called hexium_orion
+ ( = code which can be inserted in and removed from the
+ running kernel whenever you want). If you want to compile
+ it as a module, say M here and read <file:Documentation/modules.txt>.
+
+config VIDEO_HEXIUM_GEMINI
+ tristate "Hexium Gemini frame grabber"
+ depends on VIDEO_DEV && PCI
+ ---help---
+ This is a video4linux driver for the Hexium Gemini frame
+ grabber card by Hexium. Please note that the Gemini Dual
+ card is *not* fully supported.
+
+ This driver is available as a module called hexium_gemini
+ ( = code which can be inserted in and removed from the
+ running kernel whenever you want). If you want to compile
+ it as a module, say M here and read <file:Documentation/modules.txt>.
+
endmenu
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/Makefile linux-2.6.0-test1.patch/drivers/media/video/Makefile
--- linux-2.6.0-test1.work/drivers/media/video/Makefile 2003-07-15 09:42:37.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/video/Makefile 2003-05-20 09:37:41.000000000 +0200
@@ -31,6 +31,8 @@
obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
+obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
+obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/hexium.h linux-2.6.0-test1.patch/drivers/media/video/hexium.h
--- linux-2.6.0-test1.work/drivers/media/video/hexium.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/video/hexium.h 2003-07-15 10:00:55.000000000 +0200
@@ -0,0 +1,51 @@
+#ifndef __HEXIUM__
+#define __HEXIUM__
+
+#define HEXIUM_HV_PCI6_ORION 1
+#define HEXIUM_ORION_1SVHS_3BNC 2
+#define HEXIUM_ORION_4BNC 3
+#define HEXIUM_GEMUINI 4
+#define HEXIUM_GEMUINI_DUAL 5
+
+static struct saa7146_standard hexium_standards[] = {
+ {
+ .name = "PAL", .id = V4L2_STD_PAL,
+ .v_offset = 0x17, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }, {
+ .name = "NTSC", .id = V4L2_STD_NTSC,
+ .v_offset = 0x17, .v_field = 240, .v_calc = 480,
+ .h_offset = 0x06, .h_pixels = 640, .h_calc = 641+1,
+ .v_max_out = 480, .h_max_out = 640,
+ }, {
+ .name = "SECAM", .id = V4L2_STD_SECAM,
+ .v_offset = 0x14, .v_field = 288, .v_calc = 576,
+ .h_offset = 0x14, .h_pixels = 720, .h_calc = 720+1,
+ .v_max_out = 576, .h_max_out = 768,
+ }
+};
+
+
+#define HEXIUM_INPUTS 9
+static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+};
+
+#define HEXIUM_AUDIOS 0
+
+struct hexium_data
+{
+ s8 adr;
+ u8 byte;
+};
+
+#endif
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/hexium_gemini.c linux-2.6.0-test1.patch/drivers/media/video/hexium_gemini.c
--- linux-2.6.0-test1.work/drivers/media/video/hexium_gemini.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/video/hexium_gemini.c 2003-07-15 10:05:56.000000000 +0200
@@ -0,0 +1,411 @@
+/*
+ hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
+
+ Visit http://www.mihu.de/linux/saa7146/ and follow the link
+ to "hexium" for further details about this card.
+
+ Copyright (C) 2003 Michael Hunold <[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.
+*/
+
+#define DEBUG_VARIABLE debug
+
+#include <media/saa7146_vv.h>
+
+static int debug = 255;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "debug verbosity");
+
+/* global variables */
+int hexium_num = 0;
+
+#include "hexium_gemini.h"
+
+/* bring hardware to a sane state. this has to be done, just in case someone
+ wants to capture from this device before it has been properly initialized.
+ the capture engine would badly fail, because no valid signal arrives on the
+ saa7146, thus leading to timeouts and stuff. */
+static int hexium_init_done(struct saa7146_dev *dev)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+ union i2c_smbus_data data;
+ int i = 0;
+
+ DEB_D(("hexium_init_done called.\n"));
+
+ /* initialize the helper ics to useful values */
+ for (i = 0; i < sizeof(hexium_ks0127b); i++) {
+ data.byte = hexium_ks0127b[i];
+ if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
+ printk("failed for address 0x%02x\n", i);
+ }
+ }
+
+ return 0;
+}
+
+static int hexium_set_input(struct hexium *hexium, int input)
+{
+ union i2c_smbus_data data;
+
+ DEB_D((".\n"));
+
+ data.byte = hexium_input_select[input].byte;
+ if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
+{
+ union i2c_smbus_data data;
+ int i = 0;
+
+ DEB_D((".\n"));
+
+ while (vdec[i].adr != -1) {
+ data.byte = vdec[i].byte;
+ if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
+ printk("failed for address 0x%02x\n", i);
+ return -1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static struct saa7146_ext_vv vv_data;
+
+/* this function only gets called when the probing was successful */
+static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+ DEB_EE((".\n"));
+
+ hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL);
+ if (NULL == hexium) {
+ printk("hexium_v4l2.o: hexium_probe: not enough kernel memory.\n");
+ return -ENOMEM;
+ }
+ memset(hexium, 0x0, sizeof(struct hexium));
+ (struct hexium *) dev->ext_priv = hexium;
+
+ /* FIXME: enable i2c-port pins, video-port-pins
+ video port pins should be enabled here ?! */
+ saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
+
+ saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+ if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
+ DEB_S(("cannot register i2c-device. skipping.\n"));
+ kfree(hexium);
+ return -EFAULT;
+ }
+
+ /* set HWControl GPIO number 2 */
+ saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+
+ saa7146_write(dev, DD1_INIT, 0x07000700);
+ saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+ saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+ /* the rest */
+ hexium->cur_input = 0;
+ hexium_init_done(dev);
+
+ hexium_set_standard(hexium, hexium_pal);
+ hexium->cur_std = V4L2_STD_PAL;
+
+ hexium_set_input(hexium, 0);
+ hexium->cur_input = 0;
+
+ saa7146_vv_init(dev, &vv_data);
+ if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium", VFL_TYPE_GRABBER)) {
+ ERR(("cannot register capture v4l2 device. skipping.\n"));
+ return -1;
+ }
+
+ printk("hexium: found 'hexium frame grabber'-%d.\n", hexium_num);
+ hexium_num++;
+
+ return 0;
+}
+
+static int hexium_detach(struct saa7146_dev *dev)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+ DEB_EE(("dev:%p\n", dev));
+
+ saa7146_unregister_device(&hexium->video_dev, dev);
+ saa7146_vv_release(dev);
+
+ hexium_num--;
+
+ i2c_del_adapter(&hexium->i2c_adapter);
+ kfree(hexium);
+ return 0;
+}
+
+static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+/*
+ struct saa7146_vv *vv = dev->vv_data;
+*/
+ switch (cmd) {
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+ DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+
+ if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
+ return -EINVAL;
+ }
+
+ memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+
+ DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+ return 0;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ int *input = (int *) arg;
+ *input = hexium->cur_input;
+
+ DEB_D(("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 (input < 0 || input >= HEXIUM_INPUTS) {
+ return -EINVAL;
+ }
+
+ hexium->cur_input = input;
+ hexium_set_input(hexium, input);
+
+ return 0;
+ }
+ /* the saa7146 provides some controls (brightness, contrast, saturation)
+ which gets registered *after* this function. because of this we have
+ to return with a value != 0 even if the function succeded.. */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+ if (hexium_controls[i].id == qc->id) {
+ *qc = hexium_controls[i];
+ DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+ return 0;
+ }
+ }
+ return -EAGAIN;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *vc = arg;
+ int i;
+
+ for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+ if (hexium_controls[i].id == vc->id) {
+ break;
+ }
+ }
+
+ if (i < 0) {
+ return -EAGAIN;
+ }
+
+ switch (vc->id) {
+ case V4L2_CID_PRIVATE_BASE:{
+ vc->value = hexium->cur_bw;
+ DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
+ return 0;
+ }
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *vc = arg;
+ int i = 0;
+
+ for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+ if (hexium_controls[i].id == vc->id) {
+ break;
+ }
+ }
+
+ if (i < 0) {
+ return -EAGAIN;
+ }
+
+ switch (vc->id) {
+ case V4L2_CID_PRIVATE_BASE:{
+ hexium->cur_bw = vc->value;
+ break;
+ }
+ }
+
+ DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
+
+ if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
+ hexium_set_standard(hexium, hexium_pal);
+ return 0;
+ }
+ if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
+ hexium_set_standard(hexium, hexium_ntsc);
+ return 0;
+ }
+ if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
+ hexium_set_standard(hexium, hexium_secam);
+ return 0;
+ }
+ if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
+ hexium_set_standard(hexium, hexium_pal_bw);
+ return 0;
+ }
+ if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
+ hexium_set_standard(hexium, hexium_ntsc_bw);
+ return 0;
+ }
+ if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
+ /* fixme: is there no bw secam mode? */
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+ }
+ default:
+/*
+ DEB_D(("v4l2_ioctl does not handle this ioctl.\n"));
+*/
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+ if (V4L2_STD_PAL == std->id) {
+ hexium_set_standard(hexium, hexium_pal);
+ hexium->cur_std = V4L2_STD_PAL;
+ return 0;
+ } else if (V4L2_STD_NTSC == std->id) {
+ hexium_set_standard(hexium, hexium_ntsc);
+ hexium->cur_std = V4L2_STD_NTSC;
+ return 0;
+ } else if (V4L2_STD_SECAM == std->id) {
+ hexium_set_standard(hexium, hexium_secam);
+ hexium->cur_std = V4L2_STD_SECAM;
+ return 0;
+ }
+
+ return -1;
+}
+
+static struct saa7146_extension hexium_extension;
+
+static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
+ .ext_priv = "Hexium Gemini (4 BNC)",
+ .ext = &hexium_extension,
+};
+
+static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
+ .ext_priv = "Hexium Gemini Dual (4 BNC)",
+ .ext = &hexium_extension,
+};
+
+static struct pci_device_id pci_tbl[] = {
+ {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+ .subvendor = 0x17c8,
+ .subdevice = 0x2401,
+ .driver_data = (unsigned long) &hexium_gemini_4bnc,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+ .subvendor = 0x17c8,
+ .subdevice = 0x2402,
+ .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
+ },
+ {
+ .vendor = 0,
+ }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_ext_vv vv_data = {
+ .inputs = HEXIUM_INPUTS,
+ .capabilities = 0,
+ .stds = &hexium_standards[0],
+ .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
+ .std_callback = &std_callback,
+ .ioctls = &ioctls[0],
+ .ioctl = hexium_ioctl,
+};
+
+static struct saa7146_extension hexium_extension = {
+ .name = "hexium gemini",
+ .flags = SAA7146_USE_I2C_IRQ,
+
+ .pci_tbl = &pci_tbl[0],
+ .module = THIS_MODULE,
+
+ .attach = hexium_attach,
+ .detach = hexium_detach,
+
+ .irq_mask = 0,
+ .irq_func = NULL,
+};
+
+int __init hexium_init_module(void)
+{
+ if (0 != saa7146_register_extension(&hexium_extension)) {
+ DEB_S(("failed to register extension.\n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void __exit hexium_cleanup_module(void)
+{
+ saa7146_unregister_extension(&hexium_extension);
+}
+
+module_init(hexium_init_module);
+module_exit(hexium_cleanup_module);
+
+MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
+MODULE_AUTHOR("Michael Hunold <[email protected]>");
+MODULE_LICENSE("GPL");
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/hexium_gemini.h linux-2.6.0-test1.patch/drivers/media/video/hexium_gemini.h
--- linux-2.6.0-test1.work/drivers/media/video/hexium_gemini.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/video/hexium_gemini.h 2003-07-15 10:06:36.000000000 +0200
@@ -0,0 +1,103 @@
+#ifndef __HEXIUM_GEMINI__
+#define __HEXIUM_GEMINI__
+
+#include "hexium.h"
+
+static struct saa7146_extension_ioctls ioctls[] = {
+ { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
+ { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_S_STD, SAA7146_AFTER },
+ { VIDIOC_G_CTRL, SAA7146_BEFORE },
+ { VIDIOC_S_CTRL, SAA7146_BEFORE },
+ { 0, 0 }
+};
+
+#define HEXIUM_CONTROLS 1
+static struct v4l2_queryctrl hexium_controls[] = {
+ { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
+};
+
+#define HEXIUM_GEMUINI_V_1_0 1
+#define HEXIUM_GEMUINI_DUAL_V_1_0 2
+
+struct hexium
+{
+ int type;
+ struct video_device video_dev;
+ struct i2c_adapter i2c_adapter;
+
+ int cur_input; /* current input */
+ v4l2_std_id cur_std; /* current standard */
+ int cur_bw; /* current black/white status */
+};
+
+/* Samsung KS0127B decoder default registers */
+static u8 hexium_ks0127b[0x100]={
+/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
+/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
+/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
+/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
+/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
+/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
+/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
+/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static struct hexium_data hexium_pal[] = {
+ { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_pal_bw[] = {
+ { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_ntsc[] = {
+ { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_ntsc_bw[] = {
+ { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_secam[] = {
+ { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
+};
+
+static struct hexium_data hexium_input_select[] = {
+ { 0x02, 0x60 },
+ { 0x02, 0x64 },
+ { 0x02, 0x61 },
+ { 0x02, 0x65 },
+ { 0x02, 0x62 },
+ { 0x02, 0x66 },
+ { 0x02, 0x68 },
+ { 0x02, 0x69 },
+ { 0x02, 0x6A },
+};
+#endif
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/hexium_orion.c linux-2.6.0-test1.patch/drivers/media/video/hexium_orion.c
--- linux-2.6.0-test1.work/drivers/media/video/hexium_orion.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/video/hexium_orion.c 2003-07-15 10:05:42.000000000 +0200
@@ -0,0 +1,328 @@
+/*
+ hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards
+
+ Visit http://www.mihu.de/linux/saa7146/ and follow the link
+ to "hexium" for further details about this card.
+
+ Copyright (C) 2003 Michael Hunold <[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.
+*/
+
+#define DEBUG_VARIABLE debug
+
+#include <media/saa7146_vv.h>
+
+static int debug = 255;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "debug verbosity");
+
+/* global variables */
+int hexium_num = 0;
+
+#include "hexium_orion.h"
+
+/* this is only called for old HV-PCI6/Orion cards
+ without eeprom */
+static int hexium_probe(struct saa7146_dev *dev)
+{
+ struct hexium *hexium = 0;
+ union i2c_smbus_data data;
+ int err = 0;
+
+ DEB_EE((".\n"));
+
+ /* there are no hexium orion cards with revision 0 saa7146s */
+ if (0 == dev->revision) {
+ return -EFAULT;
+ }
+
+ hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL);
+ if (NULL == hexium) {
+ printk("hexium_orion.o: hexium_probe: not enough kernel memory.\n");
+ return -ENOMEM;
+ }
+ memset(hexium, 0x0, sizeof(struct hexium));
+
+ /* FIXME: enable i2c-port pins, video-port-pins
+ video port pins should be enabled here ?! */
+ saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
+
+ saa7146_write(dev, DD1_INIT, 0x02000200);
+ saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+ saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+ saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+ if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
+ DEB_S(("cannot register i2c-device. skipping.\n"));
+ kfree(hexium);
+ return -EFAULT;
+ }
+
+ /* set SAA7110 control GPIO 0 */
+ saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
+ /* set HWControl GPIO number 2 */
+ saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+
+ mdelay(10);
+
+ /* detect newer Hexium Orion cards by subsystem ids */
+ if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
+ printk("hexium_orion.o: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");
+ /* we store the pointer in our private data field */
+ (struct hexium *) dev->ext_priv = hexium;
+ hexium->type = HEXIUM_ORION_1SVHS_3BNC;
+ return 0;
+ }
+
+ if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
+ printk("hexium_orion.o: device is a Hexium Orion w/ 4 BNC inputs.\n");
+ /* we store the pointer in our private data field */
+ (struct hexium *) dev->ext_priv = hexium;
+ hexium->type = HEXIUM_ORION_4BNC;
+ return 0;
+ }
+
+ /* check if this is an old hexium Orion card by looking at
+ a saa7110 at address 0x4e */
+ if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
+ printk("hexium_orion.o: device is a Hexium HV-PCI6/Orion (old).\n");
+ /* we store the pointer in our private data field */
+ (struct hexium *) dev->ext_priv = hexium;
+ hexium->type = HEXIUM_HV_PCI6_ORION;
+ return 0;
+ }
+
+ i2c_del_adapter(&hexium->i2c_adapter);
+ kfree(hexium);
+ return -EFAULT;
+}
+
+/* bring hardware to a sane state. this has to be done, just in case someone
+ wants to capture from this device before it has been properly initialized.
+ the capture engine would badly fail, because no valid signal arrives on the
+ saa7146, thus leading to timeouts and stuff. */
+static int hexium_init_done(struct saa7146_dev *dev)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+ union i2c_smbus_data data;
+ int i = 0;
+
+ DEB_D(("hexium_init_done called.\n"));
+
+ /* initialize the helper ics to useful values */
+ for (i = 0; i < sizeof(hexium_saa7110); i++) {
+ data.byte = hexium_saa7110[i];
+ if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
+ printk("hexium_orion: failed for address 0x%02x\n", i);
+ }
+ }
+
+ return 0;
+}
+
+static struct saa7146_ext_vv vv_data;
+
+/* this function only gets called when the probing was successful */
+static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+ DEB_EE((".\n"));
+
+ saa7146_vv_init(dev, &vv_data);
+ if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium", VFL_TYPE_GRABBER)) {
+ ERR(("cannot register capture v4l2 device. skipping.\n"));
+ return -1;
+ }
+
+ printk("hexium_orion.o: found 'hexium orion' frame grabber-%d.\n", hexium_num);
+ hexium_num++;
+
+ /* the rest */
+ hexium->cur_input = 0;
+ hexium_init_done(dev);
+
+ return 0;
+}
+
+static int hexium_detach(struct saa7146_dev *dev)
+{
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+
+ DEB_EE(("dev:%p\n", dev));
+
+ saa7146_unregister_device(&hexium->video_dev, dev);
+ saa7146_vv_release(dev);
+
+ hexium_num--;
+
+ i2c_del_adapter(&hexium->i2c_adapter);
+ kfree(hexium);
+ return 0;
+}
+
+static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+/*
+ struct saa7146_vv *vv = dev->vv_data;
+*/
+ switch (cmd) {
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+ DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+
+ if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
+ return -EINVAL;
+ }
+
+ memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+
+ DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+ return 0;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ int *input = (int *) arg;
+ *input = hexium->cur_input;
+
+ DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int input = *(int *) arg;
+
+ if (input < 0 || input >= HEXIUM_INPUTS) {
+ return -EINVAL;
+ }
+
+ hexium->cur_input = input;
+
+ /* fixme: switch input here, switch audio, too! */
+// saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
+ printk("hexium_orion.o: VIDIOC_S_INPUT: fixme switch input.\n");
+
+ return 0;
+ }
+ default:
+/*
+ DEB_D(("v4l2_ioctl does not handle this ioctl.\n"));
+*/
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
+{
+ return 0;
+}
+
+static struct saa7146_extension extension;
+
+static struct saa7146_pci_extension_data hexium_hv_pci6 = {
+ .ext_priv = "Hexium HV-PCI6 / Orion",
+ .ext = &extension,
+};
+
+static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
+ .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
+ .ext = &extension,
+};
+
+static struct saa7146_pci_extension_data hexium_orion_4bnc = {
+ .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
+ .ext = &extension,
+};
+
+static struct pci_device_id pci_tbl[] = {
+ {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+ .subvendor = 0x0000,
+ .subdevice = 0x0000,
+ .driver_data = (unsigned long) &hexium_hv_pci6,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+ .subvendor = 0x17c8,
+ .subdevice = 0x0101,
+ .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
+ .subvendor = 0x17c8,
+ .subdevice = 0x2101,
+ .driver_data = (unsigned long) &hexium_orion_4bnc,
+ },
+ {
+ .vendor = 0,
+ }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_ext_vv vv_data = {
+ .inputs = HEXIUM_INPUTS,
+ .capabilities = 0,
+ .stds = &hexium_standards[0],
+ .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
+ .std_callback = &std_callback,
+ .ioctls = &ioctls[0],
+ .ioctl = hexium_ioctl,
+};
+
+static struct saa7146_extension extension = {
+ .name = "hexium HV-PCI6/Orion",
+ .flags = 0, // SAA7146_USE_I2C_IRQ,
+
+ .pci_tbl = &pci_tbl[0],
+ .module = THIS_MODULE,
+
+ .probe = hexium_probe,
+ .attach = hexium_attach,
+ .detach = hexium_detach,
+
+ .irq_mask = 0,
+ .irq_func = NULL,
+};
+
+int __init hexium_init_module(void)
+{
+ if (0 != saa7146_register_extension(&extension)) {
+ DEB_S(("failed to register extension.\n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void __exit hexium_cleanup_module(void)
+{
+ saa7146_unregister_extension(&extension);
+}
+
+module_init(hexium_init_module);
+module_exit(hexium_cleanup_module);
+
+MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
+MODULE_AUTHOR("Michael Hunold <[email protected]>");
+MODULE_LICENSE("GPL");
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/video/hexium_orion.h linux-2.6.0-test1.patch/drivers/media/video/hexium_orion.h
--- linux-2.6.0-test1.work/drivers/media/video/hexium_orion.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/video/hexium_orion.h 2003-07-15 10:01:57.000000000 +0200
@@ -0,0 +1,138 @@
+#ifndef __HEXIUM_ORION__
+#define __HEXIUM_ORION__
+
+#include "hexium.h"
+
+static struct saa7146_extension_ioctls ioctls[] = {
+ { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
+ { VIDIOC_S_STD, SAA7146_AFTER },
+ { 0, 0 }
+};
+
+struct hexium
+{
+ int type;
+ struct video_device video_dev;
+ struct i2c_adapter i2c_adapter;
+ int cur_input; /* current input */
+};
+
+/* Philips SAA7110 decoder default registers */
+static u8 hexium_saa7110[53]={
+/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
+/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
+/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
+/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
+/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
+/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
+/*30*/ 0x44,0x75,0x01,0x8C,0x03
+};
+
+static struct {
+ struct hexium_data data[8];
+} hexium_input_select[] = {
+{
+ { /* input 0 */
+ { 0x06, 0x00 },
+ { 0x20, 0xD9 },
+ { 0x21, 0x17 }, // 0x16,
+ { 0x22, 0x40 },
+ { 0x2C, 0x03 },
+ { 0x30, 0x44 },
+ { 0x31, 0x75 }, // ??
+ { 0x21, 0x16 }, // 0x03,
+ }
+}, {
+ { /* input 1 */
+ { 0x06, 0x00 },
+ { 0x20, 0xD8 },
+ { 0x21, 0x17 }, // 0x16,
+ { 0x22, 0x40 },
+ { 0x2C, 0x03 },
+ { 0x30, 0x44 },
+ { 0x31, 0x75 }, // ??
+ { 0x21, 0x16 }, // 0x03,
+ }
+}, {
+ { /* input 2 */
+ { 0x06, 0x00 },
+ { 0x20, 0xBA },
+ { 0x21, 0x07 }, // 0x05,
+ { 0x22, 0x91 },
+ { 0x2C, 0x03 },
+ { 0x30, 0x60 },
+ { 0x31, 0xB5 }, // ??
+ { 0x21, 0x05 }, // 0x03,
+ }
+}, {
+ { /* input 3 */
+ { 0x06, 0x00 },
+ { 0x20, 0xB8 },
+ { 0x21, 0x07 }, // 0x05,
+ { 0x22, 0x91 },
+ { 0x2C, 0x03 },
+ { 0x30, 0x60 },
+ { 0x31, 0xB5 }, // ??
+ { 0x21, 0x05 }, // 0x03,
+ }
+}, {
+ { /* input 4 */
+ { 0x06, 0x00 },
+ { 0x20, 0x7C },
+ { 0x21, 0x07 }, // 0x03
+ { 0x22, 0xD2 },
+ { 0x2C, 0x83 },
+ { 0x30, 0x60 },
+ { 0x31, 0xB5 }, // ??
+ { 0x21, 0x03 },
+ }
+}, {
+ { /* input 5 */
+ { 0x06, 0x00 },
+ { 0x20, 0x78 },
+ { 0x21, 0x07 }, // 0x03,
+ { 0x22, 0xD2 },
+ { 0x2C, 0x83 },
+ { 0x30, 0x60 },
+ { 0x31, 0xB5 }, // ?
+ { 0x21, 0x03 },
+ }
+}, {
+ { /* input 6 */
+ { 0x06, 0x80 },
+ { 0x20, 0x59 },
+ { 0x21, 0x17 },
+ { 0x22, 0x42 },
+ { 0x2C, 0xA3 },
+ { 0x30, 0x44 },
+ { 0x31, 0x75 },
+ { 0x21, 0x12 },
+ }
+}, {
+ { /* input 7 */
+ { 0x06, 0x80 },
+ { 0x20, 0x9A },
+ { 0x21, 0x17 },
+ { 0x22, 0xB1 },
+ { 0x2C, 0x13 },
+ { 0x30, 0x60 },
+ { 0x31, 0xB5 },
+ { 0x21, 0x14 },
+ }
+}, {
+ { /* input 8 */
+ { 0x06, 0x80 },
+ { 0x20, 0x3C },
+ { 0x21, 0x27 },
+ { 0x22, 0xC1 },
+ { 0x2C, 0x23 },
+ { 0x30, 0x44 },
+ { 0x31, 0x75 },
+ { 0x21, 0x21 },
+ }
+}
+};
+
+#endif
[DVB] - add DVB driver for Technisat Skystar2 card, which is based on
the FlexCop2 chipset by B2C2
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/b2c2/Kconfig linux-2.6.0-test1.patch/drivers/media/dvb/b2c2/Kconfig
--- linux-2.6.0-test1.work/drivers/media/dvb/b2c2/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/b2c2/Kconfig 2003-07-15 09:47:16.000000000 +0200
@@ -0,0 +1,8 @@
+config DVB_B2C2_SKYSTAR
+ tristate "Technisat Skystar2 PCI"
+ depends on DVB_CORE
+ help
+ Support for the Skystar2 PCI DVB card by Technisat, which
+ is equipped with the FlexCopII chipset by B2C2.
+
+ Say Y if you own such a device and want to use it.
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/b2c2/Makefile linux-2.6.0-test1.patch/drivers/media/dvb/b2c2/Makefile
--- linux-2.6.0-test1.work/drivers/media/dvb/b2c2/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/b2c2/Makefile 2003-07-15 09:45:20.000000000 +0200
@@ -0,0 +1,3 @@
+obj-$(DVB_B2C2_SKYSTAR) += skystar.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/b2c2/skystar2.c linux-2.6.0-test1.patch/drivers/media/dvb/b2c2/skystar2.c
--- linux-2.6.0-test1.work/drivers/media/dvb/b2c2/skystar2.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/b2c2/skystar2.c 2003-07-14 12:07:03.000000000 +0200
@@ -0,0 +1,2548 @@
+/*
+ * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card
+ * based on the FlexCopII by B2C2,Inc.
+ *
+ * Copyright (C) 2003 V.C. , [email protected]
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "dvb_i2c.h"
+#include "dvb_frontend.h"
+#include "dvb_functions.h"
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_filter.h"
+#include "dvbdev.h"
+#include "demux.h"
+#include "dvb_net.h"
+
+int debug = 0;
+#define dprintk if(debug != 0) printk
+
+#define SizeOfBufDMA1 0x3AC00
+#define SizeOfBufDMA2 0x758
+
+struct DmaQ {
+
+ u32 bus_addr;
+ u32 head;
+ u32 tail;
+ u32 buffer_size;
+ u8 *buffer;
+};
+
+struct packet_header_t {
+
+ u32 sync_byte;
+ u32 transport_error_indicator;
+ u32 payload_unit_start_indicator;
+ u32 transport_priority;
+ u32 pid;
+ u32 transport_scrambling_control;
+ u32 adaptation_field_control;
+ u32 continuity_counter;
+};
+
+struct adapter {
+
+ struct pci_dev *pdev;
+
+ u8 card_revision;
+ u32 B2C2_revision;
+ u32 PidFilterMax;
+ u32 MacFilterMax;
+ u32 irq;
+ u32 io_mem;
+ u32 io_port;
+ u8 mac_addr[8];
+ u32 dwSramType;
+
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dvb_i2c_bus *i2c_bus;
+ struct dvb_net dvbnet;
+
+ struct semaphore i2c_sem;
+
+ struct DmaQ DmaQ1;
+ struct DmaQ DmaQ2;
+
+ u32 dma_ctrl;
+ u32 dma_status;
+
+ u32 capturing;
+
+ spinlock_t lock;
+
+ u16 pids[0x27];
+ u32 mac_filter;
+};
+
+
+void linuxdelayms(u32 usecs)
+{
+ while (usecs > 0) {
+ udelay(1000);
+
+ usecs--;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// register functions
+/////////////////////////////////////////////////////////////////////
+
+void WriteRegDW(struct adapter *adapter, u32 reg, u32 value)
+{
+ u32 flags;
+
+ save_flags(flags);
+ cli();
+
+ writel(value, adapter->io_mem + reg);
+
+ restore_flags(flags);
+}
+
+u32 ReadRegDW(struct adapter *adapter, u32 reg)
+{
+ return readl(adapter->io_mem + reg);
+}
+
+u32 WriteRegOp(struct adapter * adapter, u32 reg, u32 operation, u32 andvalue, u32 orvalue)
+{
+ u32 tmp;
+
+ tmp = ReadRegDW(adapter, reg);
+
+ if (operation == 1)
+ tmp = tmp | orvalue;
+ if (operation == 2)
+ tmp = tmp & andvalue;
+ if (operation == 3)
+ tmp = (tmp & andvalue) | orvalue;
+
+ WriteRegDW(adapter, reg, tmp);
+
+ return tmp;
+}
+
+/////////////////////////////////////////////////////////////////////
+// I2C
+////////////////////////////////////////////////////////////////////
+
+u32 i2cMainWriteForFlex2(struct adapter * adapter, u32 command, u8 * buf, u32 retries)
+{
+ u32 i;
+ u32 value;
+
+ WriteRegDW(adapter, 0x100, 0);
+ WriteRegDW(adapter, 0x100, command);
+
+ for (i = 0; i < retries; i++) {
+ value = ReadRegDW(adapter, 0x100);
+
+ if ((value & 0x40000000) == 0) {
+ if ((value & 0x81000000) == 0x80000000) {
+ if (buf != 0)
+ *buf = (value >> 0x10) & 0xff;
+
+ return 1;
+ }
+
+ } else {
+
+ WriteRegDW(adapter, 0x100, 0);
+ WriteRegDW(adapter, 0x100, command);
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// device = 0x10000000 for tuner
+// 0x20000000 for eeprom
+/////////////////////////////////////////////////////////////////////
+
+u32 i2cMainSetup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len)
+{
+ u32 command;
+
+ command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr;
+
+ if (op != 0)
+ command = command | 0x03000000;
+ else
+ command = command | 0x01000000;
+
+ return command;
+}
+
+u32 FlexI2cRead4(struct adapter * adapter, u32 device, u32 chip_addr, u16 addr, u8 * buf, u8 len)
+{
+ u32 command;
+ u32 value;
+
+ int result, i;
+
+ command = i2cMainSetup(device, chip_addr, 1, addr, 0, len);
+
+ result = i2cMainWriteForFlex2(adapter, command, buf, 100000);
+
+ if ((result & 0xff) != 0) {
+ if (len > 1) {
+ value = ReadRegDW(adapter, 0x104);
+
+ for (i = 1; i < len; i++) {
+ buf[i] = value & 0xff;
+ value = value >> 8;
+ }
+ }
+ }
+
+ return result;
+}
+
+u32 FlexI2cWrite4(struct adapter * adapter, u32 device, u32 chip_addr, u32 addr, u8 * buf, u8 len)
+{
+ u32 command;
+ u32 value;
+ int i;
+
+ if (len > 1) {
+ value = 0;
+
+ for (i = len; i > 1; i--) {
+ value = value << 8;
+ value = value | buf[i - 1];
+ }
+
+ WriteRegDW(adapter, 0x104, value);
+ }
+
+ command = i2cMainSetup(device, chip_addr, 0, addr, buf[0], len);
+
+ return i2cMainWriteForFlex2(adapter, command, 0, 100000);
+}
+
+u32 fixChipAddr(u32 device, u32 bus, u32 addr)
+{
+ if (device == 0x20000000)
+ return bus | ((addr >> 8) & 3);
+
+ return bus;
+}
+
+u32 FLEXI2C_read(struct adapter * adapter, u32 device, u32 bus, u32 addr, u8 * buf, u32 len)
+{
+ u32 ChipAddr;
+ u32 bytes_to_transfer;
+ u8 *start;
+
+// dprintk("%s:\n", __FUNCTION__);
+
+ start = buf;
+
+ while (len != 0) {
+ bytes_to_transfer = len;
+
+ if (bytes_to_transfer > 4)
+ bytes_to_transfer = 4;
+
+ ChipAddr = fixChipAddr(device, bus, addr);
+
+ if (FlexI2cRead4(adapter, device, ChipAddr, addr, buf, bytes_to_transfer) == 0)
+ return buf - start;
+
+ buf = buf + bytes_to_transfer;
+ addr = addr + bytes_to_transfer;
+ len = len - bytes_to_transfer;
+ };
+
+ return buf - start;
+}
+
+u32 FLEXI2C_write(struct adapter * adapter, u32 device, u32 bus, u32 addr, u8 * buf, u32 len)
+{
+ u32 ChipAddr;
+ u32 bytes_to_transfer;
+ u8 *start;
+
+// dprintk("%s:\n", __FUNCTION__);
+
+ start = buf;
+
+ while (len != 0) {
+ bytes_to_transfer = len;
+
+ if (bytes_to_transfer > 4)
+ bytes_to_transfer = 4;
+
+ ChipAddr = fixChipAddr(device, bus, addr);
+
+ if (FlexI2cWrite4(adapter, device, ChipAddr, addr, buf, bytes_to_transfer) == 0)
+ return buf - start;
+
+ buf = buf + bytes_to_transfer;
+ addr = addr + bytes_to_transfer;
+ len = len - bytes_to_transfer;
+ }
+
+ return buf - start;
+}
+
+static int master_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg *msgs, int num)
+{
+ struct adapter *tmp = i2c->data;
+ int i, ret = 0;
+
+ if (down_interruptible(&tmp->i2c_sem))
+ return -ERESTARTSYS;
+
+ if (0) {
+ dprintk("%s:\n", __FUNCTION__);
+
+ for (i = 0; i < num; i++) {
+ printk("message %d: flags=%x, addr=0x%04x, buf=%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, (u32) msgs[i].buf, msgs[i].len);
+ }
+ }
+ // allow only the vp310 frontend to access the bus
+ if ((msgs[0].addr != 0x0E) && (msgs[0].addr != 0x61)) {
+ up(&tmp->i2c_sem);
+
+ return -EREMOTEIO;
+ }
+
+ if ((num == 1) && (msgs[0].buf != NULL)) {
+ if (msgs[0].flags == I2C_M_RD) {
+ ret = -EINVAL;
+
+ } else {
+
+ // single writes do have the reg addr in buf[0] and data in buf[1] to buf[n]
+ ret = FLEXI2C_write(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], &msgs[0].buf[1], msgs[0].len - 1);
+
+ if (ret != msgs[0].len - 1)
+ ret = -EREMOTEIO;
+ else
+ ret = num;
+ }
+
+ } else if ((num == 2) && (msgs[1].buf != NULL)) {
+
+ // i2c reads consist of a reg addr _write_ followed by a data read, so msg[1].flags has to be examined
+ if (msgs[1].flags == I2C_M_RD) {
+ ret = FLEXI2C_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
+
+ } else {
+
+ ret = FLEXI2C_write(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
+ }
+
+ if (ret != msgs[1].len)
+ ret = -EREMOTEIO;
+ else
+ ret = num;
+ }
+
+ up(&tmp->i2c_sem);
+
+ // master xfer functions always return the number of successfully
+ // transmitted messages, not the number of transmitted bytes.
+ // return -EREMOTEIO in case of failure.
+ return ret;
+}
+
+/////////////////////////////////////////////////////////////////////
+// SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board,
+// but it seems that FlexCopII can work with more than one chip)
+/////////////////////////////////////////////////////////////////////
+
+u32 SRAMSetNetDest(struct adapter * adapter, u8 dest)
+{
+ u32 tmp;
+
+ udelay(1000);
+
+ tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFFFC) | (dest & 3);
+
+ udelay(1000);
+
+ WriteRegDW(adapter, 0x714, tmp);
+ WriteRegDW(adapter, 0x714, tmp);
+
+ udelay(1000);
+
+ return tmp;
+}
+
+u32 SRAMSetCaiDest(struct adapter * adapter, u8 dest)
+{
+ u32 tmp;
+
+ udelay(1000);
+
+ tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFFF3) | ((dest & 3) << 2);
+
+ udelay(1000);
+ udelay(1000);
+
+ WriteRegDW(adapter, 0x714, tmp);
+ WriteRegDW(adapter, 0x714, tmp);
+
+ udelay(1000);
+
+ return tmp;
+}
+
+u32 SRAMSetCaoDest(struct adapter * adapter, u8 dest)
+{
+ u32 tmp;
+
+ udelay(1000);
+
+ tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFFCF) | ((dest & 3) << 4);
+
+ udelay(1000);
+ udelay(1000);
+
+ WriteRegDW(adapter, 0x714, tmp);
+ WriteRegDW(adapter, 0x714, tmp);
+
+ udelay(1000);
+
+ return tmp;
+}
+
+u32 SRAMSetMediaDest(struct adapter * adapter, u8 dest)
+{
+ u32 tmp;
+
+ udelay(1000);
+
+ tmp = (ReadRegDW(adapter, 0x714) & 0xFFFFFF3F) | ((dest & 3) << 6);
+
+ udelay(1000);
+ udelay(1000);
+
+ WriteRegDW(adapter, 0x714, tmp);
+ WriteRegDW(adapter, 0x714, tmp);
+
+ udelay(1000);
+
+ return tmp;
+}
+
+/////////////////////////////////////////////////////////////////////
+// SRAM memory is accessed through a buffer register in the FlexCop
+// chip (0x700). This register has the following structure:
+// bits 0-14 : address
+// bit 15 : read/write flag
+// bits 16-23 : 8-bit word to write
+// bits 24-27 : = 4
+// bits 28-29 : memory bank selector
+// bit 31 : busy flag
+////////////////////////////////////////////////////////////////////
+
+void FlexSramWrite(struct adapter *adapter, u32 bank, u32 addr, u8 * buf, u32 len)
+{
+ u32 i, command, retries;
+
+ for (i = 0; i < len; i++) {
+ command = bank | addr | 0x04000000 | (*buf << 0x10);
+
+ retries = 2;
+
+ while (((ReadRegDW(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+ linuxdelayms(1);
+ retries--;
+ };
+
+ if (retries == 0)
+ printk("%s: SRAM timeout\n", __FUNCTION__);
+
+ WriteRegDW(adapter, 0x700, command);
+
+ buf++;
+ addr++;
+ }
+}
+
+void FlexSramRead(struct adapter *adapter, u32 bank, u32 addr, u8 * buf, u32 len)
+{
+ u32 i, command, value, retries;
+
+ for (i = 0; i < len; i++) {
+ command = bank | addr | 0x04008000;
+
+ retries = 10000;
+
+ while (((ReadRegDW(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+ linuxdelayms(1);
+ retries--;
+ };
+
+ if (retries == 0)
+ printk("%s: SRAM timeout\n", __FUNCTION__);
+
+ WriteRegDW(adapter, 0x700, command);
+
+ retries = 10000;
+
+ while (((ReadRegDW(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+ linuxdelayms(1);
+ retries--;
+ };
+
+ if (retries == 0)
+ printk("%s: SRAM timeout\n", __FUNCTION__);
+
+ value = ReadRegDW(adapter, 0x700) >> 0x10;
+
+ *buf = (value & 0xff);
+
+ addr++;
+ buf++;
+ }
+}
+
+void SRAM_writeChunk(struct adapter *adapter, u32 addr, u8 * buf, u16 len)
+{
+ u32 bank;
+
+ bank = 0;
+
+ if (adapter->dwSramType == 0x20000) {
+ bank = (addr & 0x18000) << 0x0D;
+ }
+
+ if (adapter->dwSramType == 0x00000) {
+ if ((addr >> 0x0F) == 0)
+ bank = 0x20000000;
+ else
+ bank = 0x10000000;
+ }
+
+ FlexSramWrite(adapter, bank, addr & 0x7FFF, buf, len);
+}
+
+void SRAM_readChunk(struct adapter *adapter, u32 addr, u8 * buf, u16 len)
+{
+ u32 bank;
+
+ bank = 0;
+
+ if (adapter->dwSramType == 0x20000) {
+ bank = (addr & 0x18000) << 0x0D;
+ }
+
+ if (adapter->dwSramType == 0x00000) {
+ if ((addr >> 0x0F) == 0)
+ bank = 0x20000000;
+ else
+ bank = 0x10000000;
+ }
+
+ FlexSramRead(adapter, bank, addr & 0x7FFF, buf, len);
+}
+
+void SRAM_read(struct adapter *adapter, u32 addr, u8 * buf, u32 len)
+{
+ u32 length;
+
+ while (len != 0) {
+ length = len;
+
+ // check if the address range belongs to the same
+ // 32K memory chip. If not, the data is read from
+ // one chip at a time.
+ if ((addr >> 0x0F) != ((addr + len - 1) >> 0x0F)) {
+ length = (((addr >> 0x0F) + 1) << 0x0F) - addr;
+ }
+
+ SRAM_readChunk(adapter, addr, buf, length);
+
+ addr = addr + length;
+ buf = buf + length;
+ len = len - length;
+ }
+}
+
+void SRAM_write(struct adapter *adapter, u32 addr, u8 * buf, u32 len)
+{
+ u32 length;
+
+ while (len != 0) {
+ length = len;
+
+ // check if the address range belongs to the same
+ // 32K memory chip. If not, the data is written to
+ // one chip at a time.
+ if ((addr >> 0x0F) != ((addr + len - 1) >> 0x0F)) {
+ length = (((addr >> 0x0F) + 1) << 0x0F) - addr;
+ }
+
+ SRAM_writeChunk(adapter, addr, buf, length);
+
+ addr = addr + length;
+ buf = buf + length;
+ len = len - length;
+ }
+}
+
+void SRAM_setSize(struct adapter *adapter, u32 mask)
+{
+ WriteRegDW(adapter, 0x71C, (mask | (~0x30000 & ReadRegDW(adapter, 0x71C))));
+}
+
+u32 SRAM_init(struct adapter *adapter)
+{
+ u32 tmp;
+
+ tmp = ReadRegDW(adapter, 0x71C);
+
+ WriteRegDW(adapter, 0x71C, 1);
+
+ if (ReadRegDW(adapter, 0x71C) != 0) {
+ WriteRegDW(adapter, 0x71C, tmp);
+
+ adapter->dwSramType = tmp & 0x30000;
+
+ dprintk("%s: dwSramType = %x\n", __FUNCTION__, adapter->dwSramType);
+
+ } else {
+
+ adapter->dwSramType = 0x10000;
+
+ dprintk("%s: dwSramType = %x\n", __FUNCTION__, adapter->dwSramType);
+ }
+
+ return adapter->dwSramType;
+}
+
+int SRAM_testLocation(struct adapter *adapter, u32 mask, u32 addr)
+{
+ u8 tmp1, tmp2;
+
+ dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
+
+ SRAM_setSize(adapter, mask);
+ SRAM_init(adapter);
+
+ tmp2 = 0xA5;
+ tmp1 = 0x4F;
+
+ SRAM_write(adapter, addr, &tmp2, 1);
+ SRAM_write(adapter, addr + 4, &tmp1, 1);
+
+ tmp2 = 0;
+
+ linuxdelayms(20);
+
+ SRAM_read(adapter, addr, &tmp2, 1);
+ SRAM_read(adapter, addr, &tmp2, 1);
+
+ dprintk("%s: wrote 0xA5, read 0x%2x\n", __FUNCTION__, tmp2);
+
+ if (tmp2 != 0xA5)
+ return 0;
+
+ tmp2 = 0x5A;
+ tmp1 = 0xF4;
+
+ SRAM_write(adapter, addr, &tmp2, 1);
+ SRAM_write(adapter, addr + 4, &tmp1, 1);
+
+ tmp2 = 0;
+
+ linuxdelayms(20);
+
+ SRAM_read(adapter, addr, &tmp2, 1);
+ SRAM_read(adapter, addr, &tmp2, 1);
+
+ dprintk("%s: wrote 0x5A, read 0x%2x\n", __FUNCTION__, tmp2);
+
+ if (tmp2 != 0x5A)
+ return 0;
+
+ return 1;
+}
+
+u32 SRAM_length(struct adapter * adapter)
+{
+ if (adapter->dwSramType == 0x10000)
+ return 32768; // 32K
+ if (adapter->dwSramType == 0x00000)
+ return 65536; // 64K
+ if (adapter->dwSramType == 0x20000)
+ return 131072; // 128K
+
+ return 32768; // 32K
+}
+
+//////////////////////////////////////////////////////////////////////
+// FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
+// - for 128K there are 4x32K chips at bank 0,1,2,3.
+// - for 64K there are 2x32K chips at bank 1,2.
+// - for 32K there is one 32K chip at bank 0.
+//
+// FlexCop works only with one bank at a time. The bank is selected
+// by bits 28-29 of the 0x700 register.
+//
+// bank 0 covers addresses 0x00000-0x07FFF
+// bank 1 covers addresses 0x08000-0x0FFFF
+// bank 2 covers addresses 0x10000-0x17FFF
+// bank 3 covers addresses 0x18000-0x1FFFF
+/////////////////////////////////////////////////////////////////////
+
+int SramDetectForFlex2(struct adapter *adapter)
+{
+ u32 tmp, tmp2, tmp3;
+
+ dprintk("%s:\n", __FUNCTION__);
+
+ tmp = ReadRegDW(adapter, 0x208);
+ WriteRegDW(adapter, 0x208, 0);
+
+ tmp2 = ReadRegDW(adapter, 0x71C);
+
+ dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2);
+
+ WriteRegDW(adapter, 0x71C, 1);
+
+ tmp3 = ReadRegDW(adapter, 0x71C);
+
+ dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
+
+ WriteRegDW(adapter, 0x71C, tmp2);
+
+ // check for internal SRAM ???
+ tmp3--;
+ if (tmp3 != 0) {
+ SRAM_setSize(adapter, 0x10000);
+ SRAM_init(adapter);
+ WriteRegDW(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 32K\n", __FUNCTION__);
+
+ return 32;
+ }
+
+ if (SRAM_testLocation(adapter, 0x20000, 0x18000) != 0) {
+ SRAM_setSize(adapter, 0x20000);
+ SRAM_init(adapter);
+ WriteRegDW(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 128K\n", __FUNCTION__);
+
+ return 128;
+ }
+
+ if (SRAM_testLocation(adapter, 0x00000, 0x10000) != 0) {
+ SRAM_setSize(adapter, 0x00000);
+ SRAM_init(adapter);
+ WriteRegDW(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 64K\n", __FUNCTION__);
+
+ return 64;
+ }
+
+ if (SRAM_testLocation(adapter, 0x10000, 0x00000) != 0) {
+ SRAM_setSize(adapter, 0x10000);
+ SRAM_init(adapter);
+ WriteRegDW(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 32K\n", __FUNCTION__);
+
+ return 32;
+ }
+
+ SRAM_setSize(adapter, 0x10000);
+ SRAM_init(adapter);
+ WriteRegDW(adapter, 0x208, tmp);
+
+ dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
+
+ return 0;
+}
+
+void SLL_detectSramSize(struct adapter *adapter)
+{
+ SramDetectForFlex2(adapter);
+}
+
+/////////////////////////////////////////////////////////////////////
+// EEPROM (Skystar2 has one "24LC08B" chip on board)
+////////////////////////////////////////////////////////////////////
+
+int EEPROM_write(struct adapter *adapter, u16 addr, u8 * buf, u16 len)
+{
+ return FLEXI2C_write(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+int EEPROM_read(struct adapter *adapter, u16 addr, u8 * buf, u16 len)
+{
+ return FLEXI2C_read(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+u8 calc_LRC(u8 * buf, u32 len)
+{
+ u32 i;
+ u8 sum;
+
+ sum = 0;
+
+ for (i = 0; i < len; i++)
+ sum = sum ^ buf[i];
+
+ return sum;
+}
+
+int EEPROM_LRC_read(struct adapter *adapter, u32 addr, u32 len, u8 * buf, u32 retries)
+{
+ int i;
+
+ for (i = 0; i < retries; i++) {
+ if (EEPROM_read(adapter, addr, buf, len) == len) {
+ if (calc_LRC(buf, len - 1) == buf[len - 1])
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int EEPROM_LRC_write(struct adapter *adapter, u32 addr, u32 len, u8 * wbuf, u8 * rbuf, u32 retries)
+{
+ int i;
+
+ for (i = 0; i < retries; i++) {
+ if (EEPROM_write(adapter, addr, wbuf, len) == len) {
+ if (EEPROM_LRC_read(adapter, addr, len, rbuf, retries) == 1)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// These functions could be called from the initialization routine
+// to unlock SkyStar2 cards, locked by "Europe On Line".
+//
+// in cards from "Europe On Line" the key is:
+//
+// u8 key[20] = {
+// 0xB2, 0x01, 0x00, 0x00,
+// 0x00, 0x00, 0x00, 0x00,
+// 0x00, 0x00, 0x00, 0x00,
+// 0x00, 0x00, 0x00, 0x00,
+// };
+//
+// LRC = 0xB3;
+//
+// in unlocked cards the key is:
+//
+// u8 key[20] = {
+// 0xB2, 0x00, 0x00, 0x00,
+// 0x00, 0x00, 0x00, 0x00,
+// 0x00, 0x00, 0x00, 0x00,
+// 0x00, 0x00, 0x00, 0x00,
+// };
+//
+// LRC = 0xB2;
+/////////////////////////////////////////////////////////////////////
+
+int EEPROM_writeKey(struct adapter *adapter, u8 * key, u32 len)
+{
+ u8 rbuf[20];
+ u8 wbuf[20];
+
+ if (len != 16)
+ return 0;
+
+ memcpy(wbuf, key, len);
+
+ wbuf[16] = 0;
+ wbuf[17] = 0;
+ wbuf[18] = 0;
+ wbuf[19] = calc_LRC(wbuf, 19);
+
+ return EEPROM_LRC_write(adapter, 0x3E4, 20, wbuf, rbuf, 4);
+}
+
+int EEPROM_readKey(struct adapter *adapter, u8 * key, u32 len)
+{
+ u8 buf[20];
+
+ if (len != 16)
+ return 0;
+
+ if (EEPROM_LRC_read(adapter, 0x3E4, 20, buf, 4) == 0)
+ return 0;
+
+ memcpy(key, buf, len);
+
+ return 1;
+}
+
+int EEPROM_getMacAddr(struct adapter *adapter, char type, u8 * mac)
+{
+ u8 tmp[8];
+
+ if (EEPROM_LRC_read(adapter, 0x3F8, 8, tmp, 4) != 0) {
+ if (type != 0) {
+ mac[0] = tmp[0];
+ mac[1] = tmp[1];
+ mac[2] = tmp[2];
+ mac[3] = 0xFE;
+ mac[4] = 0xFF;
+ mac[5] = tmp[3];
+ mac[6] = tmp[4];
+ mac[7] = tmp[5];
+
+ } else {
+
+ mac[0] = tmp[0];
+ mac[1] = tmp[1];
+ mac[2] = tmp[2];
+ mac[3] = tmp[3];
+ mac[4] = tmp[4];
+ mac[5] = tmp[5];
+ }
+
+ return 1;
+
+ } else {
+
+ if (type == 0) {
+ memset(mac, 0, 6);
+
+ } else {
+
+ memset(mac, 0, 8);
+ }
+
+ return 0;
+ }
+}
+
+char EEPROM_setMacAddr(struct adapter *adapter, char type, u8 * mac)
+{
+ u8 tmp[8];
+
+ if (type != 0) {
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+ tmp[3] = mac[5];
+ tmp[4] = mac[6];
+ tmp[5] = mac[7];
+
+ } else {
+
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+ tmp[3] = mac[3];
+ tmp[4] = mac[4];
+ tmp[5] = mac[5];
+ }
+
+ tmp[6] = 0;
+ tmp[7] = calc_LRC(tmp, 7);
+
+ if (EEPROM_write(adapter, 0x3F8, tmp, 8) == 8)
+ return 1;
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// PID filter
+/////////////////////////////////////////////////////////////////////
+
+void FilterEnableStream1Filter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000001, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000001);
+ }
+}
+
+void FilterEnableStream2Filter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000002, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000002);
+ }
+}
+
+void FilterEnablePcrFilter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000004, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000004);
+ }
+}
+
+void FilterEnablePmtFilter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000008, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000008);
+ }
+}
+
+void FilterEnableEmmFilter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000010, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000010);
+ }
+}
+
+void FilterEnableEcmFilter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000020, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000020);
+ }
+}
+
+void FilterEnableNullFilter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000040, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000040);
+ }
+}
+
+void FilterEnableMaskFilter(struct adapter *adapter, u32 op)
+{
+ dprintk("%s: op=%x\n", __FUNCTION__, op);
+
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000080, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000080);
+ }
+}
+
+
+void CtrlEnableMAC(struct adapter *adapter, u32 op)
+{
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00004000, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00004000);
+ }
+}
+
+int CASetMacDstAddrFilter(struct adapter *adapter, u8 * mac)
+{
+ u32 tmp1, tmp2;
+
+ tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0];
+ tmp2 = (mac[5] << 0x08) | mac[4];
+
+ WriteRegDW(adapter, 0x418, tmp1);
+ WriteRegDW(adapter, 0x41C, tmp2);
+
+ return 0;
+}
+
+void SetIgnoreMACFilter(struct adapter *adapter, u8 op)
+{
+ if (op != 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00004000, 0);
+
+ adapter->mac_filter = 1;
+
+ } else {
+
+ if (adapter->mac_filter != 0) {
+ adapter->mac_filter = 0;
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00004000);
+ }
+ }
+}
+
+void CheckNullFilterEnable(struct adapter *adapter)
+{
+ FilterEnableNullFilter(adapter, 1);
+ FilterEnableMaskFilter(adapter, 1);
+}
+
+void InitPIDsInfo(struct adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < 0x27; i++)
+ adapter->pids[i] = 0x1FFF;
+}
+
+u32 CheckPID(struct adapter *adapter, u16 pid)
+{
+ u32 i;
+
+ if (pid == 0x1FFF)
+ return 0;
+
+ for (i = 0; i < 0x27; i++) {
+ if (adapter->pids[i] == pid)
+ return 1;
+ }
+
+ return 0;
+}
+
+u32 PidSetGroupPID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = (pid & 0x3FFF) | (ReadRegDW(adapter, 0x30C) & 0xFFFF0000);
+
+ WriteRegDW(adapter, 0x30C, value);
+
+ return value;
+}
+
+u32 PidSetGroupMASK(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = ((pid & 0x3FFF) << 0x10) | (ReadRegDW(adapter, 0x30C) & 0xFFFF);
+
+ WriteRegDW(adapter, 0x30C, value);
+
+ return value;
+}
+
+u32 PidSetStream1PID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = (pid & 0x3FFF) | (ReadRegDW(adapter, 0x300) & 0xFFFFC000);
+
+ WriteRegDW(adapter, 0x300, value);
+
+ return value;
+}
+
+u32 PidSetStream2PID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = ((pid & 0x3FFF) << 0x10) | (ReadRegDW(adapter, 0x300) & 0xFFFF);
+
+ WriteRegDW(adapter, 0x300, value);
+
+ return value;
+}
+
+u32 PidSetPcrPID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = (pid & 0x3FFF) | (ReadRegDW(adapter, 0x304) & 0xFFFFC000);
+
+ WriteRegDW(adapter, 0x304, value);
+
+ return value;
+}
+
+u32 PidSetPmtPID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = ((pid & 0x3FFF) << 0x10) | (ReadRegDW(adapter, 0x304) & 0x3FFF);
+
+ WriteRegDW(adapter, 0x304, value);
+
+ return value;
+}
+
+u32 PidSetEmmPID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = (pid & 0xFFFF) | (ReadRegDW(adapter, 0x308) & 0xFFFF0000);
+
+ WriteRegDW(adapter, 0x308, value);
+
+ return value;
+}
+
+u32 PidSetEcmPID(struct adapter * adapter, u32 pid)
+{
+ u32 value;
+
+ dprintk("%s: pid=%x\n", __FUNCTION__, pid);
+
+ value = (pid << 0x10) | (ReadRegDW(adapter, 0x308) & 0xFFFF);
+
+ WriteRegDW(adapter, 0x308, value);
+
+ return value;
+}
+
+u32 PidGetStream1PID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x300) & 0x0000FFFF;
+}
+
+u32 PidGetStream2PID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x300) >> 0x10;
+}
+
+u32 PidGetPcrPID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x304) & 0x0000FFFF;
+}
+
+u32 PidGetPmtPID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x304) >> 0x10;
+}
+
+u32 PidGetEmmPID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x308) & 0x0000FFFF;
+}
+
+u32 PidGetEcmPID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x308) >> 0x10;
+}
+
+u32 PidGetGroupPID(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x30C) & 0x0000FFFF;
+}
+
+u32 PidGetGroupMASK(struct adapter * adapter)
+{
+ return ReadRegDW(adapter, 0x30C) >> 0x10;
+}
+
+void ResetHardwarePIDFilter(struct adapter *adapter)
+{
+ PidSetStream1PID(adapter, 0x1FFF);
+
+ PidSetStream2PID(adapter, 0x1FFF);
+ FilterEnableStream2Filter(adapter, 0);
+
+ PidSetPcrPID(adapter, 0x1FFF);
+ FilterEnablePcrFilter(adapter, 0);
+
+ PidSetPmtPID(adapter, 0x1FFF);
+ FilterEnablePmtFilter(adapter, 0);
+
+ PidSetEcmPID(adapter, 0x1FFF);
+ FilterEnableEcmFilter(adapter, 0);
+
+ PidSetEmmPID(adapter, 0x1FFF);
+ FilterEnableEmmFilter(adapter, 0);
+}
+
+void OpenWholeBandwidth(struct adapter *adapter)
+{
+ PidSetGroupPID(adapter, 0);
+
+ PidSetGroupMASK(adapter, 0);
+
+ FilterEnableMaskFilter(adapter, 1);
+}
+
+int AddHwPID(struct adapter *adapter, u32 pid)
+{
+ dprintk("%s: pid=%d\n", __FUNCTION__, pid);
+
+ if (pid <= 0x1F)
+ return 1;
+
+ if ((PidGetGroupMASK(adapter) == 0) && (PidGetGroupPID(adapter) == 0))
+ return 0;
+
+ if ((PidGetStream1PID(adapter) & 0x1FFF) == 0x1FFF) {
+ PidSetStream1PID(adapter, pid & 0xFFFF);
+
+ FilterEnableStream1Filter(adapter, 1);
+
+ return 1;
+ }
+
+ if ((PidGetStream2PID(adapter) & 0x1FFF) == 0x1FFF) {
+ PidSetStream2PID(adapter, (pid & 0xFFFF));
+
+ FilterEnableStream2Filter(adapter, 1);
+
+ return 1;
+ }
+
+ if ((PidGetPcrPID(adapter) & 0x1FFF) == 0x1FFF) {
+ PidSetPcrPID(adapter, (pid & 0xFFFF));
+
+ FilterEnablePcrFilter(adapter, 1);
+
+ return 1;
+ }
+
+ if ((PidGetPmtPID(adapter) & 0x1FFF) == 0x1FFF) {
+ PidSetPmtPID(adapter, (pid & 0xFFFF));
+
+ FilterEnablePmtFilter(adapter, 1);
+
+ return 1;
+ }
+
+ if ((PidGetEmmPID(adapter) & 0x1FFF) == 0x1FFF) {
+ PidSetEmmPID(adapter, (pid & 0xFFFF));
+
+ FilterEnableEmmFilter(adapter, 1);
+
+ return 1;
+ }
+
+ if ((PidGetEcmPID(adapter) & 0x1FFF) == 0x1FFF) {
+ PidSetEcmPID(adapter, (pid & 0xFFFF));
+
+ FilterEnableEcmFilter(adapter, 1);
+
+ return 1;
+ }
+
+ return -1;
+}
+
+int RemoveHwPID(struct adapter *adapter, u32 pid)
+{
+ dprintk("%s: pid=%d\n", __FUNCTION__, pid);
+
+ if (pid <= 0x1F)
+ return 1;
+
+ if ((PidGetStream1PID(adapter) & 0x1FFF) == pid) {
+ PidSetStream1PID(adapter, 0x1FFF);
+
+ return 1;
+ }
+
+ if ((PidGetStream2PID(adapter) & 0x1FFF) == pid) {
+ PidSetStream2PID(adapter, 0x1FFF);
+
+ FilterEnableStream2Filter(adapter, 0);
+
+ return 1;
+ }
+
+ if ((PidGetPcrPID(adapter) & 0x1FFF) == pid) {
+ PidSetPcrPID(adapter, 0x1FFF);
+
+ FilterEnablePcrFilter(adapter, 0);
+
+ return 1;
+ }
+
+ if ((PidGetPmtPID(adapter) & 0x1FFF) == pid) {
+ PidSetPmtPID(adapter, 0x1FFF);
+
+ FilterEnablePmtFilter(adapter, 0);
+
+ return 1;
+ }
+
+ if ((PidGetEmmPID(adapter) & 0x1FFF) == pid) {
+ PidSetEmmPID(adapter, 0x1FFF);
+
+ FilterEnableEmmFilter(adapter, 0);
+
+ return 1;
+ }
+
+ if ((PidGetEcmPID(adapter) & 0x1FFF) == pid) {
+ PidSetEcmPID(adapter, 0x1FFF);
+
+ FilterEnableEcmFilter(adapter, 0);
+
+ return 1;
+ }
+
+ return -1;
+}
+
+int AddPID(struct adapter *adapter, u32 pid)
+{
+ int i;
+
+ dprintk("%s: pid=%d\n", __FUNCTION__, pid);
+
+ if (pid > 0x1FFE)
+ return -1;
+
+ if (CheckPID(adapter, pid) == 1)
+ return 1;
+
+ for (i = 0; i < 0x27; i++) {
+ if (adapter->pids[i] == 0x1FFF) // find free pid filter
+ {
+ adapter->pids[i] = pid;
+
+ if (AddHwPID(adapter, pid) < 0)
+ OpenWholeBandwidth(adapter);
+
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
+int RemovePID(struct adapter *adapter, u32 pid)
+{
+ u32 i;
+
+ dprintk("%s: pid=%d\n", __FUNCTION__, pid);
+
+ if (pid > 0x1FFE)
+ return -1;
+
+ for (i = 0; i < 0x27; i++) {
+ if (adapter->pids[i] == pid) {
+ adapter->pids[i] = 0x1FFF;
+
+ RemoveHwPID(adapter, pid);
+
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
+/////////////////////////////////////////////////////////////////////
+// DMA & IRQ
+/////////////////////////////////////////////////////////////////////
+
+void CtrlEnableSmc(struct adapter *adapter, u32 op)
+{
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00000800, 0);
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00000800);
+ }
+}
+
+u32 DmaEnableDisableIrq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3)
+{
+ adapter->dma_ctrl = adapter->dma_ctrl & 0x000F0000;
+
+ if (flag1 == 0) {
+ if (flag2 == 0)
+ adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000;
+ else
+ adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000;
+
+ if (flag3 == 0)
+ adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000;
+ else
+ adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000;
+
+ } else {
+
+ if (flag2 == 0)
+ adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000;
+ else
+ adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000;
+
+ if (flag3 == 0)
+ adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000;
+ else
+ adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000;
+ }
+
+ return adapter->dma_ctrl;
+}
+
+u32 IrqDmaEnableDisableIrq(struct adapter * adapter, u32 op)
+{
+ u32 value;
+
+ value = ReadRegDW(adapter, 0x208) & 0xFFF0FFFF;
+
+ if (op != 0)
+ value = value | (adapter->dma_ctrl & 0x000F0000);
+
+ WriteRegDW(adapter, 0x208, value);
+
+ return value;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to
+// system memory.
+//
+// The DMA1 buffer is divided in 2 subbuffers of equal size.
+// FlexCopII will transfer TS data to one subbuffer, signal an interrupt
+// when the subbuffer is full and continue fillig the second subbuffer.
+//
+// For DMA1:
+// subbuffer size in 32-bit words is stored in the first 24 bits of
+// register 0x004. The last 8 bits of register 0x004 contain the number
+// of subbuffers.
+//
+// the first 30 bits of register 0x000 contain the address of the first
+// subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
+// when dma1 is enabled.
+//
+// the first 30 bits of register 0x00C contain the address of the second
+// subbuffer. the last 2 bits contain 1.
+//
+// register 0x008 will contain the address of the subbuffer that was filled
+// with TS data, when FlexCopII will generate an interrupt.
+//
+// For DMA2:
+// subbuffer size in 32-bit words is stored in the first 24 bits of
+// register 0x014. The last 8 bits of register 0x014 contain the number
+// of subbuffers.
+//
+// the first 30 bits of register 0x010 contain the address of the first
+// subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
+// when dma1 is enabled.
+//
+// the first 30 bits of register 0x01C contain the address of the second
+// subbuffer. the last 2 bits contain 1.
+//
+// register 0x018 contains the address of the subbuffer that was filled
+// with TS data, when FlexCopII generates an interrupt.
+//
+///////////////////////////////////////////////////////////////////////
+
+int DmaInitDMA(struct adapter *adapter, u32 dma_channel)
+{
+ u32 subbuffers, subbufsize, subbuf0, subbuf1;
+
+ if (dma_channel == 0) {
+ dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__);
+
+ subbuffers = 2;
+
+ subbufsize = (((adapter->DmaQ1.buffer_size / 2) / 4) << 8) | subbuffers;
+
+ subbuf0 = adapter->DmaQ1.bus_addr & 0xFFFFFFFC;
+
+ subbuf1 = ((adapter->DmaQ1.bus_addr + adapter->DmaQ1.buffer_size / 2) & 0xFFFFFFFC) | 1;
+
+ dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
+ udelay(1000);
+ WriteRegDW(adapter, 0x000, subbuf0);
+
+ dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
+ udelay(1000);
+ WriteRegDW(adapter, 0x004, subbufsize);
+
+ dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1);
+ udelay(1000);
+ WriteRegDW(adapter, 0x00C, subbuf1);
+
+ dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->DmaQ1.bus_addr & 0xFFFFFFFC);
+ WriteRegDW(adapter, 0x008, adapter->DmaQ1.bus_addr & 0xFFFFFFFC);
+ udelay(1000);
+
+ if (subbuffers == 0)
+ DmaEnableDisableIrq(adapter, 0, 1, 0);
+ else
+ DmaEnableDisableIrq(adapter, 0, 1, 1);
+
+ IrqDmaEnableDisableIrq(adapter, 1);
+
+ SRAMSetMediaDest(adapter, 1);
+ SRAMSetNetDest(adapter, 1);
+ SRAMSetCaiDest(adapter, 2);
+ SRAMSetCaoDest(adapter, 2);
+ }
+
+ if (dma_channel == 1) {
+ dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__);
+
+ subbuffers = 2;
+
+ subbufsize = (((adapter->DmaQ2.buffer_size / 2) / 4) << 8) | subbuffers;
+
+ subbuf0 = adapter->DmaQ2.bus_addr & 0xFFFFFFFC;
+
+ subbuf1 = ((adapter->DmaQ2.bus_addr + adapter->DmaQ2.buffer_size / 2) & 0xFFFFFFFC) | 1;
+
+ dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
+ udelay(1000);
+ WriteRegDW(adapter, 0x010, subbuf0);
+
+ dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
+ udelay(1000);
+ WriteRegDW(adapter, 0x014, subbufsize);
+
+ dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1);
+ udelay(1000);
+ WriteRegDW(adapter, 0x01C, subbuf1);
+
+ SRAMSetCaiDest(adapter, 2);
+ }
+
+ return 0;
+}
+
+void CtrlEnableReceiveData(struct adapter *adapter, u32 op)
+{
+ if (op == 0) {
+ WriteRegOp(adapter, 0x208, 2, ~0x00008000, 0);
+
+ adapter->dma_status = adapter->dma_status & ~0x00000004;
+
+ } else {
+
+ WriteRegOp(adapter, 0x208, 1, 0, 0x00008000);
+
+ adapter->dma_status = adapter->dma_status | 0x00000004;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled
+// bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled
+
+void DmaStartStop0x2102(struct adapter *adapter, u32 dma_mask, u32 start_stop)
+{
+ u32 dma_enable, dma1_enable, dma2_enable;
+
+ dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask);
+
+ if (start_stop == 1) {
+ dprintk("%s: starting dma\n", __FUNCTION__);
+
+ dma1_enable = 0;
+ dma2_enable = 0;
+
+ if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->DmaQ1.bus_addr != 0)) {
+ adapter->dma_status = adapter->dma_status | 1;
+ dma1_enable = 1;
+ }
+
+ if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->DmaQ2.bus_addr != 0)) {
+ adapter->dma_status = adapter->dma_status | 2;
+ dma2_enable = 1;
+ }
+ // enable dma1 and dma2
+ if ((dma1_enable == 1) && (dma2_enable == 1)) {
+ WriteRegDW(adapter, 0x000, adapter->DmaQ1.bus_addr | 1);
+ WriteRegDW(adapter, 0x00C, (adapter->DmaQ1.bus_addr + adapter->DmaQ1.buffer_size / 2) | 1);
+ WriteRegDW(adapter, 0x010, adapter->DmaQ2.bus_addr | 1);
+
+ CtrlEnableReceiveData(adapter, 1);
+
+ return;
+ }
+ // enable dma1
+ if ((dma1_enable == 1) && (dma2_enable == 0)) {
+ WriteRegDW(adapter, 0x000, adapter->DmaQ1.bus_addr | 1);
+ WriteRegDW(adapter, 0x00C, (adapter->DmaQ1.bus_addr + adapter->DmaQ1.buffer_size / 2) | 1);
+
+ CtrlEnableReceiveData(adapter, 1);
+
+ return;
+ }
+ // enable dma2
+ if ((dma1_enable == 0) && (dma2_enable == 1)) {
+ WriteRegDW(adapter, 0x010, adapter->DmaQ2.bus_addr | 1);
+
+ CtrlEnableReceiveData(adapter, 1);
+
+ return;
+ }
+ // start dma
+ if ((dma1_enable == 0) && (dma2_enable == 0)) {
+ CtrlEnableReceiveData(adapter, 1);
+
+ return;
+ }
+
+ } else {
+
+ dprintk("%s: stoping dma\n", __FUNCTION__);
+
+ dma_enable = adapter->dma_status & 0x00000003;
+
+ if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) {
+ dma_enable = dma_enable & 0xFFFFFFFE;
+ }
+
+ if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) {
+ dma_enable = dma_enable & 0xFFFFFFFD;
+ }
+ //stop dma
+ if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) {
+ CtrlEnableReceiveData(adapter, 0);
+
+ udelay(3000);
+ }
+ //disable dma1
+ if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->DmaQ1.bus_addr != 0)) {
+ WriteRegDW(adapter, 0x000, adapter->DmaQ1.bus_addr);
+ WriteRegDW(adapter, 0x00C, (adapter->DmaQ1.bus_addr + adapter->DmaQ1.buffer_size / 2) | 1);
+
+ adapter->dma_status = adapter->dma_status & ~0x00000001;
+ }
+ //disable dma2
+ if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->DmaQ2.bus_addr != 0)) {
+ WriteRegDW(adapter, 0x010, adapter->DmaQ2.bus_addr);
+
+ adapter->dma_status = adapter->dma_status & ~0x00000002;
+ }
+ }
+}
+
+void OpenStream(struct adapter *adapter, u32 pid)
+{
+ u32 dma_mask;
+
+ if (adapter->capturing == 0)
+ adapter->capturing = 1;
+
+ FilterEnableMaskFilter(adapter, 1);
+
+ AddPID(adapter, pid);
+
+ dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status);
+
+ if ((adapter->dma_status & 7) != 7) {
+ dma_mask = 0;
+
+ if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) {
+ dma_mask = dma_mask | 1;
+
+ adapter->DmaQ1.head = 0;
+ adapter->DmaQ1.tail = 0;
+
+ memset(adapter->DmaQ1.buffer, 0, adapter->DmaQ1.buffer_size);
+ }
+
+ if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) {
+ dma_mask = dma_mask | 2;
+
+ adapter->DmaQ2.head = 0;
+ adapter->DmaQ2.tail = 0;
+ }
+
+ if (dma_mask != 0) {
+ IrqDmaEnableDisableIrq(adapter, 1);
+
+ DmaStartStop0x2102(adapter, dma_mask, 1);
+ }
+ }
+}
+
+void CloseStream(struct adapter *adapter, u32 pid)
+{
+ u32 dma_mask;
+
+ if (adapter->capturing != 0)
+ adapter->capturing = 0;
+
+ dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status);
+
+ dma_mask = 0;
+
+ if ((adapter->dma_status & 1) != 0)
+ dma_mask = dma_mask | 0x00000001;
+ if ((adapter->dma_status & 2) != 0)
+ dma_mask = dma_mask | 0x00000002;
+
+ if (dma_mask != 0) {
+ DmaStartStop0x2102(adapter, dma_mask, 0);
+ }
+
+ RemovePID(adapter, pid);
+}
+
+u32 InterruptServiceDMA1(struct adapter *adapter)
+{
+ struct dvb_demux *dvbdmx = &adapter->demux;
+ struct packet_header_t packet_header;
+
+ int nCurDmaCounter;
+ u32 nNumBytesParsed;
+ u32 nNumNewBytesTransferred;
+ u32 dwDefaultPacketSize = 188;
+ u8 gbTmpBuffer[188];
+ u8 *pbDMABufCurPos;
+
+ nCurDmaCounter = readl(adapter->io_mem + 0x008) - adapter->DmaQ1.bus_addr;
+ nCurDmaCounter = (nCurDmaCounter / dwDefaultPacketSize) * dwDefaultPacketSize;
+
+ if ((nCurDmaCounter < 0) || (nCurDmaCounter > adapter->DmaQ1.buffer_size)) {
+ dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__);
+
+ return 1;
+ }
+
+ adapter->DmaQ1.head = nCurDmaCounter;
+
+ if (adapter->DmaQ1.tail <= nCurDmaCounter) {
+ nNumNewBytesTransferred = nCurDmaCounter - adapter->DmaQ1.tail;
+
+ } else {
+
+ nNumNewBytesTransferred = (adapter->DmaQ1.buffer_size - adapter->DmaQ1.tail) + nCurDmaCounter;
+ }
+
+// dprintk("%s: nCurDmaCounter = %d\n" , __FUNCTION__, nCurDmaCounter);
+// dprintk("%s: DmaQ1.tail = %d\n" , __FUNCTION__, adapter->DmaQ1.tail):
+// dprintk("%s: BytesTransferred = %d\n" , __FUNCTION__, nNumNewBytesTransferred);
+
+ if (nNumNewBytesTransferred < dwDefaultPacketSize)
+ return 0;
+
+ nNumBytesParsed = 0;
+
+ while (nNumBytesParsed < nNumNewBytesTransferred) {
+ pbDMABufCurPos = adapter->DmaQ1.buffer + adapter->DmaQ1.tail;
+
+ if (adapter->DmaQ1.buffer + adapter->DmaQ1.buffer_size < adapter->DmaQ1.buffer + adapter->DmaQ1.tail + 188) {
+ memcpy(gbTmpBuffer, adapter->DmaQ1.buffer + adapter->DmaQ1.tail, adapter->DmaQ1.buffer_size - adapter->DmaQ1.tail);
+ memcpy(gbTmpBuffer + (adapter->DmaQ1.buffer_size - adapter->DmaQ1.tail), adapter->DmaQ1.buffer, (188 - (adapter->DmaQ1.buffer_size - adapter->DmaQ1.tail)));
+
+ pbDMABufCurPos = gbTmpBuffer;
+ }
+
+ if (adapter->capturing != 0) {
+ u32 *dq = (u32 *) pbDMABufCurPos;
+
+ packet_header.sync_byte = *dq & 0x000000FF;
+ packet_header.transport_error_indicator = *dq & 0x00008000;
+ packet_header.payload_unit_start_indicator = *dq & 0x00004000;
+ packet_header.transport_priority = *dq & 0x00002000;
+ packet_header.pid = ((*dq & 0x00FF0000) >> 0x10) | (*dq & 0x00001F00);
+ packet_header.transport_scrambling_control = *dq >> 0x1E;
+ packet_header.adaptation_field_control = (*dq & 0x30000000) >> 0x1C;
+ packet_header.continuity_counter = (*dq & 0x0F000000) >> 0x18;
+
+ if ((packet_header.sync_byte == 0x47) && (packet_header.transport_error_indicator == 0) && (packet_header.pid != 0x1FFF)) {
+ if (CheckPID(adapter, packet_header.pid & 0x0000FFFF) != 0) {
+ dvb_dmx_swfilter_packets(dvbdmx, pbDMABufCurPos, dwDefaultPacketSize / 188);
+
+ } else {
+
+// dprintk("%s: pid=%x\n", __FUNCTION__, packet_header.pid);
+ }
+ }
+ }
+
+ nNumBytesParsed = nNumBytesParsed + dwDefaultPacketSize;
+
+ adapter->DmaQ1.tail = adapter->DmaQ1.tail + dwDefaultPacketSize;
+
+ if (adapter->DmaQ1.tail >= adapter->DmaQ1.buffer_size)
+ adapter->DmaQ1.tail = adapter->DmaQ1.tail - adapter->DmaQ1.buffer_size;
+ };
+
+ return 1;
+}
+
+void InterruptServiceDMA2(struct adapter *adapter)
+{
+ printk("%s:\n", __FUNCTION__);
+}
+
+void isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct adapter *tmp = dev_id;
+
+ u32 value;
+
+// dprintk("%s:\n", __FUNCTION__);
+
+ spin_lock_irq(&tmp->lock);
+
+ while (((value = ReadRegDW(tmp, 0x20C)) & 0x0F) != 0) {
+ if ((value & 0x03) != 0)
+ InterruptServiceDMA1(tmp);
+ if ((value & 0x0C) != 0)
+ InterruptServiceDMA2(tmp);
+ }
+
+ spin_unlock_irq(&tmp->lock);
+}
+
+
+void InitDmaQueue(struct adapter *adapter)
+{
+ dma_addr_t dma_addr;
+
+ if (adapter->DmaQ1.buffer != 0)
+ return;
+
+ adapter->DmaQ1.head = 0;
+ adapter->DmaQ1.tail = 0;
+ adapter->DmaQ1.buffer = 0;
+
+ adapter->DmaQ1.buffer = pci_alloc_consistent(adapter->pdev, SizeOfBufDMA1 + 0x80, &dma_addr);
+
+ if (adapter->DmaQ1.buffer != 0) {
+ memset(adapter->DmaQ1.buffer, 0, SizeOfBufDMA1);
+
+ adapter->DmaQ1.bus_addr = dma_addr;
+ adapter->DmaQ1.buffer_size = SizeOfBufDMA1;
+
+ DmaInitDMA(adapter, 0);
+
+ adapter->dma_status = adapter->dma_status | 0x10000000;
+
+ dprintk("%s: allocated dma buffer at 0x%x, length=%d\n", __FUNCTION__, (int) adapter->DmaQ1.buffer, SizeOfBufDMA1);
+
+ } else {
+
+ adapter->dma_status = adapter->dma_status & ~0x10000000;
+ }
+
+ if (adapter->DmaQ2.buffer != 0)
+ return;
+
+ adapter->DmaQ2.head = 0;
+ adapter->DmaQ2.tail = 0;
+ adapter->DmaQ2.buffer = 0;
+
+ adapter->DmaQ2.buffer = pci_alloc_consistent(adapter->pdev, SizeOfBufDMA2 + 0x80, &dma_addr);
+
+ if (adapter->DmaQ2.buffer != 0) {
+ memset(adapter->DmaQ2.buffer, 0, SizeOfBufDMA2);
+
+ adapter->DmaQ2.bus_addr = dma_addr;
+ adapter->DmaQ2.buffer_size = SizeOfBufDMA2;
+
+ DmaInitDMA(adapter, 1);
+
+ adapter->dma_status = adapter->dma_status | 0x20000000;
+
+ dprintk("%s: allocated dma buffer at 0x%x, length=%d\n", __FUNCTION__, (int) adapter->DmaQ2.buffer, (int) SizeOfBufDMA2);
+
+ } else {
+
+ adapter->dma_status = adapter->dma_status & ~0x20000000;
+ }
+}
+
+void FreeDmaQueue(struct adapter *adapter)
+{
+ if (adapter->DmaQ1.buffer != 0) {
+ pci_free_consistent(adapter->pdev, SizeOfBufDMA1 + 0x80, adapter->DmaQ1.buffer, adapter->DmaQ1.bus_addr);
+
+ adapter->DmaQ1.bus_addr = 0;
+ adapter->DmaQ1.head = 0;
+ adapter->DmaQ1.tail = 0;
+ adapter->DmaQ1.buffer_size = 0;
+ adapter->DmaQ1.buffer = 0;
+ }
+
+ if (adapter->DmaQ2.buffer != 0) {
+ pci_free_consistent(adapter->pdev, SizeOfBufDMA2 + 0x80, adapter->DmaQ2.buffer, adapter->DmaQ2.bus_addr);
+
+ adapter->DmaQ2.bus_addr = 0;
+ adapter->DmaQ2.head = 0;
+ adapter->DmaQ2.tail = 0;
+ adapter->DmaQ2.buffer_size = 0;
+ adapter->DmaQ2.buffer = 0;
+ }
+}
+
+void FreeAdapterObject(struct adapter *adapter)
+{
+ dprintk("%s:\n", __FUNCTION__);
+
+ CloseStream(adapter, 0);
+
+ if (adapter->irq != 0)
+ free_irq(adapter->irq, adapter);
+
+ FreeDmaQueue(adapter);
+
+ if (adapter->io_mem != 0)
+ iounmap((void *) adapter->io_mem);
+
+ if (adapter != 0)
+ kfree(adapter);
+}
+
+int ClaimAdapter(struct adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ u16 var;
+
+ if (!request_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), pdev->name))
+ return -EBUSY;
+
+ if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), pdev->name))
+ return -EBUSY;
+
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision);
+
+ dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision);
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ pci_read_config_word(pdev, 4, &var);
+
+ if ((var & 4) == 0)
+ pci_set_master(pdev);
+
+ adapter->io_port = pdev->resource[1].start;
+
+ adapter->io_mem = (u32) ioremap(pdev->resource[0].start, 0x800);
+
+ if (adapter->io_mem == 0) {
+ dprintk("%s: can not map io memory\n", __FUNCTION__);
+
+ return 2;
+ }
+
+ dprintk("%s: io memory maped at %x\n", __FUNCTION__, adapter->io_mem);
+
+ return 1;
+}
+
+int SLL_reset_FlexCOP(struct adapter *adapter)
+{
+ WriteRegDW(adapter, 0x208, 0);
+ WriteRegDW(adapter, 0x210, 0xB2FF);
+
+ return 0;
+}
+
+u32 DriverInitialize(struct pci_dev * pdev)
+{
+ struct adapter *adapter;
+ u32 tmp;
+ u8 key[16];
+
+ if (!(adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL))) {
+ dprintk("%s: out of memory!\n", __FUNCTION__);
+
+ return -ENOMEM;
+ }
+
+ memset(adapter, 0, sizeof(struct adapter));
+
+ pdev->driver_data = adapter;
+
+ adapter->pdev = pdev;
+ adapter->irq = pdev->irq;
+
+ if ((ClaimAdapter(adapter)) != 1) {
+ FreeAdapterObject(adapter);
+
+ return 2;
+ }
+
+ IrqDmaEnableDisableIrq(adapter, 0);
+
+ if (request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter) != 0) {
+ dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq);
+
+ FreeAdapterObject(adapter);
+
+ return 2;
+ }
+
+ ReadRegDW(adapter, 0x208);
+ WriteRegDW(adapter, 0x208, 0);
+ WriteRegDW(adapter, 0x210, 0xB2FF);
+ WriteRegDW(adapter, 0x208, 0x40);
+
+ InitPIDsInfo(adapter);
+
+ PidSetGroupPID(adapter, 0);
+ PidSetGroupMASK(adapter, 0x1FE0);
+ PidSetStream1PID(adapter, 0x1FFF);
+ PidSetStream2PID(adapter, 0x1FFF);
+ PidSetPmtPID(adapter, 0x1FFF);
+ PidSetPcrPID(adapter, 0x1FFF);
+ PidSetEcmPID(adapter, 0x1FFF);
+ PidSetEmmPID(adapter, 0x1FFF);
+
+ InitDmaQueue(adapter);
+
+ if ((adapter->dma_status & 0x30000000) == 0) {
+ FreeAdapterObject(adapter);
+
+ return 2;
+ }
+
+ adapter->B2C2_revision = (ReadRegDW(adapter, 0x204) >> 0x18);
+
+ if ((adapter->B2C2_revision != 0x82) && (adapter->B2C2_revision != 0xC3))
+ if (adapter->B2C2_revision != 0x82) {
+ dprintk("%s: The revision of the FlexCopII chip on your card is - %d\n", __FUNCTION__, adapter->B2C2_revision);
+ dprintk("%s: This driver works now only with FlexCopII(rev.130) and FlexCopIIB(rev.195).\n", __FUNCTION__);
+
+ FreeAdapterObject(adapter);
+
+ return 2;
+ }
+
+ tmp = ReadRegDW(adapter, 0x204);
+
+ WriteRegDW(adapter, 0x204, 0);
+ linuxdelayms(20);
+
+ WriteRegDW(adapter, 0x204, tmp);
+ linuxdelayms(10);
+
+ tmp = ReadRegDW(adapter, 0x308);
+ WriteRegDW(adapter, 0x308, 0x4000 | tmp);
+
+ adapter->dwSramType = 0x10000;
+
+ SLL_detectSramSize(adapter);
+
+ dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, SRAM_length(adapter), adapter->dwSramType);
+
+ SRAMSetMediaDest(adapter, 1);
+ SRAMSetNetDest(adapter, 1);
+
+ CtrlEnableSmc(adapter, 0);
+
+ SRAMSetCaiDest(adapter, 2);
+ SRAMSetCaoDest(adapter, 2);
+
+ DmaEnableDisableIrq(adapter, 1, 0, 0);
+
+ if (EEPROM_getMacAddr(adapter, 0, adapter->mac_addr) != 0) {
+ printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0], adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5], adapter->mac_addr[6], adapter->mac_addr[7]
+ );
+
+ CASetMacDstAddrFilter(adapter, adapter->mac_addr);
+ CtrlEnableMAC(adapter, 1);
+ }
+
+ EEPROM_readKey(adapter, key, 16);
+
+ printk("%s key = \n %02x %02x %02x %02x \n %02x %02x %02x %02x \n %02x %02x %02x %02x \n %02x %02x %02x %02x \n", __FUNCTION__, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]
+ );
+
+ adapter->lock = SPIN_LOCK_UNLOCKED;
+
+ return 1;
+}
+
+void DriverHalt(struct pci_dev *pdev)
+{
+ struct adapter *adapter;
+
+ adapter = pci_get_drvdata(pdev);
+
+ IrqDmaEnableDisableIrq(adapter, 0);
+
+ CtrlEnableReceiveData(adapter, 0);
+
+ FreeAdapterObject(adapter);
+
+ pci_set_drvdata(pdev, NULL);
+
+ release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+
+ release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+}
+
+static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct adapter *adapter = (struct adapter *) dvbdmx->priv;
+
+ dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
+
+ OpenStream(adapter, dvbdmxfeed->pid);
+
+ return 0;
+}
+
+static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct adapter *adapter = (struct adapter *) dvbdmx->priv;
+
+ dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
+
+ CloseStream(adapter, dvbdmxfeed->pid);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// LNB control
+/////////////////////////////////////////////////////////////////////
+
+void set_tuner_tone(struct adapter *adapter, u8 tone)
+{
+ u16 wzHalfPeriodFor45MHz[] = { 0x01FF, 0x0154, 0x00FF, 0x00CC };
+ u16 ax;
+
+ dprintk("%s: %u\n", __FUNCTION__, tone);
+
+ switch (tone) {
+ case 1:
+ ax = wzHalfPeriodFor45MHz[0];
+ break;
+ case 2:
+ ax = wzHalfPeriodFor45MHz[1];
+ break;
+ case 3:
+ ax = wzHalfPeriodFor45MHz[2];
+ break;
+ case 4:
+ ax = wzHalfPeriodFor45MHz[3];
+ break;
+
+ default:
+ ax = 0;
+ }
+
+ if (ax != 0) {
+ WriteRegDW(adapter, 0x200, ((ax << 0x0F) + (ax & 0x7FFF)) | 0x40000000);
+
+ } else {
+
+ WriteRegDW(adapter, 0x200, 0x40FF8000);
+ }
+}
+
+void set_tuner_polarity(struct adapter *adapter, u8 polarity)
+{
+ u32 var;
+
+ dprintk("%s : polarity = %u \n", __FUNCTION__, polarity);
+
+ var = ReadRegDW(adapter, 0x204);
+
+ if (polarity == 0) {
+ dprintk("%s: LNB power off\n", __FUNCTION__);
+ var = var | 1;
+ };
+
+ if (polarity == 1) {
+ var = var & ~1;
+ var = var & ~4;
+ };
+
+ if (polarity == 2) {
+ var = var & ~1;
+ var = var | 4;
+ }
+
+ WriteRegDW(adapter, 0x204, var);
+}
+
+static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+ struct adapter *adapter = fe->before_after_data;
+
+ switch (cmd) {
+ case FE_SLEEP:
+ {
+ printk("%s: FE_SLEEP\n", __FUNCTION__);
+
+ set_tuner_polarity(adapter, 0);
+
+ // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend.
+ return -EOPNOTSUPP;
+ }
+
+ case FE_SET_VOLTAGE:
+ {
+ dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
+
+ switch ((fe_sec_voltage_t) arg) {
+ case SEC_VOLTAGE_13:
+
+ printk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
+
+ set_tuner_polarity(adapter, 1);
+
+ break;
+
+ case SEC_VOLTAGE_18:
+
+ printk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
+
+ set_tuner_polarity(adapter, 2);
+
+ break;
+
+ default:
+
+ return -EINVAL;
+ };
+
+ break;
+ }
+
+ case FE_SET_TONE:
+ {
+ dprintk("%s: FE_SET_TONE\n", __FUNCTION__);
+
+ switch ((fe_sec_tone_mode_t) arg) {
+ case SEC_TONE_ON:
+
+ printk("%s: SEC_TONE_ON, %x\n", __FUNCTION__, SEC_TONE_ON);
+
+ set_tuner_tone(adapter, 1);
+
+ break;
+
+ case SEC_TONE_OFF:
+
+ printk("%s: SEC_TONE_OFF, %x\n", __FUNCTION__, SEC_TONE_OFF);
+
+ set_tuner_tone(adapter, 0);
+
+ break;
+
+ default:
+
+ return -EINVAL;
+ };
+
+ break;
+ }
+
+ default:
+
+ return -EOPNOTSUPP;
+ };
+
+ return 0;
+}
+
+static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct adapter *adapter;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+
+ int ret;
+
+ if (pdev == NULL)
+ return -ENODEV;
+
+ if (DriverInitialize(pdev) != 1)
+ return -ENODEV;
+
+ dvb_register_adapter(&dvb_adapter, pdev->name);
+
+ if (dvb_adapter == NULL) {
+ printk("%s: Error registering DVB adapter\n", __FUNCTION__);
+
+ DriverHalt(pdev);
+
+ return -ENODEV;
+ }
+
+ adapter = (struct adapter *) pdev->driver_data;
+
+ adapter->dvb_adapter = dvb_adapter;
+
+ init_MUTEX(&adapter->i2c_sem);
+
+ adapter->i2c_bus = dvb_register_i2c_bus(master_xfer, adapter, adapter->dvb_adapter, 0);
+
+ if (!adapter->i2c_bus)
+ return -ENOMEM;
+
+ dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter);
+
+ dvbdemux = &adapter->demux;
+
+ dvbdemux->priv = (void *) adapter;
+ dvbdemux->filternum = 32;
+ dvbdemux->feednum = 32;
+ dvbdemux->start_feed = dvb_start_feed;
+ dvbdemux->stop_feed = dvb_stop_feed;
+ dvbdemux->write_to_decoder = 0;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+
+ dvb_dmx_init(&adapter->demux);
+
+ adapter->hw_frontend.source = DMX_FRONTEND_0;
+
+ adapter->dmxdev.filternum = 32;
+ adapter->dmxdev.demux = &dvbdemux->dmx;
+ adapter->dmxdev.capabilities = 0;
+
+ dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter);
+
+ ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
+ if (ret < 0)
+ return ret;
+
+ adapter->mem_frontend.source = DMX_MEMORY_FE;
+
+ ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
+ if (ret < 0)
+ return ret;
+
+ ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
+ if (ret < 0)
+ return ret;
+
+ dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
+ return 0;
+}
+
+static void skystar2_remove(struct pci_dev *pdev)
+{
+ struct adapter *adapter;
+ struct dvb_demux *dvbdemux;
+
+ if (pdev == NULL)
+ return;
+
+ adapter = pci_get_drvdata(pdev);
+
+ if (adapter != NULL) {
+ dvb_net_release(&adapter->dvbnet);
+ dvbdemux = &adapter->demux;
+
+ dvbdemux->dmx.close(&dvbdemux->dmx);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
+
+ dvb_dmxdev_release(&adapter->dmxdev);
+ dvb_dmx_release(&adapter->demux);
+
+ if (adapter->dvb_adapter != NULL) {
+ dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL);
+
+ if (adapter->i2c_bus != NULL)
+ dvb_unregister_i2c_bus(master_xfer, adapter->i2c_bus->adapter, adapter->i2c_bus->id);
+
+ dvb_unregister_adapter(adapter->dvb_adapter);
+ }
+
+ DriverHalt(pdev);
+ }
+}
+
+static struct pci_device_id skystar2_pci_tbl[] = {
+ {0x000013D0, 0x00002103, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000},
+ {0,},
+};
+
+static struct pci_driver skystar2_pci_driver = {
+ .name = "Technisat SkyStar2 driver",
+ .id_table = skystar2_pci_tbl,
+ .probe = skystar2_probe,
+ .remove = skystar2_remove,
+};
+
+static int skystar2_init(void)
+{
+ printk("\nTechnisat SkyStar2 driver loading\n");
+
+ return pci_module_init(&skystar2_pci_driver);
+}
+
+static void skystar2_cleanup(void)
+{
+ printk("\nTechnisat SkyStar2 driver unloading\n");
+
+ pci_unregister_driver(&skystar2_pci_driver);
+}
+
+module_init(skystar2_init);
+module_exit(skystar2_cleanup);
+
+MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
[DVB] - tda1004x DVB-T driver contributed by Andrew de Quincy and Robert Schlalach
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/frontends/Kconfig linux-2.6.0-test1.patch/drivers/media/dvb/frontends/Kconfig
--- linux-2.6.0-test1.work/drivers/media/dvb/frontends/Kconfig 2003-07-15 10:59:46.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/frontends/Kconfig 2003-06-27 13:50:04.000000000 +0200
@@ -115,3 +115,23 @@
DVB adapter simply enable all supported frontends, the
right one will get autodetected.
+config DVB_TDA1004X
+ tristate "Frontends with external TDA1004X demodulators (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.
+
+config DVB_TDA1004X_FIRMWARE_FILE
+ string "Full pathname of tda1004x.bin firmware file"
+ depends on DVB_TDA1004X
+ default "/etc/dvb/tda1004x.bin"
+ help
+ The TDA1004X requires additional firmware in order to function.
+ The firmware file can obtained as follows:
+ wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
+ unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
+ mv ttlcdacc.dll /etc/dvb/tda1004x.bin
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/frontends/Makefile linux-2.6.0-test1.patch/drivers/media/dvb/frontends/Makefile
--- linux-2.6.0-test1.work/drivers/media/dvb/frontends/Makefile 2003-07-15 10:59:46.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/frontends/Makefile 2003-06-27 13:36:23.000000000 +0200
@@ -12,5 +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
+obi-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
+obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/frontends/tda1004x.c linux-2.6.0-test1.patch/drivers/media/dvb/frontends/tda1004x.c
--- linux-2.6.0-test1.work/drivers/media/dvb/frontends/tda1004x.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1.patch/drivers/media/dvb/frontends/tda1004x.c 2003-07-14 11:56:37.000000000 +0200
@@ -0,0 +1,1158 @@
+ /*
+ Driver for Philips tda1004x 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 '/etc/dvb/tda1004x.mc'.
+ You can also pass the complete file name with the module parameter 'tda1004x_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"
+
+#ifndef CONFIG_TDA1004X_MC_LOCATION
+#define CONFIG_TDA1004X_MC_LOCATION "/etc/dvb/tda1004x.mc"
+#endif
+
+static int tda1004x_debug = 0;
+static char *tda1004x_firmware = CONFIG_TDA1004X_MC_LOCATION;
+
+
+#define TDA10045H_ADDRESS 0x08
+#define TD1344_ADDRESS 0x61
+#define TDM1316L_ADDRESS 0x63
+#define MC44BC374_ADDRESS 0x65
+
+#define TDA1004X_CHIPID 0x00
+#define TDA1004X_AUTO 0x01
+#define TDA1004X_IN_CONF1 0x02
+#define TDA1004X_IN_CONF2 0x03
+#define TDA1004X_OUT_CONF1 0x04
+#define TDA1004X_OUT_CONF2 0x05
+#define TDA1004X_STATUS_CD 0x06
+#define TDA1004X_CONFC4 0x07
+#define TDA1004X_DSSPARE2 0x0C
+#define TDA1004X_CODE_IN 0x0D
+#define TDA1004X_FWPAGE 0x0E
+#define TDA1004X_SCAN_CPT 0x10
+#define TDA1004X_DSP_CMD 0x11
+#define TDA1004X_DSP_ARG 0x12
+#define TDA1004X_DSP_DATA1 0x13
+#define TDA1004X_DSP_DATA2 0x14
+#define TDA1004X_CONFADC1 0x15
+#define TDA1004X_CONFC1 0x16
+#define TDA1004X_SIGNAL_STRENGTH 0x1a
+#define TDA1004X_SNR 0x1c
+#define TDA1004X_REG1E 0x1e
+#define TDA1004X_REG1F 0x1f
+#define TDA1004X_CBER_RESET 0x20
+#define TDA1004X_CBER_MSB 0x21
+#define TDA1004X_CBER_LSB 0x22
+#define TDA1004X_CVBER_LUT 0x23
+#define TDA1004X_VBER_MSB 0x24
+#define TDA1004X_VBER_MID 0x25
+#define TDA1004X_VBER_LSB 0x26
+#define TDA1004X_UNCOR 0x27
+#define TDA1004X_CONFPLL_P 0x2D
+#define TDA1004X_CONFPLL_M_MSB 0x2E
+#define TDA1004X_CONFPLL_M_LSB 0x2F
+#define TDA1004X_CONFPLL_N 0x30
+#define TDA1004X_UNSURW_MSB 0x31
+#define TDA1004X_UNSURW_LSB 0x32
+#define TDA1004X_WREF_MSB 0x33
+#define TDA1004X_WREF_MID 0x34
+#define TDA1004X_WREF_LSB 0x35
+#define TDA1004X_MUXOUT 0x36
+#define TDA1004X_CONFADC2 0x37
+#define TDA1004X_IOFFSET 0x38
+
+#define dprintk if (tda1004x_debug) printk
+
+static struct dvb_frontend_info tda10045h_info = {
+ .name = "Philips TDA10045H",
+ .type = FE_OFDM,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .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 tda1004x_state {
+ u8 tda1004x_address;
+ u8 tuner_address;
+ u8 initialised:1;
+};
+#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} };
+static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
+
+static int errno;
+
+
+static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data)
+{
+ int ret;
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 };
+
+ dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
+
+ msg.addr = tda_state->tda1004x_address;
+ 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 tda1004x_read_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1},
+ { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}};
+
+ dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
+
+ msg[0].addr = tda_state->tda1004x_address;
+ msg[1].addr = tda_state->tda1004x_address;
+ 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 tda1004x_write_mask(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, 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 = tda1004x_read_byte(i2c, tda_state, reg);
+ if (val < 0)
+ return val;
+
+ // mask if off
+ val = val & ~mask;
+ val |= data & 0xff;
+
+ // write it out again
+ return tda1004x_write_byte(i2c, tda_state, reg, val);
+}
+
+static int tda1004x_write_buf(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, 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 = tda1004x_write_byte(i2c, tda_state, reg + i, buf[i]);
+ if (result != 0)
+ break;
+ }
+
+ return result;
+}
+
+static int tda1004x_enable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+{
+ int result;
+ dprintk("%s\n", __FUNCTION__);
+
+ result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2);
+ dvb_delay(1);
+ return result;
+}
+
+static int tda1004x_disable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+{
+
+ dprintk("%s\n", __FUNCTION__);
+
+ return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0);
+}
+
+
+static int tda10045h_set_bandwidth(struct dvb_i2c_bus *i2c,
+ struct tda1004x_state *tda_state,
+ fe_bandwidth_t bandwidth)
+{
+ static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
+ static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
+ static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
+
+ switch (bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14);
+ tda1004x_write_buf(i2c, tda_state, TDA1004X_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x80);
+ tda1004x_write_buf(i2c, tda_state, TDA1004X_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14);
+ tda1004x_write_buf(i2c, tda_state, TDA1004X_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_IOFFSET, 0);
+
+ // done
+ return 0;
+}
+
+
+static int tda1004x_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+{
+ u8 fw_buf[65];
+ struct i2c_msg fw_msg = {.addr = 0,.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 fd;
+ int fwinfo_idx;
+ int fw_size = 0;
+ int fw_pos;
+ int tx_size;
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ mm_segment_t fs = get_fs();
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // Load the firmware
+ set_fs(get_ds());
+ fd = open(tda1004x_firmware, 0, 0);
+ if (fd < 0) {
+ printk("%s: Unable to open firmware %s\n", __FUNCTION__,
+ tda1004x_firmware);
+ return -EIO;
+ }
+ filesize = lseek(fd, 0L, 2);
+ if (filesize <= 0) {
+ printk("%s: Firmware %s is empty\n", __FUNCTION__,
+ tda1004x_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__, tda1004x_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
+ tda1004x_enable_tuner_i2c(i2c, tda_state);
+ tuner_msg.addr = 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);
+ }
+ tda1004x_disable_tuner_i2c(i2c, tda_state);
+
+ // set some valid bandwith parameters
+ switch(tda_state->tda1004x_address) {
+ case TDA10045H_ADDRESS:
+ tda10045h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ);
+ break;
+ }
+ dvb_delay(500);
+
+ // do the firmware upload
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_FWPAGE, 0);
+ fw_msg.addr = tda_state->tda1004x_address;
+ 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] = TDA1004X_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
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x10, 0);
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_DSP_CMD, 0x67);
+ if ((tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA1) != 0x67) ||
+ (tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA2) != 0x2c)) {
+ printk("%s: firmware upload failed!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ // tda setup
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0x0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0);
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0x80);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0);
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_REG1E, 0);
+ tda1004x_write_byte(i2c, tda_state, TDA1004X_REG1F, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_VBER_MSB, 0xe0, 0xa0);
+
+ // done
+ return 0;
+}
+
+static int tda1004x_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 tda1004x_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 tda1004x_set_frequency(struct dvb_i2c_bus *i2c,
+ struct tda1004x_state *tda_state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+ int tuner_frequency;
+ u8 band, cp, filter;
+ int counter, counter2;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // setup the frequency buffer
+ switch (tda_state->tuner_address) {
+ case TD1344_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
+ tda1004x_enable_tuner_i2c(i2c, tda_state);
+ 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;
+ }
+ }
+ tda1004x_disable_tuner_i2c(i2c, tda_state);
+ break;
+
+ case TDM1316L_ADDRESS:
+ // determine charge pump
+ tuner_frequency = fe_params->frequency + 36130000;
+ if (tuner_frequency < 87000000) {
+ return -EINVAL;
+ } else if (tuner_frequency < 130000000) {
+ cp = 3;
+ } else if (tuner_frequency < 160000000) {
+ cp = 5;
+ } else if (tuner_frequency < 200000000) {
+ cp = 6;
+ } else if (tuner_frequency < 290000000) {
+ cp = 3;
+ } else if (tuner_frequency < 420000000) {
+ cp = 5;
+ } else if (tuner_frequency < 480000000) {
+ cp = 6;
+ } else if (tuner_frequency < 620000000) {
+ cp = 3;
+ } else if (tuner_frequency < 830000000) {
+ cp = 5;
+ } else if (tuner_frequency < 895000000) {
+ cp = 7;
+ } else {
+ return -EINVAL;
+ }
+
+ // determine band
+ if (fe_params->frequency < 49000000) {
+ return -EINVAL;
+ } else if (fe_params->frequency < 159000000) {
+ band = 1;
+ } else if (fe_params->frequency < 444000000) {
+ band = 2;
+ } else if (fe_params->frequency < 861000000) {
+ band = 4;
+ } else {
+ return -EINVAL;
+ }
+
+ // work out filter
+ switch (fe_params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ // 6 MHz isn't supported directly, but set this to
+ // the 8 MHz setting in case we can fiddle it later
+ filter = 1;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate tuner parameters
+ tuner_frequency =
+ (((fe_params->frequency / 1000) * 6) + 217280) / 1000;
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ // tune it
+ tda1004x_enable_tuner_i2c(i2c, tda_state);
+ tuner_msg.addr = tda_state->tuner_address;
+ tuner_msg.len = 4;
+ if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+ return -EIO;
+ }
+ dvb_delay(1);
+ tda1004x_disable_tuner_i2c(i2c, tda_state);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dprintk("%s: success\n", __FUNCTION__);
+
+ // done
+ return 0;
+}
+
+static int tda1004x_set_fe(struct dvb_i2c_bus *i2c,
+ struct tda1004x_state *tda_state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+
+ // set frequency
+ tmp = tda1004x_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)) {
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 1); // enable auto
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
+ } else {
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 0); // disable auto
+
+ // set HP FEC
+ tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
+ if (tmp < 0) return tmp;
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 7, tmp);
+
+ // set LP FEC
+ if (fe_params->u.ofdm.code_rate_LP != FEC_NONE) {
+ tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
+ if (tmp < 0) return tmp;
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
+ }
+
+ // set constellation
+ switch (fe_params->u.ofdm.constellation) {
+ case QPSK:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 0);
+ break;
+
+ case QAM_16:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 1);
+ break;
+
+ case QAM_64:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 2);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set hierarchy
+ switch (fe_params->u.ofdm.hierarchy_information) {
+ case HIERARCHY_NONE:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
+ break;
+
+ case HIERARCHY_1:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
+ break;
+
+ case HIERARCHY_2:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
+ break;
+
+ case HIERARCHY_4:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ // set bandwidth
+ switch(tda_state->tda1004x_address) {
+ case TDA10045H_ADDRESS:
+ tda10045h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
+ break;
+ }
+
+ // set inversion
+ switch (fe_params->inversion) {
+ case INVERSION_OFF:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0);
+ break;
+
+ case INVERSION_ON:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0x20);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set guard interval
+ switch (fe_params->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
+ break;
+
+ case GUARD_INTERVAL_1_16:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
+ break;
+
+ case GUARD_INTERVAL_1_8:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
+ break;
+
+ case GUARD_INTERVAL_1_4:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
+ break;
+
+ case GUARD_INTERVAL_AUTO:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 2);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set transmission mode
+ switch (fe_params->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
+ break;
+
+ case TRANSMISSION_MODE_8K:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
+ break;
+
+ case TRANSMISSION_MODE_AUTO:
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 4);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // reset DSP
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
+ dvb_delay(10);
+
+ // done
+ return 0;
+}
+
+
+static int tda1004x_get_fe(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params)
+{
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // inversion status
+ fe_params->inversion = INVERSION_OFF;
+ if (tda1004x_read_byte(i2c, tda_state, TDA1004X_CONFC1) & 0x20) {
+ fe_params->inversion = INVERSION_ON;
+ }
+
+ // bandwidth
+ switch (tda1004x_read_byte(i2c, tda_state, TDA1004X_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 =
+ tda1004x_decode_fec(tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) & 7);
+ fe_params->u.ofdm.code_rate_LP =
+ tda1004x_decode_fec((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) >> 3) & 7);
+
+ // constellation
+ switch (tda1004x_read_byte(i2c, tda_state, TDA1004X_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 (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x10) {
+ fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ }
+
+ // guard interval
+ switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_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 ((tda1004x_read_byte(i2c, tda_state, TDA1004X_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 tda1004x_read_status(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status)
+{
+ int status;
+ int cber;
+ int vber;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read status
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_STATUS_CD);
+ if (status == -1) {
+ return -EIO;
+ }
+
+ // decode
+ *fe_status = 0;
+ if (status & 4) *fe_status |= FE_HAS_SIGNAL;
+ if (status & 2) *fe_status |= FE_HAS_CARRIER;
+ if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+
+ // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
+ // is getting anything valid
+ if (!(*fe_status & FE_HAS_VITERBI)) {
+ // read the CBER
+ cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
+ if (cber == -1) return -EIO;
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
+ if (status == -1) return -EIO;
+ cber |= (status << 8);
+ tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
+
+ if (cber != 65535) {
+ *fe_status |= FE_HAS_VITERBI;
+ }
+ }
+
+ // if we DO have some valid VITERBI output, but don't already have SYNC
+ // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
+ if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
+ // read the VBER
+ vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB);
+ if (vber == -1) return -EIO;
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID);
+ if (status == -1) return -EIO;
+ vber |= (status << 8);
+ status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB);
+ if (status == -1) return -EIO;
+ vber |= ((status << 16) & 0x0f);
+ tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT);
+
+ // if RS has passed some valid TS packets, then we must be
+ // getting some SYNC bytes
+ if (vber < 16632) {
+ *fe_status |= FE_HAS_SYNC;
+ }
+ }
+
+ // success
+ dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status);
+ return 0;
+}
+
+static int tda1004x_read_signal_strength(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * signal)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read it
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SIGNAL_STRENGTH);
+ if (tmp < 0)
+ return -EIO;
+
+ // done
+ *signal = (tmp << 8) | tmp;
+ dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal);
+ return 0;
+}
+
+
+static int tda1004x_read_snr(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * snr)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read it
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SNR);
+ if (tmp < 0)
+ return -EIO;
+ if (tmp) {
+ tmp = 255 - tmp;
+ }
+
+ // done
+ *snr = ((tmp << 8) | tmp);
+ dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
+ return 0;
+}
+
+static int tda1004x_read_ucblocks(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ucblocks)
+{
+ int tmp;
+ int tmp2;
+ int counter;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read the UCBLOCKS and reset
+ counter = 0;
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR);
+ if (tmp < 0)
+ return -EIO;
+ tmp &= 0x7f;
+ while (counter++ < 5) {
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
+ tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
+
+ tmp2 = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR);
+ if (tmp2 < 0)
+ return -EIO;
+ tmp2 &= 0x7f;
+ if ((tmp2 < tmp) || (tmp2 == 0))
+ break;
+ }
+
+ // done
+ if (tmp != 0x7f) {
+ *ucblocks = tmp;
+ } else {
+ *ucblocks = 0xffffffff;
+ }
+ dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
+ return 0;
+}
+
+static int tda1004x_read_ber(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ber)
+{
+ int tmp;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // read it in
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
+ if (tmp < 0) return -EIO;
+ *ber = tmp << 1;
+ tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
+ if (tmp < 0) return -EIO;
+ *ber |= (tmp << 9);
+ tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
+
+ // done
+ dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
+ return 0;
+}
+
+
+static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+ int status = 0;
+ struct dvb_i2c_bus *i2c = fe->i2c;
+ struct tda1004x_state *tda_state = (struct tda1004x_state *) &(fe->data);
+
+ dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd);
+
+ switch (cmd) {
+ case FE_GET_INFO:
+ switch(tda_state->tda1004x_address) {
+ case TDA10045H_ADDRESS:
+ memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info));
+ break;
+ }
+ break;
+
+ case FE_READ_STATUS:
+ return tda1004x_read_status(i2c, tda_state, (fe_status_t *) arg);
+
+ case FE_READ_BER:
+ return tda1004x_read_ber(i2c, tda_state, (u32 *) arg);
+
+ case FE_READ_SIGNAL_STRENGTH:
+ return tda1004x_read_signal_strength(i2c, tda_state, (u16 *) arg);
+
+ case FE_READ_SNR:
+ return tda1004x_read_snr(i2c, tda_state, (u16 *) arg);
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ return tda1004x_read_ucblocks(i2c, tda_state, (u32 *) arg);
+
+ case FE_SET_FRONTEND:
+ return tda1004x_set_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg);
+
+ case FE_GET_FRONTEND:
+ return tda1004x_get_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg);
+
+ case FE_INIT:
+ // don't bother reinitialising
+ if (tda_state->initialised)
+ return 0;
+
+ // OK, perform initialisation
+ status = tda1004x_init(i2c, tda_state);
+ if (status == 0)
+ tda_state->initialised = 1;
+ return status;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+
+static int tda1004x_attach(struct dvb_i2c_bus *i2c)
+{
+ int tda1004x_address = -1;
+ int tuner_address = -1;
+ struct tda1004x_state tda_state;
+ struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=0, .len=0 };
+ static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab };
+ static u8 tdm1316l_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+
+ dprintk("%s\n", __FUNCTION__);
+
+ // probe for frontend
+ tda_state.tda1004x_address = TDA10045H_ADDRESS;
+ if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x25) {
+ tda1004x_address = TDA10045H_ADDRESS;
+ printk("tda1004x: Detected Philips TDA10045H.\n");
+ }
+
+ // did we find a frontend?
+ if (tda1004x_address == -1) {
+ return -ENODEV;
+ }
+
+ // supported tuner?
+ tda1004x_enable_tuner_i2c(i2c, &tda_state);
+ tuner_msg.addr = TD1344_ADDRESS;
+ tuner_msg.buf = td1344_init;
+ tuner_msg.len = sizeof(td1344_init);
+ if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+ dvb_delay(1);
+ tuner_address = TD1344_ADDRESS;
+ printk("tda1004x: Detected Philips TD1344 tuner. PLEASE CHECK THIS AND REPORT BACK!.\n");
+ } else {
+ tuner_msg.addr = TDM1316L_ADDRESS;
+ tuner_msg.buf = tdm1316l_init;
+ tuner_msg.len = sizeof(tdm1316l_init);
+ if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+ dvb_delay(1);
+ tuner_address = TDM1316L_ADDRESS;
+ printk("tda1004x: Detected Philips TDM1316L tuner.\n");
+ }
+ }
+ tda1004x_disable_tuner_i2c(i2c, &tda_state);
+
+ // did we find a tuner?
+ if (tuner_address == -1) {
+ printk("tda1004x: Detected, but with unknown tuner.\n");
+ return -ENODEV;
+ }
+
+ // create state
+ tda_state.tda1004x_address = tda1004x_address;
+ tda_state.tuner_address = tuner_address;
+ tda_state.initialised = 0;
+
+ // register
+ switch(tda_state.tda1004x_address) {
+ case TDA10045H_ADDRESS:
+ dvb_register_frontend(tda1004x_ioctl, i2c, (void *)(*((u32*) &tda_state)), &tda10045h_info);
+ break;
+ }
+
+ // success
+ return 0;
+}
+
+
+static
+void tda1004x_detach(struct dvb_i2c_bus *i2c)
+{
+ dprintk("%s\n", __FUNCTION__);
+
+ dvb_unregister_frontend(tda1004x_ioctl, i2c);
+}
+
+
+static
+int __init init_tda1004x(void)
+{
+ return dvb_register_i2c_device(THIS_MODULE, tda1004x_attach, tda1004x_detach);
+}
+
+
+static
+void __exit exit_tda1004x(void)
+{
+ dvb_unregister_i2c_device(tda1004x_attach);
+}
+
+module_init(init_tda1004x);
+module_exit(exit_tda1004x);
+
+MODULE_DESCRIPTION("Philips TDA10045H DVB-T Frontend");
+MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(tda1004x_debug, "i");
+MODULE_PARM_DESC(tda1004x_debug, "enable verbose debug messages");
+
+MODULE_PARM(tda1004x_firmware, "s");
+MODULE_PARM_DESC(tda1004x_firmware, "Where to find the firmware file");
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.6.0-test1.patch/drivers/media/dvb/dvb-core/dvb_demux.c
--- linux-2.6.0-test1.work/drivers/media/dvb/dvb-core/dvb_demux.c 2003-07-15 10:59:30.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/dvb-core/dvb_demux.c 2003-07-04 11:46:12.000000000 +0200
@@ -403,13 +404,16 @@
{
int p = 0,i, j;
+ spin_lock(&demux->lock);
+
if ((i = demux->tsbufp)) {
if (count < (j=188-i)) {
memcpy(&demux->tsbuf[i], buf, count);
demux->tsbufp += count;
- return;
+ goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
+ if (demux->tsbuf[0] == 0x47)
dvb_dmx_swfilter_packet(demux, demux->tsbuf);
demux->tsbufp = 0;
p += j;
@@ -424,11 +428,14 @@
i = count-p;
memcpy(demux->tsbuf, buf+p, i);
demux->tsbufp=i;
- return;
+ goto bailout;
}
} else
p++;
}
+
+bailout:
+ spin_unlock(&demux->lock);
}
@@ -1030,9 +1051,11 @@
if (down_interruptible (&dvbdemux->mutex))
return -ERESTARTSYS;
-
dvb_dmx_swfilter(dvbdemux, buf, count);
up(&dvbdemux->mutex);
+
+ if (signal_pending(current))
+ return -EINTR;
return count;
}
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/dvb-core/dvb_net.c linux-2.6.0-test1.patch/drivers/media/dvb/dvb-core/dvb_net.c
--- linux-2.6.0-test1.work/drivers/media/dvb/dvb-core/dvb_net.c 2003-07-15 10:59:32.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/dvb-core/dvb_net.c 2003-06-29 10:21:16.000000000 +0200
@@ -57,7 +57,8 @@
#define RX_MODE_MULTI 1
#define RX_MODE_ALL_MULTI 2
#define RX_MODE_PROMISC 3
- struct work_struct wq;
+ struct work_struct set_multicast_list_wq;
+ struct work_struct restart_net_feed_wq;
};
@@ -354,7 +361,7 @@
}
-static void tq_set_multicast_list (void *data)
+static void wq_set_multicast_list (void *data)
{
struct net_device *dev = data;
struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
@@ -393,7 +400,7 @@
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);
+ schedule_work(&priv->set_multicast_list_wq);
}
@@ -404,16 +411,28 @@
return 0;
}
-static int dvb_net_set_mac(struct net_device *dev, void *p)
-{
- struct sockaddr *addr=p;
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+static void wq_restart_net_feed (void *data)
+{
+ struct net_device *dev = data;
if (netif_running(dev)) {
dvb_net_feed_stop(dev);
dvb_net_feed_start(dev);
}
+}
+
+
+static int dvb_net_set_mac (struct net_device *dev, void *p)
+{
+ struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
+ struct sockaddr *addr=p;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ if (netif_running(dev))
+ schedule_work(&priv->restart_net_feed_wq);
+
return 0;
}
@@ -493,10 +514,8 @@
net=&dvbnet->device[if_num];
demux=dvbnet->demux;
- net->base_addr = 0;
- net->irq = 0;
- net->dma = 0;
- net->mem_start = 0;
+ memset(net, 0, sizeof(struct net_device));
+
memcpy(net->name, "dvb0_0", 7);
net->name[3] = dvbnet->dvbdev->adapter->num + '0';
net->name[5] = if_num + '0';
@@ -514,7 +533,8 @@
priv->pid = pid;
priv->rx_mode = RX_MODE_UNI;
- INIT_WORK(&priv->wq, tq_set_multicast_list, net);
+ INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
+ INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
net->base_addr = pid;
@@ -536,6 +556,7 @@
return -EBUSY;
dvb_net_stop(&dvbnet->device[num]);
+ flush_scheduled_work();
kfree(priv);
unregister_netdev(&dvbnet->device[num]);
dvbnet->state[num]=0;
[DVB] - fix DMX_GET_STC to get the msb right
[DVB] - follow changes in saa7146 driver core, separate some data for DVB-C and DVB-S cards
diff -uNrwB --new-file linux-2.6.0-test1.work/drivers/media/dvb/ttpci/av7110.c linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/av7110.c
--- linux-2.6.0-test1.work/drivers/media/dvb/ttpci/av7110.c 2003-07-15 10:59:54.000000000 +0200
+++ linux-2.6.0-test1.patch/drivers/media/dvb/ttpci/av7110.c 2003-07-07 13:28:54.000000000 +0200
@@ -3257,7 +3258,7 @@
DEB_EE(("av7110: fwstc = %04hx %04hx %04hx %04hx\n",
fwstc[0], fwstc[1], fwstc[2], fwstc[3]));
- *stc = (((uint64_t)fwstc[2] & 1) << 32) |
+ *stc = (((uint64_t)(~fwstc[2]) & 1) << 32) |
(((uint64_t)fwstc[1]) << 16) | ((uint64_t)fwstc[0]);
*base = 1;
@@ -4327,6 +4328,9 @@
{ 0, 0 }
};
+static struct saa7146_ext_vv av7110_vv_data_st;
+static struct saa7146_ext_vv av7110_vv_data_c;
+
static int av7110_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
{
struct av7110 *av7110 = NULL;
@@ -4344,7 +4348,16 @@
DEB_EE(("dev: %p, av7110: %p\n",dev,av7110));
- if (saa7146_vv_init(dev)) {
+ /* special case DVB-C: these cards have an analog tuner
+ plus need some special handling, so we have separate
+ saa7146_ext_vv data for these... */
+ if (dev->pci->subsystem_vendor == 0x110a) {
+ ret = saa7146_vv_init(dev, &av7110_vv_data_c);
+ } else {
+ ret = saa7146_vv_init(dev, &av7110_vv_data_st);
+ }
+
+ if ( 0 != ret) {
ERR(("cannot init capture device. skipping.\n"));
kfree(av7110);
return -1;
@@ -4689,10 +4702,10 @@
}
-static struct saa7146_ext_vv av7110_vv_data = {
+static struct saa7146_ext_vv av7110_vv_data_st = {
.inputs = 1,
.audios = 1,
- .capabilities = V4L2_CAP_TUNER,
+ .capabilities = 0,
.flags = SAA7146_EXT_SWAP_ODD_EVEN,
.stds = &standard[0],
@@ -4703,9 +4716,23 @@
.ioctl = av7110_ioctl,
};
+static struct saa7146_ext_vv av7110_vv_data_c = {
+ .inputs = 1,
+ .audios = 1,
+ .capabilities = V4L2_CAP_TUNER,
+ .flags = 0,
+
+ .stds = &standard[0],
+ .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
+ .std_callback = &std_callback,
+
+ .ioctls = &ioctls[0],
+ .ioctl = av7110_ioctl,
+};
+
+
static struct saa7146_extension av7110_extension = {
.name = "dvb\0",
- .ext_vv_data = &av7110_vv_data,
.module = THIS_MODULE,
.pci_tbl = &pci_tbl[0],
On Tue, Jul 15, 2003 at 02:20:57PM +0200, Michael Hunold wrote:
> +
> +/////////////////////////////////////////////////////////////////////
> +// register functions
> +/////////////////////////////////////////////////////////////////////
> +
> +void WriteRegDW(struct adapter *adapter, u32 reg, u32 value)
Hm, this really isn't the proper Linux coding style. Please read
Documentation/CodingStyle on how to name functions.
> +{
> + u32 flags;
flags has to be a unsigned long.
> +
> + save_flags(flags);
> + cli();
Huh? Did you even compile this on a SMP kernel on 2.5? (Hint, it will
not...) Please fix this up.
> +u32 ReadRegDW(struct adapter *adapter, u32 reg)
> +{
> + return readl(adapter->io_mem + reg);
> +}
Why? Why not just write the readl() function whereever you call
ReadRegDW?
> +/////////////////////////////////////////////////////////////////////
> +// I2C
> +////////////////////////////////////////////////////////////////////
> +
> +u32 i2cMainWriteForFlex2(struct adapter * adapter, u32 command, u8 * buf, u32 retries)
kernel functions traditionally return an int. A negative number if
there is an error, and 0 if there isn't.
Oh, any reason for not tying this to the existing i2c core?
Or is that done somewhere else?
thanks,
greg k-h
Hello Greg KH,
thanks for reviewing these patches.
>>+
>>+/////////////////////////////////////////////////////////////////////
>>+// register functions
>>+/////////////////////////////////////////////////////////////////////
>>+
>>+void WriteRegDW(struct adapter *adapter, u32 reg, u32 value)
>
>
> Hm, this really isn't the proper Linux coding style. Please read
> Documentation/CodingStyle on how to name functions.
Yes, I know. The code was imported from an external source, and the code
was kept mostly unchanged to keep syncing easier.
But with all the problems you mentioned, I'm now going to review the
code. I'll send an updated patch later.
>>+{
>>+ u32 flags;
>
>
> flags has to be a unsigned long.
Yes.
>
>
>>+
>>+ save_flags(flags);
>>+ cli();
>
>
> Huh? Did you even compile this on a SMP kernel on 2.5? (Hint, it will
> not...) Please fix this up.
OMG. I'm sorry for having submitted something like this. It was not
tested by me, no. I'll fix it and test compiling for SMP.
>
>
>>+u32 ReadRegDW(struct adapter *adapter, u32 reg)
>>+{
>>+ return readl(adapter->io_mem + reg);
>>+}
>
>
> Why? Why not just write the readl() function whereever you call
> ReadRegDW?
I don't want to defend the original author, but perhaps these functions
were copy&pasted from a Windoze driver.
>>+/////////////////////////////////////////////////////////////////////
>>+// I2C
>>+////////////////////////////////////////////////////////////////////
>>+
>>+u32 i2cMainWriteForFlex2(struct adapter * adapter, u32 command, u8 * buf, u32 retries)
>
>
> kernel functions traditionally return an int. A negative number if
> there is an error, and 0 if there isn't.
I'll review it.
> Oh, any reason for not tying this to the existing i2c core?
> Or is that done somewhere else?
No. I2C is used by all devices at least to access the different
chipsets that make up the tuning.
In former times, the project had a hard time getting tuning to work in a
reliable way, because some of these chipsets are particularly picky when
it comes to timing and expect messages in a fixed form. Especially
probing of other i2c devices was a problem, which locked up the i2c bus
often.
I know that an class field for i2c adapters exists now and that i2c
clients can check if they want to probe that bus at all now.
The DVB core is quite self contained and we decided to copy the i2c
functionality needed for our purposes. So we ended up in using about 100
lines of code instead of the whole i2c core.
Now that you have finished improving the i2c core, perhaps we can switch
back to the kernel i2c system at a later time.
> thanks,
>
> greg k-h
CU
Michael.
On Wed, Jul 16, 2003 at 09:41:45AM +0200, Michael Hunold wrote:
>
> The DVB core is quite self contained and we decided to copy the i2c
> functionality needed for our purposes. So we ended up in using about 100
> lines of code instead of the whole i2c core.
>
> Now that you have finished improving the i2c core, perhaps we can switch
> back to the kernel i2c system at a later time.
Please, that would help reduce the number of times the i2c code has been
copied around :)
thanks,
greg k-h