From 3b3d8f7b1186f672e16cd7e4ded2f405ec43cb1c Mon Sep 17 00:00:00 2001 From: tzafrir Date: Thu, 6 Mar 2008 22:54:16 +0000 Subject: xpp.r5512: * Build: - Zaptel >= 1.4.9 is migrating to storing kernel stuff in zaptel/kernel/* - We conditionally use old/new directory scheme: In xpp/Kbuild and xpp/utils/Makefile use ZAP_KERNEL variable, so it's not confused with ZAPTEL_DIR (which appears in zaptel/Makefile as well). - Fix compile warnings on 64 bit systems. - Compile fixes for kernel-2.6.24 * UDEV: - /etc/udev/rules.d/xpp.rules now uses XPP_INIT_DIR to find astribank_hook. - astribank_hook: Modify to do nothing. Add some documentation. * Autoconfiguration -- zapconf: - Don't fail zapconf et.al. if no config file was found. - Skip the 'IRQ Missing:' line in /proc/zaptel/nnn for wcte1xp(?). - Add some newer Digium cards to our hardware inventory. - Partially handle cases where the /proc/zaptel strings does not contain info about E1/T1/J1 or NT/TE. * Better SYNC: - Finer tuning of PLL (New firmware). - Change calculation algorithm of sync offset. It now copes better with the variance in USB frame reception timing. - Statistics: . The view of results was moved from /proc/xpp/XBUS-*/summary to a new /sys/bus/astribanks/devices/xbus-*/timing and enhanced. . A new xpp_timing script shows all astribanks. . A new write only /sys/bus/astribanks/devices/xbus-*/cls is used to clear statistics. Eventually, clearing of XBUS related statistics should be done here. One that was migrated is the clearing of 'PCM [TR]X:' numbers currently appearing in /proc/xpp/XBUS-*/summary (they should be moved too later). - Shorten the strings representation sync_mode ("SYNC_MODE_AB" -> "AB") adapted their use in printk and /proc so the text is clear. - Added a command line parameter xpp.disable_pll_sync to stop all adjustments command to AB (calculations still continue as usual). * PRI: - 4 port support - set clocking master span via ztcfg, like other zaptel devices. * FXO: - Fix false hangups in some countries (voltage fluctuations). - Some countries send caller-id before first ring. Added code to handle caller-id PCM pass through according to a new command line parameter (xpd_fxo.caller_id_style). - No longer sends an event on zt_open. See #12160 . * Misc: - Adapt to zaptel-1.4.8 and above ztscan: added fields returend by new ZT_SPANSTAT_V2 ioctl() - Document sysfs and waitfor_xpds. - Miscelaneous optimizations and bugfixes. - Remove deprecated pcm_tasklet parameter. The rx_tasklet parameter has replaced it a long time ago. - Add RX_CMD counter to /proc/xpp/XBUS-*/summary - Unclutter some of the usb disconnect messages. - xpp_usb: minor preformance improvements in receive. Expose the number of pending receive URB's in /proc/xpp/XBUS-*/xpp_usb git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@3952 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- xpp/card_pri.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 136 insertions(+), 13 deletions(-) (limited to 'xpp/card_pri.c') diff --git a/xpp/card_pri.c b/xpp/card_pri.c index e055953..eeabb25 100644 --- a/xpp/card_pri.c +++ b/xpp/card_pri.c @@ -38,10 +38,6 @@ static const char rcsid[] = "$Id$"; DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */ DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)"); -#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 #define PRI_LINES_BITMASK BITMASK(31) #define PRI_DCHAN_SIGCAP ( \ @@ -57,6 +53,7 @@ DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value"); ZT_SIG_SF \ ) #define PRI_BCHAN_SIGCAP ZT_SIG_CLEAR +#define MAX_SLAVES 4 /* we have MUX of 4 clocks */ /*---------------- PRI Protocol Commands ----------------------------------*/ @@ -85,7 +82,7 @@ enum pri_protocol { static const char *pri_protocol_name(enum pri_protocol pri_protocol) { static const char *protocol_names[] = { - [PRI_PROTO_0] = "Unknown", + [PRI_PROTO_0] = "??", /* unkown */ [PRI_PROTO_E1] = "E1", [PRI_PROTO_T1] = "T1", [PRI_PROTO_J1] = "J1" @@ -237,9 +234,14 @@ struct pri_leds { #define REG_RC0 0x24 #define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */ +#define REG_CMR1 0x44 +#define REG_CMR1_DRSS (BIT(7) | BIT(6)) +#define REG_CMR1_RS (BIT(5) | BIT(4)) +#define REG_CMR1_STF BIT(2) struct PRI_priv_data { bool is_nt; + bool clock_source; struct proc_dir_entry *regfile; struct proc_dir_entry *pri_info; enum pri_protocol pri_protocol; @@ -254,6 +256,7 @@ struct PRI_priv_data { byte reg_frs0; byte reg_frs1; bool layer1_up; + int alarms; byte dchan_tx_sample; byte dchan_rx_sample; uint dchan_tx_counter; @@ -312,6 +315,22 @@ static int write_subunit(xpd_t *xpd, byte regnum, byte val) 0); /* data_H */ } +static int pri_write_reg(xpd_t *xpd, int regnum, byte val) +{ + XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X dataL=0x%02X\n", + xpd->addr.unit, xpd->addr.subunit, + regnum, val); + return xpp_register_request( + xpd->xbus, xpd, + 0, /* chipsel */ + 1, /* writing */ + 0, /* do_subreg */ + regnum, + 0, /* subreg */ + val, /* data_L */ + 0); /* data_H */ +} + static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision) { xpd_t *xpd = NULL; @@ -434,6 +453,98 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) return 0; } +static void zap_update_syncsrc(xpd_t *xpd) +{ + struct PRI_priv_data *priv; + xpd_t *subxpd; + int best_spanno = 0; + int i; + + if(!SPAN_REGISTERED(xpd)) + return; + for(i = 0; i < MAX_SLAVES; i++) { + subxpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, i); + if(!subxpd) + continue; + priv = subxpd->priv; + if(priv->clock_source) { + if(best_spanno) + XPD_ERR(xpd, "Duplicate XPD's with clock_source=1\n"); + best_spanno = subxpd->span.spanno; + } + } + for(i = 0; i < MAX_SLAVES; i++) { + subxpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, i); + if(!subxpd) + continue; + if(subxpd->span.syncsrc == best_spanno) + XPD_DBG(SYNC, xpd, "Setting SyncSource to span %d\n", best_spanno); + else + XPD_DBG(SYNC, xpd, "Slaving to span %d\n", best_spanno); + subxpd->span.syncsrc = best_spanno; + } +} + +/* + * Called from: + * - set_master_mode() -- + * As a result of ztcfg or writing to /proc/xpp/XBUS-??/XPD-/??/pri_info + * - layer1_state() -- + * As a result of an alarm. + */ +static void set_clocking(xpd_t *xpd) +{ + xbus_t *xbus; + xpd_t *best_xpd = NULL; + int best_subunit = -1; /* invalid */ + int best_subunit_prio = 0; + int i; + + xbus = get_xbus(xpd->xbus->num); + /* Find subunit with best timing priority */ + for(i = 0; i < MAX_SLAVES; i++) { + struct PRI_priv_data *priv; + xpd_t *subxpd; + + subxpd = xpd_byaddr(xbus, xpd->addr.unit, i); + if(!subxpd) + continue; + priv = subxpd->priv; + if(priv->alarms != 0) + continue; + if(subxpd->timing_priority > best_subunit_prio) { + best_xpd = subxpd; + best_subunit = i; + best_subunit_prio = subxpd->timing_priority; + } + } + /* Now set it */ + if(best_xpd && ((struct PRI_priv_data *)(best_xpd->priv))->clock_source == 0) { + byte cmr1_val = + REG_CMR1_RS | + REG_CMR1_STF | + (REG_CMR1_DRSS & (best_subunit << 6)); + XPD_DBG(SYNC, best_xpd, + "ClockSource Set: cmr1=0x%02X\n", cmr1_val); + pri_write_reg(xpd, REG_CMR1, cmr1_val); + ((struct PRI_priv_data *)(best_xpd->priv))->clock_source = 1; + } + /* clear old clock sources */ + for(i = 0; i < MAX_SLAVES; i++) { + struct PRI_priv_data *priv; + xpd_t *subxpd; + + subxpd = xpd_byaddr(xbus, xpd->addr.unit, i); + if(subxpd && subxpd != best_xpd) { + XPD_DBG(SYNC, subxpd, "Clearing clock source\n"); + priv = subxpd->priv; + priv->clock_source = 0; + } + } + zap_update_syncsrc(xpd); + put_xbus(xbus); +} + /* * Normally set by the timing parameter in zaptel.conf * If this is called by ztcfg, than it's too late to change @@ -443,11 +554,12 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) * 2. And we try to call it with a sane default from set_nt() * which is called before zaptel registration. */ -static int set_master_mode(const char *msg, xpd_t *xpd, bool is_master_mode) +static int set_master_mode(const char *msg, xpd_t *xpd) { struct PRI_priv_data *priv; byte lim0 = 0; byte xsp = 0; + bool is_master_mode = xpd->timing_priority == 0; BUG_ON(!xpd); priv = xpd->priv; @@ -467,6 +579,7 @@ static int set_master_mode(const char *msg, xpd_t *xpd, bool is_master_mode) XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, (is_master_mode) ? "MASTER" : "SLAVE"); write_subunit(xpd, REG_LIM0 , lim0); write_subunit(xpd, REG_XSP_E, xsp); + set_clocking(xpd); return 0; } @@ -485,7 +598,9 @@ static int set_nt(const char *msg, xpd_t *xpd, bool is_nt) xpd->type_name = type_name(priv->pri_protocol, is_nt); xpd->direction = (is_nt) ? TO_PHONE : TO_PSTN; XPD_DBG(SIGNAL, xpd, "%s(%s): %s %s\n", __FUNCTION__, msg, xpd->type_name, (is_nt) ? "NT" : "TE"); - set_master_mode(msg, xpd, is_nt); /* by default set master-mode from NT/TE */ + if(xpd->timing_priority == 0 && !is_nt) /* by default set timing priority from NT/TE */ + xpd->timing_priority = 1; + set_master_mode(msg, xpd); return 0; } @@ -575,7 +690,7 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) } else { /* we got real garbage */ XPD_ERR(xpd, - "Unknown config item 0x%X for %s. Ignore\n", + "Unknown config item 0x%lX for %s. Ignore\n", BIT(i), pri_protocol_name(priv->pri_protocol)); } @@ -651,7 +766,7 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) write_subunit(xpd, REG_FMR4, fmr4); XPD_DBG(GENERAL, xpd, "%s: fmr2(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR2, fmr2); write_subunit(xpd, REG_FMR2, fmr2); - set_master_mode("spanconfig", xpd, xpd->timing_priority == 0); + set_master_mode("spanconfig", xpd); elect_syncer("PRI-master_mode"); return 0; bad_lineconfig: @@ -768,6 +883,9 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on) /* Nothing to do yet */ return 0; } +#ifdef ZT_SPANSTAT_V2 + xpd->span.spantype = pri_protocol_name(priv->pri_protocol); +#endif xpd->span.linecompat = pri_linecompat(priv->pri_protocol); xpd->span.deflaw = priv->deflaw; for_each_line(xpd, i) { @@ -805,6 +923,7 @@ static int PRI_card_zaptel_postregistration(xpd_t *xpd, bool on) priv = xpd->priv; BUG_ON(!xbus); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); + zap_update_syncsrc(xpd); return(0); } @@ -829,12 +948,14 @@ static void dchan_state(xpd_t *xpd, bool up) XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel RUNNING\n"); priv->dchan_alive = 1; } else { - byte *pcm; + int d = PRI_DCHAN_IDX(priv); + + if(SPAN_REGISTERED(xpd) && d >= 0 && d < xpd->channels) { + byte *pcm; - if(SPAN_REGISTERED(xpd)) { - pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].readchunk; + pcm = (byte *)xpd->span.chans[d].readchunk; pcm[0] = 0x00; - pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].writechunk; + pcm = (byte *)xpd->span.chans[d].writechunk; pcm[0] = 0x00; } XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); @@ -1211,6 +1332,7 @@ static void layer1_state(xpd_t *xpd, byte subunit, byte data_low) if(data_low & REG_FRS0_RRA) alarms |= ZT_ALARM_YELLOW; priv->layer1_up = alarms == 0; + priv->alarms = alarms; if(!priv->layer1_up) dchan_state(xpd, 0); if(SPAN_REGISTERED(xpd) && xpd->span.alarms != alarms) { @@ -1224,6 +1346,7 @@ static void layer1_state(xpd_t *xpd, byte subunit, byte data_low) alarms, str2); xpd->span.alarms = alarms; zt_alarm_notify(&xpd->span); + set_clocking(xpd); } priv->reg_frs0 = data_low; priv->layer1_replies++; -- cgit v1.2.3