summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Bailey <dbailey@digium.com>2009-01-19 15:15:32 +0000
committerDoug Bailey <dbailey@digium.com>2009-01-19 15:15:32 +0000
commit7e03d13b98e477162a8b25a5b5e2a6886b2deedf (patch)
tree2432050a959c38cae2015521767450f6e9cea49e
parent503296d3b2283afe9e11a3558733692068f2e358 (diff)
Add line reversal MWI to wctdm and wctdm24xxp drivers
Add global and per channel polarity control to the wctdm24xxp driver Add per channel polarity control to the wctdm driver Reported by: alecdavis Patches: dahdidriver-14104.diff2.txt uploaded by dbailey (license ) Tested by: alecdavis git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@5720 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wctdm.c162
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c150
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h8
-rw-r--r--include/dahdi/user.h8
4 files changed, 253 insertions, 75 deletions
diff --git a/drivers/dahdi/wctdm.c b/drivers/dahdi/wctdm.c
index eacf33c..2d92a80 100644
--- a/drivers/dahdi/wctdm.c
+++ b/drivers/dahdi/wctdm.c
@@ -55,6 +55,7 @@
0x07 : 41mA
*/
static int loopcurrent = 20;
+#define POLARITY_XOR(card) ((reversepolarity!=0) ^ (wc->mod[(card)].fxs.reversepolarity!=0) ^ (wc->mod[(card)].fxs.vmwi_lrev!=0))
static int reversepolarity = 0;
@@ -236,6 +237,12 @@ struct wctdm {
int idletxhookstate; /* IDLE changing hook state */
int lasttxhook;
int palarms;
+ int reversepolarity; /* Reverse Line */
+ int mwisendtype;
+ int vmwimessages; /* 0=none 1-255=number of messages */
+ int vmwi_lrev:1; /* MWI Line Reversal*/
+ int vmwi_hvdc:1; /* MWI High Voltage DC Idle line */
+ int vmwi_hvac:1; /* MWI Neon High Voltage AC Idle line */
struct calregs calregs;
} fxs;
} mod[NUM_CARDS];
@@ -1040,24 +1047,21 @@ DAHDI_IRQ_HANDLER(wctdm_interrupt)
if (wc->mod[x].fxs.lasttxhook == 0x4) {
/* RINGing, prepare for OHT */
wc->mod[x].fxs.ohttimer = OHT_TIMER << 3;
- if (reversepolarity)
- wc->mod[x].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
- else
- wc->mod[x].fxs.idletxhookstate = 0x2;
+
+ /* logical XOR 3 variables
+ module parameter 'reversepolarity', global reverse all FXS lines.
+ ioctl channel variable fxs 'reversepolarity', Line Reversal Alert Signal if required.
+ ioctl channel variable fxs 'vmwi_lrev', VMWI pending.
+ */
+ wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x6 : 0x2;/* OHT mode when idle */
} else {
if (wc->mod[x].fxs.ohttimer) {
wc->mod[x].fxs.ohttimer-= DAHDI_CHUNKSIZE;
if (!wc->mod[x].fxs.ohttimer) {
- if (reversepolarity)
- wc->mod[x].fxs.idletxhookstate = 0x5; /* Switch to active */
- else
- wc->mod[x].fxs.idletxhookstate = 0x1;
+ wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to Active : Reverse Forward */
if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook == 0x6)) {
/* Apply the change if appropriate */
- if (reversepolarity)
- wc->mod[x].fxs.lasttxhook = 0x5;
- else
- wc->mod[x].fxs.lasttxhook = 0x1;
+ wc->mod[x].fxs.lasttxhook = POLARITY_XOR(x) ? 0x5 : 0x1;
wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook);
}
}
@@ -1093,9 +1097,10 @@ DAHDI_IRQ_HANDLER(wctdm_interrupt)
/* Perform processing */
if (wc->modtype[x] == MOD_TYPE_FXS) {
wctdm_proslic_check_hook(wc, x);
- if (!(wc->intcount & 0xf0))
+ if (!(wc->intcount & 0xf0)) {
wctdm_proslic_recheck_sanity(wc, x);
- } else if (wc->modtype[x] == MOD_TYPE_FXO) {
+ }
+ } else if (wc->modtype[x] == MOD_TYPE_FXO) {
wctdm_voicedaa_check_hook(wc, x);
}
break;
@@ -1314,31 +1319,31 @@ static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card){
// Delay 10ms
origjiffies=jiffies;
while((jiffies-origjiffies)<1);
- wctdm_proslic_setreg_indirect(wc, card, 88,0);
- wctdm_proslic_setreg_indirect(wc,card,89,0);
- wctdm_proslic_setreg_indirect(wc,card,90,0);
- wctdm_proslic_setreg_indirect(wc,card,91,0);
- wctdm_proslic_setreg_indirect(wc,card,92,0);
- wctdm_proslic_setreg_indirect(wc,card,93,0);
+ wctdm_proslic_setreg_indirect(wc, card, 88, 0);
+ wctdm_proslic_setreg_indirect(wc, card, 89, 0);
+ wctdm_proslic_setreg_indirect(wc, card, 90, 0);
+ wctdm_proslic_setreg_indirect(wc, card, 91, 0);
+ wctdm_proslic_setreg_indirect(wc, card, 92, 0);
+ wctdm_proslic_setreg_indirect(wc, card, 93, 0);
- wctdm_setreg(wc, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time
- wctdm_setreg(wc, card, 99,0x10);
+ wctdm_setreg(wc, card, 98, 0x10); // This is necessary if the calibration occurs other than at reset time
+ wctdm_setreg(wc, card, 99, 0x10);
for ( i=0x1f; i>0; i--)
{
- wctdm_setreg(wc, card, 98,i);
+ wctdm_setreg(wc, card, 98, i);
origjiffies=jiffies;
while((jiffies-origjiffies)<4);
- if((wctdm_getreg(wc,card,88)) == 0)
+ if((wctdm_getreg(wc, card, 88)) == 0)
break;
} // for
for ( i=0x1f; i>0; i--)
{
- wctdm_setreg(wc, card, 99,i);
+ wctdm_setreg(wc, card, 99, i);
origjiffies=jiffies;
while((jiffies-origjiffies)<4);
- if((wctdm_getreg(wc,card,89)) == 0)
+ if((wctdm_getreg(wc, card, 89)) == 0)
break;
}//for
@@ -1350,9 +1355,9 @@ static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card){
wctdm_setreg(wc, card, 64, 0);
wctdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal
wctdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration
- wctdm_setreg(wc, card, 96,0x40);
+ wctdm_setreg(wc, card, 96, 0x40);
- wctdm_getreg(wc,card,96); /* Read Reg 96 just cause */
+ wctdm_getreg(wc, card, 96); /* Read Reg 96 just cause */
wctdm_setreg(wc, card, 21, 0xFF);
wctdm_setreg(wc, card, 22, 0xFF);
@@ -1462,10 +1467,11 @@ static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual,
wait_just_a_bit(HZ/10);
/* Enable PCM, ulaw */
- if (alawoverride)
+ if (alawoverride){
wctdm_setreg(wc, card, 33, 0x20);
- else
+ } else {
wctdm_setreg(wc, card, 33, 0x28);
+ }
/* Set On-hook speed, Ringer impedence, and ringer threshold */
reg16 |= (fxo_modes[_opermode].ohs << 6);
@@ -1560,9 +1566,16 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
/* Sanity check the ProSLIC */
if (!sane && wctdm_proslic_insane(wc, card))
return -2;
+
+ /* default messages to none and method to FSK */
+ wc->mod[card].fxs.mwisendtype=DAHDI_VMWI_FSK;
+ wc->mod[card].fxs.vmwimessages=0;
+ wc->mod[card].fxs.vmwi_lrev=0;
+ wc->mod[card].fxs.vmwi_hvdc=0;
+ wc->mod[card].fxs.vmwi_hvac=0;
/* By default, don't send on hook */
- if (reversepolarity)
+ if (!reversepolarity != !wc->mod[card].fxs.reversepolarity)
wc->mod[card].fxs.idletxhookstate = 5;
else
wc->mod[card].fxs.idletxhookstate = 1;
@@ -1781,7 +1794,8 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
if(debug)
printk(KERN_DEBUG "DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
- wctdm_setreg(wc, card, 64, 0x01);
+ wc->mod[card].fxs.lasttxhook = wc->mod[card].fxs.idletxhookstate;
+ wctdm_setreg(wc, card, 64, wc->mod[card].fxs.lasttxhook);
return 0;
}
@@ -1802,17 +1816,11 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
if (get_user(x, (__user int *) data))
return -EFAULT;
wc->mod[chan->chanpos - 1].fxs.ohttimer = x << 3;
- if (reversepolarity)
- wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
- else
- wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x2;
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; /* OHT mode when idle */
if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) {
- /* Apply the change if appropriate */
- if (reversepolarity)
- wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6;
- else
- wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2;
- wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
+ /* Apply the change if appropriate */
+ wc->mod[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2;
+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
}
break;
case DAHDI_SETPOLARITY:
@@ -1824,13 +1832,63 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
if ((wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) ||
(wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00))
return -EINVAL;
-
- if ((x && !reversepolarity) || (!x && reversepolarity))
+
+ wc->mod[chan->chanpos - 1].fxs.reversepolarity = x;
+ if ( POLARITY_XOR(chan->chanpos - 1) )
wc->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04;
else
wc->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04;
wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
break;
+ case DAHDI_VMWI:
+ /* value: bits 15-8 VMWI TYPE */
+ /* bits 7-0 VMWI number of messages */
+ if (get_user(x, (__user int *) data))
+ return -EFAULT;
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+
+ wc->mod[chan->chanpos - 1].fxs.vmwimessages = (x & 255);
+ wc->mod[chan->chanpos - 1].fxs.mwisendtype = (x & ~255);
+ if (wc->mod[chan->chanpos - 1].fxs.vmwimessages){
+ x = wc->mod[chan->chanpos - 1].fxs.mwisendtype;
+ wc->mod[chan->chanpos - 1].fxs.vmwi_lrev = (x & DAHDI_VMWI_LREV)?1:0;
+ wc->mod[chan->chanpos - 1].fxs.vmwi_hvdc = (x & DAHDI_VMWI_HVDC)?1:0;
+ wc->mod[chan->chanpos - 1].fxs.vmwi_hvac = (x & DAHDI_VMWI_HVAC)?1:0;
+ } else {
+ wc->mod[chan->chanpos - 1].fxs.vmwi_lrev = 0;
+ wc->mod[chan->chanpos - 1].fxs.vmwi_hvdc = 0;
+ wc->mod[chan->chanpos - 1].fxs.vmwi_hvac = 0;
+ }
+
+ if (debug) {
+ printk(KERN_DEBUG "Setting VMWI on channel %d, type=0x%X, messages=%d, lrev=%d, hvdc=%d, hvac=%d\n",
+ chan->chanpos-1,
+ wc->mod[chan->chanpos - 1].fxs.mwisendtype,
+ wc->mod[chan->chanpos - 1].fxs.vmwimessages,
+ wc->mod[chan->chanpos - 1].fxs.vmwi_lrev,
+ wc->mod[chan->chanpos - 1].fxs.vmwi_hvdc,
+ wc->mod[chan->chanpos - 1].fxs.vmwi_hvac
+ );
+ }
+ if (POLARITY_XOR(chan->chanpos -1)) {
+ wc->mod[chan->chanpos -1 ].fxs.idletxhookstate |= 0x4;
+ /* Do not set while currently ringing or open */
+ if (wc->mod[chan->chanpos -1 ].fxs.lasttxhook != 0x04 &&
+ wc->mod[chan->chanpos -1 ].fxs.lasttxhook != 0x00) {
+ wc->mod[chan->chanpos -1 ].fxs.lasttxhook |= 0x4;
+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
+ }
+ } else {
+ wc->mod[chan->chanpos -1 ].fxs.idletxhookstate &= ~0x04;
+ /* Do not set while currently ringing or open */
+ if (wc->mod[chan->chanpos -1 ].fxs.lasttxhook != 0x04 &&
+ wc->mod[chan->chanpos -1 ].fxs.lasttxhook != 0x00) {
+ wc->mod[chan->chanpos -1 ].fxs.lasttxhook &= ~0x04;
+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
+ }
+ }
+ break;
case WCTDM_GET_STATS:
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376;
@@ -1942,10 +2000,7 @@ static int wctdm_close(struct dahdi_chan *chan)
wc->usecount--;
module_put(THIS_MODULE);
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
- if (reversepolarity)
- wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 5;
- else
- wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 1;
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x5 : 0x1;
}
/* If we're dead, release us now */
if (!wc->usecount && wc->dead)
@@ -1956,7 +2011,7 @@ static int wctdm_close(struct dahdi_chan *chan)
static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
{
struct wctdm *wc = chan->pvt;
- int reg=0;
+
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
/* XXX Enable hooksig for FXO XXX */
switch(txsig) {
@@ -1976,9 +2031,11 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
switch(txsig) {
case DAHDI_TXSIG_ONHOOK:
switch(chan->sig) {
- case DAHDI_SIG_EM:
case DAHDI_SIG_FXOKS:
case DAHDI_SIG_FXOLS:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = (wc->mod[chan->chanpos-1].fxs.vmwi_hvac ? 4 : wc->mod[chan->chanpos-1].fxs.idletxhookstate);
+ break;
+ case DAHDI_SIG_EM:
wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
break;
case DAHDI_SIG_FXOGS:
@@ -2006,7 +2063,7 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
printk(KERN_NOTICE "wctdm: Can't set tx state to %d\n", txsig);
}
if (debug)
- printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, reg);
+ printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, wc->mod[chan->chanpos-1].fxs.lasttxhook);
#if 1
wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos-1].fxs.lasttxhook);
@@ -2029,8 +2086,9 @@ static int wctdm_initialize(struct wctdm *wc)
if (alawoverride) {
printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n");
wc->span.deflaw = DAHDI_LAW_ALAW;
- } else
+ } else {
wc->span.deflaw = DAHDI_LAW_MULAW;
+ }
for (x = 0; x < NUM_CARDS; x++) {
sprintf(wc->chans[x]->name, "WCTDM/%d/%d", wc->pos, x);
wc->chans[x]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR;
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 8811673..e80ac82 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -81,6 +81,15 @@ Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db
*/
static int loopcurrent = 20;
+/* Following define is a logical exclusive OR to determine if the polarity of an fxs line is to be reversed.
+ * The items taken into account are:
+ * overall polarity reversal for the module,
+ * polarity reversal for the port,
+ * and the state of the line reversal MWI indicator
+ */
+#define POLARITY_XOR(card) ( (reversepolarity != 0) ^ (wc->mods[(card)].fxs.reversepolarity != 0) ^ (wc->mods[(card)].fxs.vmwilinereverse != 0) )
+static int reversepolarity = 0;
+
static alpha indirect_regs[] =
{
{0,255,"DTMF_ROW_0_PEAK",0x55C2},
@@ -1035,8 +1044,9 @@ static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
wc->mods[card].fxs.palarms++;
if (wc->mods[card].fxs.palarms < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm (%02x) on module %d, resetting!\n", res, card + 1);
- if (wc->mods[card].fxs.lasttxhook == 4)
- wc->mods[card].fxs.lasttxhook = 0x11;
+ if (wc->mods[card].fxs.lasttxhook == 4) {
+ wc->mods[card].fxs.lasttxhook = POLARITY_XOR(card) ? 0x15 : 0x11;
+ }
wc->sethook[card] = CMD_WR(19, res);
#if 0
wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook);
@@ -1064,8 +1074,9 @@ static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
wc->mods[card].fxs.palarms++;
if (wc->mods[card].fxs.palarms < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1);
- if (wc->mods[card].fxs.lasttxhook == 4)
- wc->mods[card].fxs.lasttxhook = 0x11;
+ if (wc->mods[card].fxs.lasttxhook == 4) {
+ wc->mods[card].fxs.lasttxhook = POLARITY_XOR(card) ? 0x15 : 0x11;;
+ }
wc->mods[card].fxs.lasttxhook |= 0x10;
wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook);
@@ -1543,16 +1554,21 @@ static inline void wctdm_isr_misc(struct wctdm *wc)
if (wc->mods[x].fxs.lasttxhook == 0x4) {
/* RINGing, prepare for OHT */
wc->mods[x].fxs.ohttimer = OHT_TIMER << 3;
- wc->mods[x].fxs.idletxhookstate = 0x2; /* OHT mode when idle */
+ wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x6 : 0x2; /* OHT mode when idle */
} else {
if (wc->mods[x].fxs.ohttimer) {
wc->mods[x].fxs.ohttimer-= DAHDI_CHUNKSIZE;
if (!wc->mods[x].fxs.ohttimer) {
- wc->mods[x].fxs.idletxhookstate = 0x1; /* Switch to active */
- if (wc->mods[x].fxs.lasttxhook == 0x2) {
+ wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to active */
+ if (wc->mods[x].fxs.lasttxhook == 0x2) {
/* Apply the change if appropriate */
wc->mods[x].fxs.lasttxhook = 0x11;
- wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook);
+ wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */
+ /* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */
+ } else if (wc->mods[x].fxs.lasttxhook == 0x6) {
+ /* Apply the change if appropriate */
+ wc->mods[x].fxs.lasttxhook = 0x15;
+ wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */
/* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */
}
}
@@ -1942,10 +1958,11 @@ static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual,
wait_just_a_bit(HZ/10);
/* Enable PCM, ulaw */
- if (alawoverride)
+ if (alawoverride) {
wctdm_setreg(wc, card, 33, 0x20);
- else
+ } else {
wctdm_setreg(wc, card, 33, 0x28);
+ }
/* Set On-hook speed, Ringer impedence, and ringer threshold */
reg16 |= (fxo_modes[_opermode].ohs << 6);
@@ -2034,8 +2051,17 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
if (!sane && wctdm_proslic_insane(wc, card))
return -2;
+ /* Initialize VMWI settings */
+ wc->mods[card].fxs.mwisendtype = 0;
+ wc->mods[card].fxs.vmwimessages = 0;
+ wc->mods[card].fxs.vmwilinereverse = 0;
+
/* By default, don't send on hook */
- wc->mods[card].fxs.idletxhookstate = 1;
+ if (!reversepolarity != !wc->mods[card].fxs.reversepolarity) {
+ wc->mods[card].fxs.idletxhookstate = 5;
+ } else {
+ wc->mods[card].fxs.idletxhookstate = 1;
+ }
wc->mods[card].fxs.lasttxhook = 0x10;
if (sane) {
@@ -2253,8 +2279,8 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
if (debug)
printk(KERN_DEBUG "DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
- wc->mods[card].fxs.lasttxhook = 0x11;
- wctdm_setreg(wc, card, 64, 0x01);
+ wc->mods[card].fxs.lasttxhook = wc->mods[card].fxs.idletxhookstate;
+ wctdm_setreg(wc, card, 64, wc->mods[card].fxs.lasttxhook);
return 0;
}
@@ -2412,13 +2438,60 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
return -EFAULT;
wc->mods[chan->chanpos - 1].fxs.ohttimer = x << 3;
wc->mods[chan->chanpos - 1].fxs.idletxhookstate = 0x2; /* OHT mode when idle */
- if (wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x1) {
+ if (wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x5) {
/* Apply the change if appropriate */
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x12;
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos -1) ? 0x16 : 0x12;
wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
/* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */
}
break;
+ case DAHDI_VMWI:
+ /* value: bits 15-8 VMWI TYPE */
+ /* bits 7-0 VMWI number of messages */
+ if (get_user(x, (__user int *) data))
+ return -EFAULT;
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+
+ wc->mods[chan->chanpos - 1].fxs.vmwimessages = (x & 255);
+ wc->mods[chan->chanpos - 1].fxs.mwisendtype = (x & ~255);
+ if (wc->mods[chan->chanpos - 1].fxs.vmwimessages){
+ x = wc->mods[chan->chanpos - 1].fxs.mwisendtype;
+ wc->mods[chan->chanpos - 1].fxs.vmwilinereverse= (x & DAHDI_VMWI_LREV)?1:0;
+ } else {
+ wc->mods[chan->chanpos - 1].fxs.vmwilinereverse= 0;
+ }
+ /* Set line polarity for new VMWI state */
+ if (POLARITY_XOR(chan->chanpos -1)) {
+ wc->mods[chan->chanpos -1 ].fxs.idletxhookstate |= 0x14;
+ /* Do not set while currently ringing or open */
+ if (wc->mods[chan->chanpos -1 ].fxs.lasttxhook != 0x04 &&
+ wc->mods[chan->chanpos -1 ].fxs.lasttxhook != 0x00) {
+ wc->mods[chan->chanpos -1 ].fxs.lasttxhook |= 0x14;
+ wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
+ }
+ } else {
+ wc->mods[chan->chanpos -1 ].fxs.idletxhookstate &= ~0x04;
+ /* Do not set while currently ringing or open */
+ if (wc->mods[chan->chanpos -1 ].fxs.lasttxhook != 0x04 &&
+ wc->mods[chan->chanpos -1 ].fxs.lasttxhook != 0x00) {
+ x = wc->mods[chan->chanpos -1 ].fxs.lasttxhook;
+ x &= ~0x04;
+ x |= 0x10;
+ wc->mods[chan->chanpos -1 ].fxs.lasttxhook = x;
+ wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
+ }
+ }
+
+ if (debug) {
+ printk(KERN_DEBUG "Setting VMWI on channel %d, type=0x%X, messages=%d, lrev=%d\n",
+ chan->chanpos-1,
+ wc->mods[chan->chanpos - 1].fxs.mwisendtype,
+ wc->mods[chan->chanpos - 1].fxs.vmwimessages,
+ wc->mods[chan->chanpos - 1].fxs.vmwilinereverse
+ );
+ }
+ break;
case WCTDM_GET_STATS:
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376;
@@ -2529,6 +2602,32 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
}
return 0;
#endif
+ case DAHDI_SETPOLARITY:
+ if (get_user(x, (__user int *) data))
+ return -EFAULT;
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+ /* Can't change polarity while ringing or when open */
+ if ((wc->mods[chan->chanpos -1 ].fxs.lasttxhook == 0x04) ||
+ (wc->mods[chan->chanpos -1 ].fxs.lasttxhook == 0x00))
+ return -EINVAL;
+ if (x) {
+ wc->mods[chan->chanpos -1 ].fxs.reversepolarity = 1;
+ } else {
+ wc->mods[chan->chanpos -1 ].fxs.reversepolarity = 0;
+ }
+ if (POLARITY_XOR(chan->chanpos -1)) {
+ wc->mods[chan->chanpos -1 ].fxs.idletxhookstate |= 0x14;
+ wc->mods[chan->chanpos -1 ].fxs.lasttxhook |= 0x14;
+ } else {
+ wc->mods[chan->chanpos -1 ].fxs.idletxhookstate &= ~0x04;
+ x = wc->mods[chan->chanpos -1 ].fxs.lasttxhook;
+ x &= ~0x04;
+ x |= 0x10;
+ wc->mods[chan->chanpos -1 ].fxs.lasttxhook = x;
+ }
+ wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
+ break;
case DAHDI_RADIO_GETPARAM:
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV)
return -ENOTTY;
@@ -2713,8 +2812,9 @@ static int wctdm_close(struct dahdi_chan *chan)
wc->usecount--;
module_put(THIS_MODULE);
for (x=0;x<wc->cards;x++) {
- if (wc->modtype[x] == MOD_TYPE_FXS)
- wc->mods[x].fxs.idletxhookstate = 1;
+ if (wc->modtype[x] == MOD_TYPE_FXS) {
+ wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 5 : 1;
+ }
if (wc->modtype[x] == MOD_TYPE_QRV)
{
int qrvcard = x & 0xfc;
@@ -2788,14 +2888,22 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
wc->mods[chan->chanpos - 1].fxs.idletxhookstate;
break;
case DAHDI_SIG_FXOGS:
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x13;
+ if (POLARITY_XOR(chan->chanpos -1)) {
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x17;
+ } else {
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x13;
+ }
break;
}
break;
case DAHDI_TXSIG_OFFHOOK:
switch(chan->sig) {
case DAHDI_SIG_EM:
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x15;
+ if (POLARITY_XOR(chan->chanpos -1)) {
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x11;
+ } else {
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x15;
+ }
break;
default:
wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 |
@@ -2934,8 +3042,9 @@ static int wctdm_initialize(struct wctdm *wc)
if (alawoverride) {
printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n");
wc->span.deflaw = DAHDI_LAW_ALAW;
- } else
+ } else {
wc->span.deflaw = DAHDI_LAW_MULAW;
+ }
for (x=0;x<wc->cards;x++) {
sprintf(wc->chans[x]->name, "WCTDM/%d/%d", wc->pos, x);
wc->chans[x]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR;
@@ -4093,6 +4202,7 @@ static void __exit wctdm_cleanup(void)
module_param(debug, int, 0600);
module_param(fxovoltage, int, 0600);
module_param(loopcurrent, int, 0600);
+module_param(reversepolarity, int, 0600);
module_param(robust, int, 0600);
module_param(opermode, charp, 0600);
module_param(lowpower, int, 0600);
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index 3974a57..1e970e4 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -245,9 +245,13 @@ struct wctdm {
int lastrxhook;
int debounce;
int ohttimer;
- int idletxhookstate; /* IDLE changing hook state */
- int lasttxhook;
+ int idletxhookstate; /* IDLE changing hook state */
+ int lasttxhook; /* Bits 0-3 are written to proslic reg 64, Bit 4 indicates if the last write is pending */
int palarms;
+ int mwisendtype;
+ int vmwimessages; /* 0=none 1-255=number of messages */
+ int vmwilinereverse; /* MWI Line Reversal*/
+ int reversepolarity; /* polarity reversal */
struct calregs calregs;
} fxs;
} mods[NUM_CARDS];
diff --git a/include/dahdi/user.h b/include/dahdi/user.h
index 2a1ae4b..554b094 100644
--- a/include/dahdi/user.h
+++ b/include/dahdi/user.h
@@ -967,11 +967,17 @@ struct dahdi_hwgain {
#define DAHDI_TC_GETINFO _IOWR(DAHDI_TC_CODE, 2, struct dahdi_transcoder_info)
/*
- * VoiceMail Waiting Indication (WMWI) -- implemented by low-level driver.
+ * VoiceMail Waiting Indication (VMWI) -- implemented by low-level driver.
* Value: number of waiting messages (hence 0: switch messages off).
*/
#define DAHDI_VMWI _IOWR(DAHDI_CODE, 94, int)
+#define DAHDI_VMWI_FSK (1 << 8) /* default FSK, no Ring Pulse Alert Signal*/
+#define DAHDI_VMWI_RPAS (1 << 9) /* Ring Pulse Alert Signal then FSK */
+#define DAHDI_VMWI_LREV (1 << 10) /* Line Reversal */
+#define DAHDI_VMWI_HVDC (1 << 11) /* HV 90VDC */
+#define DAHDI_VMWI_HVAC (1 << 12) /* HV 90VAC Neon lamp */
+
/*
* Startup or Shutdown a span
*/