From 3e06aadaa9965a951c0b0e322655f3ecd46be8e1 Mon Sep 17 00:00:00 2001 From: kpfleming Date: Mon, 22 Aug 2005 15:32:55 +0000 Subject: backport all fixes from HEAD git-svn-id: http://svn.digium.com/svn/zaptel/branches/v1-0@743 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wct4xxp.c | 141 +++++++++++++++++++++++++++++++++++--------------------------- 1 file 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;ynumbufs;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;xpvt; 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;ivpm = 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); - -- cgit v1.2.3