summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c607
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);