summaryrefslogtreecommitdiff
path: root/xpp/card_pri.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-03-06 22:54:16 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-03-06 22:54:16 +0000
commit3b3d8f7b1186f672e16cd7e4ded2f405ec43cb1c (patch)
tree5e592d92e3030b4eb28cab7585f769dbbeab2d74 /xpp/card_pri.c
parent07b404b68141bc981adbc1f5a00cbe90116fb9c1 (diff)
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
Diffstat (limited to 'xpp/card_pri.c')
-rw-r--r--xpp/card_pri.c149
1 files changed, 136 insertions, 13 deletions
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++;