summaryrefslogtreecommitdiff
path: root/xpp/card_pri.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-12-18 14:31:07 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-12-18 14:31:07 +0000
commitcfd61537b47387b0fb5c8228baad6cec16d8f6e6 (patch)
tree108deea65c09c7c273a9b981f8783efcd433eaea /xpp/card_pri.c
parent4391b4a6ee42bdfd8e097c5ee5485e9eb13f19a0 (diff)
xpp r5151:
* xpd_pri: Basically ready. * PCM synchronization changes: - Each Astribank unit ticks independently. Each with its own PLL. - HOST synchronization is gone. Loading of xpp will no longer cause useless 250 ticks per second if you have no Astribank. - Synchronization from the zaptel sync master requires setting ZAPTEL as sync source (xpp_sync ZAPTEL). * rx_tasklet is now a parameter of the module xpp, rather than of xpp_usb. * New FPGA firmware: 5128 (1151) / 5122 (1141, 1131): - Fixes synchronization issues. - PRI module: E1 should now work. * perl module and utilities: - Modules no longer magically scan system on initialization. - Scanning is by calling explicit methods. - "Serial" has been renamed "Label". It is basically unique, but should be modifieble. - Some basic documentation of zaptel perl modules. * Default sort order of zt_registration is back to SORT_CONNCTOR. * zt_registration proc file now shows the number of span registered to if registered. Try: grep . /proc/xpp/XBUS-*/XPD-*/zt_registration * genzaptelconf: Allow using a custom command instead of /etc/init.d/asterisk to start/stop asterisk. * Fixed the typo "Slagish". git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@3506 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_pri.c')
-rw-r--r--xpp/card_pri.c452
1 files changed, 347 insertions, 105 deletions
diff --git a/xpp/card_pri.c b/xpp/card_pri.c
index 1535cc2..483fc47 100644
--- a/xpp/card_pri.c
+++ b/xpp/card_pri.c
@@ -44,7 +44,6 @@ DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value");
#endif
#define PRI_LINES_BITMASK BITMASK(31)
-#define PRI_DCHAN_NUM 16
#define PRI_DCHAN_SIGCAP ( \
ZT_SIG_EM | \
ZT_SIG_CLEAR | \
@@ -82,13 +81,75 @@ enum pri_protocol {
PRI_PROTO_T1 = 2,
PRI_PROTO_J1 = 3
};
-static const char *pri_protocol_name[] = {
- [PRI_PROTO_0] = "Unknown",
- [PRI_PROTO_E1] = "E1",
- [PRI_PROTO_T1] = "T1",
- [PRI_PROTO_J1] = "J1"
+
+static const char *pri_protocol_name(enum pri_protocol pri_protocol)
+{
+ static const char *protocol_names[] = {
+ [PRI_PROTO_0] = "Unknown",
+ [PRI_PROTO_E1] = "E1",
+ [PRI_PROTO_T1] = "T1",
+ [PRI_PROTO_J1] = "J1"
+ };
+ return protocol_names[pri_protocol];
+}
+
+static int pri_num_channels(enum pri_protocol pri_protocol)
+{
+ static int num_channels[] = {
+ [PRI_PROTO_0] = 0,
+ [PRI_PROTO_E1] = 31,
+ [PRI_PROTO_T1] = 24,
+ [PRI_PROTO_J1] = 0
+ };
+ return num_channels[pri_protocol];
+}
+
+static const char *type_name(enum pri_protocol pri_protocol, bool is_nt)
+{
+ static const char *names[2][4] = {
+ /* TE */ [0] = {
+ [PRI_PROTO_0] = "Unknown_TE",
+ [PRI_PROTO_E1] = "E1_TE",
+ [PRI_PROTO_T1] = "T1_TE",
+ [PRI_PROTO_J1] = "J1_TE"
+ },
+ /* NT */ [1] = {
+ [PRI_PROTO_0] = "Unknown_NT",
+ [PRI_PROTO_E1] = "E1_NT",
+ [PRI_PROTO_T1] = "T1_NT",
+ [PRI_PROTO_J1] = "J1_NT"
+ }
+ };
+ int term = (is_nt) ? 1 : 0;
+
+ return names[term][pri_protocol];
+}
+
+static int pri_linecompat(enum pri_protocol pri_protocol)
+{
+ static const int linecompat[] = {
+ [PRI_PROTO_0] = 0,
+ [PRI_PROTO_E1] =
+ /* coding */
+ ZT_CONFIG_CCS |
+ // CAS |
+ /* framing */
+ ZT_CONFIG_AMI | ZT_CONFIG_HDB3,
+ [PRI_PROTO_T1] =
+ /* coding */
+ // ZT_CONFIG_D4 |
+ ZT_CONFIG_ESF |
+ /* framing */
+ ZT_CONFIG_AMI | ZT_CONFIG_B8ZS,
+ [PRI_PROTO_J1] = 0
};
+ DBG(GENERAL, "pri_linecompat: pri_protocol=%d\n", pri_protocol);
+ return linecompat[pri_protocol];
+}
+
+#define PRI_DCHAN_IDX(priv) ((priv)->dchan_num - 1)
+
enum pri_led_state {
PRI_LED_OFF = 0x0,
PRI_LED_ON = 0x1,
@@ -133,6 +194,10 @@ struct pri_leds {
#define REG_LIM0_LL BIT(1) /* LL (Local Loopback) */
#define REG_FMR0 0x1C
+#define REG_FMR0_E_RC0 BIT(4) /* Receive Code - LSB */
+#define REG_FMR0_E_RC1 BIT(5) /* Receive Code - MSB */
+#define REG_FMR0_E_XC0 BIT(6) /* Transmit Code - LSB */
+#define REG_FMR0_E_XC1 BIT(7) /* Transmit Code - MSB */
#define REG_FMR1 0x1D
#define REG_FMR1_XAIS BIT(0) /* Transmit AIS toward transmit end */
@@ -140,22 +205,35 @@ struct pri_leds {
#define REG_FMR1_ECM BIT(2)
#define REG_FMR1_XFS BIT(3)
#define REG_FMR1_PMOD BIT(4) /* E1 = 0, T1/J1 = 1 */
+#define REG_FMR1_EDL BIT(5)
#define REG_FMR1_AFR BIT(6)
#define REG_FMR2 0x1E
+#define REG_FMR2_E_ALMF BIT(0) /* Automatic Loss of Multiframe */
+#define REG_FMR2_T_EXZE BIT(0) /* Excessive Zeros Detection Enable */
+#define REG_FMR2_E_AXRA BIT(1) /* Automatic Transmit Remote Alarm */
+#define REG_FMR2_T_AXRA BIT(1) /* Automatic Transmit Remote Alarm */
+#define REG_FMR2_E_PLB BIT(2) /* Payload Loop-Back */
+#define REG_FMR2_E_RFS0 BIT(6) /* Receive Framing Select - LSB */
+#define REG_FMR2_E_RFS1 BIT(7) /* Receive Framing Select - MSB */
+#define REG_FMR2_T_SSP BIT(5) /* Select Synchronization/Resynchronization Procedure */
+#define REG_FMR2_T_MCSP BIT(6) /* Multiple Candidates Synchronization Procedure */
+#define REG_FMR2_T_AFRS BIT(7) /* Automatic Force Resynchronization */
+
+#define REG_FMR4 0x20
+#define REG_FMR4_FM1 BIT(1)
#define REG_RC0 0x24
#define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */
-static const char pri_name_nt[] = "PRI_NT";
-static const char pri_name_te[] = "PRI_TE";
-
struct PRI_priv_data {
bool is_nt;
struct proc_dir_entry *regfile;
struct proc_dir_entry *pri_info;
enum pri_protocol pri_protocol;
+ int deflaw;
+ unsigned int dchan_num;
bool initialized;
bool local_loopback;
reg_cmd_t requested_reply;
@@ -227,7 +305,7 @@ static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
{
xpd_t *xpd = NULL;
struct PRI_priv_data *priv;
- int channels = min(31, CHANNELS_PERXPD);
+ int channels = min(31, CHANNELS_PERXPD); /* worst case */
XBUS_DBG(GENERAL, xbus, "\n");
xpd = xpd_alloc(sizeof(struct PRI_priv_data), proto_table, channels);
@@ -235,7 +313,10 @@ static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
return NULL;
priv = xpd->priv;
xpd->revision = revision;
- xpd->type_name = proto_table->name; /* Default, changes in set_nt() */
+ priv->pri_protocol = PRI_PROTO_0; /* Default, changes in set_pri_proto() */
+ priv->deflaw = ZT_LAW_DEFAULT; /* Default, changes in set_pri_proto() */
+ xpd->type_name =
+ type_name(priv->pri_protocol, 0); /* Default, changes in set_nt() */
return xpd;
}
@@ -278,9 +359,11 @@ static bool valid_pri_modes(const xpd_t *xpd)
* May only be called on unregistered xpd's
* (the span and channel description are set according to this)
*/
-static int set_pri_proto(const char *msg, xpd_t *xpd, enum pri_protocol set_proto)
+static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
{
struct PRI_priv_data *priv;
+ int deflaw;
+ unsigned int dchan_num;
byte fmr1 =
REG_FMR1_AFR |
REG_FMR1_XFS |
@@ -290,17 +373,26 @@ static int set_pri_proto(const char *msg, xpd_t *xpd, enum pri_protocol set_prot
BUG_ON(!xpd);
priv = xpd->priv;
if(SPAN_REGISTERED(xpd)) {
- XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n",
- xpd->span.spanno, __FUNCTION__, msg);
+ XPD_NOTICE(xpd, "Registered as span %d. Cannot do setup pri protocol (%s)\n",
+ xpd->span.spanno, __FUNCTION__);
return -EBUSY;
}
switch(set_proto) {
case PRI_PROTO_E1:
+ deflaw = ZT_LAW_ALAW;
+ dchan_num = 16;
break;
case PRI_PROTO_T1:
+ deflaw = ZT_LAW_MULAW;
+ dchan_num = 24;
fmr1 |= REG_FMR1_PMOD;
break;
case PRI_PROTO_J1:
+ /*
+ * Check all assumptions
+ */
+ deflaw = ZT_LAW_MULAW;
+ dchan_num = 24;
fmr1 |= REG_FMR1_PMOD;
rc0 |= REG_RC0_SJR;
XPD_NOTICE(xpd, "J1 is not supported yet\n");
@@ -311,7 +403,18 @@ static int set_pri_proto(const char *msg, xpd_t *xpd, enum pri_protocol set_prot
return -EINVAL;
}
priv->pri_protocol = set_proto;
- XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, pri_protocol_name[set_proto]);
+ xpd->channels = pri_num_channels(set_proto);
+ xpd->pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + xpd->channels * ZT_CHUNKSIZE;
+ xpd->wanted_pcm_mask = BITMASK(xpd->channels);
+ priv->deflaw = deflaw;
+ priv->dchan_num = dchan_num;
+ xpd->type_name = type_name(priv->pri_protocol, priv->is_nt);
+ XPD_DBG(GENERAL, xpd, "%s, channels=%d, dchan_num=%d, deflaw=%d\n",
+ pri_protocol_name(set_proto),
+ xpd->channels,
+ priv->dchan_num,
+ priv->deflaw
+ );
write_subunit(xpd, REG_FMR1, fmr1);
#ifdef JAPANEZE_SUPPORT
if(rc0)
@@ -358,9 +461,9 @@ static int set_nt(const char *msg, xpd_t *xpd, bool is_nt)
return -EBUSY;
}
priv->is_nt = is_nt;
- xpd->type_name = (is_nt) ? pri_name_nt : pri_name_te;
+ 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\n", __FUNCTION__, msg, (is_nt) ? "NT" : "TE");
+ 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 */
return 0;
}
@@ -388,9 +491,27 @@ static int set_localloop(const char *msg, xpd_t *xpd, bool localloop)
return 0;
}
+#define VALID_CONFIG(bit,flg,str) [bit] = { .flags = flg, .name = str }
+
+static const struct {
+ const char *name;
+ const int flags;
+} valid_spanconfigs[sizeof(unsigned int)*8] = {
+ /* These apply to T1 */
+// VALID_CONFIG(4, ZT_CONFIG_D4, "D4"), FIXME: should support
+ VALID_CONFIG(5, ZT_CONFIG_ESF, "ESF"),
+ VALID_CONFIG(6, ZT_CONFIG_AMI, "AMI"),
+ VALID_CONFIG(7, ZT_CONFIG_B8ZS, "B8ZS"),
+ /* These apply to E1 */
+ VALID_CONFIG(8, ZT_CONFIG_CCS, "CCS"),
+ VALID_CONFIG(9, ZT_CONFIG_HDB3, "HDB3"),
+ VALID_CONFIG(10, ZT_CONFIG_CRC4, "CRC4"),
+};
+
/*
* Called only for 'span' keyword in /etc/zaptel.conf
*/
+
static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
{
xpd_t *xpd = span->pvt;
@@ -398,12 +519,44 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
const char *framingstr = "";
const char *codingstr = "";
const char *crcstr = "";
- const byte FMR2_PLB = 0 << 2; /* PLB (Payload Loopback) */
- byte fmr0 = 0;
- byte fmr2 = 0x83 | FMR2_PLB; /* AFRS | AXRA | EXZE */
+ byte fmr0 = 0; /* Dummy initilizations to */
+ byte fmr2 = 0; /* silense false gcc warnings */
+ byte fmr4 = 0x0C;
+ unsigned int bad_bits;
+ int i;
BUG_ON(!xpd);
priv = xpd->priv;
+ /*
+ * validate
+ */
+ bad_bits = lc->lineconfig & pri_linecompat(priv->pri_protocol);
+ bad_bits = bad_bits ^ lc->lineconfig;
+ for(i = 0; i < ARRAY_SIZE(valid_spanconfigs); i++) {
+ unsigned int flags = valid_spanconfigs[i].flags;
+
+ if(bad_bits & BIT(i)) {
+ if(flags) {
+ XPD_ERR(xpd,
+ "Bad config item '%s' for %s. Ignore\n",
+ valid_spanconfigs[i].name,
+ pri_protocol_name(priv->pri_protocol));
+ } else {
+ /* we got real garbage */
+ XPD_ERR(xpd,
+ "Unknown config item 0x%X for %s. Ignore\n",
+ BIT(i),
+ pri_protocol_name(priv->pri_protocol));
+ }
+ }
+ if(flags && flags != BIT(i)) {
+ ERR("%s: BUG: i=%d flags=0x%X\n",
+ __FUNCTION__, i, flags);
+ // BUG();
+ }
+ }
+ if(bad_bits)
+ goto bad_lineconfig;
if(lc->span != xpd->span.spanno) {
XPD_ERR(xpd, "I am span %d but got spanconfig for span %d\n",
xpd->span.spanno, lc->span);
@@ -413,29 +566,43 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
* FIXME: lc->name is unused by ztcfg and zaptel...
* We currently ignore it also.
*/
+ if(priv->pri_protocol == PRI_PROTO_E1)
+ fmr2 = REG_FMR2_E_AXRA | REG_FMR2_E_ALMF; /* 0x03 */
+ else if(priv->pri_protocol == PRI_PROTO_T1)
+ fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */
+ else if(priv->pri_protocol == PRI_PROTO_J1) {
+ XPD_ERR(xpd, "J1 unsupported yet\n");
+ return -ENOSYS;
+ }
if(priv->local_loopback)
- fmr2 |= 0x4;
+ fmr2 |= REG_FMR2_E_PLB;
/* framing first */
- if (lc->lineconfig & ZT_CONFIG_B8ZS)
+ if (lc->lineconfig & ZT_CONFIG_B8ZS) {
framingstr = "B8ZS";
- else if (lc->lineconfig & ZT_CONFIG_AMI) {
+ fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0;
+ } else if (lc->lineconfig & ZT_CONFIG_AMI) {
framingstr = "AMI";
- fmr0 = 0xA0;
+ fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_RC1;
} else if (lc->lineconfig & ZT_CONFIG_HDB3) {
framingstr = "HDB3";
- fmr0 = 0xF0;
- fmr2 |= 0xc0; /* CRC4 receive */ /* FIXME: move bellow to condition on CRC4? */
+ fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0;
}
/* then coding */
- if (lc->lineconfig & ZT_CONFIG_ESF)
+ if (lc->lineconfig & ZT_CONFIG_ESF) {
codingstr = "ESF";
- else if (lc->lineconfig & ZT_CONFIG_D4)
+ fmr4 |= REG_FMR4_FM1;
+ fmr2 |= REG_FMR2_T_AXRA | REG_FMR2_T_MCSP | REG_FMR2_T_SSP;
+ } else if (lc->lineconfig & ZT_CONFIG_D4) {
codingstr = "D4";
- else if (lc->lineconfig & ZT_CONFIG_CCS)
+ } else if (lc->lineconfig & ZT_CONFIG_CCS) {
codingstr = "CCS";
+ /* do nothing */
+ }
/* E1's can enable CRC checking */
- if (lc->lineconfig & ZT_CONFIG_CRC4)
+ if (lc->lineconfig & ZT_CONFIG_CRC4) {
crcstr = "CRC4";
+ fmr2 |= REG_FMR2_E_RFS1;
+ }
XPD_DBG(GENERAL, xpd, "[%s] lbo=%d lineconfig=%s/%s/%s %s (0x%X) sync=%d\n",
(priv->is_nt)?"NT":"TE",
lc->lbo,
@@ -443,20 +610,22 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
(lc->lineconfig & ZT_CONFIG_NOTOPEN)?"YELLOW":"",
lc->lineconfig,
lc->sync);
- /*
- * FIXME: validate
- */
span->lineconfig = lc->lineconfig;
xpd->timing_priority = lc->sync;
if(fmr0 != 0) {
XPD_DBG(GENERAL, xpd, "%s: fmr0(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR0, fmr0);
write_subunit(xpd, REG_FMR0, fmr0);
}
+ XPD_DBG(GENERAL, xpd, "%s: fmr4(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR4, fmr4);
+ 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);
elect_syncer("PRI-master_mode");
return 0;
+bad_lineconfig:
+ XPD_ERR(xpd, "Bad span configuration. Abort\n");
+ return -EINVAL;
}
/*
@@ -485,12 +654,6 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
proto_table = &PROTO_TABLE(PRI);
priv = xpd->priv;
xpd->xops = &proto_table->xops;
- /*
- * wanted_pcm_mask and pcm_len: constant for PRI. All 31 channels
- */
- xpd->wanted_pcm_mask = PRI_LINES_BITMASK;
- xpd->pcm_len =
- RPACKET_HEADERSIZE + sizeof(xpp_line_t) + 31 * ZT_CHUNKSIZE;
#ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating PRI_INFO file\n");
priv->pri_info = create_proc_entry(PROC_PRI_INFO_FNAME, 0644, xpd->proc_xpd_dir);
@@ -515,6 +678,10 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
priv->regfile->read_proc = proc_xpd_register_read;
priv->regfile->data = xpd;
#endif
+ /* Assume E1, changes later from user space */
+ ret = set_pri_proto(xpd, PRI_PROTO_E1);
+ if(ret < 0)
+ goto err;
ret = run_initialize_registers(xpd);
if(ret < 0)
goto err;
@@ -526,16 +693,6 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
XPD_NOTICE(xpd, "PRI protocol not set\n");
goto err;
}
- /* FIXME: now we need to fix channel number (E1/T1/J1) */
-
-#if 1
-#else
- /*
- * FPGA firmware limitation:
- * Force HOST sync *before* sending PCM
- */
- CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_HOST, 0);
-#endif
XPD_DBG(GENERAL, xpd, "done\n");
for(ret = 0; ret < NUM_LEDS; ret++) {
DO_LED(xpd, ret, PRI_LED_ON);
@@ -571,16 +728,20 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on)
xbus = xpd->xbus;
priv = xpd->priv;
BUG_ON(!xbus);
- XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ XPD_DBG(GENERAL, xpd, "%s (proto=%s, channels=%d, deflaw=%d)\n",
+ (on)?"on":"off",
+ pri_protocol_name(priv->pri_protocol),
+ xpd->channels,
+ priv->deflaw);
if(!on) {
/* Nothing to do yet */
return 0;
}
- xpd->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_CCS;
- xpd->span.deflaw = ZT_LAW_ALAW;
+ xpd->span.linecompat = pri_linecompat(priv->pri_protocol);
+ xpd->span.deflaw = priv->deflaw;
for_each_line(xpd, i) {
struct zt_chan *cur_chan = &xpd->chans[i];
- bool is_dchan = i == PRI_DCHAN_NUM - 1;
+ bool is_dchan = i == PRI_DCHAN_IDX(priv);
XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i,
(is_dchan)?"DCHAN":"CLEAR");
@@ -595,7 +756,7 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on)
} else
cur_chan->sigcap = PRI_BCHAN_SIGCAP;
}
- xpd->offhook = PRI_LINES_BITMASK;
+ xpd->offhook = xpd->wanted_pcm_mask;
xpd->span.spanconfig = pri_spanconfig;
xpd->span.chanconfig = pri_chanconfig;
xpd->span.startup = pri_startup;
@@ -640,9 +801,9 @@ static void dchan_state(xpd_t *xpd, bool up)
byte *pcm;
if(SPAN_REGISTERED(xpd)) {
- pcm = (byte *)&xpd->readchunk[(PRI_DCHAN_NUM - 1) * ZT_CHUNKSIZE];
+ pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].readchunk;
pcm[0] = 0x00;
- pcm = (byte *)&xpd->span.chans[PRI_DCHAN_NUM - 1].writechunk;
+ pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].writechunk;
pcm[0] = 0x00;
}
XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n");
@@ -730,7 +891,7 @@ static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!priv->initialized)
+ if(!priv->initialized || !xbus->self_ticking)
return 0;
/*
* Poll layer1 status (cascade subunits)
@@ -749,6 +910,26 @@ static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd)
return 0;
}
+static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ BUG_ON(!xpd);
+ if(!TRANSPORT_RUNNING(xpd->xbus))
+ return -ENODEV;
+ switch (cmd) {
+ case ZT_TONEDETECT:
+ /*
+ * Asterisk call all span types with this (FXS specific)
+ * call. Silently ignore it.
+ */
+ LINE_DBG(SIGNAL, xpd, pos, "PRI: Starting a call\n");
+ return -ENOTTY;
+ default:
+ report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
static int PRI_card_close(xpd_t *xpd, lineno_t pos)
{
//struct zt_chan *chan = &xpd->span.chans[pos];
@@ -767,7 +948,7 @@ static int pri_startup(struct zt_span *span)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!xpd->xbus->hardware_exists) {
+ if(!TRANSPORT_RUNNING(xpd->xbus)) {
XPD_DBG(GENERAL, xpd, "Startup called by zaptel. No Hardware. Ignored\n");
return -ENODEV;
}
@@ -788,7 +969,7 @@ static int pri_shutdown(struct zt_span *span)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!xpd->xbus->hardware_exists) {
+ if(!TRANSPORT_RUNNING(xpd->xbus)) {
XPD_DBG(GENERAL, xpd, "Shutdown called by zaptel. No Hardware. Ignored\n");
return -ENODEV;
}
@@ -816,22 +997,34 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
struct zt_chan *chans;
unsigned long flags;
int i;
+ int physical_chan;
+ int physical_mask = 0;
BUG_ON(!xbus);
BUG_ON(!xpd);
BUG_ON(!pack);
priv = xpd->priv;
BUG_ON(!priv);
- /* Shift channel numbers to be 1-31 rather than 0-30. It only
- * takes setting the mask: */
- RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines << 1;
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
spin_lock_irqsave(&xpd->lock, flags);
chans = xpd->span.chans;
+ physical_chan = 0;
for_each_line(xpd, i) {
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ /* In E1 - Only 0'th channel is unused */
+ if(i == 0) {
+ physical_chan++;
+ }
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ /* In T1 - Every 4'th channel is unused */
+ if((i % 4) == 0) {
+ physical_chan++;
+ }
+ }
if(IS_SET(lines, i)) {
+ physical_mask |= BIT(physical_chan);
if(SPAN_REGISTERED(xpd)) {
- if(i == PRI_DCHAN_NUM - 1) {
+ if(i == PRI_DCHAN_IDX(priv)) {
if(priv->dchan_tx_sample != chans[i].writechunk[0]) {
priv->dchan_tx_sample = chans[i].writechunk[0];
priv->dchan_tx_counter++;
@@ -849,7 +1042,9 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
pcm += ZT_CHUNKSIZE;
}
+ physical_chan++;
}
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = physical_mask;
XPD_COUNTER(xpd, PCM_WRITE)++;
spin_unlock_irqrestore(&xpd->lock, flags);
}
@@ -867,39 +1062,55 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
{
struct PRI_priv_data *priv;
- volatile u_char *r;
byte *pcm;
- xpp_line_t pcm_mask;
+ struct zt_chan *chans;
+ xpp_line_t physical_mask;
unsigned long flags;
int i;
+ int logical_chan;
+ if(!SPAN_REGISTERED(xpd))
+ return;
priv = xpd->priv;
BUG_ON(!priv);
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
- pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
- /* The mask is shifted. make it zero-based again. */
- pcm_mask = (pcm_mask >> 1) & PRI_LINES_BITMASK;
+ physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
spin_lock_irqsave(&xpd->lock, flags);
- if (xpd->timer_count & 1) {
- /* First part */
- r = xpd->readchunk;
- } else {
- r = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD;
- }
- for (i = 0; i < CHANNELS_PERXPD; i++, r += ZT_CHUNKSIZE) {
- if(IS_SET(pcm_mask, i)) {
+ chans = xpd->span.chans;
+ logical_chan = 0;
+ for (i = 0; i < CHANNELS_PERXPD; i++) {
+ volatile u_char *r;
+
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ /* In E1 - Only 0'th channel is unused */
+ if(i == 0)
+ continue;
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ /* In T1 - Every 4'th channel is unused */
+ if((i % 4) == 0)
+ continue;
+ }
+ if(logical_chan == PRI_DCHAN_IDX(priv)) {
+ if(priv->dchan_rx_sample != pcm[0]) {
+ if(print_dbg & DBG_PCM) {
+ XPD_INFO(xpd, "RX-D-Chan: prev=0x%X now=0x%X\n",
+ priv->dchan_rx_sample, pcm[0]);
+ dump_packet("RX-D-Chan", pack, 1);
+ }
+ priv->dchan_rx_sample = pcm[0];
+ priv->dchan_rx_counter++;
+ } else if(pcm[0] == 0xFF)
+ dchan_state(xpd, 0);
+ }
+ if(IS_SET(physical_mask, i)) {
+ r = chans[logical_chan].readchunk;
// memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
// fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP
memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
pcm += ZT_CHUNKSIZE;
}
+ logical_chan++;
}
- pcm = (byte *)&xpd->readchunk[(PRI_DCHAN_NUM - 1) * ZT_CHUNKSIZE];
- if(priv->dchan_rx_sample != pcm[0]) {
- priv->dchan_rx_sample = pcm[0];
- priv->dchan_rx_counter++;
- } else if(pcm[0] == 0xFF)
- dchan_state(xpd, 0);
XPD_COUNTER(xpd, PCM_READ)++;
spin_unlock_irqrestore(&xpd->lock, flags);
}
@@ -938,7 +1149,7 @@ static /* 0x0F */ HOSTCMD(PRI, RELAY_OUT, byte which, bool on)
priv = xpd->priv;
BUG_ON(!priv);
XPD_DBG(LEDS, xpd, "led_sel=%d to_state=%d\n", led_sel, to_led_state);
- XFRAME_NEW(xframe, pack, xbus, PRI, SET_LED, xpd->xbus_idx);
+ XFRAME_NEW_CMD(xframe, pack, xbus, PRI, SET_LED, xpd->xbus_idx);
pri_leds = &RPACKET_FIELD(pack, PRI, SET_LED, pri_leds);
pri_leds->state = to_led_state;
pri_leds->led_sel = led_sel;
@@ -1031,6 +1242,7 @@ static xproto_table_t PROTO_TABLE(PRI) = {
.card_tick = PRI_card_tick,
.card_pcm_fromspan = PRI_card_pcm_fromspan,
.card_pcm_tospan = PRI_card_pcm_tospan,
+ .card_ioctl = PRI_card_ioctl,
.card_close = PRI_card_close,
.card_register_reply = PRI_card_register_reply,
@@ -1065,6 +1277,13 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns
char *tok;
static const char *msg = "PROC"; /* for logs */
int ret = 0;
+ bool got_localloop = 0;
+ bool got_nolocalloop = 0;
+ bool got_te = 0;
+ bool got_nt = 0;
+ bool got_e1 = 0;
+ bool got_t1 = 0;
+ bool got_j1 = 0;
if(!xpd)
return -ENODEV;
@@ -1079,30 +1298,52 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns
}
buf[count] = '\0';
XPD_DBG(PROC, xpd, "PRI-SETUP: got %s\n", buf);
+ /*
+ * First parse. Act only of *everything* is good.
+ */
p = buf;
while((tok = strsep(&p, " \t\v\n")) != NULL) {
if(*tok == '\0')
continue;
XPD_DBG(PROC, xpd, "Got token='%s'\n", tok);
if(strnicmp(tok, "LOCALLOOP", 8) == 0)
- ret = set_localloop(msg, xpd, 1);
+ got_localloop = 1;
else if(strnicmp(tok, "NOLOCALLOOP", 8) == 0)
- ret = set_localloop(msg, xpd, 0);
+ got_nolocalloop = 1;
else if(strnicmp(tok, "NT", 2) == 0)
- ret = set_nt(msg, xpd, 1);
+ got_nt = 1;
else if(strnicmp(tok, "TE", 2) == 0)
- ret = set_nt(msg, xpd, 0);
+ got_te = 1;
else if(strnicmp(tok, "E1", 2) == 0)
- ret = set_pri_proto(msg, xpd, PRI_PROTO_E1);
+ got_e1 = 1;
else if(strnicmp(tok, "T1", 2) == 0)
- ret = set_pri_proto(msg, xpd, PRI_PROTO_T1);
+ got_t1 = 1;
else if(strnicmp(tok, "J1", 2) == 0) {
- ret = set_pri_proto(msg, xpd, PRI_PROTO_J1);
+ got_j1 = 1;
} else {
XPD_NOTICE(xpd, "PRI-SETUP: unknown keyword: '%s'\n", tok);
return -EINVAL;
}
}
+ if(got_e1)
+ ret = set_pri_proto(xpd, PRI_PROTO_E1);
+ else if(got_t1)
+ ret = set_pri_proto(xpd, PRI_PROTO_T1);
+ else if(got_j1)
+ ret = set_pri_proto(xpd, PRI_PROTO_J1);
+ if(priv->pri_protocol == PRI_PROTO_0) {
+ XPD_ERR(xpd,
+ "Must set PRI protocol (E1/T1/J1) before setting other parameters\n");
+ return -EINVAL;
+ }
+ if(got_localloop)
+ ret = set_localloop(msg, xpd, 1);
+ if(got_nolocalloop)
+ ret = set_localloop(msg, xpd, 0);
+ if(got_nt)
+ ret = set_nt(msg, xpd, 1);
+ if(got_te)
+ ret = set_nt(msg, xpd, 0);
return (ret) ? ret : count;
}
@@ -1121,10 +1362,11 @@ static int proc_pri_info_read(char *page, char **start, off_t off, int count, in
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
- len += sprintf(page + len, "PRI: %s %s%s\n",
+ len += sprintf(page + len, "PRI: %s %s%s (deflaw=%d, dchan=%d)\n",
(priv->is_nt) ? "NT" : "TE",
- pri_protocol_name[priv->pri_protocol],
- (priv->local_loopback) ? " LOCALLOOP" : "");
+ pri_protocol_name(priv->pri_protocol),
+ (priv->local_loopback) ? " LOCALLOOP" : "",
+ priv->deflaw, priv->dchan_num);
len += sprintf(page + len, "%05d Layer1: ", priv->layer1_replies);
if(priv->poll_noreplies > 1)
len += sprintf(page + len, "No Replies [%d]\n",
@@ -1199,7 +1441,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
char *p;
reg_cmd_t regcmd;
xbus_t *xbus;
- int ret;
+ int ret = -EINVAL;
struct PRI_priv_data *priv;
byte buf[MAX_PROC_WRITE];
@@ -1215,7 +1457,10 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
;
if(*p == '\0')
return 0;
-
+ if(!XBUS_GET(xbus)) {
+ XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n");
+ return -EBUSY;
+ }
memset(buf, 0, MAX_PROC_WRITE);
elements = sscanf(cmdline, "%d %c%c %x %x %x %x %x",
&chipsel,
@@ -1225,11 +1470,11 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
XPD_DBG(PROC, xpd, "'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, subreg, data);
if(elements < 3) { // At least: chipsel, op, reg_type, reg_num
ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline);
- return -EINVAL;
+ goto out;
}
if(!VALID_CHIPSEL(chipsel)) {
ERR("Bad chip select number: %d\n", chipsel);
- return -EINVAL;
+ goto out;
}
REG_FIELD(&regcmd, chipsel) = chipsel;
switch(op) {
@@ -1241,7 +1486,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
break;
default:
ERR("Unkown operation type '%c'\n", op);
- return -EINVAL;
+ goto out;
}
if(
(op == 'W' && reg_type == 'D' && elements != 5) ||
@@ -1252,7 +1497,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
ERR("Bad number of elements: '%s' (%d elements): %d %c%c %02X %02X %02X\n",
cmdline, elements,
chipsel, op, reg_type, reg_num, subreg, data);
- return -EINVAL;
+ goto out;
}
switch(reg_type) {
case 'S':
@@ -1271,15 +1516,11 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
break;
default:
ERR("Unkown register type '%c'\n", reg_type);
- return -EINVAL;
+ goto out;
}
regcmd.bytes = sizeof(regcmd) - 1;
REG_FIELD(&regcmd, read_request) = writing;
REG_FIELD(&regcmd, data_high) = 0;
- if(!down_read_trylock(&xbus->in_use)) {
- XBUS_DBG(GENERAL, xbus, "Dropped packet. Is in_use\n");
- return -EBUSY;
- }
priv->requested_reply = regcmd;
if(print_dbg)
dump_reg_cmd("PRI", &regcmd, 1);
@@ -1291,7 +1532,8 @@ static int handle_register_command(xpd_t *xpd, char *cmdline)
REG_FIELD(&regcmd, subreg),
REG_FIELD(&regcmd, data_low),
REG_FIELD(&regcmd, data_high));
- up_read(&xbus->in_use);
+out:
+ XBUS_PUT(xbus);
return ret;
}