diff options
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r-- | xpp/xpp_zap.c | 224 |
1 files changed, 126 insertions, 98 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c index e28d40a..8642b7c 100644 --- a/xpp/xpp_zap.c +++ b/xpp/xpp_zap.c @@ -79,19 +79,19 @@ static bool zaptel_is_ticking; #define ZAPTEL_BIG_LAG 500 /* usec */ -DEF_PARM_BOOL(sync_tick_active, 1, 0600, "Measure via zaptel sync_tick() method"); +DEF_PARM_BOOL(sync_tick_active, 1, 0644, "Measure via zaptel sync_tick() method"); static void sync_status_clear(void); #endif -DEF_PARM_BOOL(pcm_tasklet, 0, 0600, "Handle PCM in a tasklet (lower interrupt load)"); -DEF_PARM(int, disable_pcm, 0, 0600, "Disable all PCM transmissions"); -DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements"); -DEF_PARM_BOOL(zap_autoreg, 1, 0600, "Register spans automatically (1) or not (0)"); -DEF_PARM_BOOL(prefmaster, 1, 0600, "Do we want to be zaptel preferred sync master"); +DEF_PARM_BOOL(pcm_tasklet, 0, 0644, "Handle PCM in a tasklet (lower interrupt load)"); +DEF_PARM(int, disable_pcm, 0, 0644, "Disable all PCM transmissions"); +DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); +DEF_PARM_BOOL(zap_autoreg, 0, 0644, "Register spans automatically (1) or not (0)"); +DEF_PARM_BOOL(prefmaster, 1, 0644, "Do we want to be zaptel preferred sync master"); #ifdef XPP_EC_CHUNK -DEF_PARM_BOOL(xpp_ec, 1, 0400, "Do we use our own (1) or Zaptel's (0) echo canceller"); +DEF_PARM_BOOL(xpp_ec, 0, 0444, "Do we use our own (1) or Zaptel's (0) echo canceller"); #else static int xpp_ec = 0; #endif @@ -106,7 +106,7 @@ static int xpp_ec = 0; static void xpp_tick(unsigned long param); static int zaptel_register_xpd(xpd_t *xpd); static int zaptel_unregister_xpd(xpd_t *xpd); -static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack); +static void xpp_transmitprep(xbus_t *xbus, int unit, xpp_line_t lines, xpacket_t *pack); static void xpp_receiveprep(xpd_t *xpd); static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -129,10 +129,10 @@ static void external_sync(xbus_t *the_xbus) continue; if (!xbus->hardware_exists) continue; - CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, 1, 0); + CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_HOST, 0); } if(the_xbus) - CALL_PROTO(GLOBAL, SYNC_SOURCE, the_xbus, NULL, 1, 1); + CALL_PROTO(GLOBAL, SYNC_SOURCE, the_xbus, NULL, SYNC_MODE_AB, 0); } /* @@ -173,70 +173,94 @@ static void sync_master_is(xbus_t *xbus) static inline void send_pcm_frame(xbus_t *xbus, xframe_t *xframe) { static int rate_limit; + unsigned long flags; + struct timeval now; + long sec_diff; + long usec_diff; - if(disable_pcm) - xbus->ops->xframe_free(xbus, xframe); - else { - if(print_dbg && ((rate_limit++ % 1003) == 0)) - dump_xframe("SEND_PCM", xbus, xframe); - xframe_send(xbus, xframe); - XBUS_COUNTER(xbus, SEND_PCM)++; - } + spin_lock_irqsave(&xbus->lock, flags); + do_gettimeofday(&now); + if(unlikely(disable_pcm || !xbus->hardware_exists)) + goto dropit; + sec_diff = now.tv_sec - xbus->last_tx_sync.tv_sec; + usec_diff = sec_diff * 1000000 + (now.tv_usec - xbus->last_tx_sync.tv_usec); + if(unlikely(abs(sec_diff) > 2)) { + DBG("%s: PCM TX timing restart (sec_diff=%ld)\n", + xbus->busname, sec_diff); + xbus->last_tx_sync = now; + goto dropit; + } + if(abs(usec_diff - 1000) > TICK_TOLERANCE) { + if(print_dbg && printk_ratelimit()) + DBG("%s: Bad PCM TX timing: usec_diff=%ld.\n", + xbus->busname, usec_diff); + } + if(usec_diff > xbus->max_tx_sync) + xbus->max_tx_sync = usec_diff; + if(usec_diff < xbus->min_tx_sync) + xbus->min_tx_sync = usec_diff; + spin_unlock_irqrestore(&xbus->lock, flags); + /* OK, really send it */ + if(print_dbg == 2 && ((rate_limit++ % 1003) == 0)) + dump_xframe("SEND_PCM", xbus, xframe); + xframe_send(xbus, xframe); + XBUS_COUNTER(xbus, SEND_PCM)++; + xbus->last_tx_sync = now; + return; +dropit: + spin_unlock_irqrestore(&xbus->lock, flags); + xbus->ops->xframe_free(xbus, xframe); } /* * Calculate PCM line_count and lines from a xbus+unit number: * - Takes into account BRI subunits * - Returns an XPD pointer if we should transmit, NULL otherwise + * - Calls zt_transmit() for all registered subunits so we empty + * the relevant zaptel buffers (otherwise asterisk fails to write) + * and we have stable buffers to send. */ static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, size_t *pcm_len, xpp_line_t *plines) { - bool is_bri; - bool digital_telephony; int line_count = 0; xpp_line_t lines; - xpd_t *xpd; + xpd_t *xpd = NULL; + xpd_t *tmp_xpd; unsigned long flags; int i; + int subunit; - xpd = xpd_by_addr(xbus, unit, 0); - if(!xpd || !xpd->card_present) - return NULL; - spin_lock_irqsave(&xpd->lock, flags); - is_bri = (xpd->type == XPD_TYPE_BRI_NT) || (xpd->type == XPD_TYPE_BRI_TE); - digital_telephony = is_bri; /* or PRI */ - if(digital_telephony) { - int subunit; - - /* without D-Channel */ - lines = xpd->offhook & ~xpd->digital_signalling; - for_each_line(xpd, i) - if(IS_SET(lines, i)) - line_count++; - if(is_bri) { + lines = 0; + line_count = 0; + /* + * BRI has a single PCM highway for all subunits, so + * we agregate the next subunits into the same + * transmition. We shift 4 bits (B1, B2, D, E) + */ + for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) { + xpp_line_t tmp_lines; + + tmp_xpd = xpd_by_addr(xbus, unit, subunit); + if(!tmp_xpd || !tmp_xpd->card_present) + continue; + if(!xpd) + xpd = tmp_xpd; /* First xpd for our unit */ + if(SPAN_REGISTERED(tmp_xpd)) { /* - * BRI has a single PCM highway for all subunits, so - * we agregate the next subunits into the same - * transmition. + * calls to zt_transmit should be out of spinlocks, as it may call back + * our hook setting methods. */ - for(subunit = 1; subunit < MAX_SUBUNIT; subunit++) { - xpd_t *tmp_xpd = xpd_by_addr(xbus, unit, subunit); - xpp_line_t tmp_lines; - - if(!tmp_xpd || !tmp_xpd->card_present) - continue; - tmp_lines = xpd->offhook & ~xpd->digital_signalling; /* Without D-channel */ - for_each_line(tmp_xpd, i) - if(IS_SET(tmp_lines, i)) - line_count++; - lines = (lines << SUBUNIT_PCM_SHIFT) | tmp_lines; /* B1, B2, D, E */ - } + zt_transmit(&tmp_xpd->span); } - } else { - lines = (xpd->offhook | xpd->cid_on); - for_each_line(xpd, i) - if(IS_SET(lines, i)) + spin_lock_irqsave(&tmp_xpd->lock, flags); + tmp_lines = (tmp_xpd->offhook | tmp_xpd->cid_on) & ~tmp_xpd->digital_signalling; /* without D-Channel */ + lines |= (tmp_lines << (SUBUNIT_PCM_SHIFT * subunit)); + for_each_line(tmp_xpd, i) + if(IS_SET(tmp_lines, i)) line_count++; + spin_unlock_irqrestore(&tmp_xpd->lock, flags); + if(!IS_BRI(tmp_xpd)) + break; /* no subunits */ } /* * FIXME: Workaround a bug in sync code of the Astribank. @@ -246,9 +270,10 @@ static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, size_t *pcm_len, xpp_l lines = BIT(0); line_count = 1; } + if(!line_count) + return NULL; /* Nothing to transmit for this unit */ *pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE; *plines = lines; - spin_unlock_irqrestore(&xpd->lock, flags); return xpd; } @@ -285,18 +310,15 @@ static void xbus_tick(xbus_t *xbus) xpd_set_addr(&pack->addr, xpd->id); pack->datalen = pcm_len; RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines; - xpp_transmitprep(xpd, lines, pack); + xpp_transmitprep(xbus, unit, lines, pack); } - } if(xframe) /* clean any leftovers */ send_pcm_frame(xbus, xframe); - for(i = 0; i < MAX_XPDS; i++) { xpd = xpd_of(xbus, i); if(!xpd || !xpd->card_present) continue; - if(SPAN_REGISTERED(xpd)) xpp_receiveprep(xpd); xpd->timer_count++; @@ -311,7 +333,7 @@ static void xbus_tick(xbus_t *xbus) void xpp_tick(unsigned long param) { xbus_t *xbus; - int i, j; + int i; #ifdef ZAPTEL_SYNC_TICK do_gettimeofday (&ticked_xpp); @@ -335,26 +357,30 @@ void xpp_tick(unsigned long param) DBG("Dropped packet. %s is in_use\n", xbus->busname); continue; } - /* - * calls to zt_transmit should be out of spinlocks, as it may call back - * our hook setting methods. - */ - for(j = 0; j < MAX_XPDS; j++) { - xpd_t *xpd = xpd_of(xbus, j); - - if(xpd && SPAN_REGISTERED(xpd)) { - zt_transmit(&xpd->span); - } - } xbus_tick(xbus); + if((xpp_timer_count % (60*1000)) == 0) { + xbus->min_tx_sync = INT_MAX; + xbus->max_tx_sync = 0; + xbus->min_rx_sync = INT_MAX; + xbus->max_rx_sync = 0; + } up_read(&xbus->in_use); } } -void got_pcm_from(xpd_t *xpd) +void got_sync_from(xpd_t *xpd) { - if(xpd != sync_master) + xbus_t *xbus; + + xbus = xpd->xbus; + if(xpd != sync_master) { + static int rate_limit; + + if((rate_limit++ % 1003) == 0) + DBG("%s/%s: is not SYNC master. Go away! (%d)\n", + xbus->busname, xpd->xpdname, rate_limit); return; + } atomic_inc(&missed_ticks); if(!pcm_tasklet) { xpp_tick(0L); @@ -390,7 +416,7 @@ int zaptel_sync_tick(struct zt_span *span, int is_master) */ if(sync_master && xpd != sync_master) return 0; - do_gettimeofday (&ticked_zaptel); + do_gettimeofday(&ticked_zaptel); usec_lag_curr = (ticked_zaptel.tv_sec - ticked_xpp.tv_sec)*1000*1000 + (ticked_zaptel.tv_usec - ticked_xpp.tv_usec); @@ -458,7 +484,7 @@ static void xpd_free(xpd_t *xpd) #define REV(x,y) (10 * (x) + (y)) static byte good_revs[] = { - REV(2,4), + REV(2,6), }; #undef REV @@ -578,11 +604,14 @@ void card_detected(struct card_desc_struct *card_desc) xbus_register_xpd(xbus, xpd); if(CALL_XMETHOD(card_init, xbus, xpd) < 0) goto err; - // Turn off all channels - CALL_XMETHOD(XPD_STATE, xbus, xpd, 0); + CALL_XMETHOD(XPD_STATE, xbus, xpd, 0); /* Turn off all channels */ + CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_HOST, 0); /* Not a SYNC master (yet) */ xpd->card_present = 1; - // Turn on all channels - CALL_XMETHOD(XPD_STATE, xbus, xpd, 1); + if(xbus->last_tx_sync.tv_sec == 0 && xbus->last_tx_sync.tv_usec == 0) { + do_gettimeofday(&xbus->last_tx_sync); /* start timing ticks */ + xbus->last_rx_sync = xbus->last_tx_sync; + } + CALL_XMETHOD(XPD_STATE, xbus, xpd, 1); /* Turn on all channels */ if(zap_autoreg) zaptel_register_xpd(xpd); @@ -991,7 +1020,7 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne ERR("No bus %d exists\n", xbus_num); return -ENXIO; } - CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, 0, 0); + CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0); } else if(sscanf(buf, "%d %d", &xbus_num, &xpd_num) == 2) { NOTICE("Using deprecated syntax to update /proc/%s/%s\n", PROC_DIR, PROC_SYNC); @@ -1149,29 +1178,29 @@ error: #define PREP_REPORT_RATE 1000 -static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) +static void xpp_transmitprep(xbus_t *xbus, int unit, xpp_line_t lines, xpacket_t *pack) { byte *pcm; - int channels; struct zt_chan *chans; unsigned long flags; int i; int subunit; - xpd_t *tmp_xpd; - BUG_ON(!xpd); + BUG_ON(!xbus); BUG_ON(!pack); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); - for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) { - tmp_xpd = xpd_by_addr(xpd->xbus, xpd->addr.unit, subunit); - if(!tmp_xpd) + for(subunit = 0; subunit < MAX_SUBUNIT; subunit++, lines >>= SUBUNIT_PCM_SHIFT) { + xpd_t *tmp_xpd; + + tmp_xpd = xpd_by_addr(xbus, unit, subunit); + if(!tmp_xpd || !tmp_xpd->card_present) continue; + if(lines == 0) + break; /* Optimize */ spin_lock_irqsave(&tmp_xpd->lock, flags); - - channels = tmp_xpd->channels; chans = tmp_xpd->span.chans; - for (i = 0; i < channels; i++) { + for (i = 0; i < tmp_xpd->channels; i++) { if(IS_SET(lines, i)) { if(SPAN_REGISTERED(tmp_xpd)) { memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE); @@ -1184,7 +1213,8 @@ static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) } XPD_COUNTER(tmp_xpd, PCM_WRITE)++; spin_unlock_irqrestore(&tmp_xpd->lock, flags); - lines >>= SUBUNIT_PCM_SHIFT; + if(!IS_BRI(tmp_xpd)) + break; /* only BRI has subunits */ } } @@ -1245,10 +1275,8 @@ static void xpp_receiveprep(xpd_t *xpd) int channels = xpd->channels; struct zt_chan *chans = xpd->span.chans; unsigned long flags; - bool digital_telephony; spin_lock_irqsave(&xpd->lock, flags); - digital_telephony = (xpd->type == XPD_TYPE_BRI_NT) || (xpd->type == XPD_TYPE_BRI_TE); // if((xpd->timer_count % PREP_REPORT_RATE) == 0) // DBG("%d\n", xpd->timer_count); @@ -1266,7 +1294,7 @@ static void xpp_receiveprep(xpd_t *xpd) */ if(IS_SET(xpd->digital_signalling, i)) continue; - if(IS_SET(xpd->offhook, i) || IS_SET(xpd->cid_on, i) || digital_telephony) { + if(IS_SET(xpd->offhook, i) || IS_SET(xpd->cid_on, i) || IS_BRI(xpd)) { // memset((u_char *)readchunk, 0x5A, ZT_CHUNKSIZE); // DEBUG // fill_beep((u_char *)readchunk, 1, 1); // DEBUG: BEEP memcpy(chans[i].readchunk, (u_char *)readchunk, ZT_CHUNKSIZE); @@ -1274,7 +1302,6 @@ static void xpp_receiveprep(xpd_t *xpd) memset(chans[i].readchunk, 0x7F, ZT_CHUNKSIZE); // SILENCE } } - #if WITH_ECHO_SUPPRESSION /* FIXME: need to Echo cancel double buffered data */ for (i = 0;i < xpd->span.channels; i++) { @@ -1412,8 +1439,9 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg) case ZT_TONEDETECT: if (get_user(x, (int __user *)arg)) return -EFAULT; - DBG("xpd=%d: ZT_TONEDETECT chan=%d: TONEDETECT_ON=%d TONEDETECT_MUTE=%d\n", - xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE)); + DBG("%s/%s/%d: ZT_TONEDETECT (TONEDETECT_ON=%d TONEDETECT_MUTE=%d)\n", + xpd->xbus->busname, xpd->xpdname, pos, + (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE)); return -ENOTTY; default: /* Some span-specific commands before we give up: */ |