summaryrefslogtreecommitdiff
path: root/kernel/wctdm24xxp/base.c
diff options
context:
space:
mode:
authorsruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-03-27 21:17:46 +0000
committersruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-03-27 21:17:46 +0000
commitcd81703764c4d2884c60f3632f15d5bfc44dc31d (patch)
tree93046f7721e2be48425642d4902bafe1ffee47f6 /kernel/wctdm24xxp/base.c
parenta15be82083adbbc27fe2c5b8ce648f14b6eb93d3 (diff)
- Updated wctdm24xxp and wcte12xp driver which are now more tolerant of
systems which do not exhibit good real-time characteristics. - Bringing in improvements to battery alarm generation that was on kpflemings battery_alarms branch. (Issue #12099) git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4096 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/wctdm24xxp/base.c')
-rw-r--r--kernel/wctdm24xxp/base.c1057
1 files changed, 315 insertions, 742 deletions
diff --git a/kernel/wctdm24xxp/base.c b/kernel/wctdm24xxp/base.c
index bd47e23..ca53fa9 100644
--- a/kernel/wctdm24xxp/base.c
+++ b/kernel/wctdm24xxp/base.c
@@ -4,7 +4,7 @@
* Written by Mark Spencer <markster@digium.com>
* Support for TDM800P and VPM150M by Matthew Fredrickson <creslin@digium.com>
*
- * Copyright (C) 2005,2006, Digium, Inc.
+ * Copyright (C) 2005 - 2008 Digium, Inc.
* All rights reserved.
*
* Sections for QRV cards written by Jim Dixon <jim@lambdatel.com>
@@ -146,102 +146,11 @@ static int ectrans[4] = { 0, 1, 3, 2 };
enable for normal operation! */
/* #define PAQ_DEBUG */
-static struct fxo_mode {
- char *name;
- /* FXO */
- int ohs;
- int ohs2;
- int rz;
- int rt;
- int ilim;
- int dcv;
- int mini;
- int acim;
- int ring_osc;
- int ring_x;
-} fxo_modes[] =
-{
- { "FCC", 0, 0, 0, 1, 0, 0x3, 0, 0, }, /* US, Canada */
- { "TBR21", 0, 0, 0, 0, 1, 0x3, 0, 0x2, 0x7e6c, 0x023a, },
- /* Austria, Belgium, Denmark, Finland, France, Germany,
- Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands,
- Norway, Portugal, Spain, Sweden, Switzerland, and UK */
- { "ARGENTINA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "AUSTRALIA", 1, 0, 0, 0, 0, 0, 0x3, 0x3, },
- { "AUSTRIA", 0, 1, 0, 0, 1, 0x3, 0, 0x3, },
- { "BAHRAIN", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "BELGIUM", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "BRAZIL", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "BULGARIA", 0, 0, 0, 0, 1, 0x3, 0x0, 0x3, },
- { "CANADA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "CHILE", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "CHINA", 0, 0, 0, 0, 0, 0, 0x3, 0xf, },
- { "COLUMBIA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "CROATIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "CYRPUS", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "CZECH", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "DENMARK", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "ECUADOR", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "EGYPT", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "ELSALVADOR", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "FINLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "FRANCE", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "GERMANY", 0, 1, 0, 0, 1, 0x3, 0, 0x3, },
- { "GREECE", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "GUAM", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "HONGKONG", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "HUNGARY", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "ICELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "INDIA", 0, 0, 0, 0, 0, 0x3, 0, 0x4, },
- { "INDONESIA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "IRELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "ISRAEL", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "ITALY", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "JAPAN", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "JORDAN", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "KAZAKHSTAN", 0, 0, 0, 0, 0, 0x3, 0, },
- { "KUWAIT", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "LATVIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "LEBANON", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "LUXEMBOURG", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "MACAO", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "MALAYSIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, /* Current loop >= 20ma */
- { "MALTA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "MEXICO", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "MOROCCO", 0, 0, 0, 0, 1, 0x3, 0, 0x2, },
- { "NETHERLANDS", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "NEWZEALAND", 0, 0, 0, 0, 0, 0x3, 0, 0x4, },
- { "NIGERIA", 0, 0, 0, 0, 0x1, 0x3, 0, 0x2, },
- { "NORWAY", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "OMAN", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "PAKISTAN", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "PERU", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "PHILIPPINES", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "POLAND", 0, 0, 1, 1, 0, 0x3, 0, 0, },
- { "PORTUGAL", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "ROMANIA", 0, 0, 0, 0, 0, 3, 0, 0, },
- { "RUSSIA", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "SAUDIARABIA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "SINGAPORE", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "SLOVAKIA", 0, 0, 0, 0, 0, 0x3, 0, 0x3, },
- { "SLOVENIA", 0, 0, 0, 0, 0, 0x3, 0, 0x2, },
- { "SOUTHAFRICA", 1, 0, 1, 0, 0, 0x3, 0, 0x3, },
- { "SOUTHKOREA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "SPAIN", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "SWEDEN", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "SWITZERLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, },
- { "SYRIA", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "TAIWAN", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "THAILAND", 0, 0, 0, 0, 0, 0, 0x3, 0, },
- { "UAE", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "UK", 0, 1, 0, 0, 1, 0x3, 0, 0x5, },
- { "USA", 0, 0, 0, 0, 0, 0x3, 0, 0, },
- { "YEMEN", 0, 0, 0, 0, 0, 0x3, 0, 0, },
-};
-
#define DEBUG_CARD (1 << 0)
#define DEBUG_ECHOCAN (1 << 1)
+#include "fxo_modes.h"
+
struct wctdm_desc {
char *name;
int flags;
@@ -262,8 +171,9 @@ spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
static void wctdm_release(struct wctdm *wc);
static int fxovoltage = 0;
-static int battdebounce = DEFAULT_BATT_DEBOUNCE;
-static int battthresh = DEFAULT_BATT_THRESH;
+static unsigned int battdebounce;
+static unsigned int battalarm;
+static unsigned int battthresh;
static int debug = 0;
static int robust = 0;
static int lowpower = 0;
@@ -281,6 +191,7 @@ static int fxsrxgain = 0;
static int nativebridge = 0;
static int ringdebounce = DEFAULT_RING_DEBOUNCE;
static int fwringdetect = 0;
+static int latency = VOICEBUS_DEFAULT_LATENCY;
#ifdef VPM_SUPPORT
static int vpmsupport = 1;
static int vpmdtmfsupport = 0;
@@ -746,29 +657,26 @@ static inline void cmd_checkisr(struct wctdm *wc, int card)
}
}
-static inline void wctdm_transmitprep(struct wctdm *wc, int dbl)
+static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechunk)
{
- volatile unsigned char *writechunk;
int x,y;
- dbl = dbl % 2;
-
- writechunk = (volatile unsigned char *)(wc->writechunk);
- if (dbl)
- /* Write is at interrupt address. Start writing from normal offset */
- writechunk += SFRAME_SIZE;
-
/* Calculate Transmission */
- zt_transmit(&wc->span);
+ if (likely(wc->initialized)) {
+ zt_transmit(&wc->span);
+ }
for (x=0;x<ZT_CHUNKSIZE;x++) {
/* Send a sample, as a 32-bit word */
for (y=0;y < wc->cards;y++) {
- if (!x)
+ if (!x) {
cmd_checkisr(wc, y);
+ }
- if (y < wc->type)
- writechunk[y] = wc->chans[y].writechunk[x];
+ if (likely(wc->initialized)) {
+ if (y < wc->type)
+ writechunk[y] = wc->chans[y].writechunk[x];
+ }
cmd_dequeue(wc, writechunk, y, x);
}
#ifdef VPM_SUPPORT
@@ -776,8 +684,9 @@ static inline void wctdm_transmitprep(struct wctdm *wc, int dbl)
wc->blinktimer++;
if (wc->vpm) {
for (y=24;y<28;y++) {
- if (!x)
+ if (!x) {
cmd_checkisr(wc, y);
+ }
cmd_dequeue(wc, writechunk, y, x);
}
#ifdef FANCY_ECHOCAN
@@ -808,24 +717,6 @@ static inline void wctdm_transmitprep(struct wctdm *wc, int dbl)
}
}
-static inline void __wctdm_setctl(struct wctdm *wc, unsigned int addr, unsigned int val)
-{
- outl(val, wc->iobase + addr);
-}
-
-static inline unsigned int __wctdm_getctl(struct wctdm *wc, unsigned int addr)
-{
- return inl(wc->iobase + addr);
-}
-
-static inline void wctdm_setctl(struct wctdm *wc, unsigned int addr, unsigned int val)
-{
- unsigned long flags;
- spin_lock_irqsave(&wc->reglock, flags);
- __wctdm_setctl(wc, addr, val);
- spin_unlock_irqrestore(&wc->reglock, flags);
-}
-
static inline int wctdm_setreg_full(struct wctdm *wc, int card, int addr, int val, int inisr)
{
unsigned long flags;
@@ -902,96 +793,6 @@ static inline int wctdm_getreg(struct wctdm *wc, int card, int addr)
return ret;
}
-static inline unsigned int wctdm_getctl(struct wctdm *wc, unsigned int addr)
-{
- unsigned long flags;
- unsigned int val;
- spin_lock_irqsave(&wc->reglock, flags);
- val = __wctdm_getctl(wc, addr);
- spin_unlock_irqrestore(&wc->reglock, flags);
- return val;
-}
-
-static inline int __wctdm_sdi_clk(struct wctdm *wc)
-{
- unsigned int ret;
- wc->sdi &= ~SDI_CLK;
- __wctdm_setctl(wc, 0x0048, wc->sdi);
- ret = __wctdm_getctl(wc, 0x0048);
- wc->sdi |= SDI_CLK;
- __wctdm_setctl(wc, 0x0048, wc->sdi);
- return ret & SDI_DIN;
-}
-
-static inline void __wctdm_sdi_sendbits(struct wctdm *wc, unsigned int bits, int count)
-{
- wc->sdi &= ~SDI_DREAD;
- __wctdm_setctl(wc, 0x0048, wc->sdi);
- while(count--) {
- if (bits & (1 << count))
- wc->sdi |= SDI_DOUT;
- else
- wc->sdi &= ~SDI_DOUT;
- __wctdm_sdi_clk(wc);
- }
-}
-
-static inline unsigned int __wctdm_sdi_recvbits(struct wctdm *wc, int count)
-{
- unsigned int bits=0;
- wc->sdi |= SDI_DREAD;
- __wctdm_setctl(wc, 0x0048, wc->sdi);
- while(count--) {
- bits <<= 1;
- if (__wctdm_sdi_clk(wc))
- bits |= 1;
- else
- bits &= ~1;
- }
- return bits;
-}
-
-static inline void __wctdm_setsdi(struct wctdm *wc, unsigned char addr, unsigned short value)
-{
- unsigned int bits;
- /* Send preamble */
- bits = 0xffffffff;
- __wctdm_sdi_sendbits(wc, bits, 32);
- bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2;
- __wctdm_sdi_sendbits(wc, bits, 16);
- __wctdm_sdi_sendbits(wc, value, 16);
-
-}
-
-static inline unsigned short __wctdm_getsdi(struct wctdm *wc, unsigned char addr)
-{
- unsigned int bits;
- /* Send preamble */
- bits = 0xffffffff;
- __wctdm_sdi_sendbits(wc, bits, 32);
- bits = (0x6 << 10) | (1 << 5) | (addr);
- __wctdm_sdi_sendbits(wc, bits, 14);
- return __wctdm_sdi_recvbits(wc, 18);
-}
-
-static inline void wctdm_setsdi(struct wctdm *wc, unsigned char addr, unsigned short value)
-{
- unsigned long flags;
- spin_lock_irqsave(&wc->reglock, flags);
- __wctdm_setsdi(wc, addr, value);
- spin_unlock_irqrestore(&wc->reglock, flags);
-}
-
-static inline unsigned short wctdm_getsdi(struct wctdm *wc, unsigned char addr)
-{
- unsigned long flags;
- unsigned short val;
- spin_lock_irqsave(&wc->reglock, flags);
- val = __wctdm_getsdi(wc, addr);
- spin_unlock_irqrestore(&wc->reglock, flags);
- return val;
-}
-
#ifdef VPM_SUPPORT
static inline unsigned char wctdm_vpm_in(struct wctdm *wc, int unit, const unsigned int addr)
{
@@ -1039,17 +840,13 @@ static inline void cmd_retransmit(struct wctdm *wc)
#endif
}
-static inline void wctdm_receiveprep(struct wctdm *wc, int dbl)
+static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk)
{
- volatile unsigned char *readchunk;
int x,y;
unsigned char expected;
- dbl = dbl % 2;
+ BUG_ON(NULL == readchunk);
- readchunk = (volatile unsigned char *)wc->readchunk;
- if (dbl)
- readchunk += SFRAME_SIZE;
for (x=0;x<ZT_CHUNKSIZE;x++) {
if (x < ZT_CHUNKSIZE - 1) {
expected = wc->rxident+1;
@@ -1060,9 +857,11 @@ static inline void wctdm_receiveprep(struct wctdm *wc, int dbl)
}
}
for (y=0;y < wc->cards;y++) {
- if (y < wc->type) {
- wc->chans[y].readchunk[x] = readchunk[y];
- }
+ if (likely(wc->initialized)) {
+ if (y < wc->type) {
+ wc->chans[y].readchunk[x] = readchunk[y];
+ }
+ }
cmd_decifer(wc, readchunk, y);
}
#ifdef VPM_SUPPORT
@@ -1072,26 +871,21 @@ static inline void wctdm_receiveprep(struct wctdm *wc, int dbl)
} else if (wc->vpm150m)
cmd_decifer_vpm150m(wc, readchunk);
#endif
-#if 0
- if (cmddesc < 1024) {
- printk("RC Result: %02x\n", readchunk[EFRAME_SIZE+1]);
- }
-#endif
+
readchunk += (EFRAME_SIZE + EFRAME_GAP);
}
/* XXX We're wasting 8 taps. We should get closer :( */
- for (x=0;x<wc->type;x++) {
- if (wc->cardflag & (1 << x))
- zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->chans[x].writechunk);
+ if (likely(wc->initialized)) {
+ for (x=0;x<wc->type;x++) {
+ if (wc->cardflag & (1 << x))
+ zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->chans[x].writechunk);
+ }
+ zt_receive(&wc->span);
}
- zt_receive(&wc->span);
/* Wake up anyone sleeping to read/write a new register */
wake_up_interruptible(&wc->regq);
}
-static void wctdm_stop_dma(struct wctdm *wc);
-static void wctdm_restart_dma(struct wctdm *wc);
-
static int wait_access(struct wctdm *wc, int card)
{
unsigned char data=0;
@@ -1330,160 +1124,206 @@ if (debug) printk("QRV channel %d rx state changed to %d\n",qrvcard + 1,wc->qrvh
static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
{
+#define MS_PER_CHECK_HOOK 1
+
unsigned char res;
signed char b;
+ struct fxo *fxo = &wc->mods[card].fxo;
+
/* Try to track issues that plague slot one FXO's */
b = wc->cmdq[card].isrshadow[0]; /* Hook/Ring state */
b &= 0x9b;
- if (wc->mods[card].fxo.offhook) {
+ if (fxo->offhook) {
if (b != 0x9)
wctdm_setreg_intr(wc, card, 5, 0x9);
} else {
if (b != 0x8)
wctdm_setreg_intr(wc, card, 5, 0x8);
}
- if (!wc->mods[card].fxo.offhook) {
+ if (!fxo->offhook) {
if (fwringdetect) {
res = wc->cmdq[card].isrshadow[0] & 0x60;
- if (wc->mods[card].fxo.ringdebounce--) {
- if (res && (res != wc->mods[card].fxo.lastrdtx) && (wc->mods[card].fxo.battery == 1)) {
- if (!wc->mods[card].fxo.wasringing) {
- wc->mods[card].fxo.wasringing = 1;
+ if (fxo->ringdebounce--) {
+ if (res && (res != fxo->lastrdtx) && (fxo->battery == 1)) {
+ if (!fxo->wasringing) {
+ fxo->wasringing = 1;
if (debug)
printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
}
- wc->mods[card].fxo.lastrdtx = res;
- wc->mods[card].fxo.ringdebounce = 10;
+ fxo->lastrdtx = res;
+ fxo->ringdebounce = 10;
} else if (!res) {
- if ((wc->mods[card].fxo.ringdebounce == 0) && wc->mods[card].fxo.wasringing) {
- wc->mods[card].fxo.wasringing = 0;
+ if ((fxo->ringdebounce == 0) && fxo->wasringing) {
+ fxo->wasringing = 0;
if (debug)
printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
}
}
- } else if (res && (wc->mods[card].fxo.battery == 1)) {
- wc->mods[card].fxo.lastrdtx = res;
- wc->mods[card].fxo.ringdebounce = 10;
+ } else if (res && (fxo->battery == BATTERY_PRESENT)) {
+ fxo->lastrdtx = res;
+ fxo->ringdebounce = 10;
}
} else {
res = wc->cmdq[card].isrshadow[0];
- if ((res & 0x60) && (wc->mods[card].fxo.battery == 1)) {
- wc->mods[card].fxo.ringdebounce += (ZT_CHUNKSIZE * 16);
- if (wc->mods[card].fxo.ringdebounce >= ZT_CHUNKSIZE * ringdebounce) {
- if (!wc->mods[card].fxo.wasringing) {
- wc->mods[card].fxo.wasringing = 1;
+ if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) {
+ fxo->ringdebounce += (ZT_CHUNKSIZE * 16);
+ if (fxo->ringdebounce >= ZT_CHUNKSIZE * ringdebounce) {
+ if (!fxo->wasringing) {
+ fxo->wasringing = 1;
zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
if (debug)
printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
}
- wc->mods[card].fxo.ringdebounce = ZT_CHUNKSIZE * ringdebounce;
+ fxo->ringdebounce = ZT_CHUNKSIZE * ringdebounce;
}
} else {
- wc->mods[card].fxo.ringdebounce -= ZT_CHUNKSIZE * 4;
- if (wc->mods[card].fxo.ringdebounce <= 0) {
- if (wc->mods[card].fxo.wasringing) {
- wc->mods[card].fxo.wasringing = 0;
+ fxo->ringdebounce -= ZT_CHUNKSIZE * 4;
+ if (fxo->ringdebounce <= 0) {
+ if (fxo->wasringing) {
+ fxo->wasringing = 0;
zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
if (debug)
printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
}
- wc->mods[card].fxo.ringdebounce = 0;
+ fxo->ringdebounce = 0;
}
}
}
}
+
b = wc->cmdq[card].isrshadow[1]; /* Voltage */
if (fxovoltage) {
if (!(wc->intcount % 100)) {
printk("Port %d: Voltage: %d Debounce %d\n", card + 1,
- b, wc->mods[card].fxo.battdebounce);
+ b, fxo->battdebounce);
}
}
if (abs(b) < battthresh) {
- wc->mods[card].fxo.nobatttimer++;
-#if 0
- if (wc->mods[card].fxo.battery == 1)
- printk("Battery loss: %d (%d debounce)\n", b, wc->mods[card].fxo.battdebounce);
-#endif
- if (wc->mods[card].fxo.battery && !wc->mods[card].fxo.battdebounce) {
- if (debug & DEBUG_CARD)
- printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
- wc->mods[card].fxo.battery = 0;
+ /* possible existing states:
+ battery lost, no debounce timer
+ battery lost, debounce timer (going to battery present)
+ battery present or unknown, no debounce timer
+ battery present or unknown, debounce timer (going to battery lost)
+ */
+
+ if (fxo->battery == BATTERY_LOST) {
+ if (fxo->battdebounce) {
+ /* we were going to BATTERY_PRESENT, but battery was lost again,
+ so clear the debounce timer */
+ fxo->battdebounce = 0;
+ }
+ } else {
+ if (fxo->battdebounce) {
+ /* going to BATTERY_LOST, see if we are there yet */
+ if (--fxo->battdebounce == 0) {
+ fxo->battery = BATTERY_LOST;
+ if (debug)
+ printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
#ifdef JAPAN
- if ((!wc->ohdebounce) && wc->offhook) {
- zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
- if (debug & DEBUG_CARD)
- printk("Signalled On Hook\n");
+ if (!wc->ohdebounce && wc->offhook) {
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ if (debug)
+ printk("Signalled On Hook\n");
#ifdef ZERO_BATT_RING
- wc->onhook++;
+ wc->onhook++;
#endif
- }
+ }
#else
- zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
- zt_alarm_channel(&wc->chans[card], ZT_ALARM_RED);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ /* set the alarm timer, taking into account that part of its time
+ period has already passed while debouncing occurred */
+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
#endif
- wc->mods[card].fxo.battdebounce = battdebounce;
- } else if (!wc->mods[card].fxo.battery)
- wc->mods[card].fxo.battdebounce = battdebounce;
- } else if (abs(b) > battthresh) {
- if ((wc->mods[card].fxo.battery < 1) && !wc->mods[card].fxo.battdebounce) {
- if (debug & DEBUG_CARD)
- printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
- (b < 0) ? "-" : "+");
-#ifdef ZERO_BATT_RING
- if (wc->onhook) {
- wc->onhook = 0;
- zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
- if (debug & DEBUG_CARD)
- printk("Signalled Off Hook\n");
+ }
+ } else {
+ /* start the debounce timer to verify that battery has been lost */
+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
}
+ }
+ } else {
+ /* possible existing states:
+ battery lost or unknown, no debounce timer
+ battery lost or unknown, debounce timer (going to battery present)
+ battery present, no debounce timer
+ battery present, debounce timer (going to battery lost)
+ */
+
+ if (fxo->battery == BATTERY_PRESENT) {
+ if (fxo->battdebounce) {
+ /* we were going to BATTERY_LOST, but battery appeared again,
+ so clear the debounce timer */
+ fxo->battdebounce = 0;
+ }
+ } else {
+ if (fxo->battdebounce) {
+ /* going to BATTERY_PRESENT, see if we are there yet */
+ if (--fxo->battdebounce == 0) {
+ fxo->battery = BATTERY_PRESENT;
+ if (debug)
+ printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
+ (b < 0) ? "-" : "+");
+#ifdef ZERO_BATT_RING
+ if (wc->onhook) {
+ wc->onhook = 0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("Signalled Off Hook\n");
+ }
#else
- zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
- zt_alarm_channel(&wc->chans[card], ZT_ALARM_NONE);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
#endif
- wc->mods[card].fxo.battery = 1;
- wc->mods[card].fxo.nobatttimer = 0;
- wc->mods[card].fxo.battdebounce = battdebounce;
- } else if (wc->mods[card].fxo.battery == 1)
- wc->mods[card].fxo.battdebounce = battdebounce;
-
- if (wc->mods[card].fxo.lastpol >= 0) {
- if (b < 0) {
- wc->mods[card].fxo.lastpol = -1;
- wc->mods[card].fxo.polaritydebounce = POLARITY_DEBOUNCE;
- }
+ /* set the alarm timer, taking into account that part of its time
+ period has already passed while debouncing occurred */
+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
+ }
+ } else {
+ /* start the debounce timer to verify that battery has appeared */
+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
+ }
+ }
+
+ if (fxo->lastpol >= 0) {
+ if (b < 0) {
+ fxo->lastpol = -1;
+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
+ }
}
- if (wc->mods[card].fxo.lastpol <= 0) {
- if (b > 0) {
- wc->mods[card].fxo.lastpol = 1;
- wc->mods[card].fxo.polaritydebounce = POLARITY_DEBOUNCE;
- }
+ if (fxo->lastpol <= 0) {
+ if (b > 0) {
+ fxo->lastpol = 1;
+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
+ }
+ }
+ }
+
+ if (fxo->battalarm) {
+ if (--fxo->battalarm == 0) {
+ /* the alarm timer has expired, so update the battery alarm state
+ for this channel */
+ zt_alarm_channel(&wc->chans[card], fxo->battery ? ZT_ALARM_NONE : ZT_ALARM_RED);
}
- } else {
- /* It's something else... */
- wc->mods[card].fxo.battdebounce = battdebounce;
}
- if (wc->mods[card].fxo.battdebounce)
- wc->mods[card].fxo.battdebounce--;
- if (wc->mods[card].fxo.polaritydebounce) {
- wc->mods[card].fxo.polaritydebounce--;
- if (wc->mods[card].fxo.polaritydebounce < 1) {
- if (wc->mods[card].fxo.lastpol != wc->mods[card].fxo.polarity) {
+
+ if (fxo->polaritydebounce) {
+ fxo->polaritydebounce--;
+ if (fxo->polaritydebounce < 1) {
+ if (fxo->lastpol != fxo->polarity) {
if (debug & DEBUG_CARD)
printk("%lu Polarity reversed (%d -> %d)\n", jiffies,
- wc->mods[card].fxo.polarity,
- wc->mods[card].fxo.lastpol);
- if (wc->mods[card].fxo.polarity)
- zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
- wc->mods[card].fxo.polarity = wc->mods[card].fxo.lastpol;
+ fxo->polarity,
+ fxo->lastpol);
+ if (fxo->polarity)
+ zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
+ fxo->polarity = fxo->lastpol;
}
}
}
+#undef MS_PER_CHECK_HOOK
}
static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
@@ -1496,7 +1336,7 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
res = wc->cmdq[card].isrshadow[0]; /* Hook state */
hook = (res & 1);
-
+
if (hook != wc->mods[card].fxs.lastrxhook) {
/* Reset the debounce (must be multiple of 4ms) */
wc->mods[card].fxs.debounce = 8 * (4 * 8);
@@ -1537,15 +1377,6 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
}
-static inline void wctdm_reinit_descriptor(struct wctdm *wc, int tx, int dbl, char *s)
-{
- int o2 = 0;
- o2 += dbl * 4;
- if (!tx)
- o2 += ERING_SIZE * 4;
- wc->descripchunk[o2] = 0x80000000;
-}
-
#ifdef VPM_SUPPORT
static inline void wctdm_vpm_check(struct wctdm *wc, int x)
{
@@ -1616,6 +1447,10 @@ static inline void wctdm_isr_misc(struct wctdm *wc)
{
int x;
+ if (unlikely(!wc->initialized)) {
+ return;
+ }
+
for (x=0;x<wc->cards;x++) {
if (wc->cardflag & (1 << x)) {
if (wc->modtype[x] == MOD_TYPE_FXS) {
@@ -1661,122 +1496,22 @@ static inline void wctdm_isr_misc(struct wctdm *wc)
#endif
}
-static inline int wctdm_check_descriptor(struct wctdm *wc, int tx)
+void handle_receive(void* vbb, void* context)
{
- int o2 = 0;
- if (!tx) {
- o2 += ERING_SIZE * 4;
- o2 += wc->rdbl * 4;
- } else {
- o2 += wc->tdbl * 4;
- }
- if (!(wc->descripchunk[o2] & 0x80000000)) {
- if (tx) {
- wc->txints++;
- wctdm_transmitprep(wc, wc->tdbl);
- wctdm_reinit_descriptor(wc, tx, wc->tdbl, "txchk");
- wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
- wctdm_isr_misc(wc);
- wc->intcount++;
- } else {
- wc->rxints++;
- wctdm_receiveprep(wc, wc->rdbl);
- wctdm_reinit_descriptor(wc, tx, wc->rdbl, "rxchk");
- wc->rdbl = (wc->rdbl + 1) % ERING_SIZE;
- }
- return 1;
- }
- return 0;
-}
-
-static void wctdm_init_descriptors(struct wctdm *wc)
-{
- volatile unsigned int *descrip;
- dma_addr_t descripdma;
- dma_addr_t writedma;
- dma_addr_t readdma;
- int x;
-
- descrip = wc->descripchunk;
- descripdma = wc->descripdma;
- writedma = wc->writedma;
- readdma = wc->readdma;
-
- for (x=0;x<ERING_SIZE;x++) {
- if (x < ERING_SIZE - 1)
- descripdma += 16;
- else
- descripdma = wc->descripdma;
-
- /* Transmit descriptor */
- descrip[0 ] = 0x80000000;
- descrip[1 ] = 0xe5800000 | (SFRAME_SIZE);
- if (x % 2)
- descrip[2 ] = writedma + SFRAME_SIZE;
- else
- descrip[2 ] = writedma;
- descrip[3 ] = descripdma;
-
- /* Receive descriptor */
- descrip[0 + ERING_SIZE * 4] = 0x80000000;
- descrip[1 + ERING_SIZE * 4] = 0x01000000 | (SFRAME_SIZE);
- if (x % 2)
- descrip[2 + ERING_SIZE * 4] = readdma + SFRAME_SIZE;
- else
- descrip[2 + ERING_SIZE * 4] = readdma;
- descrip[3 + ERING_SIZE * 4] = descripdma + ERING_SIZE * 16;
-
- /* Advance descriptor */
- descrip += 4;
- }
+ struct wctdm *wc = context;
+ wc->rxints++;
+ wctdm_receiveprep(wc, vbb);
}
-ZAP_IRQ_HANDLER(wctdm_interrupt)
+void handle_transmit(void* vbb, void* context)
{
- struct wctdm *wc = dev_id;
- unsigned int ints;
- int res;
-
- /* Read and clear interrupts */
- ints = wctdm_getctl(wc, 0x0028);
-
- if (!ints)
-#ifdef LINUX26
- return IRQ_NONE;
-#else
- return;
-#endif
-
- wctdm_setctl(wc, 0x0028, ints);
-
- ints &= wc->intmask;
- if (ints & 0x00000041) {
- do {
- res = wctdm_check_descriptor(wc, 0);
- res |= wctdm_check_descriptor(wc, 1);
- } while(res);
-#if 0
- while(wctdm_check_descriptor(wc, 0));
- wctdm_setctl(wc, 0x0010, 0x00000000);
- }
- if (ints & 0x00000005) {
- while(wctdm_check_descriptor(wc, 1));
- wctdm_setctl(wc, 0x0008, 0x00000000);
-#endif
- }
-
- if (ints & 0x0000a3ae) {
- /* This will allow us to recover if interrupts are held for a long period of time */
- if (debug & DEBUG_CARD)
- printk("Abnormal interrupt %08x detected\n", ints);
- wctdm_setctl(wc, 0x0008, 0x00000000);
- wctdm_setctl(wc, 0x0010, 0x00000000);
- }
-
-#ifdef LINUX26
- return IRQ_RETVAL(1);
-#endif
-
+ struct wctdm *wc = context;
+ memset(vbb, 0, SFRAME_SIZE);
+ wc->txints++;
+ wctdm_transmitprep(wc, vbb);
+ wctdm_isr_misc(wc);
+ wc->intcount++;
+ voicebus_transmit(wc->vb, vbb);
}
static int wctdm_voicedaa_insane(struct wctdm *wc, int card)
@@ -2150,6 +1885,10 @@ static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual,
wctdm_setreg(wc, card, 24, 0x19);
}
+ /* Enable ring detector full-wave rectifier mode */
+ wctdm_setreg(wc, card, 18, 2);
+ wctdm_setreg(wc, card, 24, 0);
+
/* Set DC Termination:
Tip/Ring voltage adjust, minimum operational current, current limitation */
reg26 |= (fxo_modes[_opermode].dcv << 6);
@@ -2199,9 +1938,6 @@ static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual,
if(debug)
printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, card, 38)/16) ? -(wctdm_getreg(wc, card, 38) - 16) : wctdm_getreg(wc, card, 38), (wctdm_getreg(wc, card, 40)/16) ? -(wctdm_getreg(wc, card, 40) - 16) : wctdm_getreg(wc, card, 40), (wctdm_getreg(wc, card, 39)/16) ? -(wctdm_getreg(wc, card, 39) - 16): wctdm_getreg(wc, card, 39), (wctdm_getreg(wc, card, 41)/16)?-(wctdm_getreg(wc, card, 41) - 16) : wctdm_getreg(wc, card, 41));
- /* battery state still unknown */
- wc->mods[card].fxo.battery = -1;
-
return 0;
}
@@ -2590,33 +2326,6 @@ static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat
struct zt_radio_param p;
} stack;
-#if 0
- /* XXX */
- printk("RxInts: %d, TxInts: %d\n", wc->rxints, wc->txints);
- printk("RxIdent: %d, TxIdent: %d\n", wc->rxident, wc->txident);
- for (x=0;x<wc->cards;x++)
- printk("Card %d isrshadow: %02x/%02x\n", x, wc->cmdq[x].isrshadow[0], wc->cmdq[x].isrshadow[1]);
- cmddesc = 0;
-#endif
-#if 0
- if (wc->vpm) {
- char tmp[80];
- for (x=0;x<0x200;x++) {
- switch (x & 0xf) {
- case 0:
- sprintf(tmp, "%03x: %02x ", x, wctdm_vpm_in(wc, 0, x));
- break;
- case 0xf:
- printk("%s%02x\n", tmp, wctdm_vpm_in(wc, 0, x));
- break;
- default:
- sprintf(tmp + strlen(tmp), "%02x ", wctdm_vpm_in(wc, 0, x));
- break;
- }
- }
- }
-
-#endif
switch (cmd) {
case ZT_ONHOOKTRANSFER:
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
@@ -2904,8 +2613,7 @@ static int wctdm_open(struct zt_chan *chan)
static int wctdm_watchdog(struct zt_span *span, int event)
{
- printk("TDM: Restarting DMA\n");
- wctdm_restart_dma(span->pvt);
+ printk("TDM: Called watchdog\n");
return 0;
}
@@ -3129,15 +2837,16 @@ static int wctdm_dacs(struct zt_chan *dst, struct zt_chan *src)
static int wctdm_initialize(struct wctdm *wc)
{
int x;
+ struct pci_dev *pdev = voicebus_get_pci_dev(wc->vb);
/* Zapata stuff */
sprintf(wc->span.name, "WCTDM/%d", wc->pos);
snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
snprintf(wc->span.location, sizeof(wc->span.location) - 1,
"PCI%s Bus %02d Slot %02d", (wc->flags[0] & FLAG_EXPRESS) ? " Express" : "",
- wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+ pdev->bus->number, PCI_SLOT(pdev->devfn) + 1);
wc->span.manufacturer = "Digium";
- zap_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype));
+ strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
if (alawoverride) {
printk("ALAW override parameter detected. Device will be operating in ALAW\n");
wc->span.deflaw = ZT_LAW_ALAW;
@@ -3152,7 +2861,7 @@ static int wctdm_initialize(struct wctdm *wc)
}
wc->span.chans = wc->chans;
wc->span.channels = wc->type;
- wc->span.irq = wc->dev->irq;
+ wc->span.irq = pdev->irq;
wc->span.hooksig = wctdm_hooksig;
wc->span.open = wctdm_open;
wc->span.close = wctdm_close;
@@ -3166,10 +2875,6 @@ static int wctdm_initialize(struct wctdm *wc)
init_waitqueue_head(&wc->span.maintq);
wc->span.pvt = wc;
- if (zt_register(&wc->span, 0)) {
- printk("Unable to register span with zaptel\n");
- return -1;
- }
return 0;
}
@@ -3197,115 +2902,6 @@ static void wctdm_post_initialize(struct wctdm *wc)
strncat(wc->span.devicetype, " with VPMADT032", sizeof(wc->span.devicetype) - 1);
}
-static int wctdm_hardware_init(struct wctdm *wc)
-{
- /* Hardware stuff */
- unsigned int reg;
- unsigned long newjiffies;
-
- /* Initialize descriptors */
- wctdm_init_descriptors(wc);
-
- /* Enable I/O Access */
- pci_read_config_dword(wc->dev, 0x0004, &reg);
- reg |= 0x00000007;
- pci_write_config_dword(wc->dev, 0x0004, reg);
- printk("PCI Config reg is %08x\n", reg);
-
- wctdm_setctl(wc, 0x0000, 0xfff88001);
-
- newjiffies = jiffies + HZ/10;
- while(((reg = wctdm_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies));
- printk("%s: New Reg: %08x!\n", wc->variety, reg);
- wctdm_setctl(wc, 0x0000, 0xfff88000);
-
-
- /* Configure watchdogs, access, etc */
- wctdm_setctl(wc, 0x0030, 0x00080048);
- wctdm_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
-
-#if 0
- /* XXX Enable loopback XXX */
- reg = wctdm_getctl(wc, 0x0030);
- wctdm_setctl(wc, 0x0030, reg | 0x00000400);
-
-#else
- reg = wctdm_getctl(wc, 0x00fc);
- wctdm_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
- wctdm_setsdi(wc, 0x00, 0x0100);
- wctdm_setsdi(wc, 0x16, 0x2100);
- printk("Detected REG0: %08x\n", wctdm_getsdi(wc, 0x00));
- printk("Detected REG1: %08x\n", wctdm_getsdi(wc, 0x01));
- printk("Detected REG2: %08x\n", wctdm_getsdi(wc, 0x02));
-
- reg = wctdm_getctl(wc, 0x00fc);
- printk("(pre) Reg fc is %08x\n", reg);
-
- wctdm_setctl(wc, 0x00fc, (reg & ~0x7) | 0x4);
- wctdm_setsdi(wc, 0x00, 0x0100);
- wctdm_setsdi(wc, 0x16, 0x2100);
- reg = wctdm_getctl(wc, 0x00fc);
- printk("(post) Reg fc is %08x\n", reg);
- printk("Detected REG2: %08x\n", wctdm_getsdi(wc, 0x02));
-#endif
- printk("wctdm24xxp: reg is %08x\n", wctdm_getctl(wc, 0x0088));
-
- return 0;
-}
-
-static void wctdm_setintmask(struct wctdm *wc, unsigned int intmask)
-{
- wc->intmask = intmask;
- wctdm_setctl(wc, 0x0038, intmask);
-}
-
-static void wctdm_enable_interrupts(struct wctdm *wc)
-{
- /* Enable interrupts */
- wctdm_setintmask(wc, 0x00010041);
-}
-
-static void wctdm_restart_dma(struct wctdm *wc)
-{
-}
-
-static void wctdm_start_dma(struct wctdm *wc)
-{
- unsigned int reg;
- wmb();
- wctdm_setctl(wc, 0x0020, wc->descripdma);
- wctdm_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE));
- /* Start receiver/transmitter */
- reg = wctdm_getctl(wc, 0x0030);
- wctdm_setctl(wc, 0x0030, reg | 0x00002002);
- wctdm_setctl(wc, 0x0008, 0x00000000);
- wctdm_setctl(wc, 0x0010, 0x00000000);
- reg = wctdm_getctl(wc, 0x0028);
- wctdm_setctl(wc, 0x0028, reg);
-
-}
-
-static void wctdm_stop_dma(struct wctdm *wc)
-{
- /* Disable interrupts and reset */
- unsigned int reg;
- /* Disable interrupts */
- wctdm_setintmask(wc, 0x00000000);
- wctdm_setctl(wc, 0x0084, 0x00000000);
- wctdm_setctl(wc, 0x0048, 0x00000000);
- /* Reset the part to be on the safe side */
- reg = wctdm_getctl(wc, 0x0000);
- reg |= 0x00000001;
- wctdm_setctl(wc, 0x0000, reg);
-}
-
-static void wctdm_disable_interrupts(struct wctdm *wc)
-{
- /* Disable interrupts */
- wctdm_setintmask(wc, 0x00000000);
- wctdm_setctl(wc, 0x0084, 0x00000000);
-}
-
#ifdef VPM_SUPPORT
#ifdef VPM150M_SUPPORT
@@ -3519,6 +3115,7 @@ static void vpm150m_bh(struct work_struct *data)
if (debug & DEBUG_ECHOCAN)
printk("Echocan enable took %d ms\n", wc->intcount - start);
} else {
+ res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &pstatus);
if (debug & DEBUG_ECHOCAN)
printk("Echocan disable took %d ms\n", wc->intcount - start);
}
@@ -3702,6 +3299,7 @@ static enum vpmadt032_init_result wctdm_vpm150m_init(struct wctdm *wc)
struct vpm150m *vpm150m;
unsigned short reg;
unsigned long flags;
+ struct pci_dev* pdev = voicebus_get_pci_dev(wc->vb);
enum vpmadt032_init_result res = VPMADT032_FAILED;
#ifdef VPM150M_SUPPORT
@@ -3807,7 +3405,7 @@ static enum vpmadt032_init_result wctdm_vpm150m_init(struct wctdm *wc)
if (pingstatus || (version != 0x106)) {
#endif
#if defined(HOTPLUG_FIRMWARE)
- if ((request_firmware(&firmware, vpmadt032_firmware, &wc->dev->dev) != 0) ||
+ if ((request_firmware(&firmware, vpmadt032_firmware, &pdev->dev) != 0) ||
!firmware) {
printk("VPMADT032: firmware %s not available from userspace\n", vpmadt032_firmware);
goto failed_exit;
@@ -4024,21 +3622,8 @@ static int wctdm_locate_modules(struct wctdm *wc)
{
int x;
unsigned long flags;
- printk("Resetting the modules...\n");
- /* Initialize control register */
+ unsigned int startinglatency = voicebus_current_latency(wc->vb);
wc->ctlreg = 0x00;
- /* Set Reset */
- wctdm_setctl(wc, 0x0048, 0x00000000);
- for (x=0;x<10;x++)
- schluffen(&wc->regq);
- printk("During Resetting the modules...\n");
- /* Clear reset */
- wctdm_setctl(wc, 0x0048, 0x00010000);
- for (x=0;x<10;x++)
- schluffen(&wc->regq);
- printk("After resetting the modules...\n");
-
- wctdm_setintmask(wc, 0x0001f7fe);
/* Make sure all units go into daisy chain mode */
spin_lock_irqsave(&wc->reglock, flags);
@@ -4072,6 +3657,9 @@ static int wctdm_locate_modules(struct wctdm *wc)
for (x=0;x<wc->cards;x++) {
int sane=0,ret=0,readi=0;
retry:
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ return -EAGAIN;
+ }
/* Init with Auto Calibration */
if (!(ret = wctdm_init_proslic(wc, x, 0, 0, sane))) {
wc->cardflag |= (1 << x);
@@ -4136,11 +3724,17 @@ retry:
printk("VPM: Present and operational (Rev %c)\n", 'A' + wc->vpm - 1);
wc->ctlreg |= 0x10;
} else {
+ enum vpmadt032_init_result res;
spin_lock_irqsave(&wc->reglock, flags);
for (x = NUM_CARDS; x < NUM_CARDS + NUM_EC; x++)
wc->modtype[x] = MOD_TYPE_NONE;
spin_unlock_irqrestore(&wc->reglock, flags);
- switch (wctdm_vpm150m_init(wc)) {
+ res = wctdm_vpm150m_init(wc);
+ /* In case there was an error while we were loading the VPM module. */
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ return -EAGAIN;
+ }
+ switch (res) {
case VPMADT032_SUCCESS:
printk("VPMADT032: Present and operational (Firmware version %x)\n", wc->vpm150m->version);
wc->ctlreg |= 0x10;
@@ -4150,173 +3744,139 @@ retry:
/* nothing */
break;
default:
- return -1;
+ return -EIO;
}
}
#endif
-
+ /* In case there was an error while we were loading the VPM module. */
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ return -EAGAIN;
+ }
return 0;
}
+static struct pci_driver wctdm_driver;
+
static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct wctdm *wc;
struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data;
- int x;
+ int i;
int y;
+ int ret;
- if (pci_enable_device(pdev))
- return -EIO;
-
- if (!(wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL)))
+retry:
+ wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL);
+ if (!wc) {
+ /* \todo Print debug message. */
return -ENOMEM;
-
- spin_lock(&ifacelock);
- for (x = 0; x < WC_MAX_IFACES; x++)
- if (!ifaces[x]) break;
-
- ifaces[x] = wc;
+ }
+ memset(wc, 0, sizeof(*wc));
+ spin_lock(&ifacelock);
+ /* \todo this is a candidate for removal... */
+ for (i = 0; i < WC_MAX_IFACES; ++i) {
+ if (!ifaces[i]) {
+ ifaces[i] = wc;
+ break;
+ }
+ }
spin_unlock(&ifacelock);
-
- memset(wc, 0, sizeof(struct wctdm));
+
+ snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d",
+ wctdm_driver.name, i);
+ ret = voicebus_init(pdev, SFRAME_SIZE, wc->board_name,
+ handle_receive, handle_transmit, wc, &wc->vb);
+ if (ret) {
+ kfree(wc);
+ return ret;
+ }
+ BUG_ON(!wc->vb);
+
+ if (VOICEBUS_DEFAULT_LATENCY != latency) {
+ voicebus_set_minlatency(wc->vb, latency);
+ }
+
spin_lock_init(&wc->reglock);
wc->curcard = -1;
wc->cards = NUM_CARDS;
- wc->iobase = pci_resource_start(pdev, 0);
wc->type = d->ports;
- wc->dev = pdev;
- wc->pos = x;
+ wc->pos = i;
wc->variety = d->name;
+ wc->txident = 1;
for (y=0;y<NUM_CARDS;y++) {
wc->flags[y] = d->flags;
wc->dacssrc[y] = -1;
}
- /* Keep track of whether we need to free the region */
- if (request_region(wc->iobase, 0xff, "wctdm24xxp"))
- wc->freeregion = 1;
-
- /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses
- 32 bits. Allocate an extra set just for control too */
- wc->writechunk = pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma);
- if (!wc->writechunk) {
- printk("wctdm: Unable to allocate DMA-able memory\n");
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- return -ENOMEM;
- }
-
- wc->readchunk = wc->writechunk + SFRAME_SIZE / 2; /* in doublewords */
- wc->readdma = wc->writedma + SFRAME_SIZE * 2; /* in bytes */
-
- wc->descripchunk = wc->readchunk + SFRAME_SIZE / 2; /* in doublewords */
- wc->descripdma = wc->readdma + SFRAME_SIZE * 2; /* in bytes */
-
- /* Initialize Write/Buffers to all blank data */
- memset((void *)wc->writechunk,0x00, SFRAME_SIZE * 2);
- memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2);
-
+
init_waitqueue_head(&wc->regq);
-
+
if (wctdm_initialize(wc)) {
- printk("%s: Unable to register span with zaptel\n", wc->variety);
- /* Set Reset Low */
- wctdm_stop_dma(wc);
- /* Free Resources */
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- zt_unregister(&wc->span);
+ voicebus_release(wc->vb);
+ wc->vb = NULL;
kfree(wc);
return -EIO;
}
-
- /* Enable bus mastering */
- pci_set_master(pdev);
-
+
+
/* Keep track of which device we are */
pci_set_drvdata(pdev, wc);
-
- if (request_irq(pdev->irq, wctdm_interrupt, ZAP_IRQ_SHARED, wc->variety, wc)) {
- printk("wctdm24xxp: Unable to request IRQ %d\n", pdev->irq);
- /* Set Reset Low */
- wctdm_stop_dma(wc);
- /* Free Resources */
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- zt_unregister(&wc->span);
- kfree(wc);
- return -EIO;
- }
-
-
- if (wctdm_hardware_init(wc)) {
- /* Set Reset Low */
- wctdm_stop_dma(wc);
- /* Free Resources */
- free_irq(pdev->irq, wc);
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- zt_unregister(&wc->span);
- kfree(wc);
- return -EIO;
-
+
+ /* Start the hardware processing. */
+ if (voicebus_start(wc->vb)) {
+ BUG_ON(1);
}
- /* Enable interrupts */
- wctdm_enable_interrupts(wc);
-
- /* Start DMA */
- wctdm_start_dma(wc);
-
/* Now track down what modules are installed */
- if (wctdm_locate_modules(wc)) {
- wctdm_disable_interrupts(wc);
- /* Set Reset Low */
- wctdm_stop_dma(wc);
- /* Free Resources */
- free_irq(pdev->irq, wc);
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
- pci_set_drvdata(pdev, NULL);
- zt_unregister(&wc->span);
- kfree(wc);
- return -EIO;
+ ret = wctdm_locate_modules(wc);
+ if (-EAGAIN == ret ) {
+ /* The voicebus library increased the latency during
+ * initialization. There is a chance that the hardware is in
+ * an inconsistent state, so lets increase the default latency
+ * and start the initialization over.
+ */
+ printk(KERN_NOTICE "%s: Restarting board initialization " \
+ "after increasing latency.\n", wc->board_name);
+ latency = voicebus_current_latency(wc->vb);
+ wctdm_release(wc);
+ goto retry;
}
/* Final initialization */
wctdm_post_initialize(wc);
- printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->type);
+ /* We should be ready for zaptel to come in now. */
+ if (zt_register(&wc->span, 0)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
- return 0;
+ wc->initialized = 1;
+
+ printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->type);
+ ret = 0;
+
+ return ret;
}
static void wctdm_release(struct wctdm *wc)
{
int i;
- zt_unregister(&wc->span);
+ if (wc->initialized) {
+ zt_unregister(&wc->span);
+ }
- if (wc->freeregion)
- release_region(wc->iobase, 0xff);
+ voicebus_release(wc->vb);
+ wc->vb = NULL;
spin_lock(&ifacelock);
-
for (i = 0; i < WC_MAX_IFACES; i++)
if (ifaces[i] == wc)
break;
-
ifaces[i] = NULL;
-
spin_unlock(&ifacelock);
kfree(wc);
- printk("Freed a Wildcard\n");
}
static void __devexit wctdm_remove_one(struct pci_dev *pdev)
@@ -4338,16 +3898,7 @@ static void __devexit wctdm_remove_one(struct pci_dev *pdev)
destroy_workqueue(vpm150m->wq);
}
#endif
-
- /* Stop any DMA */
- wctdm_stop_dma(wc);
-
- /* In case hardware is still there */
- wctdm_disable_interrupts(wc);
-
- /* Immediately free resources */
- free_irq(pdev->irq, wc);
- pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ voicebus_stop(wc->vb);
#ifdef VPM150M_SUPPORT
if (vpm150m) {
@@ -4359,8 +3910,10 @@ static void __devexit wctdm_remove_one(struct pci_dev *pdev)
}
#endif
/* Release span, possibly delayed */
- if (!wc->usecount)
+ if (!wc->usecount) {
wctdm_release(wc);
+ printk("Freed a Wildcard\n");
+ }
else
wc->dead = 1;
}
@@ -4395,7 +3948,7 @@ static int __init wctdm_init(void)
int res;
int x;
- for (x=0;x<(sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
+ for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
if (!strcmp(fxo_modes[x].name, opermode))
break;
}
@@ -4403,12 +3956,31 @@ static int __init wctdm_init(void)
_opermode = x;
} else {
printk("Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode);
- for (x=0;x<sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
+ for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
printk(" %s\n", fxo_modes[x].name);
printk("Note this option is CASE SENSITIVE!\n");
return -ENODEV;
}
+ if (!strcmp(opermode, "AUSTRALIA")) {
+ boostringer = 1;
+ fxshonormode = 1;
+ }
+
+ /* for the voicedaa_check_hook defaults, if the user has not overridden
+ them by specifying them as module parameters, then get the values
+ from the selected operating mode
+ */
+ if (battdebounce == 0) {
+ battdebounce = fxo_modes[_opermode].battdebounce;
+ }
+ if (battalarm == 0) {
+ battalarm = fxo_modes[_opermode].battalarm;
+ }
+ if (battthresh == 0) {
+ battthresh = fxo_modes[_opermode].battthresh;
+ }
+
res = zap_pci_module(&wctdm_driver);
if (res)
return -ENODEV;
@@ -4425,14 +3997,14 @@ module_param(debug, int, 0600);
module_param(fxovoltage, int, 0600);
module_param(loopcurrent, int, 0600);
module_param(robust, int, 0600);
-module_param(_opermode, int, 0600);
module_param(opermode, charp, 0600);
module_param(lowpower, int, 0600);
module_param(boostringer, int, 0600);
module_param(fastringer, int, 0600);
module_param(fxshonormode, int, 0600);
-module_param(battdebounce, int, 0600);
-module_param(battthresh, int, 0600);
+module_param(battdebounce, uint, 0600);
+module_param(battalarm, uint, 0600);
+module_param(battthresh, uint, 0600);
module_param(alawoverride, int, 0600);
module_param(nativebridge, int, 0600);
module_param(fxotxgain, int, 0600);
@@ -4441,6 +4013,7 @@ module_param(fxstxgain, int, 0600);
module_param(fxsrxgain, int, 0600);
module_param(ringdebounce, int, 0600);
module_param(fwringdetect, int, 0600);
+module_param(latency, int, 0600);
#ifdef VPM_SUPPORT
module_param(vpmsupport, int, 0600);
module_param(vpmdtmfsupport, int, 0600);
@@ -4454,13 +4027,13 @@ MODULE_PARM(debug, "i");
MODULE_PARM(fxovoltage, "i");
MODULE_PARM(loopcurrent, "i");
MODULE_PARM(robust, "i");
-MODULE_PARM(_opermode, "i");
MODULE_PARM(opermode, "s");
MODULE_PARM(lowpower, "i");
MODULE_PARM(boostringer, "i");
MODULE_PARM(fastringer, "i");
MODULE_PARM(fxshonormode, "i");
MODULE_PARM(battdebounce, "i");
+MODULE_PARM(battalarm, "i");
MODULE_PARM(battthresh, "i");
MODULE_PARM(alawoverride, "i");
MODULE_PARM(nativebridge, "i");