summaryrefslogtreecommitdiff
path: root/kernel/xpp/card_fxs.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/card_fxs.c')
-rw-r--r--kernel/xpp/card_fxs.c134
1 files changed, 76 insertions, 58 deletions
diff --git a/kernel/xpp/card_fxs.c b/kernel/xpp/card_fxs.c
index 89293ea..7068bf7 100644
--- a/kernel/xpp/card_fxs.c
+++ b/kernel/xpp/card_fxs.c
@@ -174,6 +174,21 @@ static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value);
}
+static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on)
+{
+ struct FXS_priv_data *priv;
+
+ priv = xpd->priv;
+ BUG_ON(!xpd);
+ if(vmwineon && on) {
+ LINE_DBG(SIGNAL, xpd, pos, "START\n");
+ BIT_SET(priv->search_fsk_pattern, pos);
+ } else {
+ LINE_DBG(SIGNAL, xpd, pos, "STOP\n");
+ BIT_CLR(priv->search_fsk_pattern, pos);
+ }
+}
+
/*
* LED and RELAY control is done via SLIC register 0x06:
* 7 6 5 4 3 2 1 0
@@ -286,7 +301,7 @@ static void restore_leds(xpd_t *xpd)
priv = xpd->priv;
for_each_line(xpd, i) {
- if(IS_SET(xpd->offhook, i))
+ if(IS_OFFHOOK(xpd, i))
MARK_ON(priv, i, LED_GREEN);
else
MARK_OFF(priv, i, LED_GREEN);
@@ -438,7 +453,7 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
msleep(50);
}
restore_leds(xpd);
- pcm_recompute(xpd, 0);
+ CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
/*
* We should query our offhook state long enough time after we
* set the linefeed_control()
@@ -483,7 +498,7 @@ static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
xpd->span.spantype = "FXS";
#endif
for_each_line(xpd, i) {
- struct zt_chan *cur_chan = &xpd->chans[i];
+ struct zt_chan *cur_chan = XPD_CHAN(xpd, i);
XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i);
if(IS_SET(xpd->digital_outputs, i)) {
@@ -540,19 +555,18 @@ static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit)
BIT_SET(xpd->mute_dtmf, pos);
else
BIT_CLR(xpd->mute_dtmf, pos);
+ CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); /* already spinlocked */
}
-static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, bool msg_waiting)
{
int ret = 0;
BUG_ON(!xbus);
BUG_ON(!xpd);
- LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)");
- if (!vmwineon)
- return 0;
- if (on) {
+ if (vmwineon && msg_waiting) {
/* A write to register 0x40 will now turn on/off the VM led */
+ LINE_DBG(SIGNAL, xpd, pos, "NEON\n");
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
@@ -565,6 +579,7 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
} else {
/* A write to register 0x40 will now turn on/off the ringer */
+ LINE_DBG(SIGNAL, xpd, pos, "RINGER\n");
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
@@ -576,7 +591,6 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
}
-
return (ret ? -EPROTO : 0);
}
@@ -586,7 +600,7 @@ static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
bool on;
BUG_ON(!xpd);
- if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+ if (IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
return;
priv = xpd->priv;
on = IS_SET(xpd->msg_waiting, pos);
@@ -655,17 +669,16 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
return 0;
}
if(SPAN_REGISTERED(xpd))
- chan = &xpd->span.chans[pos];
+ chan = XPD_CHAN(xpd, pos);
switch(txsig) {
case ZT_TXSIG_ONHOOK:
spin_lock_irqsave(&xpd->lock, flags);
xpd->ringing[pos] = 0;
- BIT_CLR(xpd->cid_on, pos);
- BIT_CLR(priv->search_fsk_pattern, pos);
+ oht_pcm(xpd, pos, 0);
+ vmwi_search(xpd, pos, 0);
BIT_CLR(priv->want_dtmf_events, pos);
BIT_CLR(priv->want_dtmf_mute, pos);
__do_mute_dtmf(xpd, pos, 0);
- __pcm_recompute(xpd, 0); /* already spinlocked */
spin_unlock_irqrestore(&xpd->lock, flags);
if(IS_SET(xpd->digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig));
@@ -678,11 +691,11 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
*/
LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n");
linefeed_control(xbus, xpd, pos, FXS_LINE_POL_ACTIVE);
- if(IS_SET(xpd->offhook, pos))
+ if(IS_OFFHOOK(xpd, pos))
MARK_ON(priv, pos, LED_GREEN);
}
ret = send_ring(xpd, pos, 0); // RING off
- if (!IS_SET(xpd->offhook, pos))
+ if (!IS_OFFHOOK(xpd, pos))
start_stop_vm_led(xbus, xpd, pos);
txhook = priv->lasttxhook[pos];
if(chan) {
@@ -706,8 +719,7 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
}
txhook = priv->lasttxhook[pos];
if(xpd->ringing[pos]) {
- BIT_SET(xpd->cid_on, pos);
- pcm_recompute(xpd, 0);
+ oht_pcm(xpd, pos, 1);
txhook = FXS_LINE_OHTRANS;
}
xpd->ringing[pos] = 0;
@@ -725,9 +737,8 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
break;
case ZT_TXSIG_START:
xpd->ringing[pos] = 1;
- BIT_CLR(xpd->cid_on, pos);
- BIT_CLR(priv->search_fsk_pattern, pos);
- pcm_recompute(xpd, 0);
+ oht_pcm(xpd, pos, 0);
+ vmwi_search(xpd, pos, 0);
if(IS_SET(xpd->digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig));
ret = relay_out(xpd, pos, 1);
@@ -782,14 +793,15 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
LINE_DBG(SIGNAL, xpd, pos, "ZT_ONHOOKTRANSFER (%d millis)\n", val);
if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
return 0; /* Nothing to do */
- BIT_CLR(xpd->cid_on, pos);
+ oht_pcm(xpd, pos, 1); /* Get ready of VMWI FSK tones */
if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) {
- priv->ohttimer[pos] = OHT_TIMER;
+ priv->ohttimer[pos] = val;
priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS;
- BIT_SET(priv->search_fsk_pattern, pos);
- pcm_recompute(xpd, priv->search_fsk_pattern);
+ vmwi_search(xpd, pos, 1);
+ CALL_XMETHOD(card_pcm_recompute, xbus, xpd, priv->search_fsk_pattern);
+ LINE_DBG(SIGNAL, xpd, pos, "Start OHT_TIMER. wanted_pcm_mask=0x%X\n", xpd->wanted_pcm_mask);
}
- if(!IS_SET(xpd->offhook, pos))
+ if(vmwineon && !IS_OFFHOOK(xpd, pos))
start_stop_vm_led(xbus, xpd, pos);
return 0;
case ZT_TONEDETECT:
@@ -808,7 +820,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
BIT_CLR(priv->want_dtmf_events, pos);
BIT_CLR(priv->want_dtmf_mute, pos);
__do_mute_dtmf(xpd, pos, 0);
- __pcm_recompute(xpd, 0); /* already spinlocked */
spin_unlock_irqrestore(&xpd->lock, flags);
return -ENOTTY;
}
@@ -840,7 +851,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
} else {
BIT_CLR(priv->want_dtmf_mute, pos);
__do_mute_dtmf(xpd, pos, 0);
- __pcm_recompute(xpd, 0);
}
spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
@@ -886,12 +896,10 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
static int FXS_card_open(xpd_t *xpd, lineno_t chan)
{
struct FXS_priv_data *priv;
- bool is_offhook;
BUG_ON(!xpd);
priv = xpd->priv;
- is_offhook = IS_SET(xpd->offhook, chan);
- if(is_offhook)
+ if(IS_OFFHOOK(xpd, chan))
LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n");
else
LINE_DBG(SIGNAL, xpd, chan, "is onhook\n");
@@ -957,10 +965,10 @@ static void handle_linefeed(xpd_t *xpd)
if (priv->ohttimer[i]) {
priv->ohttimer[i]--;
if (!priv->ohttimer[i]) {
+ LINE_DBG(SIGNAL, xpd, i, "ohttimer expired\n");
priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
- BIT_CLR(xpd->cid_on, i);
- BIT_CLR(priv->search_fsk_pattern, i);
- pcm_recompute(xpd, 0);
+ oht_pcm(xpd, i, 0);
+ vmwi_search(xpd, i, 0);
if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) {
/* Apply the change if appropriate */
linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE);
@@ -996,16 +1004,23 @@ static void detect_vmwi(xpd_t *xpd)
static const byte FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF };
static const byte FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F };
int i;
+ xpp_line_t ignore_mask;
BUG_ON(!xpd);
xbus = xpd->xbus;
priv = xpd->priv;
BUG_ON(!priv);
+ ignore_mask =
+ xpd->offhook_state |
+ ~xpd->oht_pcm_pass |
+ ~priv->search_fsk_pattern |
+ xpd->digital_inputs |
+ xpd->digital_outputs;
for_each_line(xpd, i) {
- struct zt_chan *chan = &xpd->span.chans[i];
+ struct zt_chan *chan = XPD_CHAN(xpd, i);
byte *writechunk = chan->writechunk;
- if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i))
+ if(IS_SET(ignore_mask, i))
continue;
#if 0
if(writechunk[0] != 0x7F && writechunk[0] != 0) {
@@ -1020,10 +1035,12 @@ static void detect_vmwi(xpd_t *xpd)
printk("\n");
}
#endif
- if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE)))
+ if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE))) {
+ LINE_DBG(SIGNAL, xpd, i, "Found common FSK pattern. Start looking for ON/OFF patterns.\n");
BIT_SET(priv->found_fsk_pattern, i);
- else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
+ } else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
BIT_CLR(priv->found_fsk_pattern, i);
+ oht_pcm(xpd, i, 0);
if(unlikely(mem_equal(writechunk, FSK_ON_PATTERN, ZT_CHUNKSIZE))) {
LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n");
BIT_SET(xpd->msg_waiting, i);
@@ -1060,25 +1077,27 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
#endif
handle_fxs_leds(xpd);
handle_linefeed(xpd);
- if(priv->update_offhook_state) { /* set in FXS_card_open() */
- int i;
+ /*
+ * Hack alert (FIXME):
+ * Asterisk did FXS_card_open() and we wanted to report
+ * offhook state. However, the channel is spinlocked by zaptel
+ * so we marked it in the priv->update_offhook_state mask and
+ * now we take care of notification to zaptel and Asterisk
+ */
+ if(priv->update_offhook_state) {
+ zt_rxsig_t rxsig;
+ int i;
for_each_line(xpd, i) {
if(!IS_SET(priv->update_offhook_state, i))
continue;
- /*
- * Update zaptel with current state of line.
- */
- if(IS_SET(xpd->offhook, i)) {
- update_line_status(xpd, i, 1);
- } else {
- update_line_status(xpd, i, 0);
- }
+ rxsig = IS_OFFHOOK(xpd, i) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK;
+ notify_rxsig(xpd, i, rxsig); /* Notify after open() */
BIT_CLR(priv->update_offhook_state, i);
}
}
if(SPAN_REGISTERED(xpd)) {
- if(vmwineon && !vmwi_ioctl)
+ if(vmwineon && !vmwi_ioctl && priv->search_fsk_pattern)
detect_vmwi(xpd); /* Detect via FSK modulation */
}
return 0;
@@ -1127,11 +1146,11 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
if(IS_SET(offhook, i)) {
LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n");
MARK_ON(priv, i, LED_GREEN);
- update_line_status(xpd, i, 1);
+ hookstate_changed(xpd, i, 1);
} else {
LINE_DBG(SIGNAL, xpd, i, "ONHOOK\n");
MARK_OFF(priv, i, LED_GREEN);
- update_line_status(xpd, i, 0);
+ hookstate_changed(xpd, i, 0);
}
/*
* Must switch to low power. In high power, an ONHOOK
@@ -1140,7 +1159,6 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
do_chan_power(xbus, xpd, i, 0);
}
}
- __pcm_recompute(xpd, 0); /* in a spinlock */
}
HANDLER_DEF(FXS, SIG_CHANGED)
@@ -1182,12 +1200,12 @@ static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info)
BIT_CLR(lines, channo);
BIT_SET(lines, newchanno);
xpd->ringing[newchanno] = 0; // Stop ringing. No leds for digital inputs.
- if(offhook && !IS_SET(xpd->offhook, newchanno)) { // OFFHOOK
+ if(offhook && !IS_OFFHOOK(xpd, newchanno)) { // OFFHOOK
LINE_DBG(SIGNAL, xpd, newchanno, "OFFHOOK\n");
- update_line_status(xpd, newchanno, 1);
- } else if(!offhook && IS_SET(xpd->offhook, newchanno)) { // ONHOOK
+ hookstate_changed(xpd, newchanno, 1);
+ } else if(!offhook && IS_OFFHOOK(xpd, newchanno)) { // ONHOOK
LINE_DBG(SIGNAL, xpd, newchanno, "ONHOOK\n");
- update_line_status(xpd, newchanno, 0);
+ hookstate_changed(xpd, newchanno, 0);
}
}
}
@@ -1253,11 +1271,10 @@ static void process_dtmf(xpd_t *xpd, uint portnum, byte val)
__do_mute_dtmf(xpd, portnum, 1);
else
__do_mute_dtmf(xpd, portnum, 0);
- __pcm_recompute(xpd, 0); /* XPD is locked */
if(want_event) {
int event = (key_down) ? ZT_EVENT_DTMFDOWN : ZT_EVENT_DTMFUP;
- zt_qevent_lock(&xpd->chans[portnum], event | digit);
+ zt_qevent_lock(XPD_CHAN(xpd, portnum), event | digit);
}
}
@@ -1334,6 +1351,7 @@ static xproto_table_t PROTO_TABLE(FXS) = {
.card_zaptel_postregistration = FXS_card_zaptel_postregistration,
.card_hooksig = FXS_card_hooksig,
.card_tick = FXS_card_tick,
+ .card_pcm_recompute = generic_card_pcm_recompute,
.card_pcm_fromspan = generic_card_pcm_fromspan,
.card_pcm_tospan = generic_card_pcm_tospan,
.card_open = FXS_card_open,