summaryrefslogtreecommitdiff
path: root/wct4xxp_base.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-06-19 14:34:05 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-06-19 14:34:05 +0000
commit6446efb93dc10bb2d42fd664480fc1c8b8b0e456 (patch)
tree422ddc80377b61d6b7e3107c376d5d7e82b3de01 /wct4xxp_base.c
parent790db3fbe391a9147a1de81e9877c8a8640bd4f6 (diff)
Merge the giant mess that is the Octasic API
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@1117 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'wct4xxp_base.c')
-rw-r--r--wct4xxp_base.c380
1 files changed, 347 insertions, 33 deletions
diff --git a/wct4xxp_base.c b/wct4xxp_base.c
index 31de0ca..17f76be 100644
--- a/wct4xxp_base.c
+++ b/wct4xxp_base.c
@@ -44,6 +44,7 @@
#include <linux/moduleparam.h>
#endif
#include "wct4xxp.h"
+#include "vpm450m.h"
/*
* Tasklets provide better system interactive response at the cost of the
@@ -170,14 +171,14 @@ static inline int t4_queue_work(struct workqueue_struct *wq, struct work_struct
static int debug=0;
static int timingcable = 0;
static int highestorder;
-static int t1e1override = -1;
+static int t1e1override = 0x00; //0xFF; // -1 = jumper; 0xFF = E1
static int j1mode = 0;
static int sigmode = FRMR_MODE_NO_ADDR_CMP;
static int loopback = 0;
static int alarmdebounce = 0;
#ifdef VPM_SUPPORT
static int vpmsupport = 1;
-static int vpmdtmfsupport = 1;
+static int vpmdtmfsupport = 0;
static int vpmspans = 4;
#define VPM_DEFAULT_DTMFTHRESHOLD 1000
static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
@@ -211,6 +212,8 @@ static int altab[] = {
#define FLAG_2NDGEN (1 << 3)
#define FLAG_2PORT (1 << 4)
#define FLAG_VPM2GEN (1 << 5)
+#define FLAG_OCTOPT (1 << 6)
+#define FLAG_3RDGEN (1 << 7)
#define CANARY 0xc0de
@@ -220,8 +223,12 @@ struct devtype {
};
static struct devtype wct4xxp = { "Wildcard TE410P/TE405P (1st Gen)", 0 };
+static struct devtype wct410p3 = { "Wildcard TE410P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN };
+static struct devtype wct405p3 = { "Wildcard TE405P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN };
static struct devtype wct410p2 = { "Wildcard TE410P (2nd Gen)", FLAG_2NDGEN };
static struct devtype wct405p2 = { "Wildcard TE405P (2nd Gen)", FLAG_2NDGEN };
+static struct devtype wct205p3 = { "Wildcard TE205P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT };
+static struct devtype wct210p3 = { "Wildcard TE210P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT };
static struct devtype wct205 = { "Wildcard TE205P ", FLAG_2NDGEN | FLAG_2PORT };
static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT };
@@ -299,6 +306,8 @@ struct t4 {
int flags; /* Device flags */
int master; /* Are we master */
int ledreg; /* LED Register */
+ unsigned int gpio;
+ unsigned int gpioctl;
int stopdma; /* Set to stop DMA */
unsigned int dmactrl;
int e1recover; /* E1 recovery timer */
@@ -330,13 +339,15 @@ struct t4 {
char *variety;
int last0; /* for detecting double-missed IRQ */
int checktiming; /* Set >0 to cause the timing source to be checked */
+ struct vpm450m *vpm450m;
};
#define T4_VPM_PRESENT (1 << 28)
#ifdef VPM_SUPPORT
-static void t4_vpm_init(struct t4 *wc);
+static void t4_vpm400_init(struct t4 *wc);
+static void t4_vpm450_init(struct t4 *wc);
static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold);
#endif
static void __set_clear(struct t4 *wc, int span);
@@ -367,6 +378,9 @@ static void __t4_check_sigbits(struct t4 *wc, int span);
#define WC_GPIO 9
#define WC_LADDR 10
#define WC_LDATA 11
+#define WC_LCS (1 << 11)
+#define WC_LCS2 (1 << 12)
+#define WC_LALE (1 << 13)
#define WC_LFRMR_CS (1 << 10) /* Framer's ChipSelect signal */
#define WC_ACTIVATE (1 << 12)
#define WC_LREAD (1 << 15)
@@ -417,6 +431,44 @@ static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const un
#endif
}
+static inline void __t4_gpio_set(struct t4 *wc, unsigned bits, unsigned int val)
+{
+ unsigned int newgpio;
+ newgpio = wc->gpio & (~bits);
+ newgpio |= val;
+ if (newgpio != wc->gpio) {
+ wc->gpio = newgpio;
+ __t4_pci_out(wc, WC_GPIO, wc->gpio);
+ }
+}
+
+static inline void __t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val)
+{
+ unsigned int newgpioctl;
+ newgpioctl = wc->gpioctl & (~bits);
+ newgpioctl |= val;
+ if (newgpioctl != wc->gpioctl) {
+ wc->gpioctl = newgpioctl;
+ __t4_pci_out(wc, WC_GPIOCTL, wc->gpioctl);
+ }
+}
+
+static inline void t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_gpio_setdir(wc, bits, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void t4_gpio_set(struct t4 *wc, unsigned int bits, unsigned int val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_gpio_set(wc, bits, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
static inline void t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
{
unsigned long flags;
@@ -521,6 +573,80 @@ static inline unsigned int __t4_vpm_in(struct t4 *wc, int unit, const unsigned i
return ret & 0xff;
}
+static inline void __t4_raw_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
+{
+ int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
+ if (!octopt)
+ __t4_gpio_set(wc, 0xff, (addr >> 8));
+ __t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
+ if (!octopt)
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE));
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE));
+ if (!octopt)
+ __t4_gpio_set(wc, 0xff, (value >> 8));
+ __t4_pci_out(wc, WC_LDATA, (value & 0xffff));
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE | WC_LCS));
+ __t4_pci_out(wc, WC_LADDR, (0));
+}
+
+static inline unsigned int __t4_raw_oct_in(struct t4 *wc, const unsigned int addr)
+{
+ unsigned int ret;
+ int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
+ if (!octopt)
+ __t4_gpio_set(wc, 0xff, (addr >> 8));
+ __t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
+ if (!octopt)
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE));
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE));
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ __t4_pci_out(wc, WC_LADDR, (WC_LALE));
+#endif
+ if (!octopt) {
+ __t4_gpio_setdir(wc, 0xff, 0x00);
+ __t4_gpio_set(wc, 0xff, 0x00);
+ }
+ __t4_pci_out(wc, WC_LADDR, (WC_LREAD | WC_LALE | WC_LCS));
+ if (octopt) {
+ ret = __t4_pci_in(wc, WC_LDATA) & 0xffff;
+ } else {
+ ret = __t4_pci_in(wc, WC_LDATA) & 0xff;
+ ret |= (__t4_pci_in(wc, WC_GPIO) & 0xff) << 8;
+ }
+ __t4_pci_out(wc, WC_LADDR, (0));
+ if (!octopt)
+ __t4_gpio_setdir(wc, 0xff, 0xff);
+ return ret & 0xffff;
+}
+
+static inline unsigned int __t4_oct_in(struct t4 *wc, unsigned int addr)
+{
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ int count = 1000;
+#endif
+ __t4_raw_oct_out(wc, 0x0008, (addr >> 20));
+ __t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1));
+ __t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (1));
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count);
+ if (count != 1000)
+ printk("Yah, read can be slow...\n");
+ if (!count)
+ printk("Read timed out!\n");
+#endif
+ return __t4_raw_oct_in(wc, 0x0004);
+}
+
+static inline unsigned int t4_oct_in(struct t4 *wc, const unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int ret;
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = __t4_oct_in(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
static inline unsigned int t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr)
{
unsigned long flags;
@@ -555,6 +681,32 @@ static inline void __t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr
#endif
}
+static inline void __t4_oct_out(struct t4 *wc, unsigned int addr, unsigned int value)
+{
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ int count = 1000;
+#endif
+ __t4_raw_oct_out(wc, 0x0008, (addr >> 20));
+ __t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1));
+ __t4_raw_oct_out(wc, 0x0004, value);
+ __t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1);
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count);
+ if (count != 1000)
+ printk("Yah, write can be slow\n");
+ if (!count)
+ printk("Write timed out!\n");
+#endif
+}
+
+static inline void t4_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_oct_out(wc, addr, value);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
static inline void t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
{
unsigned long flags;
@@ -565,7 +717,49 @@ static inline void t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr,
static const char vpm_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', '*', '#'};
-static void __t4_check_vpm(struct t4 *wc, unsigned int newio)
+static void t4_check_vpm450(struct t4 *wc)
+{
+ int channel, tone, start, span;
+#if 0
+ /* There's no point checking the interrupt, it's pointless. */
+ vpm450m_checkirq(wc->vpm450m);
+#endif
+ while(vpm450m_getdtmf(wc->vpm450m, &channel, &tone, &start)) {
+ span = channel & 0x3;
+ channel >>= 2;
+ if (!wc->t1e1)
+ channel -= 5;
+ else
+ channel -= 1;
+ if (debug)
+ printk("Got tone %s of '%c' on channel %d of span %d\n",
+ (start ? "START" : "STOP"), tone, channel, span + 1);
+ if ((wc->tspans[span]->dtmfmask & (1 << channel)) && (tone != 'u')) {
+ if (start) {
+ /* The octasic is supposed to mute us, but... Yah, you
+ guessed it. */
+ if (wc->tspans[span]->dtmfmutemask & (1 << channel)) {
+ unsigned long flags;
+ struct zt_chan *chan = &wc->tspans[span]->span.chans[channel];
+ int y;
+ spin_lock_irqsave(&chan->lock, flags);
+ for (y=0;y<chan->numbufs;y++) {
+ if ((chan->inreadbuf > -1) && (chan->readidx[y]))
+ memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ wc->tspans[span]->dtmfactive |= (1 << channel);
+ zt_qevent_lock(&wc->tspans[span]->span.chans[channel], (ZT_EVENT_DTMFDOWN | tone));
+ } else {
+ wc->tspans[span]->dtmfactive &= ~(1 << channel);
+ zt_qevent_lock(&wc->tspans[span]->span.chans[channel], (ZT_EVENT_DTMFUP | tone));
+ }
+ }
+ }
+}
+
+static void __t4_check_vpm400(struct t4 *wc, unsigned int newio)
{
unsigned int digit, regval = 0;
unsigned int regbyte;
@@ -674,7 +868,7 @@ static void __hdlc_stop(struct t4 *wc, unsigned int span)
int i = 0;
if (debug & DEBUG_FRAMER) printk("Stopping HDLC controller on span %d\n", span+1);
-
+
/* Clear receive and transmit timeslots */
for (i = 0; i < 4; i++) {
__t4_framer_out(wc, span, FRMR_RTR_BASE + i, 0x00);
@@ -854,6 +1048,20 @@ static int t4_dacs(struct zt_chan *dst, struct zt_chan *src)
#ifdef VPM_SUPPORT
+void oct_set_reg(void *data, unsigned int reg, unsigned int val)
+{
+ struct t4 *wc = data;
+ t4_oct_out(wc, reg, val);
+}
+
+unsigned int oct_get_reg(void *data, unsigned int reg)
+{
+ struct t4 *wc = data;
+ unsigned int ret;
+ ret = t4_oct_in(wc, reg);
+ return ret;
+}
+
static int t4_vpm_unit(int span, int channel)
{
int unit = 0;
@@ -878,6 +1086,7 @@ static int t4_echocan(struct zt_chan *chan, int eclen)
struct t4 *wc = chan->pvt;
int channel;
int unit;
+
if (!wc->vpm)
return -ENODEV;
@@ -888,14 +1097,25 @@ static int t4_echocan(struct zt_chan *chan, int eclen)
channel = chan->chanpos;
else
channel = chan->chanpos + 4;
- unit = t4_vpm_unit(chan->span->offset, channel);
- if(debug & DEBUG_ECHOCAN)
- printk("echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length %d\n",
- wc->num, chan->chanpos, chan->span->offset, unit, channel, eclen);
- if (eclen)
- t4_vpm_out(wc,unit,channel,0x3e);
- else
- t4_vpm_out(wc,unit,channel,0x01);
+ if (wc->vpm450m) {
+ channel = channel << 2;
+ channel |= chan->span->offset;
+ if(debug & DEBUG_ECHOCAN)
+ printk("echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n",
+ wc->num, chan->chanpos, chan->span->offset, channel, eclen);
+ vpm450m_setec(wc->vpm450m, channel, eclen);
+// Mark msleep(10);
+// msleep(100); // longer test
+ } else {
+ unit = t4_vpm_unit(chan->span->offset, channel);
+ if(debug & DEBUG_ECHOCAN)
+ printk("echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length %d\n",
+ wc->num, chan->chanpos, chan->span->offset, unit, channel, eclen);
+ if (eclen)
+ t4_vpm_out(wc,unit,channel,0x3e);
+ else
+ t4_vpm_out(wc,unit,channel,0x01);
+ }
return 0;
}
#endif
@@ -907,6 +1127,7 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
struct t4 *wc = chan->pvt;
#ifdef VPM_SUPPORT
int j;
+ int channel;
struct t4_span *ts = wc->tspans[chan->span->offset];
#endif
@@ -944,6 +1165,13 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
ts->dtmfmutemask |= (1 << (chan->chanpos - 1));
else
ts->dtmfmutemask &= ~(1 << (chan->chanpos - 1));
+ if (wc->vpm450m) {
+ channel = (chan->chanpos) << 2;
+ if (!wc->t1e1)
+ channel += (4 << 2);
+ channel |= chan->span->offset;
+ vpm450m_setdtmf(wc->vpm450m, channel, j & ZT_TONEDETECT_ON, j & ZT_TONEDETECT_MUTE);
+ }
return 0;
#endif
default:
@@ -1135,7 +1363,7 @@ static int t4_shutdown(struct zt_span *span)
}
if (debug & DEBUG_MAIN) printk("Shutting down span %d (%s)\n", span->spanno, span->name);
-
+
spin_lock_irqsave(&wc->reglock, flags);
wasrunning = span->flags & ZT_FLAG_RUNNING;
@@ -1199,7 +1427,7 @@ static int t4_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
wc->tspans[lc->sync - 1]->psync = span->offset + 1;
}
wc->checktiming = 1;
-
+
/* If we're already running, then go ahead and apply the changes */
if (span->flags & ZT_FLAG_RUNNING)
return t4_startup(span);
@@ -1230,7 +1458,7 @@ static int t4_chanconfig(struct zt_chan *chan, int sigtype)
/* (re)configure signalling channel */
if ((sigtype == ZT_SIG_HARDHDLC) || (ts->sigchan == chan)) {
if (debug & DEBUG_FRAMER)
- printk("%sonfiguring hardware HDLC on %s\n", ((sigtype == ZT_SIG_HARDHDLC) ? "C" : "Unc"), chan->name);
+ printk("%sonfiguring hardware HDLC on %s\n", ((sigtype == ZT_SIG_HARDHDLC) ? "C" : "Unc"), chan->name);
if (alreadyrunning) {
if (ts->sigchan)
__hdlc_stop(wc, ts->sigchan->span->offset);
@@ -1243,6 +1471,7 @@ static int t4_chanconfig(struct zt_chan *chan, int sigtype)
}
else
ts->sigchan = NULL;
+
}
else {
ts->sigchan = (sigtype == ZT_SIG_HARDHDLC) ? chan : NULL;
@@ -1814,7 +2043,9 @@ static int t4_startup(struct zt_span *span)
#ifdef VPM_SUPPORT
if (!alreadyrunning && !wc->vpm) {
wait_a_little();
- t4_vpm_init(wc);
+ t4_vpm400_init(wc);
+ if (!wc->vpm)
+ t4_vpm450_init(wc);
wc->dmactrl |= wc->vpm;
t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
}
@@ -1942,11 +2173,13 @@ static inline void __receive_span(struct t4_span *ts)
#ifdef VPM_SUPPORT
int y;
unsigned int merged;
- if ((merged = ts->dtmfactive & ts->dtmfmutemask)) {
+ merged = ts->dtmfactive & ts->dtmfmutemask;
+ if (merged) {
for (y=0;y<ts->span.channels;y++) {
/* Mute any DTMFs which are supposed to be muted */
- if (merged & (1 << y))
+ if (merged & (1 << y)) {
memset(ts->span.chans[y].readchunk, ZT_XLAW(0, (ts->span.chans + y)), ZT_CHUNKSIZE);
+ }
}
}
#endif
@@ -2585,6 +2818,7 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
unsigned long flags;
unsigned char cis;
int x;
+ int needcheckvpm450=0;
unsigned int status;
#if 0
@@ -2599,17 +2833,18 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
inirq = 1;
/* Make sure it's really for us */
status = t4_pci_in(wc, WC_INTR);
-#if 1
+#if 1
t4_pci_out(wc, WC_INTR, status & 0x00000008);
#endif
/* Ignore if it's not for us */
- if (!(status & 0x7))
+ if (!(status & 0x7)) {
#ifdef LINUX26
return IRQ_NONE;
#else
return;
#endif
+ }
if (!wc->spansstarted) {
printk("Not prepped yet!\n");
@@ -2622,7 +2857,8 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
wc->intcount++;
#if 1
- if (wc->intcount < 20)
+ if ((wc->intcount < 20) && debug)
+
printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, __t4_framer_in(wc, 0, FRMR_CIS));
#endif
@@ -2687,7 +2923,7 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
}
#ifdef VPM_SUPPORT
if (wc->vpm) {
- if (!(wc->intcount % 16) && !(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) {
+ if (!wc->vpm450m && !(wc->intcount % 16) && !(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) {
/* Check DTMF events */
int span = (wc->intcount >> 4) & 0x3;
int y;
@@ -2724,8 +2960,16 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
}
}
}
+ }
+ if (wc->vpm450m) {
+ /* How stupid is it that the octasic can't generate an
+ interrupt when there's a tone, in spite of what their
+ documentation says? */
+ if (!(wc->intcount & 0xf)) {
+ needcheckvpm450 = 1;
+ }
} else if ((status & 0xff00) != 0xff00)
- __t4_check_vpm(wc, (status & 0xff00) >> 8);
+ __t4_check_vpm400(wc, (status & 0xff00) >> 8);
}
#endif
@@ -2746,6 +2990,11 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
}
spin_unlock_irqrestore(&wc->reglock, flags);
+ if (needcheckvpm450 && vpmdtmfsupport) {
+ t4_check_vpm450(wc);
+ needcheckvpm450 = 0;
+ }
+
#ifndef ENABLE_WORKQUEUES
t4_pci_out(wc, WC_INTR, 0);
#endif
@@ -2840,7 +3089,42 @@ static int t4_vpm_echotail(void)
return echotail;
}
-static void t4_vpm_init(struct t4 *wc)
+static void t4_vpm450_init(struct t4 *wc)
+{
+ unsigned int check1, check2;
+ int laws[4] = { 0, };
+ int x;
+ if (!vpmsupport) {
+ printk("VPM450M: Support Disabled\n");
+ return;
+ }
+ /* Turn on GPIO/DATA mux if supported */
+ t4_gpio_setdir(wc, (1 << 24), (1 << 24));
+ __t4_raw_oct_out(wc, 0x000a, 0x5678);
+ __t4_raw_oct_out(wc, 0x0004, 0x1234);
+ check1 = __t4_raw_oct_in(wc, 0x0004);
+ check2 = __t4_raw_oct_in(wc, 0x000a);
+ if (1 || debug)
+ printk("OCT Result: %04x/%04x\n", __t4_raw_oct_in(wc, 0x0004), __t4_raw_oct_in(wc, 0x000a));
+ if (__t4_raw_oct_in(wc, 0x0004) != 0x1234) {
+ printk("VPM450: Not Present\n");
+ return;
+ }
+ /* Setup alaw vs ulaw rules */
+ for (x=0;x<wc->numspans;x++) {
+ if (wc->tspans[x]->span.channels > 24)
+ laws[x] = 1;
+ }
+ if (!(wc->vpm450m = init_vpm450m(wc, laws))) {
+ printk("VPM450: Failed to initialize\n");
+ return;
+ }
+ wc->vpm = T4_VPM_PRESENT;
+ printk("VPM450: Present and operational servicing %d span(s)\n", vpmspans);
+
+}
+
+static void t4_vpm400_init(struct t4 *wc)
{
unsigned char reg;
unsigned int mask;
@@ -2848,7 +3132,7 @@ static void t4_vpm_init(struct t4 *wc)
unsigned int i, x, y, gen2vpm=0;
if (!vpmsupport) {
- printk("VPM: Support Disabled\n");
+ printk("VPM400M: Support Disabled\n");
return;
}
@@ -2869,18 +3153,18 @@ static void t4_vpm_init(struct t4 *wc)
ver = t4_vpm_in(wc, x, 0x1a0); /* revision */
if ((ver != 0x26) && (ver != 0x33)) {
- printk("VPM: %s\n", x ? "Inoperable" : "Not Present");
+ printk("VPM400: %s\n", x ? "Inoperable" : "Not Present");
return;
}
if (ver == 0x33) {
if (x && !gen2vpm) {
- printk("VPM: Inconsistent\n");
+ printk("VPM400: Inconsistent\n");
return;
}
ts->spanflags |= FLAG_VPM2GEN;
gen2vpm++;
} else if (gen2vpm) {
- printk("VPM: Inconsistent\n");
+ printk("VPM400: Inconsistent\n");
return;
}
@@ -2913,11 +3197,11 @@ static void t4_vpm_init(struct t4 *wc)
reg &= 0xE0;
if (ts->spantype == TYPE_E1) {
if (x < vpmspans)
- printk("VPM: Span %d A-law mode\n", spanno);
+ printk("VPM400: Span %d A-law mode\n", spanno);
reg |= 0x01;
} else {
if (x < vpmspans)
- printk("VPM: Span %d U-law mode\n", spanno);
+ printk("VPM400: Span %d U-law mode\n", spanno);
reg &= ~0x01;
}
t4_vpm_out(wc,x,0x20,(reg | 0x20));
@@ -2972,7 +3256,7 @@ static void t4_vpm_init(struct t4 *wc)
t4_vpm_out(wc, x, i, (x < 4) ? 0x55 : 0xAA);
}
- printk("VPM%s: Present and operational servicing %d span(s)\n", (gen2vpm ? "(2nd Gen)" : ""), vpmspans);
+ printk("VPM400%s: Present and operational servicing %d span(s)\n", (gen2vpm ? " (2nd Gen)" : ""), vpmspans);
wc->vpm = T4_VPM_PRESENT;
}
@@ -3076,6 +3360,10 @@ static int t4_hardware_init_2(struct t4 *wc)
int x;
unsigned int falcver;
+ if (t4_pci_in(wc, WC_VERSION) >= 0xc01a0165) {
+ wc->tspans[0]->spanflags |= FLAG_OCTOPT;
+ printk("Octasic optimized!\n");
+ }
/* Setup LEDS, take out of reset */
t4_pci_out(wc, WC_LEDS, 0x000000ff);
t4_activate(wc);
@@ -3308,6 +3596,21 @@ static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_i
}
printk("Found a Wildcard: %s\n", wc->variety);
+ wc->gpio = 0x00000000;
+ t4_pci_out(wc, WC_GPIO, wc->gpio);
+ t4_gpio_setdir(wc, (1 << 17), (1 << 17));
+ t4_gpio_setdir(wc, (0xff), (0xff));
+
+#if 0
+ for (x=0;x<0x10000;x++) {
+ __t4_raw_oct_out(wc, 0x0004, x);
+ __t4_raw_oct_out(wc, 0x000a, x ^ 0xffff);
+ if (__t4_raw_oct_in(wc, 0x0004) != x)
+ printk("Register 4 failed %04x\n", x);
+ if (__t4_raw_oct_in(wc, 0x000a) != (x ^ 0xffff))
+ printk("Register 10 failed %04x\n", x);
+ }
+#endif
res = 0;
} else
res = -ENOMEM;
@@ -3332,7 +3635,8 @@ static int t4_hardware_stop(struct t4 *wc)
}
t4_pci_out(wc, WC_RDADDR, 0x0000000);
t4_pci_out(wc, WC_WRADDR, 0x0000000);
- t4_pci_out(wc, WC_GPIO, 0x0000000);
+ wc->gpio = 0x00000000;
+ t4_pci_out(wc, WC_GPIO, wc->gpio);
t4_pci_out(wc, WC_LEDS, 0x00000000);
printk("\nStopped TE%dXXP, Turned off DMA\n", wc->numspans);
@@ -3347,6 +3651,10 @@ static void __devexit t4_remove_one(struct pci_dev *pdev)
/* Stop hardware */
t4_hardware_stop(wc);
+ /* Release vpm450m */
+ if (wc->vpm450m)
+ release_vpm450m(wc->vpm450m);
+ wc->vpm450m = NULL;
/* Unregister spans */
if (wc->tspans[0]->span.flags & ZT_FLAG_REGISTERED)
zt_unregister(&wc->tspans[0]->span);
@@ -3402,8 +3710,14 @@ static void __devexit t4_remove_one(struct pci_dev *pdev)
static struct pci_device_id t4_pci_tbl[] __devinitdata =
{
{ 0x10ee, 0x0314, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp },
+
+ { 0xd161, 0x0410, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p3 },
+ { 0xd161, 0x0405, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p3 },
{ 0xd161, 0x0410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p2 },
{ 0xd161, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p2 },
+
+ { 0xd161, 0x0205, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct205p3 },
+ { 0xd161, 0x0210, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p3 },
{ 0xd161, 0x0205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct205 },
{ 0xd161, 0x0210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct210 },
{ 0, }