summaryrefslogtreecommitdiff
path: root/drivers/dahdi/xpp/card_pri.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dahdi/xpp/card_pri.c')
-rw-r--r--drivers/dahdi/xpp/card_pri.c545
1 files changed, 462 insertions, 83 deletions
diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c
index 93b43b0..f83d472 100644
--- a/drivers/dahdi/xpp/card_pri.c
+++ b/drivers/dahdi/xpp/card_pri.c
@@ -40,23 +40,37 @@ static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before
static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)");
#define PRI_LINES_BITMASK BITMASK(31)
-#define PRI_DCHAN_SIGCAP ( \
- DAHDI_SIG_EM | \
- DAHDI_SIG_CLEAR | \
- DAHDI_SIG_FXSLS | \
- DAHDI_SIG_FXSGS | \
- DAHDI_SIG_FXSKS | \
- DAHDI_SIG_FXOLS | \
- DAHDI_SIG_FXOGS | \
- DAHDI_SIG_FXOKS | \
- DAHDI_SIG_CAS | \
- DAHDI_SIG_DACS | \
- DAHDI_SIG_SF \
- )
-#define PRI_BCHAN_SIGCAP (DAHDI_SIG_CLEAR | DAHDI_SIG_DACS | DAHDI_SIG_CAS)
+#define PRI_SIGCAP ( \
+ DAHDI_SIG_EM | \
+ DAHDI_SIG_CLEAR | \
+ DAHDI_SIG_FXSLS | \
+ DAHDI_SIG_FXSGS | \
+ DAHDI_SIG_FXSKS | \
+ DAHDI_SIG_HARDHDLC | \
+ DAHDI_SIG_MTP2 | \
+ DAHDI_SIG_FXOLS | \
+ DAHDI_SIG_FXOGS | \
+ DAHDI_SIG_FXOKS | \
+ DAHDI_SIG_CAS | \
+ DAHDI_SIG_EM_E1 | \
+ DAHDI_SIG_DACS_RBS \
+ )
+
+static bool is_sigtype_dchan(int sigtype)
+{
+ if((sigtype & DAHDI_SIG_HDLCRAW) == DAHDI_SIG_HDLCRAW)
+ return 1;
+ if((sigtype & DAHDI_SIG_HDLCFCS) == DAHDI_SIG_HDLCFCS)
+ return 1;
+ if((sigtype & DAHDI_SIG_HARDHDLC) == DAHDI_SIG_HARDHDLC)
+ return 1;
+ return 0;
+}
+
#define MAX_SLAVES 4 /* we have MUX of 4 clocks */
#define PRI_PORT(xpd) ((xpd)->addr.subunit)
+#define CHAN_PER_REGS(p) (((p)->is_esf) ? 2 : 4)
/*---------------- PRI Protocol Commands ----------------------------------*/
@@ -129,7 +143,7 @@ static int pri_linecompat(enum pri_protocol pri_protocol)
DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3,
[PRI_PROTO_T1] =
/* coding */
- // DAHDI_CONFIG_D4 |
+ DAHDI_CONFIG_D4 |
DAHDI_CONFIG_ESF |
/* framing */
DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS,
@@ -168,6 +182,8 @@ struct pri_leds {
byte reserved:4;
};
+#define REG_CCB1_T 0x2F /* Clear Channel Register 1 */
+
#define REG_FRS0 0x4C /* Framer Receive Status Register 0 */
#define REG_FRS0_T1_FSR BIT(0) /* T1 - Frame Search Restart Flag */
#define REG_FRS0_LMFA BIT(1) /* Loss of Multiframe Alignment */
@@ -180,8 +196,7 @@ struct pri_leds {
#define REG_FRS1 0x4D /* Framer Receive Status Register 1 */
#define REG_LIM0 0x36
-#define REG_LIM0_MAS BIT(0) /* Master Mode, DCO-R circuitry is frequency
- synchronized to the clock supplied by SYNC */
+#define REG_LIM0_MAS BIT(0) /* Master Mode, DCO-R circuitry is frequency synchronized to the clock supplied by SYNC */
#define REG_LIM0_RTRS BIT(5) /*
* Receive Termination Resistance Selection:
* integrated resistor to create 75 Ohm termination (100 || 300 = 75)
@@ -190,9 +205,6 @@ 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 */
@@ -251,6 +263,14 @@ struct pri_leds {
#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(6) /* CAS: Channel Associated Signaling Enable */
+#define REG_FMR5_T_EIBR BIT(6) /* CAS: Enable Internal Bit Robbing Access */
+
+#define REG_XC0_T 0x22 /* Transmit Control 0 */
+#define REG_XC0_BRIF BIT(5) /* Bit Robbing Idle Function */
+
+#define REG_CMDR_E 0x02 /* Command Register */
+#define REG_CMDR_RRES BIT(6) /* Receiver reset */
+#define REG_CMDR_XRES BIT(4) /* Transmitter reset */
#define REG_RC0 0x24
#define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */
@@ -286,7 +306,9 @@ struct pri_leds {
#define VAL_PC_GPOH 0x0A /* General Purpose Output, high level */
#define VAL_PC_GPOL 0x0B /* General Purpose Output, low level */
-#define NUM_CAS_RS (REG_RS16_E - REG_RS2_E + 1)
+#define NUM_CAS_RS (REG_RS16_E - REG_RS1_E + 1)
+/* and of those, the ones used in T1: */
+#define NUM_CAS_RS_T (REG_RS12_E - REG_RS1_E + 1)
struct PRI_priv_data {
bool clock_source;
@@ -294,13 +316,22 @@ struct PRI_priv_data {
struct proc_dir_entry *pri_info;
#endif
enum pri_protocol pri_protocol;
+ xpp_line_t rbslines;
int deflaw;
unsigned int dchan_num;
bool initialized;
- bool is_cas;
+ int is_cas;
+
+ unsigned int chanconfig_dchan;
+#define NO_DCHAN (0)
+#define DCHAN(p) ((p)->chanconfig_dchan)
+#define VALID_DCHAN(p) (DCHAN(p) != NO_DCHAN)
+#define SET_DCHAN(p,d) do { DCHAN(p) = (d); } while(0);
+
byte cas_rs_e[NUM_CAS_RS];
byte cas_ts_e[NUM_CAS_RS];
uint cas_replies;
+ bool is_esf;
bool local_loopback;
uint poll_noreplies;
uint layer1_replies;
@@ -452,15 +483,21 @@ static void pri_pcm_update(xpd_t *xpd)
struct PRI_priv_data *priv;
int channels = xpd->channels;
xpp_line_t mask = BITMASK(xpd->channels);
+ uint pcm_len;
+ unsigned long flags;
priv = xpd->priv;
if(priv->is_cas) {
- /* CAS: Don't send PCM to D-Channel */
- channels--;
- mask &= ~BIT(PRI_DCHAN_IDX(priv));
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ /* 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 * DAHDI_CHUNKSIZE;
- xpd->wanted_pcm_mask = mask;
+ pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + channels * DAHDI_CHUNKSIZE;
+ spin_lock_irqsave(&xpd->lock_recompute_pcm, flags);
+ update_wanted_pcm_mask(xpd, mask, pcm_len);
+ spin_unlock_irqrestore(&xpd->lock_recompute_pcm, flags);
}
/*
@@ -497,7 +534,7 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
case PRI_PROTO_E1:
deflaw = DAHDI_LAW_ALAW;
dchan_num = 16;
- default_lineconfig = DAHDI_CONFIG_CRC4 | DAHDI_CONFIG_HDB3;
+ default_lineconfig = DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4 | DAHDI_CONFIG_HDB3;
break;
case PRI_PROTO_T1:
deflaw = DAHDI_LAW_MULAW;
@@ -519,6 +556,7 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
return -EINVAL;
}
priv->pri_protocol = set_proto;
+ priv->is_cas = -1;
xpd->channels = pri_num_channels(set_proto);
pri_pcm_update(xpd);
priv->deflaw = deflaw;
@@ -610,7 +648,7 @@ static void set_clocking(xpd_t *xpd)
}
/* Now set it */
if(best_xpd && ((struct PRI_priv_data *)(best_xpd->priv))->clock_source == 0) {
- byte reg_pc_init[] = { VAL_PC_SYPR, VAL_PC_GPI, VAL_PC_GPI };
+ byte reg_pc_init[] = { VAL_PC_GPI, VAL_PC_GPI, VAL_PC_GPI };
for(i = 0; i < ARRAY_SIZE(reg_pc_init); i++) {
byte reg_pc = reg_pc_init[i];
@@ -703,7 +741,7 @@ static const struct {
const int flags;
} valid_spanconfigs[sizeof(unsigned int)*8] = {
/* These apply to T1 */
-// VALID_CONFIG(4, DAHDI_CONFIG_D4, "D4"), FIXME: should support
+ VALID_CONFIG(4, DAHDI_CONFIG_D4, "D4"),
VALID_CONFIG(5, DAHDI_CONFIG_ESF, "ESF"),
VALID_CONFIG(6, DAHDI_CONFIG_AMI, "AMI"),
VALID_CONFIG(7, DAHDI_CONFIG_B8ZS, "B8ZS"),
@@ -713,6 +751,78 @@ static const struct {
VALID_CONFIG(10, DAHDI_CONFIG_CRC4, "CRC4"),
};
+/*
+ * Mark the lines as CLEAR or RBS signalling.
+ * With T1, we need to mark the CLEAR lines on the REG_CCB1_T registers
+ * Should be called only when we are registered to DAHDI
+ * The channo parameter:
+ * channo == 0: set lines for the whole span
+ * channo != 0: only set modified lines
+ */
+static void set_rbslines(xpd_t *xpd, int channo)
+{
+ struct PRI_priv_data *priv;
+ xpp_line_t new_rbslines = 0;
+ xpp_line_t modified_lines;
+ int i;
+
+ priv = xpd->priv;
+ for_each_line(xpd, i) {
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
+
+ if(chan->flags & DAHDI_FLAG_CLEAR)
+ BIT_CLR(new_rbslines, i);
+ else
+ BIT_SET(new_rbslines, i);
+ }
+ new_rbslines &= BITMASK(xpd->channels);
+ modified_lines = priv->rbslines ^ new_rbslines;
+ XPD_DBG(DEVICES, xpd, "RBSLINES-%d(%s): 0x%X\n",
+ channo, pri_protocol_name(priv->pri_protocol), new_rbslines);
+ if((priv->pri_protocol == PRI_PROTO_T1) || (priv->pri_protocol == PRI_PROTO_J1)) {
+ byte clear_lines = 0; /* Mark clear lines */
+ bool reg_changed = 0;
+
+ for_each_line(xpd, i) {
+ int bytenum = i / 8;
+ int bitnum = i % 8;
+
+ if(!IS_SET(new_rbslines, i)) {
+ BIT_SET(clear_lines, (7 - bitnum));
+ }
+ if(IS_SET(modified_lines, i))
+ reg_changed = 1;
+ if(bitnum == 7) {
+ if(channo == 0 || reg_changed) {
+ bytenum += REG_CCB1_T;
+ XPD_DBG(DEVICES, xpd, "RBS(%s): modified=0x%X rbslines=0x%X reg=0x%X clear_lines=0x%X\n",
+ pri_protocol_name(priv->pri_protocol),
+ modified_lines, new_rbslines, bytenum, clear_lines);
+ write_subunit(xpd, bytenum, clear_lines);
+ }
+ clear_lines = 0;
+ reg_changed = 0;
+ }
+ }
+ }
+ priv->rbslines = new_rbslines;
+}
+
+static int set_mode_cas(xpd_t *xpd, bool want_cas)
+{
+ struct PRI_priv_data *priv;
+
+ priv = xpd->priv;
+ XPD_INFO(xpd, "Setting TDM to %s\n", (want_cas) ? "CAS" : "PRI");
+ if(want_cas) {
+ priv->is_cas = 1;
+ priv->dchan_alive = 0;
+ } else {
+ priv->is_cas = 0;
+ }
+ return 0;
+}
+
static int pri_lineconfig(xpd_t *xpd, int lineconfig)
{
struct PRI_priv_data *priv;
@@ -723,15 +833,14 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
byte rc0 = 0; /* FIXME: PCM offsets */
#endif
byte fmr0 = 0;
- byte fmr1 =
- REG_FMR1_AFR |
- REG_FMR1_ECM;
+ byte fmr1 = REG_FMR1_ECM;
byte fmr2 = 0;
byte fmr3 = 0; /* write only for CRC4 */
byte fmr4 = 0;
- byte imr0 = 0;
- byte xsp = 0;
+ byte cmdr = REG_CMDR_RRES | REG_CMDR_XRES;
+ byte xsp = 0;
unsigned int bad_bits;
+ bool force_cas = 0;
int i;
BUG_ON(!xpd);
@@ -767,6 +876,7 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
if(bad_bits)
goto bad_lineconfig;
if(priv->pri_protocol == PRI_PROTO_E1) {
+ fmr1 |= REG_FMR1_AFR;
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;
@@ -774,10 +884,13 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
fmr1 |= REG_FMR1_PMOD | REG_FMR1_T_CRC;
fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */
fmr4 = 0x0C;
- xsp |= REG_FMR5_T_XTM;
+ xsp &= ~REG_FMR5_T_XTM;
+ force_cas = 1; /* T1 - Chip always in CAS mode */
} else if(priv->pri_protocol == PRI_PROTO_J1) {
fmr1 |= REG_FMR1_PMOD;
fmr4 = 0x1C;
+ xsp &= ~REG_FMR5_T_XTM;
+ force_cas = 1; /* T1 - Chip always in CAS mode */
XPD_ERR(xpd, "J1 unsupported yet\n");
return -ENOSYS;
}
@@ -790,6 +903,22 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
} else if (lineconfig & DAHDI_CONFIG_AMI) {
framingstr = "AMI";
fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_RC1;
+ /*
+ * From Infineon Errata Sheet: PEF 22554, Version 3.1
+ * Problem: Incorrect CAS Receiption when
+ * using AMI receive line code
+ * Workaround: For E1,
+ * "...The receive line coding HDB3 is
+ * recommended instead."
+ * For T1,
+ * "...in T1 mode it is recommended to
+ * configure the Rx side to B8ZS coding"
+ * For both cases this is the same bit in FMR0
+ */
+ if(priv->pri_protocol == PRI_PROTO_J1)
+ XPD_NOTICE(xpd, "J1 is not supported yet\n");
+ else
+ fmr0 |= REG_FMR0_E_RC0;
} else if (lineconfig & DAHDI_CONFIG_HDB3) {
framingstr = "HDB3";
fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0;
@@ -798,23 +927,21 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
return -EINVAL;
}
/* then coding */
+ priv->is_esf = 0;
if (lineconfig & DAHDI_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;
+ priv->is_esf = 1;
} else if (lineconfig & DAHDI_CONFIG_D4) {
codingstr = "D4";
- priv->is_cas = 0;
} else if (lineconfig & DAHDI_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;
+ set_mode_cas(xpd, 0); /* In E1 we know right from the span statement. */
+ } else {
+ codingstr = "CAS"; /* In E1 we know right from the span statement. */
+ force_cas = 1;
+ set_mode_cas(xpd, 1);
}
pri_pcm_update(xpd);
/*
@@ -842,20 +969,23 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig)
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);
}
+ XPD_DBG(GENERAL, xpd, "%s: cmdr(0x%02X) = 0x%02X\n", __FUNCTION__, REG_CMDR_E, cmdr);
+ write_subunit(xpd, REG_CMDR_E, cmdr);
#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);
+ if(force_cas) {
+ xsp |= REG_XSP_E_CASEN; /* Same as REG_FMR5_T_EIBR for T1 */
+ }
+ XPD_DBG(GENERAL, xpd, "%s: xsp(0x%02X) = 0x%02X\n", __FUNCTION__, REG_XSP_E, xsp);
+ write_subunit(xpd, REG_XSP_E, xsp);
return 0;
bad_lineconfig:
XPD_ERR(xpd, "Bad lineconfig. Abort\n");
@@ -902,7 +1032,43 @@ static int pri_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc)
*/
static int pri_chanconfig(struct dahdi_chan *chan, int sigtype)
{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+
+ xpd = chan->span->pvt;
+ BUG_ON(!xpd);
+ priv = xpd->priv;
DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
+ /*
+ * Some bookkeeping to check if we have DChan defined or not
+ * FIXME: actually use this to prevent duplicate DChan definitions
+ * and prevent DChan definitions with CAS.
+ */
+ if(is_sigtype_dchan(sigtype)) {
+ if(VALID_DCHAN(priv) && DCHAN(priv) != chan->channo) {
+ ERR("channel %d (%s) marked DChan but also channel %d.\n",
+ chan->channo, chan->name, DCHAN(priv));
+ return -EINVAL;
+ } else {
+ XPD_DBG(GENERAL, xpd, "channel %d (%s) marked as DChan\n", chan->channo, chan->name);
+ SET_DCHAN(priv, chan->channo);
+ /* In T1, we don't know before-hand */
+ if(priv->pri_protocol != PRI_PROTO_E1 && priv->is_cas != 0)
+ set_mode_cas(xpd, 0);
+ }
+ } else {
+ if(chan->channo == 1) {
+ XPD_DBG(GENERAL, xpd, "channel %d (%s) marked a not DChan\n", chan->channo, chan->name);
+ SET_DCHAN(priv, NO_DCHAN);
+ }
+ /* In T1, we don't know before-hand */
+ if(priv->pri_protocol != PRI_PROTO_E1 && priv->is_cas != 1)
+ set_mode_cas(xpd, 1);
+ }
+ if(xpd->span.flags & DAHDI_FLAG_RUNNING) {
+ XPD_DBG(DEVICES, xpd, "Span is RUNNING. Updating rbslines.\n");
+ set_rbslines(xpd, chan->channo);
+ }
// FIXME: sanity checks:
// - should be supported (within the sigcap)
// - should not replace fxs <->fxo ??? (covered by previous?)
@@ -957,6 +1123,7 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
if(ret < 0)
goto err;
}
+ SET_DCHAN(priv, NO_DCHAN);
/*
* initialization script should have set correct
* operating modes.
@@ -968,7 +1135,7 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
xpd->type_name = type_name(priv->pri_protocol);
xpd->direction = TO_PSTN;
XPD_DBG(DEVICES, xpd, "%s\n", xpd->type_name);
- xpd->timing_priority = 1; /* SLAVE */
+ xpd->timing_priority = 1; /* High priority SLAVE */
set_master_mode(__FUNCTION__, xpd);
for(ret = 0; ret < NUM_LEDS; ret++) {
DO_LED(xpd, ret, PRI_LED_ON);
@@ -1030,13 +1197,14 @@ static int PRI_card_dahdi_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;
+ cur_chan->sigcap = PRI_SIGCAP;
if(is_dchan && !priv->is_cas) { /* D-CHAN */
- cur_chan->sigcap = PRI_DCHAN_SIGCAP;
//FIXME: cur_chan->flags |= DAHDI_FLAG_PRIDCHAN;
cur_chan->flags &= ~DAHDI_FLAG_HDLC;
- } else
- cur_chan->sigcap = PRI_BCHAN_SIGCAP;
+ }
}
+ if(!priv->is_cas)
+ clear_bit(DAHDI_FLAGBIT_RBS, &xpd->span.flags);
xpd->offhook_state = xpd->wanted_pcm_mask;
xpd->span.spanconfig = pri_spanconfig;
xpd->span.chanconfig = pri_chanconfig;
@@ -1060,12 +1228,6 @@ static int PRI_card_dahdi_postregistration(xpd_t *xpd, bool on)
return(0);
}
-static int PRI_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig txsig)
-{
- LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig));
- return 0;
-}
-
static void dchan_state(xpd_t *xpd, bool up)
{
struct PRI_priv_data *priv;
@@ -1073,6 +1235,9 @@ static void dchan_state(xpd_t *xpd, bool up)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
+ if(priv->is_cas) {
+ return;
+ }
if(priv->dchan_alive == up)
return;
if(!priv->layer1_up) /* No layer1, kill dchan */
@@ -1207,6 +1372,8 @@ static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
* call. Silently ignore it.
*/
LINE_DBG(SIGNAL, xpd, pos, "PRI: Starting a call\n");
+ /* fall-through */
+ case DAHDI_ONHOOKTRANSFER:
return -ENOTTY;
default:
report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
@@ -1240,6 +1407,7 @@ static int pri_startup(struct dahdi_span *span)
XPD_DBG(GENERAL, xpd, "STARTUP\n");
// Turn on all channels
CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1);
+ set_rbslines(xpd, 0);
return 0;
}
@@ -1264,31 +1432,19 @@ static int pri_shutdown(struct dahdi_span *span)
return 0;
}
-static int pri_rbsbits(struct dahdi_chan *chan, int bits)
+static int encode_rbsbits_e1(xpd_t *xpd, int pos, 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;
- }
+ BUG_ON(priv->pri_protocol != PRI_PROTO_E1);
if(pos == 15)
return 0; /* Don't write dchan in CAS */
if(pos < 0 || pos > 31) {
@@ -1307,7 +1463,6 @@ static int pri_rbsbits(struct dahdi_chan *chan, int bits)
}
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);
@@ -1315,6 +1470,94 @@ static int pri_rbsbits(struct dahdi_chan *chan, int bits)
return 0;
}
+static int encode_rbsbits_t1(xpd_t *xpd, int pos, int bits)
+{
+ struct PRI_priv_data *priv;
+ int rsnum;
+ int chan_per_reg;
+ int offset;
+ int width;
+ uint tx_bits = bits;
+ uint mask;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ BUG_ON(priv->pri_protocol != PRI_PROTO_T1);
+ if(pos < 0 || pos >= xpd->channels) {
+ XPD_ERR(xpd, "%s: Bad pos=%d\n", __FUNCTION__, pos);
+ return 0;
+ }
+ chan_per_reg = CHAN_PER_REGS(priv);
+ width = 8 / chan_per_reg;
+ rsnum = pos / chan_per_reg;
+ offset = pos % chan_per_reg;
+ mask = BITMASK(width) << (chan_per_reg - offset - 1) * width;
+ if (!priv->is_esf)
+ tx_bits >>= 2;
+ tx_bits &= BITMASK(width);
+ tx_bits <<= (chan_per_reg - offset - 1) * width;
+ if((priv->cas_ts_e[rsnum] & mask) == tx_bits) {
+#if 0
+ LINE_DBG(SIGNAL, xpd, pos, "RBS: TX: RS%02d(0x%02X, 0x%02X): REPEAT 0x%02X\n",
+ rsnum+1, mask, tx_bits, bits);
+#endif
+ return 0;
+ }
+ priv->cas_ts_e[rsnum] &= ~mask;
+ priv->cas_ts_e[rsnum] |= tx_bits;
+ LINE_DBG(SIGNAL, xpd, pos,
+ "bits=0x%02X RS%02d(%s) offset=%d tx_bits=0x%02X\n",
+ bits, rsnum+1,
+ (priv->is_esf) ? "esf" : "d4",
+ offset, tx_bits);
+ write_subunit(xpd, REG_RS1_E + rsnum , priv->cas_ts_e[rsnum]);
+ if (!priv->is_esf) {
+ /* same data should be copied to RS7..12 in D4 only */
+ write_subunit(xpd, REG_RS7_E + rsnum , priv->cas_ts_e[rsnum]);
+ }
+ priv->dchan_tx_counter++;
+ return 0;
+}
+
+static int pri_rbsbits(struct dahdi_chan *chan, int bits)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ int pos;
+
+ 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");
+ }
+ if(!priv->is_cas) {
+ XPD_NOTICE(xpd, "RBS: TX: not in CAS mode. Ignore.\n");
+ return 0;
+ }
+ if (chan->sig == DAHDI_SIG_NONE) {
+ LINE_DBG(SIGNAL, xpd, pos,
+ "RBS: TX: sigtyp=%s. , bits=0x%X. Ignore.\n",
+ sig2str(chan->sig), bits);
+ return 0;
+ }
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ if(encode_rbsbits_e1(xpd, pos, bits) < 0)
+ return -EINVAL;
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ if(encode_rbsbits_t1(xpd, pos, bits) < 0)
+ return -EINVAL;
+ } else {
+ XPD_NOTICE(xpd, "%s: protocol %s is not supported yet with CAS\n",
+ __FUNCTION__, pri_protocol_name(priv->pri_protocol));
+ return -EINVAL;
+ }
+ 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.
@@ -1491,6 +1734,7 @@ static void layer1_state(xpd_t *xpd, byte data_low)
{
struct PRI_priv_data *priv;
int alarms = 0;
+ int layer1_up_prev;
BUG_ON(!xpd);
priv = xpd->priv;
@@ -1502,6 +1746,7 @@ static void layer1_state(xpd_t *xpd, byte data_low)
alarms |= DAHDI_ALARM_BLUE;
if(data_low & REG_FRS0_RRA)
alarms |= DAHDI_ALARM_YELLOW;
+ layer1_up_prev = priv->layer1_up;
priv->layer1_up = alarms == 0;
#if 0
/*
@@ -1513,8 +1758,18 @@ static void layer1_state(xpd_t *xpd, byte data_low)
priv->layer1_up = 0;
#endif
priv->alarms = alarms;
- if(!priv->layer1_up)
+ if(!priv->layer1_up) {
dchan_state(xpd, 0);
+ } else if (priv->is_cas && !layer1_up_prev) {
+ int i;
+ int num_cas_rs = (priv->pri_protocol == PRI_PROTO_E1) ?
+ NUM_CAS_RS: NUM_CAS_RS_T;
+ XPD_DBG(SIGNAL , xpd,
+ "Returning From Alarm Refreshing Rx register data \n");
+ for(i = 0; i < num_cas_rs; i++)
+ query_subunit(xpd, REG_RS1_E + i);
+ }
+
if(SPAN_REGISTERED(xpd) && xpd->span.alarms != alarms) {
char str1[MAX_PROC_WRITE];
char str2[MAX_PROC_WRITE];
@@ -1533,7 +1788,7 @@ 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)
+static int decode_cas_e1(xpd_t *xpd, byte regnum, byte data_low)
{
struct PRI_priv_data *priv;
uint pos = regnum - REG_RS2_E;
@@ -1542,13 +1797,27 @@ static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low)
int chan2 = pos + 16;
priv = xpd->priv;
- if(!priv->is_cas)
- return;
+ BUG_ON(!priv->is_cas);
+ BUG_ON(priv->pri_protocol != PRI_PROTO_E1);
+ XPD_DBG(SIGNAL, xpd, "RBS: RX: data_low=0x%02X\n", data_low);
if(pos < 0 || pos >= NUM_CAS_RS) {
XPD_ERR(xpd, "%s: got bad pos=%d [0-%d]\n", __FUNCTION__, pos, NUM_CAS_RS);
- return;
+ return -EINVAL;
+ }
+ if(chan1 < 0 || chan1 > xpd->channels) {
+ XPD_NOTICE(xpd, "%s: %s CAS: Bad chan1 number (%d)\n",
+ __FUNCTION__,
+ pri_protocol_name(priv->pri_protocol),
+ chan1);
+ return -EINVAL;
+ }
+ if(chan2 < 0 || chan2 > xpd->channels) {
+ XPD_NOTICE(xpd, "%s: %s CAS: Bad chan2 number (%d)\n",
+ __FUNCTION__,
+ pri_protocol_name(priv->pri_protocol),
+ chan2);
+ return -EINVAL;
}
- 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;
@@ -1556,7 +1825,7 @@ static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low)
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);
+ rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos], data_low);
if(SPAN_REGISTERED(xpd)) {
if(old1 != new1)
dahdi_rbsbits(XPD_CHAN(xpd, chan1), new1);
@@ -1566,9 +1835,120 @@ static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low)
priv->dchan_rx_counter++;
priv->cas_rs_e[pos] = data_low;
} else {
+#if 0
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]);
+#endif
+ }
+ return 0;
+}
+
+static int decode_cas_t1(xpd_t *xpd, byte regnum, byte data_low)
+{
+ struct PRI_priv_data *priv;
+ uint rsnum;
+ uint chan_per_reg;
+ uint width;
+ int i;
+
+ priv = xpd->priv;
+ BUG_ON(!priv->is_cas);
+ BUG_ON(priv->pri_protocol != PRI_PROTO_T1);
+ rsnum = regnum - REG_RS1_E;
+ if(rsnum < 0 || rsnum >= 12) {
+ XPD_ERR(xpd, "Bad rsnum=%d\n", rsnum);
+ return 0;
+ }
+ if(!priv->is_esf)
+ rsnum = rsnum % 6; /* 2 identical banks of 6 registers */
+ chan_per_reg = CHAN_PER_REGS(priv);
+ width = 8 / chan_per_reg;
+ if(priv->cas_rs_e[rsnum] == data_low) {
+#if 0
+ XPD_DBG(SIGNAL, xpd, "RBS: RX: RS%02d: REPEAT 0x%02X\n",
+ rsnum+1, data_low);
+#endif
+ return 0;
}
+ XPD_DBG(SIGNAL, xpd,
+ "RBS: RX(%s,%d): RS%02d data_low=0x%02X\n",
+ (priv->is_esf) ? "esf" : "d4",
+ chan_per_reg,
+ rsnum+1, data_low);
+ for(i = 0; i < chan_per_reg; i++) {
+ uint rxsig = (data_low >> (i * width)) & BITMASK(width);
+ int pos;
+ struct dahdi_chan *chan;
+
+ if (!priv->is_esf)
+ rxsig <<= 2;
+ pos = rsnum * chan_per_reg + chan_per_reg - i - 1;
+ if(pos < 0 || pos >= xpd->channels) {
+ XPD_ERR(xpd, "%s: Bad pos=%d\n", __FUNCTION__, pos);
+ continue;
+ }
+ chan = XPD_CHAN(xpd, pos);
+ if(!chan) {
+ XPD_ERR(xpd, "%s: Null channel in pos=%d\n", __FUNCTION__, pos);
+ continue;
+ }
+ if(chan->rxsig != rxsig) {
+ LINE_DBG(SIGNAL, xpd, pos, "i=%d rxsig=0x%02X\n", i, rxsig);
+ dahdi_rbsbits(chan, rxsig);
+ }
+ }
+ priv->cas_rs_e[rsnum] = data_low;
+ return 0;
+}
+
+static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low)
+{
+ struct PRI_priv_data *priv;
+
+ priv = xpd->priv;
+ if(!priv->is_cas) {
+ static int rate_limit;
+
+ if((rate_limit++ % 10003) == 0)
+ XPD_NOTICE(xpd, "RBS: RX: not in CAS mode. Ignore.\n");
+ return;
+ }
+ if(!priv->layer1_up) {
+ static int rate_limit;
+
+ if((rate_limit++ % 10003) == 0)
+ XPD_DBG(SIGNAL, xpd, "RBS: RX: No layer1.\n");
+ }
+ if(!SPAN_REGISTERED(xpd)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 10003) == 0)
+ XPD_DBG(SIGNAL, xpd, "RBS: RX: Span not registered. Ignore.\n");
+ return;
+ }
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ if(regnum < REG_RS2_E) {
+ XPD_NOTICE(xpd,
+ "%s: received register 0x%X in protocol %s. Ignore\n",
+ __FUNCTION__, regnum, pri_protocol_name(priv->pri_protocol));
+ return;
+ }
+ if(decode_cas_e1(xpd, regnum, data_low) < 0)
+ return;
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ if(regnum > REG_RS12_E) {
+ XPD_NOTICE(xpd,
+ "%s: received register 0x%X in protocol %s. Ignore\n",
+ __FUNCTION__, regnum, pri_protocol_name(priv->pri_protocol));
+ return;
+ }
+ if(decode_cas_t1(xpd, regnum, data_low) < 0)
+ return;
+ } else {
+ XPD_NOTICE(xpd, "%s: protocol %s is not supported yet with CAS\n",
+ __FUNCTION__, pri_protocol_name(priv->pri_protocol));
+ }
+ priv->cas_replies++;
}
static int PRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
@@ -1607,7 +1987,7 @@ static int PRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
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) {
+ if(regnum >= REG_RS1_E && regnum <= REG_RS16_E) {
process_cas_dchan(xpd, regnum, data_low);
}
}
@@ -1638,7 +2018,6 @@ static xproto_table_t PROTO_TABLE(PRI) = {
.card_remove = PRI_card_remove,
.card_dahdi_preregistration = PRI_card_dahdi_preregistration,
.card_dahdi_postregistration = PRI_card_dahdi_postregistration,
- .card_hooksig = PRI_card_hooksig,
.card_tick = PRI_card_tick,
.card_pcm_recompute = generic_card_pcm_recompute,
.card_pcm_fromspan = PRI_card_pcm_fromspan,