From 7e63c5db9520d28a203482ab53b86499d32f7a96 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Thu, 7 Aug 2008 12:26:45 +0000 Subject: xpp: preliminary CAS support. Uses newer firmware (5975) for the 1151 alone. (From r4463 in branches/1.4) git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@4467 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- xpp/card_pri.c | 371 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 291 insertions(+), 80 deletions(-) (limited to 'xpp/card_pri.c') 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); -- cgit v1.2.3