From cd81703764c4d2884c60f3632f15d5bfc44dc31d Mon Sep 17 00:00:00 2001 From: sruffell Date: Thu, 27 Mar 2008 21:17:46 +0000 Subject: - 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 --- kernel/wctdm24xxp/base.c | 1057 ++++++++++++++-------------------------------- 1 file changed, 315 insertions(+), 742 deletions(-) (limited to 'kernel/wctdm24xxp/base.c') 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 * Support for TDM800P and VPM150M by Matthew Fredrickson * - * Copyright (C) 2005,2006, Digium, Inc. + * Copyright (C) 2005 - 2008 Digium, Inc. * All rights reserved. * * Sections for QRV cards written by Jim Dixon @@ -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;xcards;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;xrxident+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;xtype;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;xtype;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;xcards;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;xdescripdma; - - /* 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;xcards;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 |= 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;xcards;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;yflags[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