diff options
Diffstat (limited to 'kernel/xpp/card_bri.c')
-rw-r--r-- | kernel/xpp/card_bri.c | 141 |
1 files changed, 100 insertions, 41 deletions
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, |