diff options
Diffstat (limited to 'xpp/card_pri.c')
-rw-r--r-- | xpp/card_pri.c | 452 |
1 files changed, 347 insertions, 105 deletions
diff --git a/xpp/card_pri.c b/xpp/card_pri.c index 1535cc2..483fc47 100644 --- a/xpp/card_pri.c +++ b/xpp/card_pri.c @@ -44,7 +44,6 @@ DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value"); #endif #define PRI_LINES_BITMASK BITMASK(31) -#define PRI_DCHAN_NUM 16 #define PRI_DCHAN_SIGCAP ( \ ZT_SIG_EM | \ ZT_SIG_CLEAR | \ @@ -82,13 +81,75 @@ enum pri_protocol { PRI_PROTO_T1 = 2, PRI_PROTO_J1 = 3 }; -static const char *pri_protocol_name[] = { - [PRI_PROTO_0] = "Unknown", - [PRI_PROTO_E1] = "E1", - [PRI_PROTO_T1] = "T1", - [PRI_PROTO_J1] = "J1" + +static const char *pri_protocol_name(enum pri_protocol pri_protocol) +{ + static const char *protocol_names[] = { + [PRI_PROTO_0] = "Unknown", + [PRI_PROTO_E1] = "E1", + [PRI_PROTO_T1] = "T1", + [PRI_PROTO_J1] = "J1" + }; + return protocol_names[pri_protocol]; +} + +static int pri_num_channels(enum pri_protocol pri_protocol) +{ + static int num_channels[] = { + [PRI_PROTO_0] = 0, + [PRI_PROTO_E1] = 31, + [PRI_PROTO_T1] = 24, + [PRI_PROTO_J1] = 0 + }; + return num_channels[pri_protocol]; +} + +static const char *type_name(enum pri_protocol pri_protocol, bool is_nt) +{ + static const char *names[2][4] = { + /* TE */ [0] = { + [PRI_PROTO_0] = "Unknown_TE", + [PRI_PROTO_E1] = "E1_TE", + [PRI_PROTO_T1] = "T1_TE", + [PRI_PROTO_J1] = "J1_TE" + }, + /* NT */ [1] = { + [PRI_PROTO_0] = "Unknown_NT", + [PRI_PROTO_E1] = "E1_NT", + [PRI_PROTO_T1] = "T1_NT", + [PRI_PROTO_J1] = "J1_NT" + } + }; + int term = (is_nt) ? 1 : 0; + + return names[term][pri_protocol]; +} + +static int pri_linecompat(enum pri_protocol pri_protocol) +{ + static const int linecompat[] = { + [PRI_PROTO_0] = 0, + [PRI_PROTO_E1] = + /* coding */ + ZT_CONFIG_CCS | + // CAS | + /* framing */ + ZT_CONFIG_AMI | ZT_CONFIG_HDB3, + [PRI_PROTO_T1] = + /* coding */ + // ZT_CONFIG_D4 | + ZT_CONFIG_ESF | + /* framing */ + ZT_CONFIG_AMI | ZT_CONFIG_B8ZS, + [PRI_PROTO_J1] = 0 }; + DBG(GENERAL, "pri_linecompat: pri_protocol=%d\n", pri_protocol); + return linecompat[pri_protocol]; +} + +#define PRI_DCHAN_IDX(priv) ((priv)->dchan_num - 1) + enum pri_led_state { PRI_LED_OFF = 0x0, PRI_LED_ON = 0x1, @@ -133,6 +194,10 @@ struct pri_leds { #define REG_LIM0_LL BIT(1) /* LL (Local Loopback) */ #define REG_FMR0 0x1C +#define REG_FMR0_E_RC0 BIT(4) /* Receive Code - LSB */ +#define REG_FMR0_E_RC1 BIT(5) /* Receive Code - MSB */ +#define REG_FMR0_E_XC0 BIT(6) /* Transmit Code - LSB */ +#define REG_FMR0_E_XC1 BIT(7) /* Transmit Code - MSB */ #define REG_FMR1 0x1D #define REG_FMR1_XAIS BIT(0) /* Transmit AIS toward transmit end */ @@ -140,22 +205,35 @@ struct pri_leds { #define REG_FMR1_ECM BIT(2) #define REG_FMR1_XFS BIT(3) #define REG_FMR1_PMOD BIT(4) /* E1 = 0, T1/J1 = 1 */ +#define REG_FMR1_EDL BIT(5) #define REG_FMR1_AFR BIT(6) #define REG_FMR2 0x1E +#define REG_FMR2_E_ALMF BIT(0) /* Automatic Loss of Multiframe */ +#define REG_FMR2_T_EXZE BIT(0) /* Excessive Zeros Detection Enable */ +#define REG_FMR2_E_AXRA BIT(1) /* Automatic Transmit Remote Alarm */ +#define REG_FMR2_T_AXRA BIT(1) /* Automatic Transmit Remote Alarm */ +#define REG_FMR2_E_PLB BIT(2) /* Payload Loop-Back */ +#define REG_FMR2_E_RFS0 BIT(6) /* Receive Framing Select - LSB */ +#define REG_FMR2_E_RFS1 BIT(7) /* Receive Framing Select - MSB */ +#define REG_FMR2_T_SSP BIT(5) /* Select Synchronization/Resynchronization Procedure */ +#define REG_FMR2_T_MCSP BIT(6) /* Multiple Candidates Synchronization Procedure */ +#define REG_FMR2_T_AFRS BIT(7) /* Automatic Force Resynchronization */ + +#define REG_FMR4 0x20 +#define REG_FMR4_FM1 BIT(1) #define REG_RC0 0x24 #define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */ -static const char pri_name_nt[] = "PRI_NT"; -static const char pri_name_te[] = "PRI_TE"; - struct PRI_priv_data { bool is_nt; struct proc_dir_entry *regfile; struct proc_dir_entry *pri_info; enum pri_protocol pri_protocol; + int deflaw; + unsigned int dchan_num; bool initialized; bool local_loopback; reg_cmd_t requested_reply; @@ -227,7 +305,7 @@ 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); + int channels = min(31, CHANNELS_PERXPD); /* worst case */ XBUS_DBG(GENERAL, xbus, "\n"); xpd = xpd_alloc(sizeof(struct PRI_priv_data), proto_table, channels); @@ -235,7 +313,10 @@ static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab return NULL; priv = xpd->priv; xpd->revision = revision; - xpd->type_name = proto_table->name; /* Default, changes in set_nt() */ + priv->pri_protocol = PRI_PROTO_0; /* Default, changes in set_pri_proto() */ + priv->deflaw = ZT_LAW_DEFAULT; /* Default, changes in set_pri_proto() */ + xpd->type_name = + type_name(priv->pri_protocol, 0); /* Default, changes in set_nt() */ return xpd; } @@ -278,9 +359,11 @@ static bool valid_pri_modes(const xpd_t *xpd) * May only be called on unregistered xpd's * (the span and channel description are set according to this) */ -static int set_pri_proto(const char *msg, xpd_t *xpd, enum pri_protocol set_proto) +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 | @@ -290,17 +373,26 @@ static int set_pri_proto(const char *msg, xpd_t *xpd, enum pri_protocol set_prot BUG_ON(!xpd); priv = xpd->priv; if(SPAN_REGISTERED(xpd)) { - XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n", - xpd->span.spanno, __FUNCTION__, msg); + XPD_NOTICE(xpd, "Registered as span %d. Cannot do setup pri protocol (%s)\n", + xpd->span.spanno, __FUNCTION__); return -EBUSY; } switch(set_proto) { case PRI_PROTO_E1: + deflaw = ZT_LAW_ALAW; + dchan_num = 16; break; case PRI_PROTO_T1: + deflaw = ZT_LAW_MULAW; + dchan_num = 24; fmr1 |= REG_FMR1_PMOD; break; case PRI_PROTO_J1: + /* + * Check all assumptions + */ + deflaw = ZT_LAW_MULAW; + dchan_num = 24; fmr1 |= REG_FMR1_PMOD; rc0 |= REG_RC0_SJR; XPD_NOTICE(xpd, "J1 is not supported yet\n"); @@ -311,7 +403,18 @@ static int set_pri_proto(const char *msg, xpd_t *xpd, enum pri_protocol set_prot return -EINVAL; } priv->pri_protocol = set_proto; - XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, pri_protocol_name[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); + priv->deflaw = deflaw; + priv->dchan_num = dchan_num; + 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), + xpd->channels, + priv->dchan_num, + priv->deflaw + ); write_subunit(xpd, REG_FMR1, fmr1); #ifdef JAPANEZE_SUPPORT if(rc0) @@ -358,9 +461,9 @@ static int set_nt(const char *msg, xpd_t *xpd, bool is_nt) return -EBUSY; } priv->is_nt = is_nt; - xpd->type_name = (is_nt) ? pri_name_nt : pri_name_te; + xpd->type_name = type_name(priv->pri_protocol, is_nt); xpd->direction = (is_nt) ? TO_PHONE : TO_PSTN; - XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, (is_nt) ? "NT" : "TE"); + XPD_DBG(SIGNAL, xpd, "%s(%s): %s %s\n", __FUNCTION__, msg, xpd->type_name, (is_nt) ? "NT" : "TE"); set_master_mode(msg, xpd, is_nt); /* by default set master-mode from NT/TE */ return 0; } @@ -388,9 +491,27 @@ static int set_localloop(const char *msg, xpd_t *xpd, bool localloop) return 0; } +#define VALID_CONFIG(bit,flg,str) [bit] = { .flags = flg, .name = str } + +static const struct { + const char *name; + const int flags; +} valid_spanconfigs[sizeof(unsigned int)*8] = { + /* These apply to T1 */ +// VALID_CONFIG(4, ZT_CONFIG_D4, "D4"), FIXME: should support + VALID_CONFIG(5, ZT_CONFIG_ESF, "ESF"), + VALID_CONFIG(6, ZT_CONFIG_AMI, "AMI"), + VALID_CONFIG(7, ZT_CONFIG_B8ZS, "B8ZS"), + /* These apply to E1 */ + VALID_CONFIG(8, ZT_CONFIG_CCS, "CCS"), + VALID_CONFIG(9, ZT_CONFIG_HDB3, "HDB3"), + VALID_CONFIG(10, ZT_CONFIG_CRC4, "CRC4"), +}; + /* * Called only for 'span' keyword in /etc/zaptel.conf */ + static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) { xpd_t *xpd = span->pvt; @@ -398,12 +519,44 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) const char *framingstr = ""; const char *codingstr = ""; const char *crcstr = ""; - const byte FMR2_PLB = 0 << 2; /* PLB (Payload Loopback) */ - byte fmr0 = 0; - byte fmr2 = 0x83 | FMR2_PLB; /* AFRS | AXRA | EXZE */ + byte fmr0 = 0; /* Dummy initilizations to */ + byte fmr2 = 0; /* silense false gcc warnings */ + byte fmr4 = 0x0C; + unsigned int bad_bits; + int i; BUG_ON(!xpd); priv = xpd->priv; + /* + * validate + */ + bad_bits = lc->lineconfig & pri_linecompat(priv->pri_protocol); + bad_bits = bad_bits ^ lc->lineconfig; + for(i = 0; i < ARRAY_SIZE(valid_spanconfigs); i++) { + unsigned int flags = valid_spanconfigs[i].flags; + + if(bad_bits & BIT(i)) { + if(flags) { + XPD_ERR(xpd, + "Bad config item '%s' for %s. Ignore\n", + valid_spanconfigs[i].name, + pri_protocol_name(priv->pri_protocol)); + } else { + /* we got real garbage */ + XPD_ERR(xpd, + "Unknown config item 0x%X for %s. Ignore\n", + BIT(i), + pri_protocol_name(priv->pri_protocol)); + } + } + if(flags && flags != BIT(i)) { + ERR("%s: BUG: i=%d flags=0x%X\n", + __FUNCTION__, i, flags); + // BUG(); + } + } + if(bad_bits) + goto bad_lineconfig; if(lc->span != xpd->span.spanno) { XPD_ERR(xpd, "I am span %d but got spanconfig for span %d\n", xpd->span.spanno, lc->span); @@ -413,29 +566,43 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) * FIXME: lc->name is unused by ztcfg and zaptel... * We currently ignore it also. */ + if(priv->pri_protocol == PRI_PROTO_E1) + fmr2 = REG_FMR2_E_AXRA | REG_FMR2_E_ALMF; /* 0x03 */ + else if(priv->pri_protocol == PRI_PROTO_T1) + fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */ + else if(priv->pri_protocol == PRI_PROTO_J1) { + XPD_ERR(xpd, "J1 unsupported yet\n"); + return -ENOSYS; + } if(priv->local_loopback) - fmr2 |= 0x4; + fmr2 |= REG_FMR2_E_PLB; /* framing first */ - if (lc->lineconfig & ZT_CONFIG_B8ZS) + if (lc->lineconfig & ZT_CONFIG_B8ZS) { framingstr = "B8ZS"; - else if (lc->lineconfig & ZT_CONFIG_AMI) { + fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0; + } else if (lc->lineconfig & ZT_CONFIG_AMI) { framingstr = "AMI"; - fmr0 = 0xA0; + fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_RC1; } else if (lc->lineconfig & ZT_CONFIG_HDB3) { framingstr = "HDB3"; - fmr0 = 0xF0; - fmr2 |= 0xc0; /* CRC4 receive */ /* FIXME: move bellow to condition on CRC4? */ + fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0; } /* then coding */ - if (lc->lineconfig & ZT_CONFIG_ESF) + if (lc->lineconfig & ZT_CONFIG_ESF) { codingstr = "ESF"; - else if (lc->lineconfig & ZT_CONFIG_D4) + fmr4 |= REG_FMR4_FM1; + fmr2 |= REG_FMR2_T_AXRA | REG_FMR2_T_MCSP | REG_FMR2_T_SSP; + } else if (lc->lineconfig & ZT_CONFIG_D4) { codingstr = "D4"; - else if (lc->lineconfig & ZT_CONFIG_CCS) + } else if (lc->lineconfig & ZT_CONFIG_CCS) { codingstr = "CCS"; + /* do nothing */ + } /* E1's can enable CRC checking */ - if (lc->lineconfig & ZT_CONFIG_CRC4) + if (lc->lineconfig & ZT_CONFIG_CRC4) { crcstr = "CRC4"; + fmr2 |= REG_FMR2_E_RFS1; + } XPD_DBG(GENERAL, xpd, "[%s] lbo=%d lineconfig=%s/%s/%s %s (0x%X) sync=%d\n", (priv->is_nt)?"NT":"TE", lc->lbo, @@ -443,20 +610,22 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) (lc->lineconfig & ZT_CONFIG_NOTOPEN)?"YELLOW":"", lc->lineconfig, lc->sync); - /* - * FIXME: validate - */ span->lineconfig = lc->lineconfig; xpd->timing_priority = lc->sync; 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); XPD_DBG(GENERAL, xpd, "%s: fmr2(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR2, fmr2); write_subunit(xpd, REG_FMR2, fmr2); set_master_mode("spanconfig", xpd, xpd->timing_priority == 0); elect_syncer("PRI-master_mode"); return 0; +bad_lineconfig: + XPD_ERR(xpd, "Bad span configuration. Abort\n"); + return -EINVAL; } /* @@ -485,12 +654,6 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd) proto_table = &PROTO_TABLE(PRI); priv = xpd->priv; xpd->xops = &proto_table->xops; - /* - * wanted_pcm_mask and pcm_len: constant for PRI. All 31 channels - */ - xpd->wanted_pcm_mask = PRI_LINES_BITMASK; - xpd->pcm_len = - RPACKET_HEADERSIZE + sizeof(xpp_line_t) + 31 * ZT_CHUNKSIZE; #ifdef CONFIG_PROC_FS XPD_DBG(PROC, xpd, "Creating PRI_INFO file\n"); priv->pri_info = create_proc_entry(PROC_PRI_INFO_FNAME, 0644, xpd->proc_xpd_dir); @@ -515,6 +678,10 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd) priv->regfile->read_proc = proc_xpd_register_read; priv->regfile->data = xpd; #endif + /* Assume E1, changes later from user space */ + ret = set_pri_proto(xpd, PRI_PROTO_E1); + if(ret < 0) + goto err; ret = run_initialize_registers(xpd); if(ret < 0) goto err; @@ -526,16 +693,6 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd) XPD_NOTICE(xpd, "PRI protocol not set\n"); goto err; } - /* FIXME: now we need to fix channel number (E1/T1/J1) */ - -#if 1 -#else - /* - * FPGA firmware limitation: - * Force HOST sync *before* sending PCM - */ - CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_HOST, 0); -#endif XPD_DBG(GENERAL, xpd, "done\n"); for(ret = 0; ret < NUM_LEDS; ret++) { DO_LED(xpd, ret, PRI_LED_ON); @@ -571,16 +728,20 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on) xbus = xpd->xbus; priv = xpd->priv; BUG_ON(!xbus); - XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); + XPD_DBG(GENERAL, xpd, "%s (proto=%s, channels=%d, deflaw=%d)\n", + (on)?"on":"off", + pri_protocol_name(priv->pri_protocol), + xpd->channels, + priv->deflaw); if(!on) { /* Nothing to do yet */ return 0; } - xpd->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_CCS; - xpd->span.deflaw = ZT_LAW_ALAW; + xpd->span.linecompat = pri_linecompat(priv->pri_protocol); + xpd->span.deflaw = priv->deflaw; for_each_line(xpd, i) { struct zt_chan *cur_chan = &xpd->chans[i]; - bool is_dchan = i == PRI_DCHAN_NUM - 1; + bool is_dchan = i == PRI_DCHAN_IDX(priv); XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i, (is_dchan)?"DCHAN":"CLEAR"); @@ -595,7 +756,7 @@ static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on) } else cur_chan->sigcap = PRI_BCHAN_SIGCAP; } - xpd->offhook = PRI_LINES_BITMASK; + xpd->offhook = xpd->wanted_pcm_mask; xpd->span.spanconfig = pri_spanconfig; xpd->span.chanconfig = pri_chanconfig; xpd->span.startup = pri_startup; @@ -640,9 +801,9 @@ static void dchan_state(xpd_t *xpd, bool up) byte *pcm; if(SPAN_REGISTERED(xpd)) { - pcm = (byte *)&xpd->readchunk[(PRI_DCHAN_NUM - 1) * ZT_CHUNKSIZE]; + pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].readchunk; pcm[0] = 0x00; - pcm = (byte *)&xpd->span.chans[PRI_DCHAN_NUM - 1].writechunk; + pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].writechunk; pcm[0] = 0x00; } XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); @@ -730,7 +891,7 @@ static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd) BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); - if(!priv->initialized) + if(!priv->initialized || !xbus->self_ticking) return 0; /* * Poll layer1 status (cascade subunits) @@ -749,6 +910,26 @@ static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd) return 0; } +static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) +{ + BUG_ON(!xpd); + if(!TRANSPORT_RUNNING(xpd->xbus)) + return -ENODEV; + switch (cmd) { + case ZT_TONEDETECT: + /* + * Asterisk call all span types with this (FXS specific) + * call. Silently ignore it. + */ + LINE_DBG(SIGNAL, xpd, pos, "PRI: Starting a call\n"); + return -ENOTTY; + default: + report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); + return -ENOTTY; + } + return 0; +} + static int PRI_card_close(xpd_t *xpd, lineno_t pos) { //struct zt_chan *chan = &xpd->span.chans[pos]; @@ -767,7 +948,7 @@ static int pri_startup(struct zt_span *span) BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); - if(!xpd->xbus->hardware_exists) { + if(!TRANSPORT_RUNNING(xpd->xbus)) { XPD_DBG(GENERAL, xpd, "Startup called by zaptel. No Hardware. Ignored\n"); return -ENODEV; } @@ -788,7 +969,7 @@ static int pri_shutdown(struct zt_span *span) BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); - if(!xpd->xbus->hardware_exists) { + if(!TRANSPORT_RUNNING(xpd->xbus)) { XPD_DBG(GENERAL, xpd, "Shutdown called by zaptel. No Hardware. Ignored\n"); return -ENODEV; } @@ -816,22 +997,34 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp struct zt_chan *chans; unsigned long flags; int i; + int physical_chan; + int physical_mask = 0; BUG_ON(!xbus); BUG_ON(!xpd); BUG_ON(!pack); priv = xpd->priv; BUG_ON(!priv); - /* Shift channel numbers to be 1-31 rather than 0-30. It only - * takes setting the mask: */ - RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines << 1; pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); chans = xpd->span.chans; + physical_chan = 0; for_each_line(xpd, i) { + if(priv->pri_protocol == PRI_PROTO_E1) { + /* In E1 - Only 0'th channel is unused */ + if(i == 0) { + physical_chan++; + } + } else if(priv->pri_protocol == PRI_PROTO_T1) { + /* In T1 - Every 4'th channel is unused */ + if((i % 4) == 0) { + physical_chan++; + } + } if(IS_SET(lines, i)) { + physical_mask |= BIT(physical_chan); if(SPAN_REGISTERED(xpd)) { - if(i == PRI_DCHAN_NUM - 1) { + 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++; @@ -849,7 +1042,9 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; } + physical_chan++; } + RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = physical_mask; XPD_COUNTER(xpd, PCM_WRITE)++; spin_unlock_irqrestore(&xpd->lock, flags); } @@ -867,39 +1062,55 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; - volatile u_char *r; byte *pcm; - xpp_line_t pcm_mask; + struct zt_chan *chans; + xpp_line_t physical_mask; unsigned long flags; int i; + int logical_chan; + if(!SPAN_REGISTERED(xpd)) + return; priv = xpd->priv; BUG_ON(!priv); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); - pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); - /* The mask is shifted. make it zero-based again. */ - pcm_mask = (pcm_mask >> 1) & PRI_LINES_BITMASK; + physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); spin_lock_irqsave(&xpd->lock, flags); - if (xpd->timer_count & 1) { - /* First part */ - r = xpd->readchunk; - } else { - r = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD; - } - for (i = 0; i < CHANNELS_PERXPD; i++, r += ZT_CHUNKSIZE) { - if(IS_SET(pcm_mask, i)) { + chans = xpd->span.chans; + logical_chan = 0; + for (i = 0; i < CHANNELS_PERXPD; i++) { + volatile u_char *r; + + if(priv->pri_protocol == PRI_PROTO_E1) { + /* In E1 - Only 0'th channel is unused */ + if(i == 0) + continue; + } else if(priv->pri_protocol == PRI_PROTO_T1) { + /* In T1 - Every 4'th channel is unused */ + if((i % 4) == 0) + continue; + } + if(logical_chan == PRI_DCHAN_IDX(priv)) { + if(priv->dchan_rx_sample != pcm[0]) { + if(print_dbg & DBG_PCM) { + XPD_INFO(xpd, "RX-D-Chan: prev=0x%X now=0x%X\n", + priv->dchan_rx_sample, pcm[0]); + dump_packet("RX-D-Chan", pack, 1); + } + priv->dchan_rx_sample = pcm[0]; + priv->dchan_rx_counter++; + } else if(pcm[0] == 0xFF) + dchan_state(xpd, 0); + } + if(IS_SET(physical_mask, i)) { + r = chans[logical_chan].readchunk; // memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG // fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP memcpy((u_char *)r, pcm, ZT_CHUNKSIZE); pcm += ZT_CHUNKSIZE; } + logical_chan++; } - pcm = (byte *)&xpd->readchunk[(PRI_DCHAN_NUM - 1) * ZT_CHUNKSIZE]; - if(priv->dchan_rx_sample != pcm[0]) { - priv->dchan_rx_sample = pcm[0]; - priv->dchan_rx_counter++; - } else if(pcm[0] == 0xFF) - dchan_state(xpd, 0); XPD_COUNTER(xpd, PCM_READ)++; spin_unlock_irqrestore(&xpd->lock, flags); } @@ -938,7 +1149,7 @@ static /* 0x0F */ HOSTCMD(PRI, RELAY_OUT, byte which, bool on) priv = xpd->priv; BUG_ON(!priv); XPD_DBG(LEDS, xpd, "led_sel=%d to_state=%d\n", led_sel, to_led_state); - XFRAME_NEW(xframe, pack, xbus, PRI, SET_LED, xpd->xbus_idx); + XFRAME_NEW_CMD(xframe, pack, xbus, PRI, SET_LED, xpd->xbus_idx); pri_leds = &RPACKET_FIELD(pack, PRI, SET_LED, pri_leds); pri_leds->state = to_led_state; pri_leds->led_sel = led_sel; @@ -1031,6 +1242,7 @@ static xproto_table_t PROTO_TABLE(PRI) = { .card_tick = PRI_card_tick, .card_pcm_fromspan = PRI_card_pcm_fromspan, .card_pcm_tospan = PRI_card_pcm_tospan, + .card_ioctl = PRI_card_ioctl, .card_close = PRI_card_close, .card_register_reply = PRI_card_register_reply, @@ -1065,6 +1277,13 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns char *tok; static const char *msg = "PROC"; /* for logs */ int ret = 0; + bool got_localloop = 0; + bool got_nolocalloop = 0; + bool got_te = 0; + bool got_nt = 0; + bool got_e1 = 0; + bool got_t1 = 0; + bool got_j1 = 0; if(!xpd) return -ENODEV; @@ -1079,30 +1298,52 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns } buf[count] = '\0'; XPD_DBG(PROC, xpd, "PRI-SETUP: got %s\n", buf); + /* + * First parse. Act only of *everything* is good. + */ p = buf; while((tok = strsep(&p, " \t\v\n")) != NULL) { if(*tok == '\0') continue; XPD_DBG(PROC, xpd, "Got token='%s'\n", tok); if(strnicmp(tok, "LOCALLOOP", 8) == 0) - ret = set_localloop(msg, xpd, 1); + got_localloop = 1; else if(strnicmp(tok, "NOLOCALLOOP", 8) == 0) - ret = set_localloop(msg, xpd, 0); + got_nolocalloop = 1; else if(strnicmp(tok, "NT", 2) == 0) - ret = set_nt(msg, xpd, 1); + got_nt = 1; else if(strnicmp(tok, "TE", 2) == 0) - ret = set_nt(msg, xpd, 0); + got_te = 1; else if(strnicmp(tok, "E1", 2) == 0) - ret = set_pri_proto(msg, xpd, PRI_PROTO_E1); + got_e1 = 1; else if(strnicmp(tok, "T1", 2) == 0) - ret = set_pri_proto(msg, xpd, PRI_PROTO_T1); + got_t1 = 1; else if(strnicmp(tok, "J1", 2) == 0) { - ret = set_pri_proto(msg, xpd, PRI_PROTO_J1); + got_j1 = 1; } else { XPD_NOTICE(xpd, "PRI-SETUP: unknown keyword: '%s'\n", tok); return -EINVAL; } } + if(got_e1) + ret = set_pri_proto(xpd, PRI_PROTO_E1); + else if(got_t1) + ret = set_pri_proto(xpd, PRI_PROTO_T1); + else if(got_j1) + ret = set_pri_proto(xpd, PRI_PROTO_J1); + if(priv->pri_protocol == PRI_PROTO_0) { + XPD_ERR(xpd, + "Must set PRI protocol (E1/T1/J1) before setting other parameters\n"); + return -EINVAL; + } + if(got_localloop) + ret = set_localloop(msg, xpd, 1); + if(got_nolocalloop) + ret = set_localloop(msg, xpd, 0); + if(got_nt) + ret = set_nt(msg, xpd, 1); + if(got_te) + ret = set_nt(msg, xpd, 0); return (ret) ? ret : count; } @@ -1121,10 +1362,11 @@ static int proc_pri_info_read(char *page, char **start, off_t off, int count, in spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); - len += sprintf(page + len, "PRI: %s %s%s\n", + len += sprintf(page + len, "PRI: %s %s%s (deflaw=%d, dchan=%d)\n", (priv->is_nt) ? "NT" : "TE", - pri_protocol_name[priv->pri_protocol], - (priv->local_loopback) ? " LOCALLOOP" : ""); + pri_protocol_name(priv->pri_protocol), + (priv->local_loopback) ? " LOCALLOOP" : "", + priv->deflaw, priv->dchan_num); len += sprintf(page + len, "%05d Layer1: ", priv->layer1_replies); if(priv->poll_noreplies > 1) len += sprintf(page + len, "No Replies [%d]\n", @@ -1199,7 +1441,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) char *p; reg_cmd_t regcmd; xbus_t *xbus; - int ret; + int ret = -EINVAL; struct PRI_priv_data *priv; byte buf[MAX_PROC_WRITE]; @@ -1215,7 +1457,10 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) ; if(*p == '\0') return 0; - + if(!XBUS_GET(xbus)) { + XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n"); + return -EBUSY; + } memset(buf, 0, MAX_PROC_WRITE); elements = sscanf(cmdline, "%d %c%c %x %x %x %x %x", &chipsel, @@ -1225,11 +1470,11 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) XPD_DBG(PROC, xpd, "'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, subreg, data); if(elements < 3) { // At least: chipsel, op, reg_type, reg_num ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline); - return -EINVAL; + goto out; } if(!VALID_CHIPSEL(chipsel)) { ERR("Bad chip select number: %d\n", chipsel); - return -EINVAL; + goto out; } REG_FIELD(®cmd, chipsel) = chipsel; switch(op) { @@ -1241,7 +1486,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) break; default: ERR("Unkown operation type '%c'\n", op); - return -EINVAL; + goto out; } if( (op == 'W' && reg_type == 'D' && elements != 5) || @@ -1252,7 +1497,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) ERR("Bad number of elements: '%s' (%d elements): %d %c%c %02X %02X %02X\n", cmdline, elements, chipsel, op, reg_type, reg_num, subreg, data); - return -EINVAL; + goto out; } switch(reg_type) { case 'S': @@ -1271,15 +1516,11 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) break; default: ERR("Unkown register type '%c'\n", reg_type); - return -EINVAL; + goto out; } regcmd.bytes = sizeof(regcmd) - 1; REG_FIELD(®cmd, read_request) = writing; REG_FIELD(®cmd, data_high) = 0; - if(!down_read_trylock(&xbus->in_use)) { - XBUS_DBG(GENERAL, xbus, "Dropped packet. Is in_use\n"); - return -EBUSY; - } priv->requested_reply = regcmd; if(print_dbg) dump_reg_cmd("PRI", ®cmd, 1); @@ -1291,7 +1532,8 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) REG_FIELD(®cmd, subreg), REG_FIELD(®cmd, data_low), REG_FIELD(®cmd, data_high)); - up_read(&xbus->in_use); +out: + XBUS_PUT(xbus); return ret; } |