summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-28 01:23:19 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-28 01:23:19 +0000
commitff8823199f375d709a689dd017950d575b649df6 (patch)
tree7244e80bb45da5f27b747c8bc9aee36b984dd5cd /xpp/xpp_zap.c
parent121cb4b570046fe612938d1eb401181c970b4636 (diff)
Merge xpp rev. 3495:
------------------------------------------------------------------------ r2243 | tzafrir | 2007-02-28 02:05:59 +0200 (Wed, 28 Feb 2007) | 4 lines * xpp rev. 3495: fix a race in the FXO driver of recent weeks. * Add the Astribank BRI driver (though still needs bristuffed zaptel to build and thus will not build by default) ------------------------------------------------------------------------ r2239 | tzafrir | 2007-02-27 08:14:18 +0200 (Tue, 27 Feb 2007) | 18 lines Xorcom rev. 3491: * Version of xpp modules is set from xpp/.version, rather than "unknown". * Astribank devices are now initialized in parallel: faster startup when there are multiple Astribanks. * Re-added support for the old format of /proc/xpp/sync write: (echo N 0 > /proc/xpp/sync ) . The new format (SYNC=NN) is preffered. * Firmware update to fix a PCM issue. * Fixed a build issue with kernel 2.6.8 . * Fixed missing initialization in Zaptel::Xpp::Xbus . * genzaptelconf will now set FXS ports as LS by default. To set them as KS, use fxs_default_start=ks in /etc/default/zaptel / /etc/sysconfig/zaptel (Also a workaround for #7755 ). * Groundwork for sync from zaptel master span: if zaptel is built with ZAPTEL_SYNC_TIC (see zaptel/team/tzafrir/sync ), xpp will report its drift from the zaptel sync master. * USB firmware update: had bad lines checksums (and fxload did not report). * fpga_load can now better report bad hex file checksum ;-) . ------------------------------------------------------------------------ r2223 | tzafrir | 2007-02-24 03:05:05 +0200 (Sat, 24 Feb 2007) | 3 lines Add the Zaptel and Zaptel::Xpp perl modules, and some simple utilities that use them. disabled by default for now. ------------------------------------------------------------------------ r2222 | tzafrir | 2007-02-24 02:55:05 +0200 (Sat, 24 Feb 2007) | 2 lines Make the xpp/utils/Makefile in 1.2 closer to the one in 1.4 . git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2247 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c263
1 files changed, 171 insertions, 92 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index b3e7017..e28d40a 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -63,6 +63,27 @@ static xpd_t *sync_master = NULL; // Start with host based sync
static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
+#ifdef ZAPTEL_SYNC_TICK
+/*
+ * Statistics variables
+ */
+static struct timeval ticked_zaptel;
+static struct timeval ticked_xpp;
+static long usec_lag_curr; /* current: zaptel - xpp */
+static long usec_lag_prev; /* previous: zaptel - xpp */
+static long usec_delta; /* previous - current */
+static long usec_sigma; /* sum of deltas */
+static long status_cleared_at;
+static long since_status_clear;
+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");
+
+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");
@@ -96,11 +117,11 @@ static void xpd_free(xpd_t *xpd);
static DECLARE_TASKLET(tasklet_tick, xpp_tick, 0L);
static atomic_t missed_ticks = ATOMIC_INIT(0); /* In pcm_tasklet mode */
-static void external_sync(xpd_t *the_xpd)
+static void external_sync(xbus_t *the_xbus)
{
- int i, j;
+ int i;
- DBG("SYNC %s\n", (the_xpd)?"Astribanks":"HOST");
+ DBG("%s\n", (the_xbus) ? the_xbus->busname : "HOST");
// Shut all down
for(i = 0; i < MAX_BUSES; i++) {
xbus_t *xbus = xbus_of(i);
@@ -108,25 +129,27 @@ static void external_sync(xpd_t *the_xpd)
continue;
if (!xbus->hardware_exists)
continue;
- for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xpd_of(xbus, j);
- if(xpd) {
- CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, 0);
- }
- }
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, 1, 0);
}
- if(the_xpd)
- CALL_XMETHOD(SYNC_SOURCE, the_xpd->xbus, the_xpd, 1, 1);
+ if(the_xbus)
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, the_xbus, NULL, 1, 1);
}
/*
* Change sync_master. May block. Cannot be called from atomic context
*/
-void sync_master_is(xpd_t *xpd)
+static void sync_master_is(xbus_t *xbus)
{
- DBG("SYNC MASTER CHANGED: %s => %s\n",
- (sync_master) ? sync_master->xpdname : "HOST",
- (xpd) ? xpd->xpdname : "HOST");
+ xpd_t *xpd = (xbus)? xpd_of(xbus, 0) : NULL;
+
+ if(xbus && !xpd) {
+ NOTICE("Cannot set sync master to %s (has no XPD #0).\n",
+ xbus->busname);
+ xbus = NULL; /* Fallback to HOST */
+ }
+ DBG("SYNC MASTER CHANGING: %s => %s\n",
+ (sync_master) ? sync_master->xbus->busname : "HOST",
+ (xbus) ? xbus->busname : "HOST");
/* First stop all generators */
if(sync_master) {
tasklet_kill(&tasklet_tick);
@@ -135,7 +158,7 @@ void sync_master_is(xpd_t *xpd)
/* Now set a new master */
sync_master = xpd;
if(sync_master) { // XPD
- external_sync(xpd);
+ external_sync(xbus);
} else { // HOST
external_sync(NULL);
if(!timer_pending(&xpp_timer)) {
@@ -290,21 +313,18 @@ void xpp_tick(unsigned long param)
xbus_t *xbus;
int i, j;
- if(!sync_master) { /* Called from timer */
-#if 0
- static int rate_limit = 0;
- if(rate_limit++ % 1000 == 0)
- DBG("FROM_TIMER\n");
+#ifdef ZAPTEL_SYNC_TICK
+ do_gettimeofday (&ticked_xpp);
#endif
+ if(!sync_master) /* Called from timer */
mod_timer(&xpp_timer, jiffies + 1); /* Must be 1KHz rate */
- } else
+ else
atomic_dec(&missed_ticks);
/* Statistics */
if((xpp_timer_count % SAMPLE_TICKS) == 0) {
xpp_last_jiffies = jiffies;
}
xpp_timer_count++;
-
for(i = 0; i < MAX_BUSES; i++) {
xbus = xbus_of(i);
if(!xbus)
@@ -343,8 +363,52 @@ void got_pcm_from(xpd_t *xpd)
tasklet_schedule(&tasklet_tick);
}
+#ifdef ZAPTEL_SYNC_TICK
+static void sync_status_clear(void)
+{
+ struct timeval now;
+
+ do_gettimeofday (&now);
+ usec_sigma = 0;
+ status_cleared_at = now.tv_sec;
+}
+
+int zaptel_sync_tick(struct zt_span *span, int is_master)
+{
+ xpd_t *xpd = span->pvt;
+
+ if(!sync_tick_active) {
+ zaptel_is_ticking = 0;
+ usec_sigma = 0;
+ return 0; /* No auto sync from zaptel */
+ }
+ BUG_ON(!xpd);
+ /*
+ * Calculate only if:
+ * - Called for the sync_master
+ * - HOST sync (for information only)
+ */
+ if(sync_master && xpd != sync_master)
+ return 0;
+ 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);
+ if(usec_lag_curr > ZAPTEL_BIG_LAG) {
+ if(printk_ratelimit())
+ NOTICE("Big lag of Xpp ticks relative to zaptel ticks: %ld\n", usec_lag_curr);
+ }
+ usec_delta = usec_lag_curr - usec_lag_prev;
+ usec_sigma += usec_delta;
+ zaptel_is_ticking = 1;
+ since_status_clear = ticked_zaptel.tv_sec - status_cleared_at;
+ usec_lag_prev = usec_lag_curr;
+ return 0;
+}
+#endif
+
#if HZ != 1000
-#warning "xpp_timer must be sampled EXACTLY 1000/per second"
+#warning "HZ != 1000. PCM would be good only with Astribank sync"
#endif
static void xpd_free(xpd_t *xpd)
@@ -467,6 +531,7 @@ void card_detected(struct card_desc_struct *card_desc)
goto err;
}
xpd->addr = card_desc->xpd_addr;
+ xpd->offhook = card_desc->line_status;
/* For USB-1 disable some channels */
if(xbus->max_packet_size < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
@@ -580,14 +645,6 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->cid_on, i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "lasttxhook");
- for_each_line(xpd, i) {
- len += sprintf(page + len, "%d ", xpd->lasttxhook[i]);
- }
- len += sprintf(page + len, "\n\t%-17s: ", "idletxhookstate");
- for_each_line(xpd, i) {
- len += sprintf(page + len, "%d ", xpd->idletxhookstate[i]);
- }
len += sprintf(page + len, "\n\t%-17s: ", "ringing");
for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", xpd->ringing[i]);
@@ -671,7 +728,6 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
{
xpd_t *xpd = NULL;
size_t alloc_size = sizeof(xpd_t) + privsize;
- int i;
DBG("%s: xpd #%d\n", xbus->busname, xpd_num);
if(!VALID_XPD_NUM(xpd_num)) {
@@ -704,10 +760,6 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
xpd->digital_outputs = 0;
xpd->digital_inputs = 0;
- for_each_line(xpd, i) {
- xpd->idletxhookstate[i] = FXS_LINE_ENABLED; /* By default, don't send on hook */
- }
-
atomic_set(&xpd->zt_registered, 0);
atomic_set(&xpd->open_counter, 0);
@@ -824,6 +876,8 @@ void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
* it may call back into our xpp_hooksig() and cause
* a nested spinlock scenario
*/
+ DBG("%s/%s/%d: rxsig=%s\n", xpd->xbus->busname, xpd->xpdname, pos,
+ (rxsig == ZT_RXSIG_ONHOOK) ? "ONHOOK" : "OFFHOOK");
if(SPAN_REGISTERED(xpd))
zt_hooksig(&xpd->chans[pos], rxsig);
}
@@ -859,13 +913,32 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
len += sprintf(page + len, "# To modify sync source write into this file:\n");
len += sprintf(page + len, "# HOST - For host based sync\n");
- len += sprintf(page + len, "# 0 0 - XBUS-0/XPD-0 provide sync\n");
- len += sprintf(page + len, "# m n - XBUS-m/XPD-n provide sync\n");
+ len += sprintf(page + len, "# SYNC=nn - XBUS-nn provide sync\n");
+#ifdef ZAPTEL_SYNC_TICK
+ len += sprintf(page + len, "# CLS - Clear Statistics\n");
+#endif
+ len += sprintf(page + len, "# QUERY=nn - Query XBUS-nn for sync information (DEBUG)\n");
if(!sync_master)
len += sprintf(page + len, "HOST\n");
else
- len += sprintf(page + len, "%s/%s\n", sync_master->xbus->busname, sync_master->xpdname);
- len += sprintf(page + len, "tick: #%d\n", xpp_timer_count);
+ len += sprintf(page + len, "SYNC=%02d\n", sync_master->xbus->num);
+#ifdef ZAPTEL_SYNC_TICK
+ if(sync_tick_active) {
+ len += sprintf(page + len, "\nZaptel Reference Sync:\n");
+ if(zaptel_is_ticking) {
+ len += sprintf(page + len, "\t%-19s: %5ld (usec)\n",
+ "current lag", usec_lag_curr);
+ len += sprintf(page + len, "\t%-19s: %5ld (usec)\n",
+ "delta lag", usec_delta);
+ len += sprintf(page + len, "\t%-19s: %5ld (usec)\n",
+ "sigma of deltas", usec_sigma);
+ len += sprintf(page + len, "\t%-19s: %5ld seconds ago\n",
+ "status cleared", since_status_clear);
+ } else
+ len += sprintf(page + len, "\tNot activated\n");
+ }
+#endif
+ len += sprintf(page + len, "\ntick: #%d\n", xpp_timer_count);
xpp_timer_rate = 0;
now = jiffies;
if(now - xpp_last_jiffies > 0) {
@@ -892,9 +965,6 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
int xbus_num;
int xpd_num;
xbus_t *xbus;
- xpd_t *xpd;
- int ret;
- int setit;
// DBG("%s: count=%ld\n", __FUNCTION__, count);
if(count >= MAX_PROC_WRITE)
@@ -904,39 +974,40 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
buf[count] = '\0';
if(strncmp("HOST", buf, 4) == 0) {
sync_master_is(NULL);
- goto out;
- }
- ret = sscanf(buf, "%d %d %d", &xbus_num, &xpd_num, &setit);
- if(ret == 2) {
- // For backward compatibility: before query was introduced,
- // only two parameters were possible
- setit = 1;
- ret = 3;
- }
- if(ret != 3 || (setit != 0 && setit != 1)) {
- ERR("Bad format for SYNC.\n");
- ERR("Usage: <bus_num> <xpd_num> <0/1> # 0 - QUERY, 1 - SET\n");
- return -EINVAL;
- }
- if(xbus_num >= MAX_BUSES) {
- ERR("Invalid xbus number %d\n", xbus_num);
- return -EINVAL;
- }
- xbus = xbus_of(xbus_num);
- if(!xbus) {
- ERR("No bus %d exists\n", xbus_num);
- return -EINVAL;
- }
- xpd = xpd_of(xbus, xpd_num);
- if(!xpd) {
- ERR("%s: XPD number %d does not exist\n", __FUNCTION__, xpd_num);
- return -ENXIO;
- }
- DBG("%s: %d/%d %s\n", __FUNCTION__, xbus_num, xpd_num, (setit)?"SET":"QUERY");
- if(setit) {
- sync_master_is(xpd);
+#ifdef ZAPTEL_SYNC_TICK
+ } else if(strncmp("CLS", buf, 3) == 0) {
+ sync_status_clear();
+#endif
+ } else if(sscanf(buf, "SYNC=%d", &xbus_num) == 1) {
+ DBG("SYNC=%d\n", xbus_num);
+ if((xbus = xbus_of(xbus_num)) == NULL) {
+ ERR("No bus %d exists\n", xbus_num);
+ return -ENXIO;
+ }
+ sync_master_is(xbus);
+ } else if(sscanf(buf, "QUERY=%d", &xbus_num) == 1) {
+ DBG("QUERY=%d\n", xbus_num);
+ if((xbus = xbus_of(xbus_num)) == NULL) {
+ ERR("No bus %d exists\n", xbus_num);
+ return -ENXIO;
+ }
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, 0, 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);
+ if(xpd_num != 0) {
+ ERR("Currently can only set sync for XPD #0\n");
+ return -EINVAL;
+ }
+ if((xbus = xbus_of(xbus_num)) == NULL) {
+ ERR("No bus %d exists\n", xbus_num);
+ return -ENXIO;
+ }
+ sync_master_is(xbus);
+ } else {
+ ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf);
+ count = -EINVAL;
}
-out:
return count;
}
@@ -1291,6 +1362,8 @@ int xpp_open(struct zt_chan *chan)
BIT_SET(xpd->offhook, pos);
DBG("chan=%d (open_counter=%d)\n", pos, xbus->open_counter);
spin_unlock_irqrestore(&xbus->lock, flags);
+ if(xpd->xops->card_open)
+ xpd->xops->card_open(xpd, pos);
return 0;
}
@@ -1305,21 +1378,13 @@ int xpp_close(struct zt_chan *chan)
spin_lock_irqsave(&xbus->lock, flags);
xbus->open_counter--;
atomic_dec(&xpd->open_counter);
- if(xpd->direction == TO_PHONE) { /* Hangup phone */
- xpd->idletxhookstate[pos] = FXS_LINE_ENABLED;
- }
if (!xbus->hardware_exists && xbus->open_counter == 0)
should_remove = 1;
if(IS_SET(xpd->digital_signalling, pos)) /* D-chan onhook */
BIT_CLR(xpd->offhook, pos);
spin_unlock_irqrestore(&xbus->lock, flags);
-#ifdef CONFIG_ZAPATA_BRI_DCHANS
- /* Clear D-Channel pending data */
- chan->bytes2receive = 0;
- chan->eofrx = 0;
- chan->bytes2transmit = 0;
- chan->eoftx = 0;
-#endif
+ if(xpd->xops->card_close)
+ xpd->xops->card_close(xpd, pos);
DBG("chan=%d (open_counter=%d, should_remove=%d)\n", pos, xbus->open_counter, should_remove);
if(should_remove) {
DBG("Going to remove: %s\n", xbus->busname);
@@ -1536,6 +1601,9 @@ static int zaptel_unregister_xpd(xpd_t *xpd)
xpd->xops->card_zaptel_preregistration(xpd, 0);
atomic_dec(&xpd->zt_registered);
zt_unregister(&xpd->span);
+#ifdef ZAPTEL_SYNC_TICK
+ zaptel_is_ticking = 0;
+#endif
if(xpd->card_present)
xpd->xops->card_zaptel_postregistration(xpd, 0);
return 0;
@@ -1580,6 +1648,9 @@ static int zaptel_register_xpd(xpd_t *xpd)
span->hooksig = xpp_hooksig; /* Only with RBS bits */
span->ioctl = xpp_ioctl;
span->maint = xpp_maint;
+#ifdef ZAPTEL_SYNC_TICK
+ span->sync_tick = zaptel_sync_tick;
+#endif
if (xpp_ec)
span->echocan = xpp_echocan;
#ifdef CONFIG_ZAPTEL_WATCHDOG
@@ -1658,18 +1729,23 @@ int __init xpp_zap_init(void)
INFO("%s revision %s MAX_XPDS=%d (%d*%d)\n", THIS_MODULE->name, XPP_VERSION,
MAX_XPDS, MAX_UNIT, MAX_SUBUNIT);
#if WITH_ECHO_SUPPRESSION
- INFO("FEATURE: %s (with ECHO_SUPPRESSION)\n", THIS_MODULE->name);
+ INFO("FEATURE: %s with ECHO_SUPPRESSION\n", THIS_MODULE->name);
#else
- INFO("FEATURE: %s (without ECHO_SUPPRESSION)\n", THIS_MODULE->name);
+ INFO("FEATURE: %s without ECHO_SUPPRESSION\n", THIS_MODULE->name);
#endif
if (xpp_ec)
- INFO("FEATURE: %s (with XPP_EC_CHUNK)\n", THIS_MODULE->name);
+ INFO("FEATURE: %s with XPP_EC_CHUNK\n", THIS_MODULE->name);
else
- INFO("FEATURE: %s (without XPP_EC_CHUNK)\n", THIS_MODULE->name);
+ INFO("FEATURE: %s without XPP_EC_CHUNK\n", THIS_MODULE->name);
#ifdef CONFIG_ZAPATA_BRI_DCHANS
- INFO("FEATURE: %s (with BRISTUFF support)\n", THIS_MODULE->name);
+ INFO("FEATURE: %s with BRISTUFF support\n", THIS_MODULE->name);
+#else
+ INFO("FEATURE: %s without BRISTUFF support\n", THIS_MODULE->name);
+#endif
+#ifdef ZAPTEL_SYNC_TICK
+ INFO("FEATURE: %s with sync_tick() from ZAPTEL\n", THIS_MODULE->name);
#else
- INFO("FEATURE: %s (without BRISTUFF support)\n", THIS_MODULE->name);
+ INFO("FEATURE: %s without sync_tick() from ZAPTEL\n", THIS_MODULE->name);
#endif
#ifdef CONFIG_PROC_FS
@@ -1697,6 +1773,9 @@ int __init xpp_zap_init(void)
/* Only timer init. We add it only *after* zt_register */
init_timer(&xpp_timer);
sync_master_is(NULL); /* Internal ticking */
+#ifdef ZAPTEL_SYNC_TICK
+ sync_status_clear();
+#endif
return 0;
err:
do_cleanup();