summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctdm.c
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 /drivers/dahdi/wctdm.c
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
Diffstat (limited to 'drivers/dahdi/wctdm.c')
-rw-r--r--drivers/dahdi/wctdm.c162
1 files changed, 110 insertions, 52 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;