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.c224
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: */