summaryrefslogtreecommitdiff
path: root/xpp/card_pri.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/card_pri.c')
-rw-r--r--xpp/card_pri.c371
1 files changed, 291 insertions, 80 deletions
diff --git a/xpp/card_pri.c b/xpp/card_pri.c
index 335b933..6b2f487 100644
--- a/xpp/card_pri.c
+++ b/xpp/card_pri.c
@@ -53,7 +53,7 @@ static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in
ZT_SIG_DACS | \
ZT_SIG_SF \
)
-#define PRI_BCHAN_SIGCAP (ZT_SIG_CLEAR | ZT_SIG_DACS)
+#define PRI_BCHAN_SIGCAP (ZT_SIG_CLEAR | ZT_SIG_DACS | ZT_SIG_CAS)
#define MAX_SLAVES 4 /* we have MUX of 4 clocks */
#define PRI_PORT(xpd) ((xpd)->addr.subunit)
@@ -66,6 +66,7 @@ static int proc_pri_info_read(char *page, char **start, off_t off, int count, in
static int proc_pri_info_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
static int pri_startup(struct zt_span *span);
static int pri_shutdown(struct zt_span *span);
+static int pri_rbsbits(struct zt_chan *chan, int bits);
static int pri_lineconfig(xpd_t *xpd, int lineconfig);
#define PROC_REGISTER_FNAME "slics"
@@ -128,7 +129,6 @@ static int pri_linecompat(enum pri_protocol pri_protocol)
[PRI_PROTO_E1] =
/* coding */
ZT_CONFIG_CCS |
- // CAS |
ZT_CONFIG_CRC4 |
/* framing */
ZT_CONFIG_AMI | ZT_CONFIG_HDB3,
@@ -195,6 +195,9 @@ struct pri_leds {
*/
#define REG_LIM0_LL BIT(1) /* LL (Local Loopback) */
+#define REG_IMR0_E 0x14 /* Interrupt Mask Register 0 */
+#define REG_IMR0_E_CASC BIT(3)
+
#define REG_FMR0 0x1C
#define REG_FMR0_E_RC0 BIT(4) /* Receive Code - LSB */
#define REG_FMR0_E_RC1 BIT(5) /* Receive Code - MSB */
@@ -205,7 +208,7 @@ struct pri_leds {
#define REG_FMR1_XAIS BIT(0) /* Transmit AIS toward transmit end */
#define REG_FMR1_SSD0 BIT(1)
#define REG_FMR1_ECM BIT(2)
-#define REG_FMR1_XFS BIT(3)
+#define REG_FMR1_XFS BIT(3) /* Transmit Framing Select */
#define REG_FMR1_PMOD BIT(4) /* E1 = 0, T1/J1 = 1 */
#define REG_FMR1_EDL BIT(5)
#define REG_FMR1_AFR BIT(6)
@@ -222,8 +225,28 @@ struct pri_leds {
#define REG_FMR2_T_MCSP BIT(6) /* Multiple Candidates Synchronization Procedure */
#define REG_FMR2_T_AFRS BIT(7) /* Automatic Force Resynchronization */
+#define REG_FMR3 0x31
+#define REG_FMR3_EXTIW BIT(0) /* Extended CRC4 to Non-CRC4 Interworking */
+
#define REG_FMR4 0x20
+#define REG_FMR4_FM0 BIT(0)
#define REG_FMR4_FM1 BIT(1)
+#define REG_FMR4_AUTO BIT(2)
+#define REG_FMR4_SSC0 BIT(3)
+#define REG_FMR4_SSC1 BIT(4)
+#define REG_FMR4_XRA BIT(5) /* Transmit Remote Alarm (Yellow Alarm) */
+#define REG_FMR4_TM BIT(6)
+#define REG_FMR4_AIS3 BIT(7)
+
+#define REG_XSW_E 0x20
+#define REG_XSW_E_XY4 BIT(0)
+#define REG_XSW_E_XY3 BIT(1)
+#define REG_XSW_E_XY2 BIT(2)
+#define REG_XSW_E_XY1 BIT(3)
+#define REG_XSW_E_XY0 BIT(4)
+#define REG_XSW_E_XRA BIT(5) /* Transmit Remote Alarm (Yellow Alarm) */
+#define REG_XSW_E_XTM BIT(6)
+#define REG_XSW_E_XSIS BIT(7)
#define REG_XSP_E 0x21
#define REG_FMR5_T 0x21
@@ -231,7 +254,7 @@ struct pri_leds {
#define REG_FMR5_T_XTM BIT(2) /* Transmit Transparent Mode */
#define REG_XSP_E_AXS BIT(3) /* Automatic Transmission of Submultiframe Status */
#define REG_XSP_E_EBP BIT(4) /* E-Bit Polarity, Si-bit position of every outgoing CRC multiframe */
-#define REG_XSP_E_CASEN BIT(7) /* Channel Associated Signaling Enable */
+#define REG_XSP_E_CASEN BIT(6) /* CAS: Channel Associated Signaling Enable */
#define REG_RC0 0x24
#define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */
@@ -241,6 +264,25 @@ struct pri_leds {
#define REG_CMR1_RS (BIT(5) | BIT(4))
#define REG_CMR1_STF BIT(2)
+#define REG_RS1_E 0x70 /* Receive CAS Register 1 */
+#define REG_RS2_E 0x71 /* Receive CAS Register 2 */
+#define REG_RS3_E 0x72 /* Receive CAS Register 3 */
+#define REG_RS4_E 0x73 /* Receive CAS Register 4 */
+#define REG_RS5_E 0x74 /* Receive CAS Register 5 */
+#define REG_RS6_E 0x75 /* Receive CAS Register 6 */
+#define REG_RS7_E 0x76 /* Receive CAS Register 7 */
+#define REG_RS8_E 0x77 /* Receive CAS Register 8 */
+#define REG_RS9_E 0x78 /* Receive CAS Register 9 */
+#define REG_RS10_E 0x79 /* Receive CAS Register 10 */
+#define REG_RS11_E 0x7A /* Receive CAS Register 11 */
+#define REG_RS12_E 0x7B /* Receive CAS Register 12 */
+#define REG_RS13_E 0x7C /* Receive CAS Register 13 */
+#define REG_RS14_E 0x7D /* Receive CAS Register 14 */
+#define REG_RS15_E 0x7E /* Receive CAS Register 15 */
+#define REG_RS16_E 0x7F /* Receive CAS Register 16 */
+
+#define NUM_CAS_RS (REG_RS16_E - REG_RS2_E + 1)
+
struct PRI_priv_data {
bool is_nt;
bool clock_source;
@@ -249,6 +291,10 @@ struct PRI_priv_data {
int deflaw;
unsigned int dchan_num;
bool initialized;
+ bool is_cas;
+ byte cas_rs_e[NUM_CAS_RS];
+ byte cas_ts_e[NUM_CAS_RS];
+ uint cas_replies;
bool local_loopback;
uint poll_noreplies;
uint layer1_replies;
@@ -391,6 +437,22 @@ static bool valid_pri_modes(const xpd_t *xpd)
return 1;
}
+static void pri_pcm_update(xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+ int channels = xpd->channels;
+ xpp_line_t mask = BITMASK(xpd->channels);
+
+ priv = xpd->priv;
+ if(priv->is_cas) {
+ /* CAS: Don't send PCM to D-Channel */
+ channels--;
+ mask &= ~BIT(PRI_DCHAN_IDX(priv));
+ }
+ xpd->pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + channels * ZT_CHUNKSIZE;
+ xpd->wanted_pcm_mask = mask;
+}
+
/*
* Set E1/T1/J1
* May only be called on unregistered xpd's
@@ -401,12 +463,7 @@ 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 |
- REG_FMR1_ECM;
int default_lineconfig = 0;
- byte rc0 = 0; /* FIXME: PCM offsets */
int ret;
BUG_ON(!xpd);
@@ -416,6 +473,16 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
xpd->span.spanno, __FUNCTION__);
return -EBUSY;
}
+ if(priv->pri_protocol != PRI_PROTO_0) {
+ if(priv->pri_protocol == set_proto) {
+ XPD_NOTICE(xpd, "Already in protocol %s. Ignored\n", pri_protocol_name(set_proto));
+ return 0;
+ } else {
+ XPD_INFO(xpd, "Switching from %s to %s\n",
+ pri_protocol_name(priv->pri_protocol),
+ pri_protocol_name(set_proto));
+ }
+ }
switch(set_proto) {
case PRI_PROTO_E1:
deflaw = ZT_LAW_ALAW;
@@ -426,7 +493,6 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
deflaw = ZT_LAW_MULAW;
dchan_num = 24;
default_lineconfig = ZT_CONFIG_ESF | ZT_CONFIG_B8ZS;
- fmr1 |= REG_FMR1_PMOD;
break;
case PRI_PROTO_J1:
/*
@@ -434,8 +500,6 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
*/
deflaw = ZT_LAW_MULAW;
dchan_num = 24;
- fmr1 |= REG_FMR1_PMOD;
- rc0 |= REG_RC0_SJR;
default_lineconfig = 0; /* FIXME: J1??? */
XPD_NOTICE(xpd, "J1 is not supported yet\n");
return -ENOSYS;
@@ -446,10 +510,10 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
}
priv->pri_protocol = 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);
+ pri_pcm_update(xpd);
priv->deflaw = deflaw;
priv->dchan_num = dchan_num;
+ priv->local_loopback = 0;
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),
@@ -457,11 +521,6 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
priv->dchan_num,
priv->deflaw
);
- write_subunit(xpd, REG_FMR1, fmr1);
-#ifdef JAPANEZE_SUPPORT
- if(rc0)
- write_subunit(xpd, REG_RC0, rc0);
-#endif
/*
* Must set default now, so layer1 polling (Register REG_FRS0) would
* give reliable results.
@@ -566,6 +625,29 @@ static void set_clocking(xpd_t *xpd)
put_xbus(xbus);
}
+static void set_reg_lim0(const char *msg, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+ bool is_master_mode;
+ bool localloop;
+ byte lim0 = 0;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ is_master_mode = xpd->timing_priority == 0;
+ localloop = priv->local_loopback;
+ lim0 |= (localloop) ? REG_LIM0_LL : 0;
+ if(is_master_mode)
+ lim0 |= REG_LIM0_MAS;
+ else
+ lim0 &= ~REG_LIM0_MAS;
+ XPD_DBG(SIGNAL, xpd, "%s(%s): %s, %s\n", __FUNCTION__, msg,
+ (is_master_mode) ? "MASTER" : "SLAVE",
+ (localloop) ? "LOCALLOOP" : "NO_LOCALLOOP");
+ write_subunit(xpd, REG_LIM0 , lim0);
+}
+
/*
* Normally set by the timing parameter in zaptel.conf
* If this is called by ztcfg, than it's too late to change
@@ -578,28 +660,11 @@ static void set_clocking(xpd_t *xpd)
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);
+ XPD_DBG(SIGNAL, xpd, "\n");
priv = xpd->priv;
- lim0 |= (priv->local_loopback) ? REG_LIM0_LL : 0;
- if(is_master_mode)
- lim0 |= REG_LIM0_MAS;
- else
- lim0 &= ~REG_LIM0_MAS;
- if(priv->pri_protocol == PRI_PROTO_E1)
- {
- lim0 &= ~REG_LIM0_RTRS; /* Receive termination: Integrated resistor is switched off (100 Ohm, no internal 300 Ohm) */;
- xsp |= REG_XSP_E_EBP | REG_XSP_E_AXS | REG_XSP_E_XSIF;
- } else if(priv->pri_protocol == PRI_PROTO_T1) {
- lim0 |= REG_LIM0_RTRS; /* Receive termination: Integrated resistor is switched on (100 Ohm || 300 Ohm = 75 Ohm) */
- xsp |= REG_FMR5_T_XTM;
- }
- 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_reg_lim0(__FUNCTION__, xpd);
set_clocking(xpd);
return 0;
}
@@ -607,18 +672,20 @@ static int set_master_mode(const char *msg, xpd_t *xpd)
static int set_nt(const char *msg, xpd_t *xpd, bool is_nt)
{
struct PRI_priv_data *priv;
+ const char *tname;
BUG_ON(!xpd);
priv = xpd->priv;
+ tname = type_name(priv->pri_protocol, is_nt);
+ XPD_DBG(SIGNAL, xpd, "%s(%s): %s %s\n", __FUNCTION__, msg, tname, (is_nt) ? "NT" : "TE");
if(SPAN_REGISTERED(xpd)) {
XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n",
xpd->span.spanno, __FUNCTION__, msg);
return -EBUSY;
}
priv->is_nt = is_nt;
- xpd->type_name = type_name(priv->pri_protocol, is_nt);
+ xpd->type_name = tname;
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");
if(xpd->timing_priority == 0 && !is_nt) /* by default set timing priority from NT/TE */
xpd->timing_priority = 1;
set_master_mode(msg, xpd);
@@ -628,33 +695,17 @@ static int set_nt(const char *msg, xpd_t *xpd, bool is_nt)
static int set_localloop(const char *msg, xpd_t *xpd, bool localloop)
{
struct PRI_priv_data *priv;
- byte lim0 = 0;
- byte xsp = 0;
BUG_ON(!xpd);
priv = xpd->priv;
+ XPD_DBG(SIGNAL, xpd, "(%s): %s\n", msg, (localloop)?"YES":"NO");
if(SPAN_REGISTERED(xpd)) {
XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n",
xpd->span.spanno, __FUNCTION__, msg);
return -EBUSY;
}
- lim0 |= (localloop) ? REG_LIM0_LL : 0;
- if(priv->is_nt)
- lim0 |= REG_LIM0_MAS;
- else
- lim0 &= ~REG_LIM0_MAS;
- if(priv->pri_protocol == PRI_PROTO_E1)
- {
- lim0 |= REG_LIM0_RTRS; /* Receive termination: Integrated resistor is switched on (100 Ohm || 300 Ohm = 75 Ohm) */
- xsp |= REG_XSP_E_EBP | REG_XSP_E_AXS | REG_XSP_E_XSIF;
- } else if(priv->pri_protocol == PRI_PROTO_T1) {
- lim0 &= ~REG_LIM0_RTRS ; /* Receive termination: Integrated resistor is switched off (100 Ohm, no internal 300 Ohm) */;
- xsp |= REG_FMR5_T_XTM;
- }
priv->local_loopback = localloop;
- XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, (localloop) ? "LOCALLOOP" : "NO");
- write_subunit(xpd, REG_LIM0 , lim0);
- write_subunit(xpd, REG_XSP_E, xsp);
+ set_reg_lim0(__FUNCTION__, xpd);
return 0;
}
@@ -681,9 +732,18 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
const char *framingstr = "";
const char *codingstr = "";
const char *crcstr = "";
- byte fmr0 = 0; /* Dummy initilizations to */
- byte fmr2 = 0; /* silense false gcc warnings */
- byte fmr4 = 0; /* Dummy initilizations to */
+#ifdef JAPANEZE_SUPPORT
+ byte rc0 = 0; /* FIXME: PCM offsets */
+#endif
+ byte fmr0 = 0;
+ byte fmr1 =
+ REG_FMR1_AFR |
+ REG_FMR1_ECM;
+ byte fmr2 = 0;
+ byte fmr3 = 0; /* write only for CRC4 */
+ byte fmr4 = 0;
+ byte imr0 = 0;
+ byte xsp;
unsigned int bad_bits;
int i;
@@ -722,10 +782,14 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
if(priv->pri_protocol == PRI_PROTO_E1) {
fmr2 = REG_FMR2_E_AXRA | REG_FMR2_E_ALMF; /* 0x03 */
fmr4 = 0x9F; /* E1.XSW: All spare bits = 1*/
+ xsp |= REG_XSP_E_EBP | REG_XSP_E_AXS | REG_XSP_E_XSIF;
} else if(priv->pri_protocol == PRI_PROTO_T1) {
+ fmr1 |= REG_FMR1_PMOD;
fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */
fmr4 = 0x0C;
+ xsp |= REG_FMR5_T_XTM;
} else if(priv->pri_protocol == PRI_PROTO_J1) {
+ fmr1 |= REG_FMR1_PMOD;
fmr4 = 0x1C;
XPD_ERR(xpd, "J1 unsupported yet\n");
return -ENOSYS;
@@ -742,36 +806,65 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
} else if (lineconfig & ZT_CONFIG_HDB3) {
framingstr = "HDB3";
fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0;
+ } else {
+ XPD_NOTICE(xpd, "Bad lineconfig. Not (B8ZS|AMI|HDB3). Ignored.\n");
+ return -EINVAL;
}
/* then coding */
if (lineconfig & ZT_CONFIG_ESF) {
codingstr = "ESF";
+ priv->is_cas = 0;
fmr4 |= REG_FMR4_FM1;
fmr2 |= REG_FMR2_T_AXRA | REG_FMR2_T_MCSP | REG_FMR2_T_SSP;
} else if (lineconfig & ZT_CONFIG_D4) {
codingstr = "D4";
+ priv->is_cas = 0;
} else if (lineconfig & ZT_CONFIG_CCS) {
codingstr = "CCS";
+ priv->is_cas = 0;
/* do nothing */
+ } else { /* CAS */
+ codingstr = "CAS";
+ imr0 |= REG_IMR0_E_CASC;
+ xsp |= REG_XSP_E_CASEN;
+ priv->is_cas = 1;
}
+ pri_pcm_update(xpd);
/* E1's can enable CRC checking */
if (lineconfig & ZT_CONFIG_CRC4) {
crcstr = "CRC4";
+ fmr1 |= REG_FMR1_XFS;
fmr2 |= REG_FMR2_E_RFS1;
+ fmr3 |= REG_FMR3_EXTIW;
}
XPD_DBG(GENERAL, xpd, "[%s] lineconfig=%s/%s/%s %s (0x%X)\n",
(priv->is_nt)?"NT":"TE",
framingstr, codingstr, crcstr,
(lineconfig & ZT_CONFIG_NOTOPEN)?"YELLOW":"",
lineconfig);
- 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);
+ set_reg_lim0(__FUNCTION__, xpd);
+ XPD_DBG(GENERAL, xpd, "%s: fmr1(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR1, fmr1);
+ write_subunit(xpd, REG_FMR1, fmr1);
XPD_DBG(GENERAL, xpd, "%s: fmr2(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR2, fmr2);
write_subunit(xpd, REG_FMR2, fmr2);
+ 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: xsp(0x%02X) = 0x%02X\n", __FUNCTION__, REG_XSP_E, xsp);
+ write_subunit(xpd, REG_XSP_E, xsp);
+ if(fmr3) {
+ XPD_DBG(GENERAL, xpd, "%s: fmr3(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR3, fmr3);
+ write_subunit(xpd, REG_FMR3, fmr3);
+ }
+#ifdef JAPANEZE_SUPPORT
+ if(rc0) {
+ XPD_DBG(GENERAL, xpd, "%s: rc0(0x%02X) = 0x%02X\n", __FUNCTION__, REG_RC0, rc0);
+ write_subunit(xpd, REG_RC0, rc0);
+ }
+#endif
+ XPD_DBG(GENERAL, xpd, "%s: imr0(0x%02X) = 0x%02X\n", __FUNCTION__, REG_IMR0_E, imr0);
+ write_subunit(xpd, REG_IMR0_E, imr0);
return 0;
bad_lineconfig:
XPD_ERR(xpd, "Bad lineconfig. Abort\n");
@@ -830,7 +923,6 @@ 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); /* worst case */
- int ret = 0;
XBUS_DBG(GENERAL, xbus, "\n");
xpd = xpd_alloc(sizeof(struct PRI_priv_data), proto_table, channels);
@@ -845,10 +937,6 @@ static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
goto err;
if(pri_proc_create(xbus, xpd) < 0)
goto err;
- /* Assume E1, changes later from user space */
- ret = set_pri_proto(xpd, PRI_PROTO_E1);
- if(ret < 0)
- goto err;
return xpd;
err:
xpd_free(xpd);
@@ -866,6 +954,15 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
xpd->type = XPD_TYPE_PRI;
proto_table = &PROTO_TABLE(PRI);
priv = xpd->priv;
+ if(priv->pri_protocol == PRI_PROTO_0) {
+ /*
+ * init_card_* script didn't set pri protocol
+ * Let's have a default E1
+ */
+ ret = set_pri_proto(xpd, PRI_PROTO_E1);
+ if(ret < 0)
+ goto err;
+ }
/*
* initialization script should have set correct
* operating modes.
@@ -932,7 +1029,7 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on)
xpd->type_name, xbus->num, xpd->addr.unit, xpd->addr.subunit, i);
cur_chan->chanpos = i + 1;
cur_chan->pvt = xpd;
- if(is_dchan) { /* D-CHAN */
+ if(is_dchan && !priv->is_cas) { /* D-CHAN */
cur_chan->sigcap = PRI_DCHAN_SIGCAP;
//FIXME: cur_chan->flags |= ZT_FLAG_PRIDCHAN;
cur_chan->flags &= ~ZT_FLAG_HDLC;
@@ -944,6 +1041,7 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on)
xpd->span.chanconfig = pri_chanconfig;
xpd->span.startup = pri_startup;
xpd->span.shutdown = pri_shutdown;
+ xpd->span.rbsbits = pri_rbsbits;
return 0;
}
@@ -1165,6 +1263,57 @@ static int pri_shutdown(struct zt_span *span)
return 0;
}
+static int pri_rbsbits(struct zt_chan *chan, int bits)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ int pos;
+ byte val;
+ int reg_pos;
+ int regnum;
+ unsigned long flags;
+
+
+ xpd = chan->pvt;
+ BUG_ON(!xpd);
+ pos = chan->chanpos - 1;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!priv->layer1_up) {
+ XPD_DBG(SIGNAL, xpd, "RBS: TX: No layer1. Ignore.\n");
+ return 0;
+ }
+ if(priv->pri_protocol != PRI_PROTO_E1) {
+ XPD_NOTICE(xpd, "%s: protocol %s is not supported yet with CAS\n",
+ __FUNCTION__, pri_protocol_name(priv->pri_protocol));
+ return 0;
+ }
+ if(pos == 15)
+ return 0; /* Don't write dchan in CAS */
+ if(pos < 0 || pos > 31) {
+ XPD_NOTICE(xpd, "%s: pos=%d out of range. Ignore\n", __FUNCTION__, pos);
+ return 0;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(pos >= 16) {
+ /* Low nibble */
+ reg_pos = pos - 16;
+ val = (priv->cas_ts_e[reg_pos] & 0xF0) | (bits & 0x0F);
+ } else {
+ /* High nibble */
+ reg_pos = pos;
+ val = (priv->cas_ts_e[reg_pos] & 0x0F) | ((bits << 4) & 0xF0);
+ }
+ regnum = REG_RS2_E + reg_pos;
+ priv->cas_ts_e[reg_pos] = val;
+ priv->dchan_tx_counter++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ LINE_DBG(SIGNAL, xpd, pos, "RBS: TX: bits=0x%X (reg=0x%X val=0x%02X)\n",
+ bits, regnum, val);
+ pri_write_reg(xpd, regnum, val);
+ return 0;
+}
+
/*! Copy PCM chunks from the buffers of the xpd to a new packet
* \param xbus xbus of source xpd.
* \param xpd source xpd.
@@ -1216,6 +1365,8 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
priv->dchan_tx_counter++;
} else if(chans[i].writechunk[0] == 0xFF)
dchan_state(xpd, 0);
+ else
+ chans[i].writechunk[0] = 0xFF; /* Clobber for next tick */
}
#ifdef DEBUG_PCMTX
if(pcmtx >= 0 && pcmtx_chan == i)
@@ -1223,9 +1374,8 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
else
#endif
memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
- // fill_beep((u_char *)pcm, xpd->addr.subunit, 2);
} else
- memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
+ memset((u_char *)pcm, ZT_XLAW(0, (&chans[i])), ZT_CHUNKSIZE);
pcm += ZT_CHUNKSIZE;
}
physical_chan++;
@@ -1276,7 +1426,7 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
if((i % 4) == 0)
continue;
}
- if(logical_chan == PRI_DCHAN_IDX(priv)) {
+ if(logical_chan == PRI_DCHAN_IDX(priv) && !priv->is_cas) {
if(priv->dchan_rx_sample != pcm[0]) {
if(debug & DBG_PCM) {
XPD_INFO(xpd, "RX-D-Chan: prev=0x%X now=0x%X\n",
@@ -1381,17 +1531,59 @@ static void layer1_state(xpd_t *xpd, byte data_low)
XPD_DBG(REGS, xpd, "subunit=%d data_low=0x%02X\n", xpd->addr.subunit, data_low);
}
+static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low)
+{
+ struct PRI_priv_data *priv;
+ uint pos = regnum - REG_RS2_E;
+ int rsnum = pos + 2;
+ int chan1 = pos;
+ int chan2 = pos + 16;
+
+ priv = xpd->priv;
+ if(!priv->is_cas)
+ return;
+ if(pos < 0 || pos >= NUM_CAS_RS) {
+ XPD_ERR(xpd, "%s: got bad pos=%d [0-%d]\n", __FUNCTION__, pos, NUM_CAS_RS);
+ return;
+ }
+ priv->cas_replies++;
+ if(priv->cas_rs_e[pos] != data_low) {
+ int old1 = (priv->cas_rs_e[pos] >> 4) & 0xF;
+ int old2 = priv->cas_rs_e[pos] & 0xF;
+ int new1 = (data_low >> 4) & 0xF;
+ int new2 = data_low & 0xF;
+
+ XPD_DBG(SIGNAL, xpd, "RBS: RX: RS%02d (channel %2d, channel %2d): 0x%02X -> 0x%02X\n",
+ rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos], data_low);
+ if(SPAN_REGISTERED(xpd)) {
+ if(old1 != new1)
+ zt_rbsbits(&xpd->span.chans[chan1], new1);
+ if(old2 != new2)
+ zt_rbsbits(&xpd->span.chans[chan2], new2);
+ }
+ priv->dchan_rx_counter++;
+ priv->cas_rs_e[pos] = data_low;
+ } else {
+ XPD_DBG(SIGNAL, xpd, "RBS: RX: RS%02d (channel %2d, channel %2d): REPEAT 0x%02X\n",
+ rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos]);
+ }
+}
+
static int PRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
{
unsigned long flags;
struct PRI_priv_data *priv;
struct xpd_addr addr;
xpd_t *orig_xpd;
+ byte regnum;
+ byte data_low;
/* Map UNIT + PORTNUM to XPD */
orig_xpd = xpd;
addr.unit = orig_xpd->addr.unit;
addr.subunit = info->portnum;
+ regnum = REG_FIELD(info, regnum);
+ data_low = REG_FIELD(info, data_low);
xpd = xpd_byaddr(xbus, addr.unit, addr.subunit);
if(!xpd) {
static int rate_limit;
@@ -1408,10 +1600,15 @@ static int PRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
info->bytes, info->eoframe);
goto end;
}
- if(REG_FIELD(info, regnum) == REG_FRS0 && !REG_FIELD(info, do_subreg))
- layer1_state(xpd, REG_FIELD(info, data_low));
- if(REG_FIELD(info, regnum) == REG_FRS1 && !REG_FIELD(info, do_subreg))
- priv->reg_frs1 = REG_FIELD(info, data_low);
+ if(regnum == REG_FRS0 && !REG_FIELD(info, do_subreg))
+ layer1_state(xpd, data_low);
+ else if(regnum == REG_FRS1 && !REG_FIELD(info, do_subreg))
+ priv->reg_frs1 = data_low;
+ if(priv->is_cas && !REG_FIELD(info, do_subreg)) {
+ if(regnum >= REG_RS2_E && regnum <= REG_RS16_E) {
+ process_cas_dchan(xpd, regnum, data_low);
+ }
+ }
/* Update /proc info only if reply relate to the last slic read request */
if(
REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
@@ -1584,6 +1781,20 @@ static int proc_pri_info_read(char *page, char **start, off_t off, int count, in
len += sprintf(page + len, " YELLOW");
len += sprintf(page + len, "\n");
}
+ if(priv->is_cas) {
+ len += sprintf(page + len,
+ "CAS: replies=%d\n", priv->cas_replies);
+ len += sprintf(page + len, " CAS-TS: ");
+ for(i = 0; i < NUM_CAS_RS; i++) {
+ len += sprintf(page + len, " %02X", priv->cas_ts_e[i]);
+ }
+ len += sprintf(page + len, "\n");
+ len += sprintf(page + len, " CAS-RS: ");
+ for(i = 0; i < NUM_CAS_RS; i++) {
+ len += sprintf(page + len, " %02X", priv->cas_rs_e[i]);
+ }
+ len += sprintf(page + len, "\n");
+ }
len += sprintf(page + len, "D-Channel: TX=[%5d] (0x%02X) RX=[%5d] (0x%02X) ",
priv->dchan_tx_counter, priv->dchan_tx_sample,
priv->dchan_rx_counter, priv->dchan_rx_sample);