summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctdm24xxp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dahdi/wctdm24xxp')
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c156
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h12
2 files changed, 96 insertions, 72 deletions
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 29cf17c..51a2c65 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -623,7 +623,7 @@ static inline void cmd_dequeue(struct wctdm *wc, unsigned char *writechunk, int
if (!curcmd) {
/* If nothing else, use filler */
if (wc->modtype[card] == MOD_TYPE_FXS)
- curcmd = CMD_RD(64);
+ curcmd = CMD_RD(LINE_STATE);
else if (wc->modtype[card] == MOD_TYPE_FXO)
curcmd = CMD_RD(12);
else if (wc->modtype[card] == MOD_TYPE_QRV)
@@ -818,7 +818,7 @@ static inline void cmd_checkisr(struct wctdm *wc, int card)
#ifdef PAQ_DEBUG
wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(19); /* Transistor interrupts */
#else
- wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(64); /* Battery mode */
+ wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(LINE_STATE);
#endif
} else if (wc->modtype[card] == MOD_TYPE_FXO) {
wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(29); /* Battery */
@@ -1186,6 +1186,7 @@ static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
{
struct fxs *const fxs = &wc->mods[card].fxs;
int res;
+ unsigned long flags;
#ifdef PAQ_DEBUG
res = wc->cmdq[card].isrshadow[1];
res &= ~0x3;
@@ -1194,17 +1195,7 @@ static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
fxs->palarms++;
if (fxs->palarms < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm (%02x) on module %d, resetting!\n", res, card + 1);
- if (fxs->lasttxhook == SLIC_LF_RINGING) {
- fxs->lasttxhook = 0x10 | POLARITY_XOR(card) ?
- SLIC_LF_ACTIVE_REV :
- SLIC_LF_ACTIVE_FWD;
- }
wc->sethook[card] = CMD_WR(19, res);
-#if 0
- wc->sethook[card] = CMD_WR(64, fxs->lasttxhook);
-#endif
-
- /* wctdm_setreg_intr(wc, card, 64, fxs->lasttxhook); */
/* Update shadow register to avoid extra power alarms until next read */
wc->cmdq[card].isrshadow[1] = 0;
} else {
@@ -1213,28 +1204,31 @@ static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
}
}
#else
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
res = wc->cmdq[card].isrshadow[1];
/* This makes sure the lasthook was put in reg 64 the linefeed reg */
- if (((res & 0x0f) | 0x10) == fxs->lasttxhook)
- fxs->lasttxhook &= 0x0f;
+ if (((res & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING) == fxs->lasttxhook)
+ fxs->lasttxhook &= SLIC_LF_SETMASK;
res = !res && /* reg 64 has to be zero at last isr read */
- !(fxs->lasttxhook & 0x10) && /* not a transition */
+ !(fxs->lasttxhook & SLIC_LF_OPPENDING) && /* not a transition */
fxs->lasttxhook; /* not an intended zero */
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
if (res) {
fxs->palarms++;
if (fxs->palarms < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1);
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
if (fxs->lasttxhook == SLIC_LF_RINGING) {
fxs->lasttxhook = POLARITY_XOR(card) ?
SLIC_LF_ACTIVE_REV :
SLIC_LF_ACTIVE_FWD;;
}
- fxs->lasttxhook |= 0x10;
- wc->sethook[card] = CMD_WR(64, fxs->lasttxhook);
+ fxs->lasttxhook |= SLIC_LF_OPPENDING;
+ wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
- /* wctdm_setreg_intr(wc, card, 64, fxs->lasttxhook); */
/* Update shadow register to avoid extra power alarms until next read */
wc->cmdq[card].isrshadow[1] = fxs->lasttxhook;
} else {
@@ -1751,6 +1745,7 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec
static void wctdm_isr_misc_fxs(struct wctdm *wc, int card)
{
struct fxs *const fxs = &wc->mods[card].fxs;
+ unsigned long flags;
if (!(wc->intcount % 10000)) {
/* Accept an alarm once per 10 seconds */
@@ -1774,19 +1769,19 @@ static void wctdm_isr_misc_fxs(struct wctdm *wc, int card)
/* Switch to active */
fxs->idletxhookstate = POLARITY_XOR(card) ? SLIC_LF_ACTIVE_REV :
SLIC_LF_ACTIVE_FWD;
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
if (SLIC_LF_OHTRAN_FWD == fxs->lasttxhook) {
/* Apply the change if appropriate */
- fxs->lasttxhook = 0x10 | SLIC_LF_ACTIVE_FWD;
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_FWD;
/* Data enqueued here */
- wc->sethook[card] = CMD_WR(64, fxs->lasttxhook);
- /* wctdm_setreg_intr(wc, x, 64, fxs->lasttxhook); */
+ wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook);
} else if (SLIC_LF_OHTRAN_REV == fxs->lasttxhook) {
/* Apply the change if appropriate */
- fxs->lasttxhook = 0x10 | SLIC_LF_ACTIVE_REV;
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_REV;
/* Data enqueued here */
- wc->sethook[card] = CMD_WR(64, fxs->lasttxhook);
- /* wctdm_setreg_intr(wc, x, 64, fxs->lasttxhook); */
+ wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook);
}
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
}
}
@@ -1915,7 +1910,7 @@ static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card)
unsigned char vbat;
/* Turn off linefeed */
- wctdm_setreg(wc, card, 64, 0);
+ wctdm_setreg(wc, card, LINE_STATE, 0);
/* Power down */
wctdm_setreg(wc, card, 14, 0x10);
@@ -2167,6 +2162,31 @@ static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx)
return 0;
}
+static int set_lasttxhook_interruptible(struct fxs *fxs, unsigned newval, int * psethook)
+{
+ int res = 0;
+ unsigned long flags;
+ int timeout = 0;
+
+ do {
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
+ if (SLIC_LF_OPPENDING & fxs->lasttxhook) {
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
+ if (timeout++ > 100)
+ return -1;
+ msleep(1);
+ } else {
+ fxs->lasttxhook = (newval & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING;
+ *psethook = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
+ break;
+ }
+ } while (1);
+
+ return res;
+}
+
+/* Must be called from within an interruptible context */
static int set_vmwi(struct wctdm *wc, int chan_idx)
{
int x;
@@ -2181,23 +2201,22 @@ static int set_vmwi(struct wctdm *wc, int chan_idx)
/* Set line polarity for new VMWI state */
if (POLARITY_XOR(chan_idx)) {
- fxs->idletxhookstate |= 0x10 | SLIC_LF_REVMASK;
+ fxs->idletxhookstate |= SLIC_LF_OPPENDING | SLIC_LF_REVMASK;
/* Do not set while currently ringing or open */
- if ((fxs->lasttxhook != SLIC_LF_RINGING) &&
- (fxs->lasttxhook != SLIC_LF_OPEN)) {
- fxs->lasttxhook |= 0x10 | SLIC_LF_REVMASK;
- wc->sethook[chan_idx] = CMD_WR(64, fxs->lasttxhook);
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) &&
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) {
+ x = fxs->lasttxhook;
+ x |= SLIC_LF_REVMASK;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan_idx]);
}
} else {
fxs->idletxhookstate &= ~SLIC_LF_REVMASK;
/* Do not set while currently ringing or open */
- if ((fxs->lasttxhook != SLIC_LF_RINGING) &&
- (fxs->lasttxhook != SLIC_LF_OPEN)) {
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) &&
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) {
x = fxs->lasttxhook;
x &= ~SLIC_LF_REVMASK;
- x |= 0x10;
- fxs->lasttxhook = x;
- wc->sethook[chan_idx] = CMD_WR(64, fxs->lasttxhook);
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan_idx]);
}
}
if (debug) {
@@ -2336,7 +2355,6 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
} else {
wc->mods[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_FWD;
}
- wc->mods[card].fxs.lasttxhook = 0x10;
if (sane) {
/* Make sure we turn off the DC->DC converter to prevent anything from blowing up */
@@ -2379,6 +2397,7 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
}
if (!fast) {
+ spin_lock_init(&wc->mods[card].fxs.lasttxhooklock);
/* Check for power leaks */
if (wctdm_proslic_powerleak_test(wc, card)) {
@@ -2554,7 +2573,7 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
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 = wc->mods[card].fxs.idletxhookstate;
- wctdm_setreg(wc, card, 64, wc->mods[card].fxs.lasttxhook);
+ wctdm_setreg(wc, card, LINE_STATE, wc->mods[card].fxs.lasttxhook);
return 0;
}
@@ -2718,19 +2737,12 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
SLIC_LF_ACTIVE_REV :
SLIC_LF_ACTIVE_FWD;
- if ((fxs->lasttxhook == SLIC_LF_ACTIVE_FWD) ||
- (fxs->lasttxhook == SLIC_LF_ACTIVE_REV)) {
-
- /* Apply the change if appropriate */
- fxs->lasttxhook = 0x10 |
- POLARITY_XOR(chan->chanpos - 1) ?
- SLIC_LF_OHTRAN_REV :
- SLIC_LF_OHTRAN_FWD;
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_FWD) ||
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_REV)) {
- wc->sethook[chan->chanpos - 1] =
- CMD_WR(64, fxs->lasttxhook);
- /* wctdm_setreg(wc, chan->chanpos - 1, 64,
- * fxs->lasttxhook); */
+ set_lasttxhook_interruptible(fxs, POLARITY_XOR(chan->chanpos - 1)
+ ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD ,
+ &wc->sethook[chan->chanpos - 1]);
}
break;
case DAHDI_VMWI_CONFIG:
@@ -2794,9 +2806,10 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val);
} else {
regop.val &= 0xff;
- if (regop.reg == 64)
- fxs->lasttxhook = (regop.val & 0x0f) | 0x10;
-
+ if (regop.reg == LINE_STATE) {
+ /* Set feedback register to indicate the new state that is being set */
+ fxs->lasttxhook = (regop.val & 0x0f) | SLIC_LF_OPPENDING;
+ }
printk(KERN_INFO "Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos);
wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val);
}
@@ -2849,23 +2862,23 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
return -EINVAL;
/* Can't change polarity while ringing or when open */
- if ((fxs->lasttxhook == SLIC_LF_RINGING) ||
- (fxs->lasttxhook == SLIC_LF_OPEN))
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_RINGING) ||
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_OPEN))
return -EINVAL;
fxs->reversepolarity = (x) ? 1 : 0;
if (POLARITY_XOR(chan->chanpos -1)) {
fxs->idletxhookstate |= SLIC_LF_REVMASK;
- fxs->lasttxhook |= 0x10 | SLIC_LF_REVMASK;
+ x = fxs->lasttxhook;
+ x |= SLIC_LF_REVMASK;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan->chanpos - 1]);
} else {
fxs->idletxhookstate &= ~SLIC_LF_REVMASK;
x = fxs->lasttxhook;
x &= ~SLIC_LF_REVMASK;
- x |= 0x10;
- fxs->lasttxhook = x;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan->chanpos - 1]);
}
- wc->sethook[chan->chanpos - 1] = CMD_WR(64, fxs->lasttxhook);
break;
case DAHDI_RADIO_GETPARAM:
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV)
@@ -3075,6 +3088,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,qrvcard;
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) {
qrvcard = (chan->chanpos - 1) & 0xfc;
@@ -3110,23 +3124,25 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
default:
printk(KERN_NOTICE "wctdm24xxp: Can't set tx state to %d\n", txsig);
}
- } else {
+ } else { /* Else this is an fxs port */
+ unsigned long flags;
struct fxs *const fxs = &wc->mods[chan->chanpos - 1].fxs;
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
switch(txsig) {
case DAHDI_TXSIG_ONHOOK:
switch(chan->sig) {
case DAHDI_SIG_EM:
case DAHDI_SIG_FXOKS:
case DAHDI_SIG_FXOLS:
- fxs->lasttxhook = 0x10 |
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
fxs->idletxhookstate;
break;
case DAHDI_SIG_FXOGS:
if (POLARITY_XOR(chan->chanpos -1)) {
- fxs->lasttxhook = 0x10 |
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
SLIC_LF_RING_OPEN;
} else {
- fxs->lasttxhook = 0x10 |
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
SLIC_LF_TIP_OPEN;
}
break;
@@ -3136,34 +3152,32 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
switch(chan->sig) {
case DAHDI_SIG_EM:
if (POLARITY_XOR(chan->chanpos -1)) {
- fxs->lasttxhook = 0x10 |
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
SLIC_LF_ACTIVE_FWD;
} else {
- fxs->lasttxhook = 0x10 |
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
SLIC_LF_ACTIVE_REV;
}
break;
default:
- fxs->lasttxhook = 0x10 |
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
fxs->idletxhookstate;
break;
}
break;
case DAHDI_TXSIG_START:
- fxs->lasttxhook = 0x10 | SLIC_LF_RINGING;
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_RINGING;
break;
case DAHDI_TXSIG_KEWL:
- fxs->lasttxhook = 0x10 | SLIC_LF_OPEN;
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_OPEN;
break;
default:
printk(KERN_NOTICE "wctdm24xxp: Can't set tx state to %d\n", txsig);
}
+ wc->sethook[chan->chanpos - 1] = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
if (debug & DEBUG_CARD)
printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, reg);
-
-
- wc->sethook[chan->chanpos - 1] = CMD_WR(64, fxs->lasttxhook);
- /* wctdm_setreg(wc, chan->chanpos - 1, 64, fxs->lasttxhook); */
}
return 0;
}
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index ba362f0..ca3074f 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -194,7 +194,17 @@ struct wctdm {
int debounce;
int ohttimer;
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 */
+ /* lasttxhook reflects the last value written to the proslic's reg
+ * 64 (LINEFEED_CONTROL) in bits 0-2. Bit 4 indicates if the last
+ * write is pending i.e. it is in process of being written to the
+ * register
+ * NOTE: in order for this value to actually be written to the
+ * proslic, the appropriate matching value must be written into the
+ * sethook variable so that it gets queued and handled by the
+ * voicebus ISR.
+ */
+ int lasttxhook;
+ spinlock_t lasttxhooklock;
int palarms;
struct dahdi_vmwi_info vmwisetting;
int vmwi_active_messages;