From 4ba510314a8dcd24bbcd32af137439c75f4c652f Mon Sep 17 00:00:00 2001 From: tzafrir Date: Sun, 30 Nov 2008 12:10:03 +0000 Subject: xpp: PCM changes and related bugfixes. * Power-denial signalling is now sent to Zaptel to decide if we're LS or KS (and not hang up ourselves always). * Fix card_fxo's caller_id_style=1 (FSK). * Macro XPD_CHAN: s/xpd->chans[i]/XPD_CHAN(xpd, i)/ to reduce diff from DAHDI. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4590 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/xpp/.version | 2 +- kernel/xpp/card_bri.c | 141 +++++++++++++++++++++++++++++++++++--------------- kernel/xpp/card_fxo.c | 116 +++++++++++++++++++++-------------------- kernel/xpp/card_fxs.c | 134 ++++++++++++++++++++++++++--------------------- kernel/xpp/card_pri.c | 44 ++++++++-------- kernel/xpp/xbus-pcm.c | 65 +++++++++++------------ kernel/xpp/xbus-pcm.h | 4 +- kernel/xpp/xpd.h | 13 +++-- kernel/xpp/xpp_zap.c | 132 ++++++++++++++++++++++++++++------------------ kernel/xpp/xpp_zap.h | 6 ++- kernel/xpp/xproto.c | 1 + kernel/xpp/xproto.h | 3 +- 12 files changed, 386 insertions(+), 275 deletions(-) diff --git a/kernel/xpp/.version b/kernel/xpp/.version index e7cb22c..1e3ee87 100644 --- a/kernel/xpp/.version +++ b/kernel/xpp/.version @@ -1 +1 @@ -trunk-r6058 +branch-rel-6171-r6408 diff --git a/kernel/xpp/card_bri.c b/kernel/xpp/card_bri.c index ea78ea6..fb6be03 100644 --- a/kernel/xpp/card_bri.c +++ b/kernel/xpp/card_bri.c @@ -208,7 +208,6 @@ struct BRI_priv_data { bool reg30_good; uint reg30_ticks; bool layer1_up; - xpp_line_t card_pcm_mask; /* * D-Chan: buffers + extra state info. @@ -460,8 +459,8 @@ static int rx_dchan(xpd_t *xpd, reg_cmd_t *regcmd) #ifdef XPP_DEBUGFS xbus_log(xbus, xpd, 0, regcmd, sizeof(reg_cmd_t)); /* 0 = RX */ #endif - dchan = &xpd->span.chans[2]; - if(!IS_SET(xpd->offhook, 2)) { /* D-chan is used? */ + dchan = XPD_CHAN(xpd, 2); + if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */ static int rate_limit; if((rate_limit++ % 1000) == 0) @@ -534,7 +533,7 @@ static int tx_dchan(xpd_t *xpd) BUG_ON(!priv); if(!SPAN_REGISTERED(xpd) || !(xpd->span.flags & ZT_FLAG_RUNNING)) return 0; - dchan = &xpd->chans[2]; + dchan = XPD_CHAN(xpd, 2); len = dchan->bytes2transmit; /* dchan's hdlc package len */ eoframe = dchan->eoftx; /* dchan's end of frame */ dchan->bytes2transmit = 0; @@ -659,9 +658,6 @@ static int BRI_card_zaptel_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct BRI_priv_data *priv; - xpp_line_t tmp_pcm_mask; - int tmp_pcm_len; - unsigned long flags; int i; BUG_ON(!xpd); @@ -680,7 +676,7 @@ static int BRI_card_zaptel_preregistration(xpd_t *xpd, bool on) xpd->span.deflaw = ZT_LAW_ALAW; BIT_SET(xpd->digital_signalling, 2); /* D-Channel */ 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 BRI channel %d\n", i); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d", @@ -705,35 +701,11 @@ static int BRI_card_zaptel_preregistration(xpd_t *xpd, bool on) } else cur_chan->sigcap = BRI_BCHAN_SIGCAP; } - xpd->offhook = BIT(0) | BIT(1); /* 2*bchan */ - - /* - * Compute PCM lentgh and mask - * We know all cards have been initialized until now - */ - tmp_pcm_mask = 0; - if(xpd->addr.subunit == 0) { - int line_count = 0; - - for(i = 0; i < MAX_SUBUNIT; i++) { - xpd_t *sub_xpd = xpd_byaddr(xbus, xpd->addr.unit, i); - if(sub_xpd) { - tmp_pcm_mask |= PCM_SHIFT(sub_xpd->wanted_pcm_mask, i); - line_count += 2; - } - } - tmp_pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE; - } else - tmp_pcm_len = 0; - spin_lock_irqsave(&xpd->lock, flags); - xpd->pcm_len = tmp_pcm_len; - xpd->wanted_pcm_mask = xpd->offhook; - priv->card_pcm_mask = tmp_pcm_mask; + CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0); xpd->span.spanconfig = bri_spanconfig; xpd->span.chanconfig = bri_chanconfig; xpd->span.startup = bri_startup; xpd->span.shutdown = bri_shutdown; - spin_unlock_irqrestore(&xpd->lock, flags); return 0; } @@ -943,15 +915,38 @@ static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a return 0; } +static int BRI_card_open(xpd_t *xpd, lineno_t pos) +{ + struct BRI_priv_data *priv; + + BUG_ON(!xpd); + priv = xpd->priv; + if(pos == 2) { + LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK the whole span\n"); + BIT_SET(xpd->offhook_state, 0); + BIT_SET(xpd->offhook_state, 1); + BIT_SET(xpd->offhook_state, 2); + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); + } + return 0; +} + static int BRI_card_close(xpd_t *xpd, lineno_t pos) { - struct zt_chan *chan = &xpd->span.chans[pos]; + struct zt_chan *chan = XPD_CHAN(xpd, pos); /* Clear D-Channel pending data */ chan->bytes2receive = 0; chan->eofrx = 0; chan->bytes2transmit = 0; chan->eoftx = 0; + if(pos == 2) { + LINE_DBG(SIGNAL, xpd, pos, "ONHOOK the whole span\n"); + BIT_CLR(xpd->offhook_state, 0); + BIT_CLR(xpd->offhook_state, 1); + BIT_CLR(xpd->offhook_state, 2); + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); + } return 0; } @@ -1031,7 +1026,7 @@ static int bri_startup(struct zt_span *span) // Turn on all channels CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); if(SPAN_REGISTERED(xpd)) { - dchan = &span->chans[2]; + dchan = XPD_CHAN(xpd, 2); span->flags |= ZT_FLAG_RUNNING; /* * Zaptel (wrongly) assume that D-Channel need HDLC decoding @@ -1066,14 +1061,74 @@ static int bri_shutdown(struct zt_span *span) return 0; } -static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_lines, xpacket_t *pack) +void BRI_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t dont_care) +{ + int i; + int line_count; + xpp_line_t pcm_mask; + xpd_t *main_xpd; + unsigned long flags; + + BUG_ON(!xpd); + main_xpd = xpd_byaddr(xbus, xpd->addr.unit, 0); + if(!main_xpd) { + XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n"); + return; + } + /* + * We calculate all subunits, so use the main lock + * as a mutex for the whole operation. + */ + spin_lock_irqsave(&main_xpd->lock_recompute_pcm, flags); + line_count = 0; + pcm_mask = 0; + for(i = 0; i < MAX_SUBUNIT; i++) { + xpd_t *sub_xpd = xpd_byaddr(xbus, main_xpd->addr.unit, i); + + if(sub_xpd) { + xpp_line_t lines = + sub_xpd->offhook_state & ~sub_xpd->digital_signalling; + + if(lines) { + pcm_mask |= PCM_SHIFT(lines, i); + line_count += 2; + } + /* subunits have fake pcm_len and wanted_pcm_mask */ + if(i > 0) { + sub_xpd->pcm_len = 0; + sub_xpd->wanted_pcm_mask = lines; + } + } + } + /* + * FIXME: Workaround a bug in sync code of the Astribank. + * Send dummy PCM for sync. + */ + if(main_xpd->addr.unit == 0 && line_count == 0) { + pcm_mask = BIT(0); + line_count = 1; + } + /* + * The main unit account for all subunits (pcm_len and wanted_pcm_mask). + */ + main_xpd->pcm_len = (line_count) + ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE + : 0L; + main_xpd->wanted_pcm_mask = pcm_mask; + XPD_DBG(SIGNAL, main_xpd, "pcm_len=%d wanted_pcm_mask=0x%X (%s)\n", + main_xpd->pcm_len, main_xpd->wanted_pcm_mask, + xpd->xpdname); + spin_unlock_irqrestore(&main_xpd->lock_recompute_pcm, flags); +} + +static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { byte *pcm; - struct zt_chan *chans; unsigned long flags; int i; int subunit; xpp_line_t pcm_mask = 0; + xpp_line_t wanted_lines; BUG_ON(!xbus); @@ -1087,18 +1142,20 @@ static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_li if(!tmp_xpd || !tmp_xpd->card_present) continue; spin_lock_irqsave(&tmp_xpd->lock, flags); - chans = tmp_xpd->span.chans; + wanted_lines = tmp_xpd->wanted_pcm_mask; for_each_line(tmp_xpd, i) { + struct zt_chan *chan = XPD_CHAN(tmp_xpd, i); + if(IS_SET(wanted_lines, i)) { if(SPAN_REGISTERED(tmp_xpd)) { #ifdef DEBUG_PCMTX - int channo = tmp_xpd->span.chans[i].channo; + int channo = chan->channo; if(pcmtx >= 0 && pcmtx_chan == channo) memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE); else #endif - memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE); + memcpy((u_char *)pcm, chan->writechunk, ZT_CHUNKSIZE); } else memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; @@ -1142,7 +1199,7 @@ static void BRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) volatile u_char *r; if(IS_SET(tmp_mask, i)) { - r = tmp_xpd->span.chans[i].readchunk; + r = XPD_CHAN(tmp_xpd, i)->readchunk; // memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG memcpy((u_char *)r, pcm, ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; @@ -1395,9 +1452,11 @@ static xproto_table_t PROTO_TABLE(BRI) = { .card_zaptel_postregistration = BRI_card_zaptel_postregistration, .card_hooksig = BRI_card_hooksig, .card_tick = BRI_card_tick, + .card_pcm_recompute = BRI_card_pcm_recompute, .card_pcm_fromspan = BRI_card_pcm_fromspan, .card_pcm_tospan = BRI_card_pcm_tospan, .card_ioctl = BRI_card_ioctl, + .card_open = BRI_card_open, .card_close = BRI_card_close, .card_register_reply = BRI_card_register_reply, diff --git a/kernel/xpp/card_fxo.c b/kernel/xpp/card_fxo.c index 30c9de8..2090773 100644 --- a/kernel/xpp/card_fxo.c +++ b/kernel/xpp/card_fxo.c @@ -175,6 +175,27 @@ struct FXO_priv_data { /*---------------- FXO: Static functions ----------------------------------*/ +static const char *power2str(enum power_state pw) +{ + switch(pw) { + case POWER_UNKNOWN: return "UNKOWN"; + case POWER_OFF: return "OFF"; + case POWER_ON: return "ON"; + } + return NULL; +} + +static void power_change(xpd_t *xpd, int portno, enum power_state pw) +{ + struct FXO_priv_data *priv; + + priv = xpd->priv; + LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n", + power2str(priv->power[portno]), + power2str(pw)); + priv->power[portno] = pw; +} + static void reset_battery_readings(xpd_t *xpd, lineno_t pos) { struct FXO_priv_data *priv = xpd->priv; @@ -265,30 +286,15 @@ static void handle_fxo_leds(xpd_t *xpd) static void update_zap_ring(xpd_t *xpd, int pos, bool on) { - zt_rxsig_t rxsig; - BUG_ON(!xpd); - if(on) { - if(caller_id_style == CID_STYLE_BELL) { - LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n"); - BIT_CLR(xpd->cid_on, pos); - } - rxsig = ZT_RXSIG_RING; - } else { - if(caller_id_style == CID_STYLE_BELL) { - LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: on\n"); - BIT_SET(xpd->cid_on, pos); - } - rxsig = ZT_RXSIG_OFFHOOK; - } - pcm_recompute(xpd, 0); + if(caller_id_style == CID_STYLE_BELL) + oht_pcm(xpd, pos, !on); /* * We should not spinlock before calling zt_hooksig() as * it may call back into our xpp_hooksig() and cause * a nested spinlock scenario */ - if(SPAN_REGISTERED(xpd)) - zt_hooksig(&xpd->chans[pos], rxsig); + notify_rxsig(xpd, pos, (on) ? ZT_RXSIG_RING : ZT_RXSIG_OFFHOOK); } static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_zap) @@ -349,15 +355,9 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) else MARK_OFF(priv, pos, LED_GREEN); ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value); - if(to_offhook) { - BIT_SET(xpd->offhook, pos); - } else { - BIT_CLR(xpd->offhook, pos); - } - if(caller_id_style != CID_STYLE_ETSI_DTMF) { - LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n"); - BIT_CLR(xpd->cid_on, pos); - } + mark_offhook(xpd, pos, to_offhook); + if(caller_id_style != CID_STYLE_ETSI_DTMF) + oht_pcm(xpd, pos, 0); #ifdef WITH_METERING priv->metering_count[pos] = 0; priv->metering_tone_state = 0L; @@ -366,7 +366,7 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) reset_battery_readings(xpd, pos); /* unstable during hook changes */ priv->power_denial_safezone[pos] = (to_offhook) ? POWER_DENIAL_SAFEZONE : 0; if(!to_offhook) - priv->power[pos] = POWER_UNKNOWN; + power_change(xpd, pos, POWER_UNKNOWN); priv->cidtimer[pos] = xpd->timer_count; spin_unlock_irqrestore(&xpd->lock, flags); return ret; @@ -469,10 +469,11 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) for_each_line(xpd, i) { do_sethook(xpd, i, 0); priv->polarity[i] = POL_UNKNOWN; /* will be updated on next battery sample */ + priv->polarity_debounce[i] = 0; priv->battery[i] = BATTERY_UNKNOWN; /* will be updated on next battery sample */ priv->power[i] = POWER_UNKNOWN; /* will be updated on next battery sample */ if(caller_id_style == CID_STYLE_ETSI_DTMF) - BIT_SET(xpd->cid_on, i); + oht_pcm(xpd, i, 1); } XPD_DBG(GENERAL, xpd, "done\n"); for_each_line(xpd, i) { @@ -486,7 +487,7 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) do_led(xpd, i, LED_GREEN, 0); msleep(50); } - pcm_recompute(xpd, 0); + CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0); return 0; } @@ -519,7 +520,7 @@ static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on) xpd->span.spantype = "FXO"; #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 FXO channel %d\n", i); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%02d/%1d%1d/%d", @@ -585,7 +586,6 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig) txsig2str(txsig), txsig); return -EINVAL; } - pcm_recompute(xpd, 0); return ret; } @@ -602,11 +602,11 @@ static void zap_report_battery(xpd_t *xpd, lineno_t chan) break; case BATTERY_OFF: LINE_DBG(SIGNAL, xpd, chan, "Send ZT_ALARM_RED\n"); - zt_alarm_channel(&xpd->chans[chan], ZT_ALARM_RED); + zt_alarm_channel(XPD_CHAN(xpd, chan), ZT_ALARM_RED); break; case BATTERY_ON: LINE_DBG(SIGNAL, xpd, chan, "Send ZT_ALARM_NONE\n"); - zt_alarm_channel(&xpd->chans[chan], ZT_ALARM_NONE); + zt_alarm_channel(XPD_CHAN(xpd, chan), ZT_ALARM_NONE); break; } } @@ -636,7 +636,7 @@ static void poll_metering(xbus_t *xbus, xpd_t *xpd) int i; for_each_line(xpd, i) { - if (IS_SET(xpd->offhook, i)) + if (IS_OFFHOOK(xpd, i)) DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0); } } @@ -689,7 +689,7 @@ static void handle_fxo_power_denial(xpd_t *xpd) DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0); } } - if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_SET(xpd->offhook, i)) { + if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_OFFHOOK(xpd, i)) { /* * Ring detection by the firmware takes some time. * Therefore we delay our decision until we are @@ -700,9 +700,10 @@ static void handle_fxo_power_denial(xpd_t *xpd) LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n"); priv->power_denial_delay[i] = 0; BIT_CLR(priv->maybe_power_denial, i); - do_sethook(xpd, i, 0); - update_line_status(xpd, i, 0); - pcm_recompute(xpd, 0); + /* + * Let Asterisk decide what to do + */ + notify_rxsig(xpd, i, ZT_RXSIG_ONHOOK); } } else { priv->power_denial_delay[i] = 0; @@ -731,7 +732,7 @@ static void check_etsi_dtmf(xpd_t *xpd) timer_count = xpd->timer_count; for_each_line(xpd, portno) { /* Skip offhook and ringing ports */ - if(IS_SET(xpd->offhook, portno) || xpd->ringing[portno]) + if(IS_OFFHOOK(xpd, portno) || xpd->ringing[portno]) continue; if(IS_SET(priv->cidfound, portno)) { if(timer_count > priv->cidtimer[portno] + 4000) { @@ -743,7 +744,7 @@ static void check_etsi_dtmf(xpd_t *xpd) continue; } if(timer_count > priv->cidtimer[portno] + 400) { - struct zt_chan *chan = &xpd->span.chans[portno]; + struct zt_chan *chan = XPD_CHAN(xpd, portno); int sample; int i; @@ -922,8 +923,11 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) priv->battery[portno] = BATTERY_OFF; if(SPAN_REGISTERED(xpd)) zap_report_battery(xpd, portno); - priv->polarity[portno] = POL_UNKNOWN; /* What's the polarity ? */ - priv->power[portno] = POWER_UNKNOWN; /* What's the current ? */ + /* What's the polarity ? */ + priv->polarity[portno] = POL_UNKNOWN; + priv->polarity_debounce[portno] = 0; + /* What's the current ? */ + power_change(xpd, portno, POWER_UNKNOWN); /* * Stop further processing for now */ @@ -976,7 +980,7 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) msec = priv->polarity_debounce[portno]++ * poll_battery_interval; if (msec >= POLREV_THRESHOLD) { priv->polarity_debounce[portno] = 0; - if(pol != POL_UNKNOWN) { + if(pol != POL_UNKNOWN && priv->polarity[portno] != POL_UNKNOWN) { char *polname = NULL; if(pol == POL_POSITIVE) @@ -993,14 +997,12 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) * 2. In some countries used to report caller-id during onhook * but before first ring. */ - if(caller_id_style == CID_STYLE_ETSI_FSK) { - LINE_DBG(SIGNAL, xpd, portno, "Caller-ID PCM: on\n"); - BIT_SET(xpd->cid_on, portno); /* will be cleared on ring/offhook */ - } + if(caller_id_style == CID_STYLE_ETSI_FSK) + oht_pcm(xpd, portno, 1); /* will be cleared on ring/offhook */ if(SPAN_REGISTERED(xpd)) { LINE_DBG(SIGNAL, xpd, portno, "Send ZT_EVENT_POLARITY: %s\n", polname); - zt_qevent_lock(&xpd->chans[portno], ZT_EVENT_POLARITY); + zt_qevent_lock(XPD_CHAN(xpd, portno), ZT_EVENT_POLARITY); } } priv->polarity[portno] = pol; @@ -1024,7 +1026,7 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno) * During ringing, current is not stable. * During onhook there should not be current anyway. */ - if(xpd->ringing[portno] || !IS_SET(xpd->offhook, portno)) + if(xpd->ringing[portno] || !IS_OFFHOOK(xpd, portno)) goto ignore_it; /* * Power denial with no battery voltage is meaningless @@ -1036,15 +1038,16 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno) goto ignore_it; if(data_low < POWER_DENIAL_CURRENT) { if(priv->power[portno] == POWER_ON) { - LINE_DBG(SIGNAL, xpd, portno, "power: ON -> OFF\n"); - priv->power[portno] = POWER_OFF; + power_change(xpd, portno, POWER_OFF); priv->power_denial_minimum[portno] = POWER_DENIAL_TIME; } } else { - LINE_DBG(SIGNAL, xpd, portno, "power: ON\n"); - priv->power[portno] = POWER_ON; - priv->power_denial_minimum[portno] = 0; - update_line_status(xpd, portno, 1); + if(priv->power[portno] != POWER_ON) { + power_change(xpd, portno, POWER_ON); + priv->power_denial_minimum[portno] = 0; + /* We are now OFFHOOK */ + hookstate_changed(xpd, portno, 1); + } } return; ignore_it: @@ -1135,6 +1138,7 @@ static xproto_table_t PROTO_TABLE(FXO) = { .card_zaptel_postregistration = FXO_card_zaptel_postregistration, .card_hooksig = FXO_card_hooksig, .card_tick = FXO_card_tick, + .card_pcm_recompute = generic_card_pcm_recompute, .card_pcm_fromspan = generic_card_pcm_fromspan, .card_pcm_tospan = generic_card_pcm_tospan, .card_ioctl = FXO_card_ioctl, 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, diff --git a/kernel/xpp/card_pri.c b/kernel/xpp/card_pri.c index 970a2a5..78d2025 100644 --- a/kernel/xpp/card_pri.c +++ b/kernel/xpp/card_pri.c @@ -1037,7 +1037,7 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on) xpd->span.linecompat = pri_linecompat(priv->pri_protocol); xpd->span.deflaw = priv->deflaw; for_each_line(xpd, i) { - struct zt_chan *cur_chan = &xpd->chans[i]; + struct zt_chan *cur_chan = XPD_CHAN(xpd, i); bool is_dchan = i == PRI_DCHAN_IDX(priv); XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i, @@ -1053,7 +1053,7 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on) } else cur_chan->sigcap = PRI_BCHAN_SIGCAP; } - xpd->offhook = xpd->wanted_pcm_mask; + xpd->offhook_state = xpd->wanted_pcm_mask; xpd->span.spanconfig = pri_spanconfig; xpd->span.chanconfig = pri_chanconfig; xpd->span.startup = pri_startup; @@ -1102,9 +1102,9 @@ static void dchan_state(xpd_t *xpd, bool up) if(SPAN_REGISTERED(xpd) && d >= 0 && d < xpd->channels) { byte *pcm; - pcm = (byte *)xpd->span.chans[d].readchunk; + pcm = (byte *)XPD_CHAN(xpd, d)->readchunk; pcm[0] = 0x00; - pcm = (byte *)xpd->span.chans[d].writechunk; + pcm = (byte *)XPD_CHAN(xpd, d)->writechunk; pcm[0] = 0x00; } XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); @@ -1233,7 +1233,7 @@ static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a static int PRI_card_close(xpd_t *xpd, lineno_t pos) { - //struct zt_chan *chan = &xpd->span.chans[pos]; + //struct zt_chan *chan = XPD_CHAN(xpd, pos); dchan_state(xpd, 0); return 0; } @@ -1342,13 +1342,13 @@ static int pri_rbsbits(struct zt_chan *chan, int bits) * send 31 channels to the device, but they should be called 1-31 rather * than 0-30 . */ -static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) +static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; byte *pcm; - struct zt_chan *chans; unsigned long flags; int i; + xpp_line_t wanted_lines; int physical_chan; int physical_mask = 0; @@ -1359,9 +1359,11 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp BUG_ON(!priv); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); - chans = xpd->span.chans; + wanted_lines = xpd->wanted_pcm_mask; physical_chan = 0; for_each_line(xpd, i) { + struct zt_chan *chan = XPD_CHAN(xpd, i); + if(priv->pri_protocol == PRI_PROTO_E1) { /* In E1 - Only 0'th channel is unused */ if(i == 0) { @@ -1373,28 +1375,28 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp physical_chan++; } } - if(IS_SET(lines, i)) { + if(IS_SET(wanted_lines, i)) { physical_mask |= BIT(physical_chan); if(SPAN_REGISTERED(xpd)) { #ifdef DEBUG_PCMTX - int channo = xpd->span.chans[i].channo; + int channo = XPD_CHAN(xpd, i)->channo; if(pcmtx >= 0 && pcmtx_chan == channo) memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE); else #endif - memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE); + memcpy((u_char *)pcm, chan->writechunk, ZT_CHUNKSIZE); if(i == PRI_DCHAN_IDX(priv)) { - if(priv->dchan_tx_sample != chans[i].writechunk[0]) { - priv->dchan_tx_sample = chans[i].writechunk[0]; + if(priv->dchan_tx_sample != chan->writechunk[0]) { + priv->dchan_tx_sample = chan->writechunk[0]; priv->dchan_tx_counter++; - } else if(chans[i].writechunk[0] == 0xFF) + } else if(chan->writechunk[0] == 0xFF) dchan_state(xpd, 0); else - chans[i].writechunk[0] = 0xFF; /* Clobber for next tick */ + chan->writechunk[0] = 0xFF; /* Clobber for next tick */ } } else - memset((u_char *)pcm, ZT_XLAW(0, (&chans[i])), ZT_CHUNKSIZE); + memset((u_char *)pcm, ZT_XLAW(0, chan), ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; } physical_chan++; @@ -1418,7 +1420,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; byte *pcm; - struct zt_chan *chans; xpp_line_t physical_mask; unsigned long flags; int i; @@ -1431,7 +1432,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); spin_lock_irqsave(&xpd->lock, flags); - chans = xpd->span.chans; logical_chan = 0; for (i = 0; i < CHANNELS_PERXPD; i++) { volatile u_char *r; @@ -1458,9 +1458,8 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) dchan_state(xpd, 0); } if(IS_SET(physical_mask, i)) { - r = chans[logical_chan].readchunk; + r = XPD_CHAN(xpd, logical_chan)->readchunk; // memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG - // fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP memcpy((u_char *)r, pcm, ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; } @@ -1576,9 +1575,9 @@ static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low) rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos], data_low); if(SPAN_REGISTERED(xpd)) { if(old1 != new1) - zt_rbsbits(&xpd->span.chans[chan1], new1); + zt_rbsbits(XPD_CHAN(xpd, chan1), new1); if(old2 != new2) - zt_rbsbits(&xpd->span.chans[chan2], new2); + zt_rbsbits(XPD_CHAN(xpd, chan2), new2); } priv->dchan_rx_counter++; priv->cas_rs_e[pos] = data_low; @@ -1657,6 +1656,7 @@ static xproto_table_t PROTO_TABLE(PRI) = { .card_zaptel_postregistration = PRI_card_zaptel_postregistration, .card_hooksig = PRI_card_hooksig, .card_tick = PRI_card_tick, + .card_pcm_recompute = generic_card_pcm_recompute, .card_pcm_fromspan = PRI_card_pcm_fromspan, .card_pcm_tospan = PRI_card_pcm_tospan, .card_ioctl = PRI_card_ioctl, diff --git a/kernel/xpp/xbus-pcm.c b/kernel/xpp/xbus-pcm.c index a5c186c..ef92a88 100644 --- a/kernel/xpp/xbus-pcm.c +++ b/kernel/xpp/xbus-pcm.c @@ -580,19 +580,18 @@ void elect_syncer(const char *msg) * This function is used by FXS/FXO. The pcm_mask argument signifies * channels which should be *added* to the automatic calculation. * Normally, this argument is 0. - * - * The caller should spinlock the XPD before calling it. */ -void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) +void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask) { int i; int line_count = 0; + unsigned long flags; - XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask); + spin_lock_irqsave(&xpd->lock_recompute_pcm, flags); + //XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask); /* Add/remove all the trivial cases */ - pcm_mask |= xpd->offhook; - pcm_mask |= xpd->cid_on; - pcm_mask &= ~xpd->digital_signalling; /* No PCM in D-Channels */ + pcm_mask |= xpd->offhook_state; + pcm_mask |= xpd->oht_pcm_pass; pcm_mask &= ~xpd->digital_inputs; pcm_mask &= ~xpd->digital_outputs; for_each_line(xpd, i) @@ -610,18 +609,9 @@ void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE : 0L; xpd->wanted_pcm_mask = pcm_mask; -} - -/* - * A spinlocked version of __pcm_recompute() - */ -void pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) -{ - unsigned long flags; - - spin_lock_irqsave(&xpd->lock, flags); - __pcm_recompute(xpd, pcm_mask); - spin_unlock_irqrestore(&xpd->lock, flags); + XPD_DBG(SIGNAL, xpd, "pcm_len=%d wanted_pcm_mask=0x%X\n", + xpd->pcm_len, xpd->wanted_pcm_mask); + spin_unlock_irqrestore(&xpd->lock_recompute_pcm, flags); } void fill_beep(u_char *buf, int num, int duration) @@ -676,11 +666,12 @@ static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, co static void do_ec(xpd_t *xpd) { #ifdef WITH_ECHO_SUPPRESSION - struct zt_chan *chans = xpd->span.chans; int i; /* FIXME: need to Echo cancel double buffered data */ for (i = 0;i < xpd->span.channels; i++) { + struct zt_chan *chan = XPD_CHAN(xpd, i); + if(unlikely(IS_SET(xpd->digital_signalling, i))) /* Don't echo cancel BRI D-chans */ continue; if(!IS_SET(xpd->wanted_pcm_mask, i)) /* No ec for unwanted PCM */ @@ -688,12 +679,12 @@ static void do_ec(xpd_t *xpd) #ifdef XPP_EC_CHUNK /* even if defined, parameterr xpp_ec can override at run-time */ if (xpp_ec) - xpp_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]); + xpp_ec_chunk(chan, chan->readchunk, xpd->ec_chunk2[i]); else #endif - zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]); + zt_ec_chunk(chan, chan->readchunk, xpd->ec_chunk2[i]); memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], ZT_CHUNKSIZE); - memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE); + memcpy(xpd->ec_chunk1[i], chan->writechunk, ZT_CHUNKSIZE); } #endif } @@ -821,31 +812,33 @@ dropit: * Generic implementations of card_pcmfromspan()/card_pcmtospan() * For FXS/FXO */ -void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) +void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { byte *pcm; - struct zt_chan *chans; unsigned long flags; + xpp_line_t wanted_lines; int i; BUG_ON(!xbus); BUG_ON(!xpd); BUG_ON(!pack); - RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines; + wanted_lines = xpd->wanted_pcm_mask; + RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = wanted_lines; pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); - chans = xpd->span.chans; for (i = 0; i < xpd->channels; i++) { - if(IS_SET(lines, i)) { + struct zt_chan *chan = XPD_CHAN(xpd, i); + + if(IS_SET(wanted_lines, i)) { if(SPAN_REGISTERED(xpd)) { #ifdef DEBUG_PCMTX - int channo = xpd->span.chans[i].channo; + int channo = chan->channo; if(pcmtx >= 0 && pcmtx_chan == channo) memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE); else #endif - memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE); + memcpy((u_char *)pcm, chan->writechunk, ZT_CHUNKSIZE); } else memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; @@ -874,7 +867,7 @@ void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) if(!SPAN_REGISTERED(xpd)) goto out; for (i = 0; i < xpd->channels; i++) { - volatile u_char *r = xpd->span.chans[i].readchunk; + volatile u_char *r = XPD_CHAN(xpd, i)->readchunk; bool got_data = IS_SET(pcm_mask, i); if(got_data && !IS_SET(pcm_mute, i)) { @@ -974,7 +967,6 @@ static void xbus_tick(xbus_t *xbus) xpd_t *xpd; xframe_t *xframe = NULL; xpacket_t *pack = NULL; - size_t pcm_len; bool sent_sync_bit = 0; /* @@ -990,7 +982,7 @@ static void xbus_tick(xbus_t *xbus) xmit_mask |= xpd->silence_pcm; xmit_mask |= xpd->digital_signalling; for_each_line(xpd, j) { - xpd->chans[j].chanmute = (optimize_chanmute) + XPD_CHAN(xpd, j)->chanmute = (optimize_chanmute) ? !IS_SET(xmit_mask, j) : 0; } @@ -1006,6 +998,8 @@ static void xbus_tick(xbus_t *xbus) * Fill xframes */ for(i = 0; i < MAX_XPDS; i++) { + size_t pcm_len; + if((xpd = xpd_of(xbus, i)) == NULL) continue; pcm_len = xpd->pcm_len; @@ -1038,7 +1032,7 @@ static void xbus_tick(xbus_t *xbus) XPACKET_ADDR_SYNC(pack) = 1; sent_sync_bit = 1; } - CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, xpd->wanted_pcm_mask, pack); + CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, pack); XBUS_COUNTER(xbus, TX_PACK_PCM)++; } } @@ -1301,8 +1295,7 @@ EXPORT_SYMBOL(xpp_echocan); #ifdef ZAPTEL_SYNC_TICK EXPORT_SYMBOL(zaptel_sync_tick); #endif -EXPORT_SYMBOL(__pcm_recompute); -EXPORT_SYMBOL(pcm_recompute); +EXPORT_SYMBOL(generic_card_pcm_recompute); EXPORT_SYMBOL(generic_card_pcm_tospan); EXPORT_SYMBOL(generic_card_pcm_fromspan); #ifdef DEBUG_PCMTX diff --git a/kernel/xpp/xbus-pcm.h b/kernel/xpp/xbus-pcm.h index 3265f68..b4c0cf6 100644 --- a/kernel/xpp/xbus-pcm.h +++ b/kernel/xpp/xbus-pcm.h @@ -100,9 +100,9 @@ int xbus_pcm_init(struct proc_dir_entry *top); void xbus_pcm_shutdown(void); int send_pcm_frame(xbus_t *xbus, xframe_t *xframe); void pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); -void __pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); /* non locking */ void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe); -void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack); +void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask); +void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); void fill_beep(u_char *buf, int num, int duration); const char *sync_mode_name(enum sync_mode mode); diff --git a/kernel/xpp/xpd.h b/kernel/xpp/xpd.h index 35688d6..c0bfcc0 100644 --- a/kernel/xpp/xpd.h +++ b/kernel/xpp/xpd.h @@ -29,13 +29,8 @@ #ifdef __KERNEL__ #include #include -#include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) -#include -#else #include -#endif #include #ifdef XPP_DEBUGFS #ifndef CONFIG_DEBUG_FS @@ -146,6 +141,8 @@ struct xpd { char xpdname[XPD_NAMELEN]; struct zt_span span; struct zt_chan *chans; +#define XPD_CHAN(xpd,chan) (&((xpd)->chans[(chan)])) + int channels; xpd_type_t type; const char *type_name; @@ -153,14 +150,16 @@ struct xpd { xpd_direction_t direction; /* TO_PHONE, TO_PSTN */ int subunits; /* all siblings */ xpp_line_t no_pcm; /* Temporary: disable PCM (for USB-1) */ - xpp_line_t offhook; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */ - xpp_line_t cid_on; + xpp_line_t offhook_state; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */ + xpp_line_t oht_pcm_pass; /* Transfer on-hook PCM */ xpp_line_t msg_waiting; /* Voice Mail Waiting Indication */ xpp_line_t digital_outputs; /* 0 - no, 1 - yes */ xpp_line_t digital_inputs; /* 0 - no, 1 - yes */ xpp_line_t digital_signalling; /* BRI signalling channels */ uint timing_priority; /* from 'span' directives in zapata.conf */ + /* Assure atomicity of changes to pcm_len and wanted_pcm_mask */ + spinlock_t lock_recompute_pcm; /* maintained by card drivers */ uint pcm_len; /* allocation length of PCM packet (dynamic) */ xpp_line_t wanted_pcm_mask; diff --git a/kernel/xpp/xpp_zap.c b/kernel/xpp/xpp_zap.c index 3ce9bff..b1a1bbe 100644 --- a/kernel/xpp/xpp_zap.c +++ b/kernel/xpp/xpp_zap.c @@ -216,7 +216,7 @@ __must_check int xpd_common_init(xbus_t *xbus, xpd_t *xpd, int unit, int subunit snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit); xpd->subtype = subtype; xpd->subunits = subunits; - xpd->offhook = 0; + xpd->offhook_state = 0; /* For USB-1 disable some channels */ if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) { @@ -328,11 +328,11 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo } len += sprintf(page + len, "\n\t%-17s: ", "offhook"); for_each_line(xpd, i) { - len += sprintf(page + len, "%d ", IS_SET(xpd->offhook, i)); + len += sprintf(page + len, "%d ", IS_OFFHOOK(xpd, i)); } - len += sprintf(page + len, "\n\t%-17s: ", "cid_on"); + len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass"); for_each_line(xpd, i) { - len += sprintf(page + len, "%d ", IS_SET(xpd->cid_on, i)); + len += sprintf(page + len, "%d ", IS_SET(xpd->oht_pcm_pass, i)); } len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting"); for_each_line(xpd, i) { @@ -350,7 +350,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | W D"); for_each_line(xpd, i) { - struct zt_chan *chans = xpd->span.chans; + struct zt_chan *chan = XPD_CHAN(xpd, i); byte rchunk[ZT_CHUNKSIZE]; byte wchunk[ZT_CHUNKSIZE]; byte *rp; @@ -363,8 +363,8 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo continue; if(IS_SET(xpd->digital_signalling, i)) continue; - rp = chans[i].readchunk; - wp = chans[i].writechunk; + rp = chan->readchunk; + wp = chan->writechunk; memcpy(rchunk, rp, ZT_CHUNKSIZE); memcpy(wchunk, wp, ZT_CHUNKSIZE); len += sprintf(page + len, "\n port %2d> | ", i); @@ -386,7 +386,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nSignalling:\n"); for_each_line(xpd, i) { - struct zt_chan *chan = &xpd->span.chans[i]; + struct zt_chan *chan = XPD_CHAN(xpd, i); len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig); } } @@ -438,12 +438,13 @@ xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channel } xpd->priv = (byte *)xpd + sizeof(xpd_t); spin_lock_init(&xpd->lock); + spin_lock_init(&xpd->lock_recompute_pcm); xpd->xbus = NULL; xpd->xbus_idx = -1; xpd->channels = channels; xpd->chans = NULL; xpd->card_present = 0; - xpd->offhook = 0x0; /* ONHOOK */ + xpd->offhook_state = 0x0; /* ONHOOK */ xpd->type = proto_table->type; xpd->xproto = proto_table; xpd->xops = &proto_table->xops; @@ -493,8 +494,9 @@ void xpd_disconnect(xpd_t *xpd) update_xpd_status(xpd, ZT_ALARM_NOTOPEN); /* TODO: Should this be done before releasing the spinlock? */ XPD_DBG(DEVICES, xpd, "Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n"); - for (i=0; ispan.channels; i++) - zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED); + for (i=0; ispan.channels; i++) { + zt_qevent_lock(XPD_CHAN(xpd, i),ZT_EVENT_REMOVED); + } } out: spin_unlock_irqrestore(&xpd->lock, flags); @@ -535,18 +537,64 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag) XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag); } -void update_line_status(xpd_t *xpd, int pos, bool to_offhook) +/* + * Used to block/pass PCM during onhook-transfers. E.g: + * - Playing FSK after FXS ONHOOK for MWI (non-neon style) + * - Playing DTFM/FSK for FXO Caller-ID detection. + */ +void oht_pcm(xpd_t *xpd, int pos, bool pass) { - zt_rxsig_t rxsig; + if(pass) { + LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: pass\n"); + BIT_SET(xpd->oht_pcm_pass, pos); + } else { + LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: block\n"); + BIT_CLR(xpd->oht_pcm_pass, pos); + } + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); +} - BUG_ON(!xpd); +/* + * Update our hookstate -- for PCM block/pass + */ +void mark_offhook(xpd_t *xpd, int pos, bool to_offhook) +{ if(to_offhook) { - BIT_SET(xpd->offhook, pos); - rxsig = ZT_RXSIG_OFFHOOK; + LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK\n"); + BIT_SET(xpd->offhook_state, pos); } else { - BIT_CLR(xpd->offhook, pos); - BIT_CLR(xpd->cid_on, pos); - rxsig = ZT_RXSIG_ONHOOK; + LINE_DBG(SIGNAL, xpd, pos, "ONHOOK\n"); + BIT_CLR(xpd->offhook_state, pos); + } + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); +} + +/* + * Send a signalling notification to Asterisk + */ +void notify_rxsig(xpd_t *xpd, int pos, zt_rxsig_t rxsig) +{ + /* + * We should not spinlock before calling zt_hooksig() as + * it may call back into our xpp_hooksig() and cause + * a nested spinlock scenario + */ + LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", rxsig2str(rxsig)); + if(SPAN_REGISTERED(xpd)) + zt_hooksig(XPD_CHAN(xpd, pos), rxsig); +} + +/* + * Called when hardware state changed: + * - FXS -- the phone was picked up or hanged-up. + * - FXO -- we answered the phone or handed-up. + */ +void hookstate_changed(xpd_t *xpd, int pos, bool to_offhook) +{ + BUG_ON(!xpd); + mark_offhook(xpd, pos, to_offhook); + if(!to_offhook) { + oht_pcm(xpd, pos, 0); /* * To prevent latest PCM to stay in buffers * indefinitely, mark this channel for a @@ -556,14 +604,7 @@ void update_line_status(xpd_t *xpd, int pos, bool to_offhook) */ BIT_SET(xpd->silence_pcm, pos); } - /* - * We should not spinlock before calling zt_hooksig() as - * it may call back into our xpp_hooksig() and cause - * a nested spinlock scenario - */ - LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", (rxsig == ZT_RXSIG_ONHOOK) ? "ONHOOK" : "OFFHOOK"); - if(SPAN_REGISTERED(xpd)) - zt_hooksig(&xpd->chans[pos], rxsig); + notify_rxsig(xpd, pos, (to_offhook) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK); } #ifdef CONFIG_PROC_FS @@ -704,8 +745,6 @@ int xpp_open(struct zt_chan *chan) spin_lock_irqsave(&xbus->lock, flags); atomic_inc(&xbus->xbus_ref_count); atomic_inc(&xpd->open_counter); - if(IS_SET(xpd->digital_signalling, pos)) /* D-chan offhook */ - BIT_SET(xpd->offhook, pos); DBG(DEVICES, "chan=%d (xbus_ref_count=%d)\n", pos, atomic_read(&xbus->xbus_ref_count)); spin_unlock_irqrestore(&xbus->lock, flags); @@ -723,8 +762,6 @@ int xpp_close(struct zt_chan *chan) spin_lock_irqsave(&xbus->lock, flags); atomic_dec(&xpd->open_counter); - if(IS_SET(xpd->digital_signalling, pos)) /* D-chan onhook */ - BIT_CLR(xpd->offhook, pos); spin_unlock_irqrestore(&xbus->lock, flags); if(xpd->xops->card_close) xpd->xops->card_close(xpd, pos); @@ -977,26 +1014,18 @@ static int zaptel_register_xpd(xpd_t *xpd) atomic_inc(&xpd->zt_registered); xpd->xops->card_zaptel_postregistration(xpd, 1); /* - * Update zaptel about our state - */ -#if 0 - /* - * FIXME: since asterisk didn't open the channel yet, the report - * is discarded anyway. OTOH, we cannot report in xpp_open or - * xpp_chanconfig since zaptel call them with a spinlock on the channel - * and zt_hooksig tries to acquire the same spinlock, resulting in - * double spinlock deadlock (we are lucky that RH/Fedora kernel are - * compiled with spinlock debugging).... tough. + * Update zaptel about our state: + * - Since asterisk didn't open the channel yet, + * the report is discarded anyway. + * - Our FXS driver have another notification mechanism that + * is triggered (indirectly) by the open() of the channe. + * - The real fix should be in Asterisk (to get the correct state + * after open). */ for_each_line(xpd, cn) { - struct zt_chan *chans = xpd->span.chans; - - if(IS_SET(xpd->offhook, cn)) { - LINE_NOTICE(xpd, cn, "Report OFFHOOK to zaptel\n"); - zt_hooksig(&chans[cn], ZT_RXSIG_OFFHOOK); - } - } -#endif + if(IS_OFFHOOK(xpd, cn)) + notify_rxsig(xpd, cn, ZT_RXSIG_OFFHOOK); + } return 0; } @@ -1075,7 +1104,10 @@ EXPORT_SYMBOL(xpd_alloc); EXPORT_SYMBOL(xpd_free); EXPORT_SYMBOL(xpd_disconnect); EXPORT_SYMBOL(update_xpd_status); -EXPORT_SYMBOL(update_line_status); +EXPORT_SYMBOL(oht_pcm); +EXPORT_SYMBOL(mark_offhook); +EXPORT_SYMBOL(notify_rxsig); +EXPORT_SYMBOL(hookstate_changed); EXPORT_SYMBOL(xpp_open); EXPORT_SYMBOL(xpp_close); EXPORT_SYMBOL(xpp_ioctl); diff --git a/kernel/xpp/xpp_zap.h b/kernel/xpp/xpp_zap.h index dd56657..8a4ffad 100644 --- a/kernel/xpp/xpp_zap.h +++ b/kernel/xpp/xpp_zap.h @@ -34,13 +34,17 @@ xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channel void xpd_free(xpd_t *xpd); void xpd_remove(xpd_t *xpd); void update_xpd_status(xpd_t *xpd, int alarm_flag); -void update_line_status(xpd_t *xpd, int pos, bool good); +void hookstate_changed(xpd_t *xpd, int pos, bool good); int xpp_open(struct zt_chan *chan); int xpp_close(struct zt_chan *chan); int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg); int xpp_maint(struct zt_span *span, int cmd); void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd); int total_registered_spans(void); +void oht_pcm(xpd_t *xpd, int pos, bool pass); +void mark_offhook(xpd_t *xpd, int pos, bool to_offhook); +#define IS_OFFHOOK(xpd,pos) IS_SET((xpd)->offhook_state, (pos)) +void notify_rxsig(xpd_t *xpd, int pos, zt_rxsig_t rxsig); #ifdef CONFIG_PROC_FS #include diff --git a/kernel/xpp/xproto.c b/kernel/xpp/xproto.c index c3aa34e..ae6a9b2 100644 --- a/kernel/xpp/xproto.c +++ b/kernel/xpp/xproto.c @@ -435,6 +435,7 @@ int xproto_register(const xproto_table_t *proto_table) CHECK_XOP(card_init); CHECK_XOP(card_remove); CHECK_XOP(card_tick); + CHECK_XOP(card_pcm_recompute); CHECK_XOP(card_pcm_fromspan); CHECK_XOP(card_pcm_tospan); CHECK_XOP(card_zaptel_preregistration); diff --git a/kernel/xpp/xproto.h b/kernel/xpp/xproto.h index 4691094..cbf0726 100644 --- a/kernel/xpp/xproto.h +++ b/kernel/xpp/xproto.h @@ -221,7 +221,8 @@ struct xops { int (*card_init)(xbus_t *xbus, xpd_t *xpd); int (*card_remove)(xbus_t *xbus, xpd_t *xpd); int (*card_tick)(xbus_t *xbus, xpd_t *xpd); - void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack); + void (*card_pcm_recompute)(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask); + void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); void (*card_pcm_tospan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); int (*card_zaptel_preregistration)(xpd_t *xpd, bool on); int (*card_zaptel_postregistration)(xpd_t *xpd, bool on); -- cgit v1.2.3