summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-08-22 15:32:55 +0000
committerkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-08-22 15:32:55 +0000
commit3e06aadaa9965a951c0b0e322655f3ecd46be8e1 (patch)
tree203b80ee32c50cf96bcd33ba5db41b7041806305
parent28254b088c433860f83528ca33dc5b499feca182 (diff)
backport all fixes from HEAD
git-svn-id: http://svn.digium.com/svn/zaptel/branches/v1-0@743 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xwct4xxp.c141
1 files changed, 80 insertions, 61 deletions
diff --git a/wct4xxp.c b/wct4xxp.c
index 948e142..92bb889 100755
--- a/wct4xxp.c
+++ b/wct4xxp.c
@@ -56,7 +56,12 @@
/* Work queues are a way to better distribute load on SMP systems */
#ifdef LINUX26
-#define ENABLE_WORKQUEUES
+/*
+ * Work queues can significantly improve performance and scalability
+ * on multi-processor machines, but requires bypassing some kernel
+ * API's, so it's not guaranteed to be compatible with all kernels.
+ */
+/* #define ENABLE_WORKQUEUES */
#endif
/* Enable prefetching may help performance */
@@ -169,8 +174,15 @@ static int loopback = 0;
static int alarmdebounce = 0;
#ifdef VPM_SUPPORT
static int vpmsupport = 1;
-#endif
-static int noburst = 0;
+#define VPM_DEFAULT_DTMFTHRESHOLD 1000
+static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+static int lastdtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+#endif
+/* Enabling bursting can more efficiently utilize PCI bus bandwidth, but
+ can also cause PCI bus starvation, especially in combination with other
+ aggressive cards. Please note that burst mode has no effect on CPU
+ utilization / max number of calls / etc. */
+static int noburst = 1;
static int debugslips = 0;
static int polling = 0;
@@ -310,6 +322,7 @@ struct t4 {
#ifdef VPM_SUPPORT
static void t4_vpm_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);
static int t4_startup(struct zt_span *span);
@@ -523,9 +536,12 @@ static inline void t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr,
spin_unlock_irqrestore(&wc->reglock, flags);
}
+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)
{
unsigned int digit, regval = 0;
+ unsigned int regbyte;
int x, i;
short energy;
static unsigned int lastio = 0;
@@ -541,27 +557,22 @@ static void __t4_check_vpm(struct t4 *wc, unsigned int newio)
continue;
ts = wc->tspans[x%4];
/* Start of DTMF detection process */
- regval = __t4_vpm_in(wc, x, 0xb8);
- __t4_vpm_out(wc, x, 0xb8, regval); /* Write 1 to clear */
- regval = regval << 8;
- regval |= __t4_vpm_in(wc, x, 0xb9);
- __t4_vpm_out(wc, x, 0xb9, regval & 0xff);
+ regbyte = __t4_vpm_in(wc, x, 0xb8);
+ __t4_vpm_out(wc, x, 0xb8, regbyte); /* Write 1 to clear */
+ regval = regbyte << 8;
+ regbyte = __t4_vpm_in(wc, x, 0xb9);
+ __t4_vpm_out(wc, x, 0xb9, regbyte);
+ regval |= regbyte;
for(i = 0; (i < MAX_DTMF_DET) && regval; i++) {
if(regval & 0x0001) {
int channel = (i << 1) + (x >> 2);
int base = channel - 1;
+
if (!wc->t1e1)
base -= 4;
- digit = __t4_vpm_in(wc, x, 0xa8 + i);
- if (digit < 10)
- digit += '0';
- else if (digit < 0xe)
- digit += 'A' - 0xe;
- else if (digit == 0xe)
- digit = '*';
- else if (digit == 0xf)
- digit = '#';
+ regbyte = __t4_vpm_in(wc, x, 0xa8 + i);
+ digit = vpm_digits[regbyte];
energy = __t4_vpm_in(wc, x, 0x58 + channel);
energy = ZT_XLAW(energy, ts->chans);
ts->dtmfactive |= (1 << base);
@@ -571,10 +582,6 @@ static void __t4_check_vpm(struct t4 *wc, unsigned int newio)
zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFUP | ts->dtmfdigit[base]));
}
ts->dtmfdigit[base] = digit;
- if (ts->dtmfdigit[base]) {
- if (ts->dtmfmask & (1 << base))
- zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFUP | ts->dtmfdigit[base]));
- }
if (ts->dtmfmask & (1 << base))
zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFDOWN | digit));
if (ts->dtmfmutemask & (1 << base)) {
@@ -584,7 +591,7 @@ static void __t4_check_vpm(struct t4 *wc, unsigned int newio)
int y;
spin_lock_irqsave(&chan->lock, flags);
for (y=0;y<chan->numbufs;y++) {
- if (chan->readidx[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);
@@ -719,9 +726,17 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
struct t4_span *ts = wc->tspans[chan->span->offset];
#endif
+#ifdef VPM_SUPPORT
+ if (dtmfthreshold == 0)
+ dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+ if (lastdtmfthreshold != dtmfthreshold) {
+ lastdtmfthreshold = dtmfthreshold;
+ t4_vpm_set_dtmf_threshold(wc, dtmfthreshold);
+ }
+#endif
+
switch(cmd) {
case WCT4_GET_REGS:
- wc = chan->pvt;
for (x=0;x<NUM_PCI;x++)
regs.pci[x] = t4_pci_in(wc, x);
for (x=0;x<NUM_REGS;x++)
@@ -737,7 +752,6 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
case ZT_TONEDETECT:
if (get_user(j, (int *)data))
return -EFAULT;
- wc = chan->pvt;
if (!wc->vpm)
return -ENOSYS;
if (j & ZT_TONEDETECT_ON)
@@ -2283,25 +2297,36 @@ static int t4_reset_dma(struct t4 *wc)
#endif
#ifdef VPM_SUPPORT
+static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold)
+{
+ unsigned int x;
+
+ for (x = 0; x < 8; x++) {
+ t4_vpm_out(wc, x, 0xC4, (threshold >> 8) & 0xFF);
+ t4_vpm_out(wc, x, 0xC5, (threshold & 0xFF));
+ }
+ printk("VPM: DTMF threshold set to %d\n", threshold);
+}
+
static void t4_vpm_init(struct t4 *wc)
{
unsigned char reg;
unsigned int mask;
unsigned int ver;
- int i,x,y;
+ unsigned int i, x, y;
+
if (!vpmsupport) {
printk("VPM: Support Disabled\n");
return;
}
for (x=0;x<8;x++) {
- struct t4_span *ts = wc->tspans[x & 0x3];
+ int spanno = x & 0x3;
+ struct t4_span *ts = wc->tspans[spanno];
+
ver = t4_vpm_in(wc, x, 0x1a0); /* revision */
if (ver != 0x26) {
- if (x)
- printk("VPM: Inopperable\n");
- else
- printk("VPM: Not Present\n");
+ printk("VPM: %s\n", x ? "Inoperable" : "Not Present");
return;
}
@@ -2317,36 +2342,33 @@ static void t4_vpm_init(struct t4 *wc)
t4_vpm_out(wc, x, 0x1a3, reg & ~2);
/* Setup timeslots */
- t4_vpm_out(wc, x, 0x02f, 0x20 | ((x%4) << 3));
- if (x < 4)
- mask = 0x55555555;
- else
- mask = 0xaaaaaaaa;
+ t4_vpm_out(wc, x, 0x02f, 0x20 | (spanno << 3));
/* Setup Echo length (128 taps) */
t4_vpm_out(wc, x, 0x022, 0x00);
t4_vpm_out(wc, x, 0x023, 0x7f);
- /* Setup the tdm channel masks for all LV's*/
- for (i=0;i<4;i++)
- t4_vpm_out(wc, x, 0x30+i, (mask >> (i << 3)) & 0xff);
+ /* Setup the tdm channel masks for all chips*/
+ mask = (x < 4) ? 0x55555555 : 0xaaaaaaaa;
+ for (i = 0; i < 4; i++)
+ t4_vpm_out(wc, x, 0x30 + i, (mask >> (i << 3)) & 0xff);
/* Setup convergence rate */
reg = t4_vpm_in(wc,x,0x20);
reg &= 0xE0;
if (ts->spantype == TYPE_E1) {
if (x < 4)
- printk("VPM: Span %d A-law mode\n", x & 0x3);
+ printk("VPM: Span %d A-law mode\n", spanno);
reg |= 0x01;
} else {
if (x < 4)
- printk("VPM: Span %d U-law mode\n", x & 0x3);
+ printk("VPM: Span %d U-law mode\n", spanno);
reg &= ~0x01;
}
t4_vpm_out(wc,x,0x20,(reg | 0x20));
/* Initialize echo cans */
- for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+ for (i = 0 ; i < MAX_TDM_CHAN; i++) {
if (mask & (0x00000001 << i))
t4_vpm_out(wc,x,i,0x00);
}
@@ -2366,25 +2388,21 @@ static void t4_vpm_init(struct t4 *wc)
t4_vpm_out(wc,x,0x78 + i,0x01);
}
- /* Enable DTMF detectors */
- for (i=0;i<MAX_DTMF_DET;i++) {
- if(x < 4)
- t4_vpm_out(wc, x, 0x98+i,(i*2)|0x40);
- else
- t4_vpm_out(wc, x, 0x98+i, ((i*2)+1)|0x40);
- }
- for (i=0xb8;i<0xbe;i++)
- t4_vpm_out(wc, x, i, 0xff);
- if(x < 4) {
- for(i=0;i<4;i++)
- t4_vpm_out(wc, x, 0xc0+i, 0x55);
- } else {
- for(i = 0; i < 4; i++)
- t4_vpm_out(wc, x, 0xc0+i, 0xaa);
+ /* set DTMF detection threshold */
+ t4_vpm_set_dtmf_threshold(wc, dtmfthreshold);
+
+ /* Enable DTMF detectors */
+ for (i = 0; i < MAX_DTMF_DET; i++) {
+ t4_vpm_out(wc, x, 0x98 + i, 0x40 | (i * 2) | ((x < 4) ? 0 : 1));
}
- }
- printk("VPM: Present and operational\n");
- wc->vpm = T4_VPM_PRESENT;
+ for (i = 0xB8; i < 0xBE; i++)
+ t4_vpm_out(wc, x, i, 0xFF);
+ for (i = 0xC0; i < 0xC4; i++)
+ t4_vpm_out(wc, x, i, (x < 4) ? 0x55 : 0xAA);
+
+ }
+ printk("VPM: Present and operational\n");
+ wc->vpm = T4_VPM_PRESENT;
}
#endif
@@ -2851,7 +2869,7 @@ static void __exit t4_cleanup(void)
MODULE_AUTHOR("Mark Spencer");
-MODULE_DESCRIPTION("Unified TE4XXP/TE2XXP PCI Driver");
+MODULE_DESCRIPTION("Unified TE4XXP-TE2XXP PCI Driver");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
@@ -2867,6 +2885,7 @@ module_param(alarmdebounce, int, 0600);
module_param(j1mode, int, 0600);
#ifdef VPM_SUPPORT
module_param(vpmsupport, int, 0600);
+module_param(dtmfthreshold, int, 0600);
#endif
#else
MODULE_PARM(debug, "i");
@@ -2880,6 +2899,7 @@ MODULE_PARM(alarmdebounce, "i");
MODULE_PARM(j1mode, "i");
#ifdef VPM_SUPPORT
MODULE_PARM(vpmsupport, "i");
+MODULE_PARM(dtmfthreshold, "i");
#endif
#endif
@@ -2887,4 +2907,3 @@ MODULE_DEVICE_TABLE(pci, t4_pci_tbl);
module_init(t4_init);
module_exit(t4_cleanup);
-