diff options
Diffstat (limited to 'drivers/dahdi/xpp/card_pri.c')
-rw-r--r-- | drivers/dahdi/xpp/card_pri.c | 545 |
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, |