diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-27 06:14:18 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-27 06:14:18 +0000 |
commit | 75a1b90515aa90729ba32cb9698a6db53e19cdd4 (patch) | |
tree | 2fbd3fc7760e0326d61150659f619446b4b71e48 /xpp/xpp_zap.c | |
parent | d2bc5edd30ddb4258feca767eb6cd5d2bc96ad30 (diff) |
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 ;-) .
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@2239 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r-- | xpp/xpp_zap.c | 263 |
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(); |