From a39b7271370a81fb32864c2de52f3c9aabfc6d8d Mon Sep 17 00:00:00 2001 From: sruffell Date: Fri, 4 Apr 2008 04:29:20 +0000 Subject: svn merge -c4096 https://origsvn.digium.com/svn/zaptel/branches/1.4/kernel/wctdm.c . git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@4132 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wctdm.c | 385 ++++++++++++++++++++++++++++++---------------------------------- 1 file changed, 179 insertions(+), 206 deletions(-) (limited to 'wctdm.c') diff --git a/wctdm.c b/wctdm.c index 2cfcf00..0b50771 100644 --- a/wctdm.c +++ b/wctdm.c @@ -108,101 +108,10 @@ static alpha indirect_regs[] = {43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, }; -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, }, -}; - #include "zaptel.h" +#include "fxo_modes.h" + #ifdef LINUX26 #include #endif @@ -249,14 +158,7 @@ static struct fxo_mode { #define DEFAULT_RING_DEBOUNCE 64 /* Ringer Debounce (64 ms) */ -/* the constants below control the 'debounce' periods enforced by the - check_hook routines; these routines are called once every 4 interrupts - (the interrupt cycles around the four modules), so the periods are - specified in _4 millisecond_ increments -*/ -#define DEFAULT_BATT_DEBOUNCE 4 /* Battery debounce (64 ms) */ -#define POLARITY_DEBOUNCE 4 /* Polarity debounce (64 ms) */ -#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ +#define POLARITY_DEBOUNCE 64 /* Polarity debounce (64 ms) */ #define OHT_TIMER 6000 /* How long after RING to retain OHT */ @@ -285,6 +187,12 @@ enum proslic_power_warn { PROSLIC_POWER_WARNED, }; +enum battery_state { + BATTERY_UNKNOWN = 0, + BATTERY_PRESENT, + BATTERY_LOST, +}; + struct wctdm { struct pci_dev *dev; char *variety; @@ -303,7 +211,7 @@ struct wctdm { spinlock_t lock; union { - struct { + struct fxo { #ifdef AUDIO_RINGCHECK unsigned int pegtimer; int pegcount; @@ -315,14 +223,14 @@ struct wctdm { #endif int ringdebounce; int offhook; - int battdebounce; - int nobatttimer; - int battery; + unsigned int battdebounce; + unsigned int battalarm; + enum battery_state battery; int lastpol; int polarity; int polaritydebounce; } fxo; - struct { + struct fxs { int oldrxhook; int debouncehook; int lastrxhook; @@ -364,8 +272,9 @@ static struct wctdm *ifaces[WC_MAX_IFACES]; static void wctdm_release(struct wctdm *wc); -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 ringdebounce = DEFAULT_RING_DEBOUNCE; static int fwringdetect = 0; static int debug = 0; @@ -827,13 +736,20 @@ static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card) } } +#define zt_alarm_channel(a,b) zt_qevent_lock(a,( (b)==ZT_ALARM_NONE )? \ + ZT_EVENT_NOALARM : ZT_EVENT_ALARM) + static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) { +#define MS_PER_CHECK_HOOK 16 + #ifndef AUDIO_RINGCHECK unsigned char res; #endif signed char b; int poopy = 0; + struct fxo *fxo = &wc->mod[card].fxo; + /* Try to track issues that plague slot one FXO's */ b = wc->reg0shadow[card]; if ((b & 0x2) || !(b & 0x8)) { @@ -843,7 +759,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) poopy++; } b &= 0x9b; - if (wc->mod[card].fxo.offhook) { + if (fxo->offhook) { if (b != 0x9) wctdm_setreg(wc, card, 5, 0x9); } else { @@ -853,147 +769,189 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) if (poopy) return; #ifndef AUDIO_RINGCHECK - if (!wc->mod[card].fxo.offhook) { + if (!fxo->offhook) { if (fwringdetect) { res = wc->reg0shadow[card] & 0x60; - if (wc->mod[card].fxo.ringdebounce--) { - if (res && (res != wc->mod[card].fxo.lastrdtx) && wc->mod[card].fxo.battery) { - if (!wc->mod[card].fxo.wasringing) { - wc->mod[card].fxo.wasringing = 1; + if (fxo->ringdebounce--) { + if (res && (res != fxo->lastrdtx) && + (fxo->battery == BATTERY_PRESENT)) { + 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->mod[card].fxo.lastrdtx = res; - wc->mod[card].fxo.ringdebounce = 10; + fxo->lastrdtx = res; + fxo->ringdebounce = 10; } else if (!res) { - if ((wc->mod[card].fxo.ringdebounce == 0) && wc->mod[card].fxo.wasringing) { - wc->mod[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->mod[card].fxo.battery) { - wc->mod[card].fxo.lastrdtx = res; - wc->mod[card].fxo.ringdebounce = 10; + } else if (res && (fxo->battery == BATTERY_PRESENT)) { + fxo->lastrdtx = res; + fxo->ringdebounce = 10; } } else { res = wc->reg0shadow[card]; - if ((res & 0x60) && wc->mod[card].fxo.battery) { - wc->mod[card].fxo.ringdebounce += (ZT_CHUNKSIZE * 16); - if (wc->mod[card].fxo.ringdebounce >= ZT_CHUNKSIZE * ringdebounce) { - if (!wc->mod[card].fxo.wasringing) { - wc->mod[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->mod[card].fxo.ringdebounce = ZT_CHUNKSIZE * ringdebounce; + fxo->ringdebounce = ZT_CHUNKSIZE * ringdebounce; } } else { - wc->mod[card].fxo.ringdebounce -= ZT_CHUNKSIZE * 4; - if (wc->mod[card].fxo.ringdebounce <= 0) { - if (wc->mod[card].fxo.wasringing) { - wc->mod[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->mod[card].fxo.ringdebounce = 0; + fxo->ringdebounce = 0; } } } } #endif + b = wc->reg1shadow[card]; -#if 0 - { - static int count = 0; - if (!(count++ % 100)) { - printk("Card %d: Voltage: %d Debounce %d\n", card + 1, - b, wc->mod[card].fxo.battdebounce); - } - } -#endif + if (abs(b) < battthresh) { - wc->mod[card].fxo.nobatttimer++; -#if 0 - if (wc->mod[card].fxo.battery) - printk("Battery loss: %d (%d debounce)\n", b, wc->mod[card].fxo.battdebounce); -#endif - if (wc->mod[card].fxo.battery && !wc->mod[card].fxo.battdebounce) { - if (debug) - printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1); - wc->mod[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) - 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_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->mod[card].fxo.battdebounce = battdebounce; - } else if (!wc->mod[card].fxo.battery) - wc->mod[card].fxo.battdebounce = battdebounce; + } } else if (abs(b) > battthresh) { if (!wc->mod[card].fxo.battery && !wc->mod[card].fxo.battdebounce) { 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"); + /* 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_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); #endif - wc->mod[card].fxo.battery = 1; - wc->mod[card].fxo.nobatttimer = 0; - wc->mod[card].fxo.battdebounce = battdebounce; - } else if (wc->mod[card].fxo.battery) - wc->mod[card].fxo.battdebounce = battdebounce; + /* 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 (wc->mod[card].fxo.lastpol >= 0) { - if (b < 0) { - wc->mod[card].fxo.lastpol = -1; - wc->mod[card].fxo.polaritydebounce = POLARITY_DEBOUNCE; - } + if (fxo->lastpol >= 0) { + if (b < 0) { + fxo->lastpol = -1; + fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK; + } } - if (wc->mod[card].fxo.lastpol <= 0) { - if (b > 0) { - wc->mod[card].fxo.lastpol = 1; - wc->mod[card].fxo.polaritydebounce = POLARITY_DEBOUNCE; - } + if (fxo->lastpol <= 0) { + if (b > 0) { + fxo->lastpol = 1; + fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK; + } } - } else { - /* It's something else... */ - wc->mod[card].fxo.battdebounce = battdebounce; - } - if (wc->mod[card].fxo.battdebounce) - wc->mod[card].fxo.battdebounce--; - if (wc->mod[card].fxo.polaritydebounce) { - wc->mod[card].fxo.polaritydebounce--; - if (wc->mod[card].fxo.polaritydebounce < 1) { - if (wc->mod[card].fxo.lastpol != wc->mod[card].fxo.polarity) { + } + + 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); + } + } + + if (fxo->polaritydebounce) { + if (--fxo->polaritydebounce == 0) { + if (fxo->lastpol != fxo->polarity) { if (debug) printk("%lu Polarity reversed (%d -> %d)\n", jiffies, - wc->mod[card].fxo.polarity, - wc->mod[card].fxo.lastpol); - if (wc->mod[card].fxo.polarity) - zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY); - wc->mod[card].fxo.polarity = wc->mod[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) @@ -2398,7 +2356,8 @@ 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; } @@ -2406,16 +2365,30 @@ 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