diff options
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r-- | xpp/xpp_zap.c | 607 |
1 files changed, 263 insertions, 344 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c index fb49e69..dcbb435 100644 --- a/xpp/xpp_zap.c +++ b/xpp/xpp_zap.c @@ -100,6 +100,10 @@ DEF_PARM_BOOL(xpp_ec, 0, 0444, "Do we use our own (1) or Zaptel's (0) echo cance #else static int xpp_ec = 0; #endif +#ifdef DEBUG_PCMTX +DEF_PARM(int, pcmtx, -1, 0644, "Forced PCM value to transmit (negative to disable)"); +DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value"); +#endif // DEF_ARRAY(int, pcmtx, 4, 0, "Forced PCM values to transmit"); #include "zap_debug.h" @@ -143,11 +147,14 @@ void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1) EXPORT_SYMBOL(xbus_flip_bit); #endif +#ifdef ZAPTEL_SYNC_TICK +static void send_drift(int drift); +#endif 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(xbus_t *xbus, int unit, xpp_line_t lines, xpacket_t *pack); static void xpp_receiveprep(xpd_t *xpd); +static void do_ec(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); static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data); @@ -212,7 +219,6 @@ 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; unsigned long sec_diff; @@ -241,10 +247,10 @@ static inline void send_pcm_frame(xbus_t *xbus, xframe_t *xframe) 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); + if(print_dbg & DBG_PCM ) + dump_xframe("TX_XFRAME_PCM", xbus, xframe); xframe_send(xbus, xframe); - XBUS_COUNTER(xbus, SEND_PCM)++; + XBUS_COUNTER(xbus, TX_XFRAME_PCM)++; xbus->last_tx_sync = now; return; dropit: @@ -253,121 +259,155 @@ dropit: } /* - * 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. + * Generic implementations of card_pcmfromspan()/card_pcmtospan() + * For FXS/FXO */ -static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, size_t *pcm_len, xpp_line_t *plines) +void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) { - int line_count = 0; - xpp_line_t lines; - xpd_t *xpd = NULL; - xpd_t *tmp_xpd; + byte *pcm; + struct zt_chan *chans; unsigned long flags; int i; - int subunit; - 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)) { - /* - * calls to zt_transmit should be out of spinlocks, as it may call back - * our hook setting methods. - */ - zt_transmit(&tmp_xpd->span); + BUG_ON(!xbus); + BUG_ON(!xpd); + BUG_ON(!pack); + RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = 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)) { + if(SPAN_REGISTERED(xpd)) { +#ifdef DEBUG_PCMTX + if(pcmtx >= 0 && pcmtx_chan == i) + memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE); + else +#endif + memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE); + // fill_beep((u_char *)pcm, xpd->addr.subunit, 2); + } else + memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE); + pcm += ZT_CHUNKSIZE; } - 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. - * Send dummy PCM for sync. - */ - if(unit == 0 && lines == 0) { - lines = BIT(0); - line_count = 1; + XPD_COUNTER(xpd, PCM_WRITE)++; + spin_unlock_irqrestore(&xpd->lock, flags); +} + +void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) +{ + volatile u_char *r; + byte *pcm; + xpp_line_t pcm_mask; + unsigned long flags; + int i; + + pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); + pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); + spin_lock_irqsave(&xpd->lock, flags); + if (xpd->timer_count & 1) + r = xpd->readchunk; /* First part */ + else + r = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD; + for (i = 0; i < CHANNELS_PERXPD; i++, r += ZT_CHUNKSIZE) { + /* + * We don't copy signalling buffers (they may be + * longer than ZT_CHUNKSIZE). + */ + if(IS_SET(pcm_mask, i)) { + // 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; + } } - 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; - return xpd; + XPD_COUNTER(xpd, PCM_READ)++; + spin_unlock_irqrestore(&xpd->lock, flags); } static void xbus_tick(xbus_t *xbus) { - int unit; int i; - xpp_line_t lines; xpd_t *xpd; xframe_t *xframe = NULL; xpacket_t *pack = NULL; size_t pcm_len; - for(unit = 0; unit < MAX_UNIT; unit++) { - if((xpd = unit_pcm_calc(xbus, unit, &pcm_len, &lines)) == NULL) + /* + * Update zaptel + */ + for(i = 0; i < MAX_XPDS; i++) { + xpd = xpd_of(xbus, i); + if(xpd && SPAN_REGISTERED(xpd)) { + /* + * calls to zt_transmit should be out of spinlocks, as it may call back + * our hook setting methods. + */ +#ifdef OPTIMIZE_CHANMUTE + int j; + + for_each_line(xpd, j) + xpd->chans[j].chanmute = !IS_SET(xpd->wanted_pcm_mask, j) && !IS_SET(xpd->digital_signalling, j); +#endif + zt_transmit(&xpd->span); + } + } + /* + * Fill xframes + */ + for(i = 0; i < MAX_XPDS; i++) { + if((xpd = xpd_of(xbus, i)) == NULL) continue; - if(lines && SPAN_REGISTERED(xpd)) { - do { - // pack = NULL; /* FORCE single packet frames */ - if(xframe && !pack) { /* FULL frame */ - send_pcm_frame(xbus, xframe); - xframe = NULL; - } - if(!xframe) { /* Alloc frame */ - xframe = xbus->ops->xframe_new(xbus, GFP_ATOMIC); - if (!xframe) { - ERR("%s: failed to allocate new xframe\n", __FUNCTION__); - return; + pcm_len = xpd->pcm_len; + if(SPAN_REGISTERED(xpd)) { + if(pcm_len && xpd->card_present) { + do { + // pack = NULL; /* FORCE single packet frames */ + if(xframe && !pack) { /* FULL frame */ + send_pcm_frame(xbus, xframe); + xframe = NULL; + XBUS_COUNTER(xbus, TX_PCM_FRAG)++; + } + if(!xframe) { /* Alloc frame */ + xframe = xbus->ops->xframe_new(xbus, GFP_ATOMIC); + if (!xframe) { + ERR("%s: failed to allocate new xframe\n", __FUNCTION__); + return; + } } - } - pack = xframe_next_packet(xframe, pcm_len); - } while(!pack); - XPACKET_INIT(pack, GLOBAL, PCM_WRITE); - xpd_set_addr(&pack->addr, xpd->id); - pack->datalen = pcm_len; - RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines; - xpp_transmitprep(xbus, unit, lines, pack); + pack = xframe_next_packet(xframe, pcm_len); + } while(!pack); + XPACKET_INIT(pack, GLOBAL, PCM_WRITE); + xpd_set_addr(&pack->addr, xpd->xbus_idx); + pack->datalen = pcm_len; + CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, xpd->wanted_pcm_mask, pack); + XBUS_COUNTER(xbus, TX_PACK_PCM)++; + } } } if(xframe) /* clean any leftovers */ send_pcm_frame(xbus, xframe); + /* + * Receive PCM + */ 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++; + xpd->timer_count = xpp_timer_count; /* * Must be called *after* tx/rx so * D-Chan counters may be cleared */ CALL_XMETHOD(card_tick, xbus, xpd); } +#ifdef ZAPTEL_SYNC_TICK + if(xbus->sync_adjustment != xbus->sync_adjustment_offset) + send_drift(xbus->sync_adjustment_offset); +#endif } void xpp_tick(unsigned long param) @@ -398,13 +438,15 @@ void xpp_tick(unsigned long param) DBG("Dropped packet. %s is in_use\n", xbus->busname); continue; } - 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; + /* Reset sync LEDs once in a while */ + if((xpp_timer_count % 10000) == 0) + CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus, NULL); + if(atomic_dec_and_test(&xbus->pcm_nesting)) { + xbus_tick(xbus); + } else { + ERR("%s: NESTING ATTEMPT: %d\n", xbus->busname, atomic_read(&xbus->pcm_nesting)); } + atomic_inc(&xbus->pcm_nesting); up_read(&xbus->in_use); } } @@ -508,8 +550,7 @@ int zaptel_sync_tick(struct zt_span *span, int is_master) offset = SYNC_ADJ_MIN; if(offset > SYNC_ADJ_MAX) offset = SYNC_ADJ_MAX; - if(xbus->sync_adjustment != offset) /* Only fix if needed */ - send_drift(offset); + xbus->sync_adjustment_offset = offset; } } return 0; @@ -520,10 +561,6 @@ noop: } #endif -#if HZ != 1000 -#warning "HZ != 1000. PCM would be good only with Astribank sync" -#endif - static void xpd_free(xpd_t *xpd) { xbus_t *xbus = NULL; @@ -594,8 +631,9 @@ void card_detected(struct card_desc_struct *card_desc) { xbus_t *xbus; xpd_t *xpd = NULL; - int xpd_num; byte type; + int unit; + int subunit; byte rev; const xops_t *xops; const xproto_table_t *proto_table; @@ -604,46 +642,57 @@ void card_detected(struct card_desc_struct *card_desc) BUG_ON(!card_desc); BUG_ON(card_desc->magic != CARD_DESC_MAGIC); xbus = card_desc->xbus; - xpd_num = XPD_NUM(card_desc->xpd_addr); type = card_desc->type; + unit = card_desc->xpd_addr.unit; + subunit = card_desc->xpd_addr.subunit; rev = card_desc->rev; BUG_ON(!xbus); if(!good_rev(rev)) { - NOTICE("%s: New XPD #%d (%d-%d) type=%d has bad firmware revision %d.%d\n", xbus->busname, - xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit, + NOTICE("%s: XPD at %d%d: type=%d has bad firmware revision %d.%d\n", + xbus->busname, + unit, subunit, type, rev / 10, rev % 10); goto err; } - INFO("%s: New XPD #%d (%d-%d) type=%d Revision %d.%d\n", xbus->busname, - xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit, - type, rev / 10, rev % 10); - xpd = xpd_of(xbus, xpd_num); + INFO("%s: New XPD at %d%d type=%d Revision %d.%d\n", xbus->busname, + unit, subunit, type, rev / 10, rev % 10); + xpd = xpd_byaddr(xbus, unit, subunit); if(xpd) { if(type == XPD_TYPE_NOMODULE) { - NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num); + NOTICE("%s: XPD at %d%d removed\n", __FUNCTION__, + unit, subunit); BUG(); goto out; } - NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num); + NOTICE("%s: XPD at %d%d already exists\n", __FUNCTION__, + unit, subunit); goto out; } if(type == XPD_TYPE_NOMODULE) { - DBG("No module at address=%d\n", xpd_num); + NOTICE("%s: XPD at %d%d Missing\n", __FUNCTION__, + unit, subunit); goto out; } proto_table = xproto_get(type); if(!proto_table) { - NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type); + NOTICE("%s: XPD at %d%d: missing protocol table for type=%d. Ignored.\n", + __FUNCTION__, + unit, subunit, + type); goto out; } xops = &proto_table->xops; BUG_ON(!xops); - xpd = xops->card_new(xbus, xpd_num, proto_table, rev); + xpd = xops->card_new(xbus, unit, subunit, proto_table, rev); if(!xpd) { - NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev); + NOTICE("card_new(%s,%d,%d,%d,%d) failed. Ignored.\n", + xbus->busname, unit, subunit, proto_table->type, rev); + xproto_put(xpd->xproto); goto err; } xpd->addr = card_desc->xpd_addr; + xpd->xbus_idx = XPD_IDX(unit,subunit); + snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit); xpd->offhook = card_desc->line_status; /* For USB-1 disable some channels */ @@ -737,13 +786,15 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo len += sprintf(page + len, "%s (%s ,card %s, span %s) %s\n" "timer_count: %d span->mainttimer=%d\n" , - xpd->xpdname, xproto_name(xpd->type), + xpd->xpdname, xpd->type_name, (xpd->card_present) ? "present" : "missing", (SPAN_REGISTERED(xpd)) ? "registered" : "NOT registered", (xpd == sync_master) ? "SYNC MASTER" : "SYNC SLAVE", xpd->timer_count, xpd->span.mainttimer ); len += sprintf(page + len, "Address: U=%d S=%d\n\n", xpd->addr.unit, xpd->addr.subunit); + len += sprintf(page + len, "pcm_len=%d\n\n", xpd->pcm_len); + len += sprintf(page + len, "wanted_pcm_mask=0x%04X\n\n", xpd->wanted_pcm_mask); len += sprintf(page + len, "STATES:"); len += sprintf(page + len, "\n\t%-17s: ", "output_relays"); for_each_line(xpd, i) { @@ -771,7 +822,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo } #if 1 if(SPAN_REGISTERED(xpd)) { - len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | delay"); + len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | pass"); for_each_line(xpd, i) { struct zt_chan *chans = xpd->span.chans; byte rchunk[ZT_CHUNKSIZE]; @@ -802,7 +853,8 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo for(j = 0; j < ZT_CHUNKSIZE; j++) { len += sprintf(page + len, "%02X ", wchunk[j]); } - len += sprintf(page + len, " | "); + len += sprintf(page + len, " | %c", + (IS_SET(xpd->wanted_pcm_mask, i))?'+':' '); } } #endif @@ -840,35 +892,33 @@ out: * xpd_alloc - Allocator for new XPD's * */ -xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision) +xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channels) { xpd_t *xpd = NULL; size_t alloc_size = sizeof(xpd_t) + privsize; + int type = proto_table->type; - DBG("%s: xpd #%d\n", xbus->busname, xpd_num); - if(!VALID_XPD_NUM(xpd_num)) { - ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num); - goto err; - } + DBG("%s: type=%d channels=%d\n", __FUNCTION__, type, channels); if(channels > CHANNELS_PERXPD) { - ERR("%s: too many channels %d for xpd #%d\n", __FUNCTION__, channels, xpd_num); + ERR("%s: type=%d: too many channels %d\n", + __FUNCTION__, type, channels); goto err; } if((xpd = kmalloc(alloc_size, GFP_KERNEL)) == NULL) { - ERR("%s: Unable to allocate memory for xpd #%d\n", __FUNCTION__, xpd_num); + ERR("%s: type=%d: Unable to allocate memory\n", + __FUNCTION__, type); goto err; } memset(xpd, 0, alloc_size); xpd->priv = (byte *)xpd + sizeof(xpd_t); spin_lock_init(&xpd->lock); - xpd->xbus = xbus; - xpd->id = xpd_num; + xpd->xbus = NULL; + xpd->xbus_idx = -1; xpd->channels = channels; xpd->chans = NULL; xpd->card_present = 0; - snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%02x", xpd_num); xpd->offhook = 0x0; /* ONHOOK */ xpd->type = proto_table->type; xpd->xproto = proto_table; @@ -944,8 +994,8 @@ void xpd_remove(xpd_t *xpd) BUG_ON(!xpd); xbus = xpd->xbus; - INFO("%s: Remove XPD #%d from\n", xbus->busname, xpd->id); - + INFO("%s: Remove XPD-%1d%1d\n", xbus->busname, + xpd->addr.unit, xpd->addr.subunit); zaptel_unregister_xpd(xpd); CALL_XMETHOD(card_remove, xbus, xpd); xpd_free(xpd); @@ -998,27 +1048,6 @@ void update_line_status(xpd_t *xpd, int pos, bool to_offhook) zt_hooksig(&xpd->chans[pos], rxsig); } -void update_zap_ring(xpd_t *xpd, int pos, bool on) -{ - zt_rxsig_t rxsig; - - BUG_ON(!xpd); - if(on) { - BIT_CLR(xpd->cid_on, pos); - rxsig = ZT_RXSIG_RING; - } else { - BIT_SET(xpd->cid_on, pos); - rxsig = ZT_RXSIG_OFFHOOK; - } - /* - * 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); -} - #ifdef CONFIG_PROC_FS int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -1040,27 +1069,34 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi } #ifdef ZAPTEL_SYNC_TICK if(sync_tick_active) { - len += sprintf(page + len, "\nZaptel Reference Sync (%s):\n", + if(!zaptel_is_ticking) { + len += sprintf(page + len, + "Zaptel Reference Sync Not activated\n"); + goto noextsync; + } + len += sprintf(page + len, "Zaptel Reference Sync (%s):\n", (have_sync_mastership)?"xpp":"external"); - if(zaptel_is_ticking) { - if(sync_master) { - struct timeval now; - xbus_t *xbus = sync_master->xbus; - - do_gettimeofday(&now); - len += sprintf(page + len, "\t%-19s: %5ld seconds ago\n", - "PLL updated", - (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at); - } - len += sprintf(page + len, "\t%-19s: %5ld (usec)\n", - "current lag", usec_lag_curr); - len += sprintf(page + len, "\t%-19s: %5ld (usec)\n", - "average lag", average_lag); - } else - len += sprintf(page + len, "\tNot activated\n"); - } - len += sprintf(page + len, "zaptel_tick: #%d\n", zaptel_tick_count); - len += sprintf(page + len, "tick - zaptel_tick = %d\n", xpp_timer_count - zaptel_tick_count); + len += sprintf(page + len, "\tzaptel_tick: #%d\n", zaptel_tick_count); + len += sprintf(page + len, "\ttick - zaptel_tick = %d\n", + xpp_timer_count - zaptel_tick_count); + len += sprintf(page + len, "\t%-19s: %5ld (usec)\n", + "current lag", usec_lag_curr); + len += sprintf(page + len, "\t%-19s: %5ld (usec)\n", + "average lag", average_lag); + if(sync_master) { + struct timeval now; + xbus_t *xbus = sync_master->xbus; + + do_gettimeofday(&now); + len += sprintf(page + len, "\t%-19s: %5ld seconds ago\n", + "PLL updated", + (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at); + len += sprintf(page + len, "\t%-19s: %5d\n", + "offset", + xbus->sync_adjustment_offset); + } + } +noextsync: #endif len += sprintf(page + len, "\ntick: #%d\n", xpp_timer_count); xpp_timer_rate = 0; @@ -1224,89 +1260,36 @@ static int proc_xpd_blink_write(struct file *file, const char __user *buffer, un #endif -/** - * - * Frame is freed: - * - In case of error, by this function. - * - Otherwise, by the underlying sending mechanism - */ -int xframe_send(xbus_t *xbus, xframe_t *xframe) -{ - int ret = -ENODEV; - - if(!xframe) { - DBG("null xframe\n"); - return -EINVAL; - } - if(!xbus) { - DBG("null xbus\n"); - ret = -EINVAL; - goto error; - } - if (!xbus->hardware_exists) { - DBG("xbus %s Dropped a xframe -- NO HARDWARE.", xbus->busname); - ret = -ENODEV; - goto error; - } - if(down_read_trylock(&xbus->in_use)) { - ret = xbus->ops->xframe_send(xbus, xframe); - XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe); - up_read(&xbus->in_use); - } else { - DBG("Dropped xframe. %s is in_use\n", xbus->busname); - } - return ret; - -error: - xbus->ops->xframe_free(xbus, xframe); - return ret; -} - #define XPP_MAX_LEN 512 /*------------------------- Zaptel Interfaces ----------------------*/ -#define PREP_REPORT_RATE 1000 - -static void xpp_transmitprep(xbus_t *xbus, int unit, xpp_line_t lines, xpacket_t *pack) +void pcm_recompute(xpd_t *xpd) { - byte *pcm; - struct zt_chan *chans; - unsigned long flags; int i; - int subunit; - - - BUG_ON(!xbus); - BUG_ON(!pack); - pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); - for(subunit = 0; subunit < MAX_SUBUNIT; subunit++, lines >>= SUBUNIT_PCM_SHIFT) { - xpd_t *tmp_xpd; + xpp_line_t tmp_pcm_mask; + int line_count = 0; + unsigned long flags; - 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); - chans = tmp_xpd->span.chans; - 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); - // fill_beep((u_char *)pcm, tmp_xpd->addr.subunit, 2); - // memset((u_char *)pcm, pcmtx[tmp_xpd->addr.subunit % 4], ZT_CHUNKSIZE); - } else - memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE); - pcm += ZT_CHUNKSIZE; - } - } - XPD_COUNTER(tmp_xpd, PCM_WRITE)++; - spin_unlock_irqrestore(&tmp_xpd->lock, flags); - if(!IS_BRI(tmp_xpd)) - break; /* only BRI has subunits */ + tmp_pcm_mask = (xpd->offhook | xpd->cid_on) & ~xpd->digital_signalling; /* without D-Channel */ + for_each_line(xpd, i) + if(IS_SET(tmp_pcm_mask, i)) + line_count++; + /* + * FIXME: Workaround a bug in sync code of the Astribank. + * Send dummy PCM for sync. + */ + if(xpd->addr.unit == 0 && tmp_pcm_mask == 0) { + tmp_pcm_mask = BIT(0); + line_count = 1; } + spin_lock_irqsave(&xpd->lock, flags); + xpd->pcm_len = (line_count) + ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE + : 0L; + xpd->wanted_pcm_mask = tmp_pcm_mask; + spin_unlock_irqrestore(&xpd->lock, flags); } void fill_beep(u_char *buf, int num, int duration) @@ -1358,6 +1341,30 @@ static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, co } #endif +static void do_ec(xpd_t *xpd) +{ + struct zt_chan *chans = xpd->span.chans; + int i; + +#if WITH_ECHO_SUPPRESSION + /* FIXME: need to Echo cancel double buffered data */ + for (i = 0;i < xpd->span.channels; i++) { + if(unlikely(IS_SET(xpd->digital_signalling, i))) /* Don't echo cancel BRI D-chans */ + continue; +#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]); + else +#endif + zt_ec_chunk(&chans[i], chans[i].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); + } +#endif +} + + static void xpp_receiveprep(xpd_t *xpd) { @@ -1368,8 +1375,8 @@ static void xpp_receiveprep(xpd_t *xpd) unsigned long flags; spin_lock_irqsave(&xpd->lock, flags); -// if((xpd->timer_count % PREP_REPORT_RATE) == 0) -// DBG("%d\n", xpd->timer_count); + // if((xpd->timer_count % 1000) == 0) + // DBG("%d\n", xpd->timer_count); if (xpd->timer_count & 1) { /* First part */ @@ -1383,7 +1390,7 @@ static void xpp_receiveprep(xpd_t *xpd) * We don't copy signalling buffers (they may be * longer than ZT_CHUNKSIZE). */ - if(IS_SET(xpd->digital_signalling, i)) + if(unlikely(IS_SET(xpd->digital_signalling, i))) continue; if(IS_SET(xpd->offhook, i) || IS_SET(xpd->cid_on, i) || IS_BRI(xpd)) { // memset((u_char *)readchunk, 0x5A, ZT_CHUNKSIZE); // DEBUG @@ -1393,22 +1400,7 @@ 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++) { - if(IS_SET(xpd->digital_signalling, i)) /* Don't echo cancel PRI/BRI D-chans */ - continue; -#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]); - else -#endif - zt_ec_chunk(&chans[i], chans[i].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); - } -#endif + do_ec(xpd); spin_unlock_irqrestore(&xpd->lock, flags); /* * This should be out of spinlocks, as it may call back our hook setting @@ -1418,51 +1410,6 @@ static void xpp_receiveprep(xpd_t *xpd) } /* - * Called only for 'span' keyword in /etc/zaptel.conf - */ -static int xpp_startup(struct zt_span *span) -{ - xpd_t *xpd = span->pvt; - - BUG_ON(!xpd); - // Turn on all channels - CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); - if(!xpd->xops->span_startup) { - NOTICE("%s/%s: %s called\n", xpd->xbus->busname, xpd->xpdname, __FUNCTION__); - return 0; - } - return xpd->xops->span_startup(xpd); -} - -/* - * Called only for 'span' keyword in /etc/zaptel.conf - */ -static int xpp_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) -{ - xpd_t *xpd = span->pvt; - - DBG("%s\n", xpd->xpdname); - return 0; -} - -/* - * Called only for 'span' keyword in /etc/zaptel.conf - */ -static int xpp_shutdown(struct zt_span *span) -{ - xpd_t *xpd = span->pvt; - - BUG_ON(!xpd); - // Turn off all channels - CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0); - if(!xpd->xops->span_shutdown) { - NOTICE("%s/%s: %s called\n", xpd->xbus->busname, xpd->xpdname, __FUNCTION__); - return 0; - } - return xpd->xops->span_shutdown(xpd); -} - -/* * Called from zaptel with spinlock held on chan. Must not call back * zaptel functions. */ @@ -1515,25 +1462,9 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg) { xpd_t *xpd = chan->pvt; int pos = chan->chanpos - 1; - int x; int ret = 0; switch (cmd) { - case ZT_ONHOOKTRANSFER: - if (get_user(x, (int __user *)arg)) - return -EFAULT; - DBG("%s/%s/%d: ZT_ONHOOKTRANSFER (%d millis)\n", - xpd->xbus->busname, xpd->xpdname, pos, x); - if(xpd->xops->chan_onhooktransfer) - ret = CALL_XMETHOD(chan_onhooktransfer, xpd->xbus, xpd, pos, x); - return ret; - case ZT_TONEDETECT: - if (get_user(x, (int __user *)arg)) - return -EFAULT; - 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: */ if (xpd->xops->card_ioctl != NULL) { @@ -1609,20 +1540,6 @@ int xpp_maint(struct zt_span *span, int cmd) return ret; } -/* - * Set signalling type (if appropriate) - * Called from zaptel with spinlock held on chan. Must not call back - * zaptel functions. - */ -static int xpp_chanconfig(struct zt_chan *chan, int sigtype) -{ - DBG("channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype)); - // FIXME: sanity checks: - // - should be supported (within the sigcap) - // - should not replace fxs <->fxo ??? (covered by previous?) - return 0; -} - #if 0 /* Okay, now we get to the signalling. You have several options: */ @@ -1737,19 +1654,19 @@ static int zaptel_register_xpd(xpd_t *xpd) BUG_ON(!xpd); xops = xpd->xops; + xbus = xpd->xbus; if (SPAN_REGISTERED(xpd)) { ERR("xpd %s already registered\n", xpd->xpdname); return -EEXIST; } cn = xpd->channels; - DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn); - + DBG("%s/%s: Initializing span: %d channels.\n", + xbus->busname, xpd->xpdname, cn); memset(xpd->chans, 0, sizeof(struct zt_chan)*cn); memset(&xpd->span, 0, sizeof(struct zt_span)); span = &xpd->span; - xbus = xpd->xbus; snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname); span->deflaw = ZT_LAW_MULAW; init_waitqueue_head(&span->maintq); @@ -1757,10 +1674,6 @@ static int zaptel_register_xpd(xpd_t *xpd) span->channels = cn; span->chans = xpd->chans; - span->startup = xpp_startup; - span->shutdown = xpp_shutdown; - span->spanconfig = xpp_spanconfig; - span->chanconfig = xpp_chanconfig; span->open = xpp_open; span->close = xpp_close; span->flags = ZT_FLAG_RBS; @@ -1777,6 +1690,8 @@ static int zaptel_register_xpd(xpd_t *xpd) #endif DBG("Registering span of %s.\n", xpd->xpdname); + snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%02d/%1d%1d: %s", + xbus->num, xpd->addr.unit, xpd->addr.subunit, xpd->type_name); xpd->xops->card_zaptel_preregistration(xpd, 1); if(zt_register(&xpd->span, prefmaster)) { xbus_t *xbus = xpd->xbus; @@ -1866,6 +1781,9 @@ int __init xpp_zap_init(void) #else INFO("FEATURE: %s without sync_tick() from ZAPTEL\n", THIS_MODULE->name); #endif +#ifdef OPTIMIZE_CHANMUTE + INFO("FEATURE: %s with CHANMUTE optimization\n", THIS_MODULE->name); +#endif #ifdef CONFIG_PROC_FS xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL); if(!xpp_proc_toplevel) { @@ -1907,9 +1825,10 @@ EXPORT_SYMBOL(print_dbg); EXPORT_SYMBOL(card_detected); EXPORT_SYMBOL(xpd_alloc); EXPORT_SYMBOL(xpd_disconnect); -EXPORT_SYMBOL(xframe_send); +EXPORT_SYMBOL(pcm_recompute); +EXPORT_SYMBOL(generic_card_pcm_fromspan); +EXPORT_SYMBOL(generic_card_pcm_tospan); EXPORT_SYMBOL(update_xpd_status); -EXPORT_SYMBOL(update_zap_ring); EXPORT_SYMBOL(update_line_status); EXPORT_SYMBOL(fill_beep); EXPORT_SYMBOL(xpp_open); |