diff options
Diffstat (limited to 'drivers/dahdi/xpp/card_pri.c')
-rw-r--r-- | drivers/dahdi/xpp/card_pri.c | 363 |
1 files changed, 295 insertions, 68 deletions
diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c index e83044d..990fc0b 100644 --- a/drivers/dahdi/xpp/card_pri.c +++ b/drivers/dahdi/xpp/card_pri.c @@ -53,7 +53,7 @@ static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in DAHDI_SIG_DACS | \ DAHDI_SIG_SF \ ) -#define PRI_BCHAN_SIGCAP (DAHDI_SIG_CLEAR | DAHDI_SIG_DACS) +#define PRI_BCHAN_SIGCAP (DAHDI_SIG_CLEAR | DAHDI_SIG_DACS | DAHDI_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 dahdi_span *span); static int pri_shutdown(struct dahdi_span *span); +static int pri_rbsbits(struct dahdi_chan *chan, int bits); static int pri_lineconfig(xpd_t *xpd, int lineconfig); #define PROC_REGISTER_FNAME "slics" @@ -119,7 +120,6 @@ static int pri_linecompat(enum pri_protocol pri_protocol) [PRI_PROTO_E1] = /* coding */ DAHDI_CONFIG_CCS | - // CAS | DAHDI_CONFIG_CRC4 | /* framing */ DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3, @@ -186,6 +186,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 */ @@ -196,7 +199,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) @@ -213,8 +216,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 @@ -222,7 +245,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 */ @@ -232,6 +255,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 clock_source; struct proc_dir_entry *pri_info; @@ -239,6 +281,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; @@ -381,6 +427,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 * DAHDI_CHUNKSIZE; + xpd->wanted_pcm_mask = mask; +} + /* * Set E1/T1/J1 * May only be called on unregistered xpd's @@ -391,12 +453,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); @@ -406,6 +463,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 = DAHDI_LAW_ALAW; @@ -416,7 +483,6 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) deflaw = DAHDI_LAW_MULAW; dchan_num = 24; default_lineconfig = DAHDI_CONFIG_ESF | DAHDI_CONFIG_B8ZS; - fmr1 |= REG_FMR1_PMOD; break; case PRI_PROTO_J1: /* @@ -424,8 +490,6 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) */ deflaw = DAHDI_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; @@ -436,10 +500,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 * DAHDI_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); XPD_DBG(GENERAL, xpd, "%s, channels=%d, dchan_num=%d, deflaw=%d\n", pri_protocol_name(set_proto), @@ -447,11 +511,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. @@ -478,7 +537,7 @@ static void dahdi_update_syncsrc(xpd_t *xpd) if(!subxpd) continue; priv = subxpd->priv; - if(priv->clock_source) { + if(priv->clock_source && priv->alarms == 0) { if(best_spanno) XPD_ERR(xpd, "Duplicate XPD's with clock_source=1\n"); best_spanno = subxpd->span.spanno; @@ -556,6 +615,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 /etc/dahdi/system.conf * If this is called by dahdi_cfg, than it's too late to change @@ -566,28 +648,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; } @@ -632,9 +697,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 = 0; unsigned int bad_bits; int i; @@ -673,10 +747,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; @@ -693,36 +771,65 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig) } 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; + } else { + XPD_NOTICE(xpd, "Bad lineconfig. Not (B8ZS|AMI|HDB3). Ignored.\n"); + return -EINVAL; } /* then coding */ 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; } 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; } + pri_pcm_update(xpd); /* E1's can enable CRC checking */ if (lineconfig & DAHDI_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->clock_source)?"MASTER":"SLAVE", framingstr, codingstr, crcstr, (lineconfig & DAHDI_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"); @@ -781,7 +888,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); @@ -795,10 +901,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); @@ -812,9 +914,19 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd) xproto_table_t *proto_table; BUG_ON(!xpd); + XPD_DBG(GENERAL, xpd, "\n"); 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. @@ -884,7 +996,7 @@ 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; - if(is_dchan) { /* D-CHAN */ + 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; @@ -896,6 +1008,7 @@ static int PRI_card_dahdi_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; } @@ -1117,6 +1230,57 @@ static int pri_shutdown(struct dahdi_span *span) return 0; } +static int pri_rbsbits(struct dahdi_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. @@ -1162,22 +1326,25 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp if(IS_SET(lines, i)) { physical_mask |= BIT(physical_chan); if(SPAN_REGISTERED(xpd)) { +#ifdef DEBUG_PCMTX + int channo = xpd->span.chans[i]->channo; + + if(pcmtx >= 0 && pcmtx_chan == channo) + memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); + else +#endif + memcpy((u_char *)pcm, chans[i]->writechunk, DAHDI_CHUNKSIZE); if(i == PRI_DCHAN_IDX(priv)) { if(priv->dchan_tx_sample != chans[i]->writechunk[0]) { priv->dchan_tx_sample = chans[i]->writechunk[0]; priv->dchan_tx_counter++; } 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) - memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); - else -#endif - memcpy((u_char *)pcm, chans[i]->writechunk, DAHDI_CHUNKSIZE); - // fill_beep((u_char *)pcm, xpd->addr.subunit, 2); } else - memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); + memset((u_char *)pcm, DAHDI_XLAW(0, chans[i]), DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } physical_chan++; @@ -1228,7 +1395,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", @@ -1243,7 +1410,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) if(IS_SET(physical_mask, i)) { r = chans[logical_chan]->readchunk; // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG - // fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } @@ -1333,17 +1499,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) + dahdi_rbsbits(xpd->span.chans[chan1], new1); + if(old2 != new2) + dahdi_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; @@ -1360,10 +1568,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) && @@ -1524,6 +1737,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); |