diff options
-rw-r--r-- | drivers/dahdi/xpp/card_bri.c | 146 | ||||
-rw-r--r-- | drivers/dahdi/xpp/card_fxo.c | 190 | ||||
-rw-r--r-- | drivers/dahdi/xpp/card_fxs.c | 134 | ||||
-rw-r--r-- | drivers/dahdi/xpp/card_global.c | 4 | ||||
-rw-r--r-- | drivers/dahdi/xpp/card_pri.c | 47 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_1_30 | 2 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_2_30 | 2 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_3_30 | 2 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_4_30 | 2 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.c | 67 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.h | 3 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-pcm.c | 235 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-pcm.h | 6 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-sysfs.c | 91 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpd.h | 10 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpp_dahdi.c | 123 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpp_dahdi.h | 6 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpp_usb.c | 2 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xproto.c | 1 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xproto.h | 3 |
20 files changed, 618 insertions, 458 deletions
diff --git a/drivers/dahdi/xpp/card_bri.c b/drivers/dahdi/xpp/card_bri.c index 571a10f..07d5614 100644 --- a/drivers/dahdi/xpp/card_bri.c +++ b/drivers/dahdi/xpp/card_bri.c @@ -208,7 +208,6 @@ struct BRI_priv_data { bool reg30_good; uint reg30_ticks; bool layer1_up; - xpp_line_t card_pcm_mask; /* * D-Chan: buffers + extra state info. @@ -460,8 +459,8 @@ static int rx_dchan(xpd_t *xpd, reg_cmd_t *regcmd) #ifdef XPP_DEBUGFS xbus_log(xbus, xpd, 0, regcmd, sizeof(reg_cmd_t)); /* 0 = RX */ #endif - dchan = xpd->span.chans[2]; - if(!IS_SET(xpd->offhook, 2)) { /* D-chan is used? */ + dchan = XPD_CHAN(xpd, 2); + if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */ static int rate_limit; if((rate_limit++ % 1000) == 0) @@ -525,7 +524,7 @@ out: static int tx_dchan(xpd_t *xpd) { struct BRI_priv_data *priv; - struct dahdi_chan *dchan; + struct dahdi_chan *dchan; int len; int eoframe; int ret; @@ -534,7 +533,7 @@ static int tx_dchan(xpd_t *xpd) BUG_ON(!priv); if(!SPAN_REGISTERED(xpd) || !(xpd->span.flags & DAHDI_FLAG_RUNNING)) return 0; - dchan = xpd->chans[2]; + dchan = XPD_CHAN(xpd, 2); len = dchan->bytes2transmit; /* dchan's hdlc package len */ eoframe = dchan->eoftx; /* dchan's end of frame */ dchan->bytes2transmit = 0; @@ -561,6 +560,7 @@ static int tx_dchan(xpd_t *xpd) priv->txframe_begin = 1; else priv->txframe_begin = 0; + XPD_DBG(COMMANDS, xpd, "eoframe=%d len=%d\n", eoframe, len); ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, xpd->addr.subunit, eoframe, priv->dchan_tbuf, len); if(ret < 0) @@ -657,9 +657,6 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct BRI_priv_data *priv; - xpp_line_t tmp_pcm_mask; - int tmp_pcm_len; - unsigned long flags; int i; BUG_ON(!xpd); @@ -676,7 +673,7 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on) xpd->span.deflaw = DAHDI_LAW_ALAW; BIT_SET(xpd->digital_signalling, 2); /* D-Channel */ for_each_line(xpd, i) { - struct dahdi_chan *cur_chan = xpd->chans[i]; + struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d", @@ -701,35 +698,11 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on) } else cur_chan->sigcap = BRI_BCHAN_SIGCAP; } - xpd->offhook = BIT(0) | BIT(1); /* 2*bchan */ - - /* - * Compute PCM lentgh and mask - * We know all cards have been initialized until now - */ - tmp_pcm_mask = 0; - if(xpd->addr.subunit == 0) { - int line_count = 0; - - for(i = 0; i < MAX_SUBUNIT; i++) { - xpd_t *sub_xpd = xpd_byaddr(xbus, xpd->addr.unit, i); - if(sub_xpd) { - tmp_pcm_mask |= PCM_SHIFT(sub_xpd->wanted_pcm_mask, i); - line_count += 2; - } - } - tmp_pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE; - } else - tmp_pcm_len = 0; - spin_lock_irqsave(&xpd->lock, flags); - xpd->pcm_len = tmp_pcm_len; - xpd->wanted_pcm_mask = xpd->offhook; - priv->card_pcm_mask = tmp_pcm_mask; + CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0); xpd->span.spanconfig = bri_spanconfig; xpd->span.chanconfig = bri_chanconfig; xpd->span.startup = bri_startup; xpd->span.shutdown = bri_shutdown; - spin_unlock_irqrestore(&xpd->lock, flags); return 0; } @@ -939,15 +912,38 @@ static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a return 0; } +static int BRI_card_open(xpd_t *xpd, lineno_t pos) +{ + struct BRI_priv_data *priv; + + BUG_ON(!xpd); + priv = xpd->priv; + if(pos == 2) { + LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK the whole span\n"); + BIT_SET(xpd->offhook_state, 0); + BIT_SET(xpd->offhook_state, 1); + BIT_SET(xpd->offhook_state, 2); + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); + } + return 0; +} + static int BRI_card_close(xpd_t *xpd, lineno_t pos) { - struct dahdi_chan *chan = xpd->span.chans[pos]; + struct dahdi_chan *chan = XPD_CHAN(xpd, pos); /* Clear D-Channel pending data */ chan->bytes2receive = 0; chan->eofrx = 0; chan->bytes2transmit = 0; chan->eoftx = 0; + if(pos == 2) { + LINE_DBG(SIGNAL, xpd, pos, "ONHOOK the whole span\n"); + BIT_CLR(xpd->offhook_state, 0); + BIT_CLR(xpd->offhook_state, 1); + BIT_CLR(xpd->offhook_state, 2); + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); + } return 0; } @@ -1014,7 +1010,7 @@ static int bri_startup(struct dahdi_span *span) { xpd_t *xpd = span->pvt; struct BRI_priv_data *priv; - struct dahdi_chan *dchan; + struct dahdi_chan *dchan; BUG_ON(!xpd); priv = xpd->priv; @@ -1027,7 +1023,7 @@ static int bri_startup(struct dahdi_span *span) // Turn on all channels CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); if(SPAN_REGISTERED(xpd)) { - dchan = span->chans[2]; + dchan = XPD_CHAN(xpd, 2); span->flags |= DAHDI_FLAG_RUNNING; /* * Dahdi (wrongly) assume that D-Channel need HDLC decoding @@ -1062,14 +1058,74 @@ static int bri_shutdown(struct dahdi_span *span) return 0; } -static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_lines, xpacket_t *pack) +void BRI_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t dont_care) +{ + int i; + int line_count; + xpp_line_t pcm_mask; + xpd_t *main_xpd; + unsigned long flags; + + BUG_ON(!xpd); + main_xpd = xpd_byaddr(xbus, xpd->addr.unit, 0); + if(!main_xpd) { + XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n"); + return; + } + /* + * We calculate all subunits, so use the main lock + * as a mutex for the whole operation. + */ + spin_lock_irqsave(&main_xpd->lock_recompute_pcm, flags); + line_count = 0; + pcm_mask = 0; + for(i = 0; i < MAX_SUBUNIT; i++) { + xpd_t *sub_xpd = xpd_byaddr(xbus, main_xpd->addr.unit, i); + + if(sub_xpd) { + xpp_line_t lines = + sub_xpd->offhook_state & ~sub_xpd->digital_signalling; + + if(lines) { + pcm_mask |= PCM_SHIFT(lines, i); + line_count += 2; + } + /* subunits have fake pcm_len and wanted_pcm_mask */ + if(i > 0) { + sub_xpd->pcm_len = 0; + sub_xpd->wanted_pcm_mask = lines; + } + } + } + /* + * FIXME: Workaround a bug in sync code of the Astribank. + * Send dummy PCM for sync. + */ + if(main_xpd->addr.unit == 0 && line_count == 0) { + pcm_mask = BIT(0); + line_count = 1; + } + /* + * The main unit account for all subunits (pcm_len and wanted_pcm_mask). + */ + main_xpd->pcm_len = (line_count) + ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE + : 0L; + main_xpd->wanted_pcm_mask = pcm_mask; + XPD_DBG(SIGNAL, main_xpd, "pcm_len=%d wanted_pcm_mask=0x%X (%s)\n", + main_xpd->pcm_len, main_xpd->wanted_pcm_mask, + xpd->xpdname); + spin_unlock_irqrestore(&main_xpd->lock_recompute_pcm, flags); +} + +static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { byte *pcm; - struct dahdi_chan **chans; unsigned long flags; int i; int subunit; xpp_line_t pcm_mask = 0; + xpp_line_t wanted_lines; BUG_ON(!xbus); @@ -1083,18 +1139,20 @@ static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_li if(!tmp_xpd || !tmp_xpd->card_present) continue; spin_lock_irqsave(&tmp_xpd->lock, flags); - chans = tmp_xpd->span.chans; + wanted_lines = tmp_xpd->wanted_pcm_mask; for_each_line(tmp_xpd, i) { + struct dahdi_chan *chan = XPD_CHAN(tmp_xpd, i); + if(IS_SET(wanted_lines, i)) { if(SPAN_REGISTERED(tmp_xpd)) { #ifdef DEBUG_PCMTX - int channo = tmp_xpd->span.chans[i]->channo; + int channo = chan->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); + memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); } else memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; @@ -1138,7 +1196,7 @@ static void BRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) volatile u_char *r; if(IS_SET(tmp_mask, i)) { - r = tmp_xpd->span.chans[i]->readchunk; + r = XPD_CHAN(tmp_xpd, i)->readchunk; // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; @@ -1391,9 +1449,11 @@ static xproto_table_t PROTO_TABLE(BRI) = { .card_dahdi_postregistration = BRI_card_dahdi_postregistration, .card_hooksig = BRI_card_hooksig, .card_tick = BRI_card_tick, + .card_pcm_recompute = BRI_card_pcm_recompute, .card_pcm_fromspan = BRI_card_pcm_fromspan, .card_pcm_tospan = BRI_card_pcm_tospan, .card_ioctl = BRI_card_ioctl, + .card_open = BRI_card_open, .card_close = BRI_card_close, .card_register_reply = BRI_card_register_reply, diff --git a/drivers/dahdi/xpp/card_fxo.c b/drivers/dahdi/xpp/card_fxo.c index d56382e..61ea204 100644 --- a/drivers/dahdi/xpp/card_fxo.c +++ b/drivers/dahdi/xpp/card_fxo.c @@ -40,6 +40,8 @@ static DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval #endif static DEF_PARM(int, ring_debounce, 50, 0644, "Number of ticks to debounce a false RING indication"); static DEF_PARM(int, caller_id_style, 0, 0444, "Caller-Id detection style: 0 - [BELL], 1 - [ETSI_FSK], 2 - [ETSI_DTMF]"); +static DEF_PARM(int, power_denial_safezone, 650, 0644, "msec after offhook to ignore power-denial ( (0 - disable power-denial)"); +static DEF_PARM(int, power_denial_minlen, 80, 0644, "Minimal detected power-denial length (msec) (0 - disable power-denial)"); enum cid_style { CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */ @@ -71,8 +73,6 @@ enum fxo_leds { #define BAT_THRESHOLD 3 #define BAT_DEBOUNCE 1000 /* compensate for battery voltage fluctuation (in ticks) */ #define POWER_DENIAL_CURRENT 3 -#define POWER_DENIAL_TIME 80 /* ticks */ -#define POWER_DENIAL_SAFEZONE 100 /* ticks */ #define POWER_DENIAL_DELAY 2500 /* ticks */ /* Shortcuts */ @@ -138,10 +138,8 @@ struct FXO_priv_data { enum polarity_state polarity[CHANNELS_PERXPD]; ushort polarity_debounce[CHANNELS_PERXPD]; enum power_state power[CHANNELS_PERXPD]; - xpp_line_t maybe_power_denial; - ushort power_denial_debounce[CHANNELS_PERXPD]; ushort power_denial_delay[CHANNELS_PERXPD]; - ushort power_denial_minimum[CHANNELS_PERXPD]; + ushort power_denial_length[CHANNELS_PERXPD]; ushort power_denial_safezone[CHANNELS_PERXPD]; xpp_line_t cidfound; /* 0 - OFF, 1 - ON */ unsigned int cidtimer[CHANNELS_PERXPD]; @@ -169,14 +167,33 @@ struct FXO_priv_data { /*---------------- FXO: Static functions ----------------------------------*/ +static const char *power2str(enum power_state pw) +{ + switch(pw) { + case POWER_UNKNOWN: return "UNKOWN"; + case POWER_OFF: return "OFF"; + case POWER_ON: return "ON"; + } + return NULL; +} + +static void power_change(xpd_t *xpd, int portno, enum power_state pw) +{ + struct FXO_priv_data *priv; + + priv = xpd->priv; + LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n", + power2str(priv->power[portno]), + power2str(pw)); + priv->power[portno] = pw; +} + static void reset_battery_readings(xpd_t *xpd, lineno_t pos) { struct FXO_priv_data *priv = xpd->priv; priv->nobattery_debounce[pos] = 0; - priv->power_denial_debounce[pos] = 0; priv->power_denial_delay[pos] = 0; - BIT_CLR(priv->maybe_power_denial, pos); } static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) }; @@ -259,30 +276,15 @@ static void handle_fxo_leds(xpd_t *xpd) static void update_dahdi_ring(xpd_t *xpd, int pos, bool on) { - enum dahdi_rxsig rxsig; - BUG_ON(!xpd); - if(on) { - if(caller_id_style == CID_STYLE_BELL) { - LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n"); - BIT_CLR(xpd->cid_on, pos); - } - rxsig = DAHDI_RXSIG_RING; - } else { - if(caller_id_style == CID_STYLE_BELL) { - LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: on\n"); - BIT_SET(xpd->cid_on, pos); - } - rxsig = DAHDI_RXSIG_OFFHOOK; - } - pcm_recompute(xpd, 0); + if(caller_id_style == CID_STYLE_BELL) + oht_pcm(xpd, pos, !on); /* * We should not spinlock before calling dahdi_hooksig() as * it may call back into our xpp_hooksig() and cause * a nested spinlock scenario */ - if(SPAN_REGISTERED(xpd)) - dahdi_hooksig(xpd->chans[pos], rxsig); + notify_rxsig(xpd, pos, (on) ? DAHDI_RXSIG_RING : DAHDI_RXSIG_OFFHOOK); } static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_dahdi) @@ -343,24 +345,22 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) else MARK_OFF(priv, pos, LED_GREEN); ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value); - if(to_offhook) { - BIT_SET(xpd->offhook, pos); - } else { - BIT_CLR(xpd->offhook, pos); - } - if(caller_id_style != CID_STYLE_ETSI_DTMF) { - LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n"); - BIT_CLR(xpd->cid_on, pos); - } + mark_offhook(xpd, pos, to_offhook); + if(caller_id_style != CID_STYLE_ETSI_DTMF) + oht_pcm(xpd, pos, 0); #ifdef WITH_METERING priv->metering_count[pos] = 0; priv->metering_tone_state = 0L; DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_METERING, 0x2D); #endif reset_battery_readings(xpd, pos); /* unstable during hook changes */ - priv->power_denial_safezone[pos] = (to_offhook) ? POWER_DENIAL_SAFEZONE : 0; - if(!to_offhook) - priv->power[pos] = POWER_UNKNOWN; + if(to_offhook) { + priv->power_denial_safezone[pos] = power_denial_safezone; + } else { + power_change(xpd, pos, POWER_UNKNOWN); + priv->power_denial_length[pos] = 0; + priv->power_denial_safezone[pos] = 0; + } priv->cidtimer[pos] = xpd->timer_count; spin_unlock_irqrestore(&xpd->lock, flags); return ret; @@ -461,10 +461,11 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) for_each_line(xpd, i) { do_sethook(xpd, i, 0); priv->polarity[i] = POL_UNKNOWN; /* will be updated on next battery sample */ + priv->polarity_debounce[i] = 0; priv->battery[i] = BATTERY_UNKNOWN; /* will be updated on next battery sample */ priv->power[i] = POWER_UNKNOWN; /* will be updated on next battery sample */ if(caller_id_style == CID_STYLE_ETSI_DTMF) - BIT_SET(xpd->cid_on, i); + oht_pcm(xpd, i, 1); } XPD_DBG(GENERAL, xpd, "done\n"); for_each_line(xpd, i) { @@ -478,7 +479,7 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) do_led(xpd, i, LED_GREEN, 0); msleep(50); } - pcm_recompute(xpd, 0); + CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0); return 0; } @@ -509,7 +510,7 @@ static int FXO_card_dahdi_preregistration(xpd_t *xpd, bool on) XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); xpd->span.spantype = "FXO"; for_each_line(xpd, i) { - struct dahdi_chan *cur_chan = xpd->chans[i]; + struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); XPD_DBG(GENERAL, xpd, "setting FXO channel %d\n", i); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%02d/%1d%1d/%d", @@ -563,7 +564,6 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig /* XXX Enable hooksig for FXO XXX */ switch(txsig) { case DAHDI_TXSIG_START: - break; case DAHDI_TXSIG_OFFHOOK: ret = do_sethook(xpd, pos, 1); break; @@ -575,7 +575,6 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig txsig2str(txsig), txsig); return -EINVAL; } - pcm_recompute(xpd, 0); return ret; } @@ -592,11 +591,11 @@ static void dahdi_report_battery(xpd_t *xpd, lineno_t chan) break; case BATTERY_OFF: LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_RED\n"); - dahdi_alarm_channel(xpd->chans[chan], DAHDI_ALARM_RED); + dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_RED); break; case BATTERY_ON: LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_NONE\n"); - dahdi_alarm_channel(xpd->chans[chan], DAHDI_ALARM_NONE); + dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_NONE); break; } } @@ -626,7 +625,7 @@ static void poll_metering(xbus_t *xbus, xpd_t *xpd) int i; for_each_line(xpd, i) { - if (IS_SET(xpd->offhook, i)) + if (IS_OFFHOOK(xpd, i)) DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0); } } @@ -656,20 +655,13 @@ static void handle_fxo_power_denial(xpd_t *xpd) struct FXO_priv_data *priv; int i; + if(!power_denial_safezone) + return; /* Ignore power denials */ priv = xpd->priv; for_each_line(xpd, i) { - if(priv->power_denial_minimum[i] > 0) { - priv->power_denial_minimum[i]--; - if(priv->power_denial_minimum[i] <= 0) { - /* - * But maybe the FXS started to ring (and the firmware haven't - * detected it yet). This would cause false power denials. - * So we just flag it and schedule more ticks to wait. - */ - LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n"); - priv->power_denial_debounce[i] = 0; - BIT_SET(priv->maybe_power_denial, i); - } + if(xpd->ringing[i] || !IS_OFFHOOK(xpd, i)) { + priv->power_denial_delay[i] = 0; + continue; } if(priv->power_denial_safezone[i] > 0) { if(--priv->power_denial_safezone[i]) { @@ -678,25 +670,36 @@ static void handle_fxo_power_denial(xpd_t *xpd) */ DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0); } + continue; } - if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_SET(xpd->offhook, i)) { + if(priv->power_denial_length[i] > 0) { + priv->power_denial_length[i]--; + if(priv->power_denial_length[i] <= 0) { + /* + * But maybe the FXS started to ring (and the firmware haven't + * detected it yet). This would cause false power denials. + * So we just flag it and schedule more ticks to wait. + */ + LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n"); + priv->power_denial_delay[i] = POWER_DENIAL_DELAY; + } + continue; + } + if (priv->power_denial_delay[i] > 0) { /* * Ring detection by the firmware takes some time. * Therefore we delay our decision until we are * sure that no ring has started during this time. */ - priv->power_denial_delay[i]++; - if (priv->power_denial_delay[i] >= POWER_DENIAL_DELAY) { + priv->power_denial_delay[i]--; + if (priv->power_denial_delay[i] <= 0) { LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n"); priv->power_denial_delay[i] = 0; - BIT_CLR(priv->maybe_power_denial, i); - do_sethook(xpd, i, 0); - update_line_status(xpd, i, 0); - pcm_recompute(xpd, 0); + /* + * Let Asterisk decide what to do + */ + notify_rxsig(xpd, i, DAHDI_RXSIG_ONHOOK); } - } else { - priv->power_denial_delay[i] = 0; - BIT_CLR(priv->maybe_power_denial, i); } } } @@ -705,7 +708,7 @@ static void handle_fxo_power_denial(xpd_t *xpd) * For caller-id CID_STYLE_ETSI_DTMF: * - No indication is passed before the CID * - We try to detect it and send "fake" polarity reversal. - * - The zapata.conf should have cidstart=polarity + * - The chan_dahdi.conf should have cidstart=polarity * - Based on an idea in http://bugs.digium.com/view.php?id=9096 */ static void check_etsi_dtmf(xpd_t *xpd) @@ -721,7 +724,7 @@ static void check_etsi_dtmf(xpd_t *xpd) timer_count = xpd->timer_count; for_each_line(xpd, portno) { /* Skip offhook and ringing ports */ - if(IS_SET(xpd->offhook, portno) || xpd->ringing[portno]) + if(IS_OFFHOOK(xpd, portno) || xpd->ringing[portno]) continue; if(IS_SET(priv->cidfound, portno)) { if(timer_count > priv->cidtimer[portno] + 4000) { @@ -733,7 +736,7 @@ static void check_etsi_dtmf(xpd_t *xpd) continue; } if(timer_count > priv->cidtimer[portno] + 400) { - struct dahdi_chan *chan = xpd->span.chans[portno]; + struct dahdi_chan *chan = XPD_CHAN(xpd, portno); int sample; int i; @@ -773,7 +776,6 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) return 0; } -/* FIXME: based on data from from wctdm.h */ #include <dahdi/wctdm_user.h> /* * The first register is the ACIM, the other are coefficient registers. @@ -912,8 +914,11 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) priv->battery[portno] = BATTERY_OFF; if(SPAN_REGISTERED(xpd)) dahdi_report_battery(xpd, portno); - priv->polarity[portno] = POL_UNKNOWN; /* What's the polarity ? */ - priv->power[portno] = POWER_UNKNOWN; /* What's the current ? */ + /* What's the polarity ? */ + priv->polarity[portno] = POL_UNKNOWN; + priv->polarity_debounce[portno] = 0; + /* What's the current ? */ + power_change(xpd, portno, POWER_UNKNOWN); /* * Stop further processing for now */ @@ -966,7 +971,7 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) msec = priv->polarity_debounce[portno]++ * poll_battery_interval; if (msec >= POLREV_THRESHOLD) { priv->polarity_debounce[portno] = 0; - if(pol != POL_UNKNOWN) { + if(pol != POL_UNKNOWN && priv->polarity[portno] != POL_UNKNOWN) { char *polname = NULL; if(pol == POL_POSITIVE) @@ -983,14 +988,12 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) * 2. In some countries used to report caller-id during onhook * but before first ring. */ - if(caller_id_style == CID_STYLE_ETSI_FSK) { - LINE_DBG(SIGNAL, xpd, portno, "Caller-ID PCM: on\n"); - BIT_SET(xpd->cid_on, portno); /* will be cleared on ring/offhook */ - } + if(caller_id_style == CID_STYLE_ETSI_FSK) + oht_pcm(xpd, portno, 1); /* will be cleared on ring/offhook */ if(SPAN_REGISTERED(xpd)) { LINE_DBG(SIGNAL, xpd, portno, "Send DAHDI_EVENT_POLARITY: %s\n", polname); - dahdi_qevent_lock(xpd->chans[portno], DAHDI_EVENT_POLARITY); + dahdi_qevent_lock(XPD_CHAN(xpd, portno), DAHDI_EVENT_POLARITY); } } priv->polarity[portno] = pol; @@ -1014,7 +1017,7 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno) * During ringing, current is not stable. * During onhook there should not be current anyway. */ - if(xpd->ringing[portno] || !IS_SET(xpd->offhook, portno)) + if(xpd->ringing[portno] || !IS_OFFHOOK(xpd, portno)) goto ignore_it; /* * Power denial with no battery voltage is meaningless @@ -1026,20 +1029,20 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno) goto ignore_it; if(data_low < POWER_DENIAL_CURRENT) { if(priv->power[portno] == POWER_ON) { - LINE_DBG(SIGNAL, xpd, portno, "power: ON -> OFF\n"); - priv->power[portno] = POWER_OFF; - priv->power_denial_minimum[portno] = POWER_DENIAL_TIME; + power_change(xpd, portno, POWER_OFF); + priv->power_denial_length[portno] = power_denial_minlen; } } else { - LINE_DBG(SIGNAL, xpd, portno, "power: ON\n"); - priv->power[portno] = POWER_ON; - priv->power_denial_minimum[portno] = 0; - update_line_status(xpd, portno, 1); + if(priv->power[portno] != POWER_ON) { + power_change(xpd, portno, POWER_ON); + priv->power_denial_length[portno] = 0; + /* We are now OFFHOOK */ + hookstate_changed(xpd, portno, 1); + } } return; ignore_it: - BIT_CLR(priv->maybe_power_denial, portno); - priv->power_denial_debounce[portno] = 0; + priv->power_denial_delay[portno] = 0; } #ifdef WITH_METERING @@ -1125,6 +1128,7 @@ static xproto_table_t PROTO_TABLE(FXO) = { .card_dahdi_postregistration = FXO_card_dahdi_postregistration, .card_hooksig = FXO_card_hooksig, .card_tick = FXO_card_tick, + .card_pcm_recompute = generic_card_pcm_recompute, .card_pcm_fromspan = generic_card_pcm_fromspan, .card_pcm_tospan = generic_card_pcm_tospan, .card_ioctl = FXO_card_ioctl, @@ -1242,14 +1246,6 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in curr = "."; len += sprintf(page + len, "%4s ", curr); } - len += sprintf(page + len, "\n\t%-17s: ", "maybe"); - for_each_line(xpd, i) { - len += sprintf(page + len, "%4d ", IS_SET(priv->maybe_power_denial, i)); - } - len += sprintf(page + len, "\n\t%-17s: ", "debounce"); - for_each_line(xpd, i) { - len += sprintf(page + len, "%4d ", priv->power_denial_debounce[i]); - } len += sprintf(page + len, "\n\t%-17s: ", "safezone"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->power_denial_safezone[i]); diff --git a/drivers/dahdi/xpp/card_fxs.c b/drivers/dahdi/xpp/card_fxs.c index cbd4ddd..b79dbe7 100644 --- a/drivers/dahdi/xpp/card_fxs.c +++ b/drivers/dahdi/xpp/card_fxs.c @@ -174,6 +174,21 @@ static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on) return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value); } +static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on) +{ + struct FXS_priv_data *priv; + + priv = xpd->priv; + BUG_ON(!xpd); + if(vmwineon && on) { + LINE_DBG(SIGNAL, xpd, pos, "START\n"); + BIT_SET(priv->search_fsk_pattern, pos); + } else { + LINE_DBG(SIGNAL, xpd, pos, "STOP\n"); + BIT_CLR(priv->search_fsk_pattern, pos); + } +} + /* * LED and RELAY control is done via SLIC register 0x06: * 7 6 5 4 3 2 1 0 @@ -286,7 +301,7 @@ static void restore_leds(xpd_t *xpd) priv = xpd->priv; for_each_line(xpd, i) { - if(IS_SET(xpd->offhook, i)) + if(IS_OFFHOOK(xpd, i)) MARK_ON(priv, i, LED_GREEN); else MARK_OFF(priv, i, LED_GREEN); @@ -436,7 +451,7 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd) msleep(50); } restore_leds(xpd); - pcm_recompute(xpd, 0); + CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0); /* * We should query our offhook state long enough time after we * set the linefeed_control() @@ -479,7 +494,7 @@ static int FXS_card_dahdi_preregistration(xpd_t *xpd, bool on) XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); xpd->span.spantype = "FXS"; for_each_line(xpd, i) { - struct dahdi_chan *cur_chan = xpd->chans[i]; + struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i); if(IS_SET(xpd->digital_outputs, i)) { @@ -536,19 +551,18 @@ static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit) BIT_SET(xpd->mute_dtmf, pos); else BIT_CLR(xpd->mute_dtmf, pos); + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); /* already spinlocked */ } -static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on) +static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, bool msg_waiting) { int ret = 0; BUG_ON(!xbus); BUG_ON(!xpd); - LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)"); - if (!vmwineon) - return 0; - if (on) { + if (vmwineon && msg_waiting) { /* A write to register 0x40 will now turn on/off the VM led */ + LINE_DBG(SIGNAL, xpd, pos, "NEON\n"); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00); @@ -561,6 +575,7 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on) ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46); } else { /* A write to register 0x40 will now turn on/off the ringer */ + LINE_DBG(SIGNAL, xpd, pos, "RINGER\n"); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E); @@ -572,7 +587,6 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on) ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36); } - return (ret ? -EPROTO : 0); } @@ -582,7 +596,7 @@ static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos) bool on; BUG_ON(!xpd); - if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos)) + if (IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos)) return; priv = xpd->priv; on = IS_SET(xpd->msg_waiting, pos); @@ -651,17 +665,16 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig return 0; } if(SPAN_REGISTERED(xpd)) - chan = xpd->span.chans[pos]; + chan = XPD_CHAN(xpd, pos); switch(txsig) { case DAHDI_TXSIG_ONHOOK: spin_lock_irqsave(&xpd->lock, flags); xpd->ringing[pos] = 0; - BIT_CLR(xpd->cid_on, pos); - BIT_CLR(priv->search_fsk_pattern, pos); + oht_pcm(xpd, pos, 0); + vmwi_search(xpd, pos, 0); BIT_CLR(priv->want_dtmf_events, pos); BIT_CLR(priv->want_dtmf_mute, pos); __do_mute_dtmf(xpd, pos, 0); - __pcm_recompute(xpd, 0); /* already spinlocked */ spin_unlock_irqrestore(&xpd->lock, flags); if(IS_SET(xpd->digital_outputs, pos)) { LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig)); @@ -674,11 +687,11 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig */ LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n"); linefeed_control(xbus, xpd, pos, FXS_LINE_POL_ACTIVE); - if(IS_SET(xpd->offhook, pos)) + if(IS_OFFHOOK(xpd, pos)) MARK_ON(priv, pos, LED_GREEN); } ret = send_ring(xpd, pos, 0); // RING off - if (!IS_SET(xpd->offhook, pos)) + if (!IS_OFFHOOK(xpd, pos)) start_stop_vm_led(xbus, xpd, pos); txhook = priv->lasttxhook[pos]; if(chan) { @@ -702,8 +715,7 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig } txhook = priv->lasttxhook[pos]; if(xpd->ringing[pos]) { - BIT_SET(xpd->cid_on, pos); - pcm_recompute(xpd, 0); + oht_pcm(xpd, pos, 1); txhook = FXS_LINE_OHTRANS; } xpd->ringing[pos] = 0; @@ -721,9 +733,8 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig break; case DAHDI_TXSIG_START: xpd->ringing[pos] = 1; - BIT_CLR(xpd->cid_on, pos); - BIT_CLR(priv->search_fsk_pattern, pos); - pcm_recompute(xpd, 0); + oht_pcm(xpd, pos, 0); + vmwi_search(xpd, pos, 0); if(IS_SET(xpd->digital_outputs, pos)) { LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig)); ret = relay_out(xpd, pos, 1); @@ -778,14 +789,15 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a LINE_DBG(SIGNAL, xpd, pos, "DAHDI_ONHOOKTRANSFER (%d millis)\n", val); if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos)) return 0; /* Nothing to do */ - BIT_CLR(xpd->cid_on, pos); + oht_pcm(xpd, pos, 1); /* Get ready of VMWI FSK tones */ if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) { - priv->ohttimer[pos] = OHT_TIMER; + priv->ohttimer[pos] = val; priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS; - BIT_SET(priv->search_fsk_pattern, pos); - pcm_recompute(xpd, priv->search_fsk_pattern); + vmwi_search(xpd, pos, 1); + CALL_XMETHOD(card_pcm_recompute, xbus, xpd, priv->search_fsk_pattern); + LINE_DBG(SIGNAL, xpd, pos, "Start OHT_TIMER. wanted_pcm_mask=0x%X\n", xpd->wanted_pcm_mask); } - if(!IS_SET(xpd->offhook, pos)) + if(vmwineon && !IS_OFFHOOK(xpd, pos)) start_stop_vm_led(xbus, xpd, pos); return 0; case DAHDI_TONEDETECT: @@ -804,7 +816,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a BIT_CLR(priv->want_dtmf_events, pos); BIT_CLR(priv->want_dtmf_mute, pos); __do_mute_dtmf(xpd, pos, 0); - __pcm_recompute(xpd, 0); /* already spinlocked */ spin_unlock_irqrestore(&xpd->lock, flags); return -ENOTTY; } @@ -836,7 +847,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a } else { BIT_CLR(priv->want_dtmf_mute, pos); __do_mute_dtmf(xpd, pos, 0); - __pcm_recompute(xpd, 0); } spin_unlock_irqrestore(&xpd->lock, flags); return 0; @@ -882,12 +892,10 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a static int FXS_card_open(xpd_t *xpd, lineno_t chan) { struct FXS_priv_data *priv; - bool is_offhook; BUG_ON(!xpd); priv = xpd->priv; - is_offhook = IS_SET(xpd->offhook, chan); - if(is_offhook) + if(IS_OFFHOOK(xpd, chan)) LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n"); else LINE_DBG(SIGNAL, xpd, chan, "is onhook\n"); @@ -953,10 +961,10 @@ static void handle_linefeed(xpd_t *xpd) if (priv->ohttimer[i]) { priv->ohttimer[i]--; if (!priv->ohttimer[i]) { + LINE_DBG(SIGNAL, xpd, i, "ohttimer expired\n"); priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE; - BIT_CLR(xpd->cid_on, i); - BIT_CLR(priv->search_fsk_pattern, i); - pcm_recompute(xpd, 0); + oht_pcm(xpd, i, 0); + vmwi_search(xpd, i, 0); if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) { /* Apply the change if appropriate */ linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE); @@ -992,16 +1000,23 @@ static void detect_vmwi(xpd_t *xpd) static const byte FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF }; static const byte FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F }; int i; + xpp_line_t ignore_mask; BUG_ON(!xpd); xbus = xpd->xbus; priv = xpd->priv; BUG_ON(!priv); + ignore_mask = + xpd->offhook_state | + ~xpd->oht_pcm_pass | + ~priv->search_fsk_pattern | + xpd->digital_inputs | + xpd->digital_outputs; for_each_line(xpd, i) { - struct dahdi_chan *chan = xpd->span.chans[i]; + struct dahdi_chan *chan = XPD_CHAN(xpd, i); byte *writechunk = chan->writechunk; - if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i)) + if(IS_SET(ignore_mask, i)) continue; #if 0 if(writechunk[0] != 0x7F && writechunk[0] != 0) { @@ -1016,10 +1031,12 @@ static void detect_vmwi(xpd_t *xpd) printk("\n"); } #endif - if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE))) + if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE))) { + LINE_DBG(SIGNAL, xpd, i, "Found common FSK pattern. Start looking for ON/OFF patterns.\n"); BIT_SET(priv->found_fsk_pattern, i); - else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) { + } else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) { BIT_CLR(priv->found_fsk_pattern, i); + oht_pcm(xpd, i, 0); if(unlikely(mem_equal(writechunk, FSK_ON_PATTERN, DAHDI_CHUNKSIZE))) { LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n"); BIT_SET(xpd->msg_waiting, i); @@ -1056,25 +1073,27 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd) #endif handle_fxs_leds(xpd); handle_linefeed(xpd); - if(priv->update_offhook_state) { /* set in FXS_card_open() */ - int i; + /* + * Hack alert (FIXME): + * Asterisk did FXS_card_open() and we wanted to report + * offhook state. However, the channel is spinlocked by dahdi + * so we marked it in the priv->update_offhook_state mask and + * now we take care of notification to dahdi and Asterisk + */ + if(priv->update_offhook_state) { + enum dahdi_rxsig rxsig; + int i; for_each_line(xpd, i) { if(!IS_SET(priv->update_offhook_state, i)) continue; - /* - * Update dahdi with current state of line. - */ - if(IS_SET(xpd->offhook, i)) { - update_line_status(xpd, i, 1); - } else { - update_line_status(xpd, i, 0); - } + rxsig = IS_OFFHOOK(xpd, i) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK; + notify_rxsig(xpd, i, rxsig); /* Notify after open() */ BIT_CLR(priv->update_offhook_state, i); } } if(SPAN_REGISTERED(xpd)) { - if(vmwineon && !vmwi_ioctl) + if(vmwineon && !vmwi_ioctl && priv->search_fsk_pattern) detect_vmwi(xpd); /* Detect via FSK modulation */ } return 0; @@ -1123,11 +1142,11 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_ if(IS_SET(offhook, i)) { LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n"); MARK_ON(priv, i, LED_GREEN); - update_line_status(xpd, i, 1); + hookstate_changed(xpd, i, 1); } else { LINE_DBG(SIGNAL, xpd, i, "ONHOOK\n"); MARK_OFF(priv, i, LED_GREEN); - update_line_status(xpd, i, 0); + hookstate_changed(xpd, i, 0); } /* * Must switch to low power. In high power, an ONHOOK @@ -1136,7 +1155,6 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_ do_chan_power(xbus, xpd, i, 0); } } - __pcm_recompute(xpd, 0); /* in a spinlock */ } HANDLER_DEF(FXS, SIG_CHANGED) @@ -1178,12 +1196,12 @@ static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info) BIT_CLR(lines, channo); BIT_SET(lines, newchanno); xpd->ringing[newchanno] = 0; // Stop ringing. No leds for digital inputs. - if(offhook && !IS_SET(xpd->offhook, newchanno)) { // OFFHOOK + if(offhook && !IS_OFFHOOK(xpd, newchanno)) { // OFFHOOK LINE_DBG(SIGNAL, xpd, newchanno, "OFFHOOK\n"); - update_line_status(xpd, newchanno, 1); - } else if(!offhook && IS_SET(xpd->offhook, newchanno)) { // ONHOOK + hookstate_changed(xpd, newchanno, 1); + } else if(!offhook && IS_OFFHOOK(xpd, newchanno)) { // ONHOOK LINE_DBG(SIGNAL, xpd, newchanno, "ONHOOK\n"); - update_line_status(xpd, newchanno, 0); + hookstate_changed(xpd, newchanno, 0); } } } @@ -1249,11 +1267,10 @@ static void process_dtmf(xpd_t *xpd, uint portnum, byte val) __do_mute_dtmf(xpd, portnum, 1); else __do_mute_dtmf(xpd, portnum, 0); - __pcm_recompute(xpd, 0); /* XPD is locked */ if(want_event) { int event = (key_down) ? DAHDI_EVENT_DTMFDOWN : DAHDI_EVENT_DTMFUP; - dahdi_qevent_lock(xpd->chans[portnum], event | digit); + dahdi_qevent_lock(XPD_CHAN(xpd, portnum), event | digit); } } @@ -1330,6 +1347,7 @@ static xproto_table_t PROTO_TABLE(FXS) = { .card_dahdi_postregistration = FXS_card_dahdi_postregistration, .card_hooksig = FXS_card_hooksig, .card_tick = FXS_card_tick, + .card_pcm_recompute = generic_card_pcm_recompute, .card_pcm_fromspan = generic_card_pcm_fromspan, .card_pcm_tospan = generic_card_pcm_tospan, .card_open = FXS_card_open, diff --git a/drivers/dahdi/xpp/card_global.c b/drivers/dahdi/xpp/card_global.c index a8264e4..7f7397b 100644 --- a/drivers/dahdi/xpp/card_global.c +++ b/drivers/dahdi/xpp/card_global.c @@ -374,7 +374,9 @@ static int proc_xpd_register_write(struct file *file, const char __user *buffer, XPD_NOTICE(xpd, "Failed writing command: '%s'\n", buf); return ret; } - msleep(1); /* don't overflow command queue */ + /* Don't flood command_queue */ + if(xframe_queue_count(&xpd->xbus->command_queue) > 5) + msleep(6); } return count; } diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c index e590339..3cdf3a8 100644 --- a/drivers/dahdi/xpp/card_pri.c +++ b/drivers/dahdi/xpp/card_pri.c @@ -587,7 +587,7 @@ static void set_clocking(xpd_t *xpd) xbus_t *xbus; xpd_t *best_xpd = NULL; int best_subunit = -1; /* invalid */ - int best_subunit_prio = 0; + unsigned int best_subunit_prio = INT_MAX; int i; xbus = xpd->xbus; @@ -602,7 +602,7 @@ static void set_clocking(xpd_t *xpd) priv = subxpd->priv; if(priv->alarms != 0) continue; - if(subxpd->timing_priority > best_subunit_prio) { + if(subxpd->timing_priority > 0 && subxpd->timing_priority < best_subunit_prio) { best_xpd = subxpd; best_subunit = i; best_subunit_prio = subxpd->timing_priority; @@ -1016,7 +1016,7 @@ static int PRI_card_dahdi_preregistration(xpd_t *xpd, bool on) xpd->span.linecompat = pri_linecompat(priv->pri_protocol); xpd->span.deflaw = priv->deflaw; for_each_line(xpd, i) { - struct dahdi_chan *cur_chan = xpd->chans[i]; + struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); bool is_dchan = i == PRI_DCHAN_IDX(priv); XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i, @@ -1032,7 +1032,7 @@ static int PRI_card_dahdi_preregistration(xpd_t *xpd, bool on) } else cur_chan->sigcap = PRI_BCHAN_SIGCAP; } - xpd->offhook = xpd->wanted_pcm_mask; + xpd->offhook_state = xpd->wanted_pcm_mask; xpd->span.spanconfig = pri_spanconfig; xpd->span.chanconfig = pri_chanconfig; xpd->span.startup = pri_startup; @@ -1081,9 +1081,9 @@ static void dchan_state(xpd_t *xpd, bool up) if(SPAN_REGISTERED(xpd) && d >= 0 && d < xpd->channels) { byte *pcm; - pcm = (byte *)xpd->span.chans[d]->readchunk; + pcm = (byte *)XPD_CHAN(xpd, d)->readchunk; pcm[0] = 0x00; - pcm = (byte *)xpd->span.chans[d]->writechunk; + pcm = (byte *)XPD_CHAN(xpd, d)->writechunk; pcm[0] = 0x00; } XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); @@ -1212,7 +1212,7 @@ static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a static int PRI_card_close(xpd_t *xpd, lineno_t pos) { - //struct dahdi_chan *chan = &xpd->span.chans[pos]; + //struct dahdi_chan *chan = XPD_CHAN(xpd, pos); dchan_state(xpd, 0); return 0; } @@ -1321,13 +1321,13 @@ static int pri_rbsbits(struct dahdi_chan *chan, int bits) * send 31 channels to the device, but they should be called 1-31 rather * than 0-30 . */ -static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) +static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; byte *pcm; - struct dahdi_chan **chans; unsigned long flags; int i; + xpp_line_t wanted_lines; int physical_chan; int physical_mask = 0; @@ -1338,9 +1338,11 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp BUG_ON(!priv); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); - chans = xpd->span.chans; + wanted_lines = xpd->wanted_pcm_mask; physical_chan = 0; for_each_line(xpd, i) { + struct dahdi_chan *chan = XPD_CHAN(xpd, i); + if(priv->pri_protocol == PRI_PROTO_E1) { /* In E1 - Only 0'th channel is unused */ if(i == 0) { @@ -1352,28 +1354,28 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp physical_chan++; } } - if(IS_SET(lines, i)) { + if(IS_SET(wanted_lines, i)) { physical_mask |= BIT(physical_chan); if(SPAN_REGISTERED(xpd)) { #ifdef DEBUG_PCMTX - int channo = xpd->span.chans[i]->channo; + int channo = XPD_CHAN(xpd, 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); + memcpy((u_char *)pcm, chan->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]; + if(priv->dchan_tx_sample != chan->writechunk[0]) { + priv->dchan_tx_sample = chan->writechunk[0]; priv->dchan_tx_counter++; - } else if(chans[i]->writechunk[0] == 0xFF) + } else if(chan->writechunk[0] == 0xFF) dchan_state(xpd, 0); else - chans[i]->writechunk[0] = 0xFF; /* Clobber for next tick */ + chan->writechunk[0] = 0xFF; /* Clobber for next tick */ } } else - memset((u_char *)pcm, DAHDI_XLAW(0, chans[i]), DAHDI_CHUNKSIZE); + memset((u_char *)pcm, DAHDI_XLAW(0, chan), DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } physical_chan++; @@ -1397,7 +1399,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; byte *pcm; - struct dahdi_chan **chans; xpp_line_t physical_mask; unsigned long flags; int i; @@ -1410,7 +1411,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); spin_lock_irqsave(&xpd->lock, flags); - chans = xpd->span.chans; logical_chan = 0; for (i = 0; i < CHANNELS_PERXPD; i++) { volatile u_char *r; @@ -1437,7 +1437,7 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) dchan_state(xpd, 0); } if(IS_SET(physical_mask, i)) { - r = chans[logical_chan]->readchunk; + r = XPD_CHAN(xpd, logical_chan)->readchunk; // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; @@ -1554,9 +1554,9 @@ static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low) 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); + dahdi_rbsbits(XPD_CHAN(xpd, chan1), new1); if(old2 != new2) - dahdi_rbsbits(xpd->span.chans[chan2], new2); + dahdi_rbsbits(XPD_CHAN(xpd, chan2), new2); } priv->dchan_rx_counter++; priv->cas_rs_e[pos] = data_low; @@ -1635,6 +1635,7 @@ static xproto_table_t PROTO_TABLE(PRI) = { .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, .card_pcm_tospan = PRI_card_pcm_tospan, .card_ioctl = PRI_card_ioctl, diff --git a/drivers/dahdi/xpp/init_card_1_30 b/drivers/dahdi/xpp/init_card_1_30 index 96ab2ca..fafd2c1 100755 --- a/drivers/dahdi/xpp/init_card_1_30 +++ b/drivers/dahdi/xpp/init_card_1_30 @@ -47,7 +47,7 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); -BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); } +BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; diff --git a/drivers/dahdi/xpp/init_card_2_30 b/drivers/dahdi/xpp/init_card_2_30 index 13a28cf..34f8a0b 100755 --- a/drivers/dahdi/xpp/init_card_2_30 +++ b/drivers/dahdi/xpp/init_card_2_30 @@ -47,7 +47,7 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); -BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf", "$init_dir/utils/zconf"); } +BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; diff --git a/drivers/dahdi/xpp/init_card_3_30 b/drivers/dahdi/xpp/init_card_3_30 index c06e885..3355f7b 100755 --- a/drivers/dahdi/xpp/init_card_3_30 +++ b/drivers/dahdi/xpp/init_card_3_30 @@ -60,7 +60,7 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); -BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); } +BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; diff --git a/drivers/dahdi/xpp/init_card_4_30 b/drivers/dahdi/xpp/init_card_4_30 index 1748ac2..6d56398 100755 --- a/drivers/dahdi/xpp/init_card_4_30 +++ b/drivers/dahdi/xpp/init_card_4_30 @@ -58,7 +58,7 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); -BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); } +BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c index 09d5de9..6be6f0e 100644 --- a/drivers/dahdi/xpp/xbus-core.c +++ b/drivers/dahdi/xpp/xbus-core.c @@ -68,7 +68,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e #ifdef OLD_PROC static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data); #endif -static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv); +static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv); static void transport_destroy(xbus_t *xbus); /* Data structures */ @@ -813,7 +813,11 @@ static int xbus_initialize(xbus_t *xbus) int unit; int subunit; xpd_t *xpd; + struct timeval time_start; + struct timeval time_end; + unsigned long timediff; + do_gettimeofday(&time_start); XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n", refcount_xbus(xbus)); for(unit = 0; unit < MAX_UNIT; unit++) { @@ -843,8 +847,13 @@ static int xbus_initialize(xbus_t *xbus) goto err; } } + do_gettimeofday(&time_end); + timediff = usec_diff(&time_end, &time_start); + timediff /= 1000*100; + XBUS_INFO(xbus, "Initialized in %ld.%1ld sec\n", timediff/10, timediff%10); return 0; err: + xbus_setstate(xbus, XBUS_STATE_FAIL); return -EINVAL; } @@ -909,7 +918,7 @@ void xbus_populate(void *data) * all others will reach the device before it. */ xbus_request_sync(xbus, SYNC_MODE_PLL); - elect_syncer("xbus_poll(end)"); /* FIXME: try to do it later */ + elect_syncer("xbus_populate(end)"); /* FIXME: try to do it later */ out: XBUS_DBG(DEVICES, xbus, "Leaving\n"); wake_up(&worker->wait_for_xpd_initialization); @@ -917,6 +926,7 @@ out: up(&xbus->in_worker); return; failed: + xbus_setstate(xbus, XBUS_STATE_FAIL); goto out; } @@ -1193,7 +1203,6 @@ void xbus_deactivate(xbus_t *xbus, bool is_disconnected) xpd_unreg_request(xpd); } } - elect_syncer("deactivate"); XBUS_DBG(DEVICES, xbus, "[%s] Waiting for queues\n", xbus->label); xbus_command_queue_clean(xbus); xbus_command_queue_waitempty(xbus); @@ -1202,6 +1211,7 @@ void xbus_deactivate(xbus_t *xbus, bool is_disconnected) xbus_release_xpds(xbus); if(!is_disconnected) xbus_setstate(xbus, XBUS_STATE_IDLE); + elect_syncer("deactivate"); } void xbus_disconnect(xbus_t *xbus) @@ -1305,7 +1315,7 @@ void xbus_free(xbus_t *xbus) KZFREE(xbus); } -xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv) +xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv) { int err; xbus_t *xbus = NULL; @@ -1319,7 +1329,7 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv) } snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num); XBUS_DBG(DEVICES, xbus, "\n"); - transport_init(xbus, ops, max_send_size, priv); + transport_init(xbus, ops, max_send_size, transport_device, priv); spin_lock_init(&xbus->lock); init_waitqueue_head(&xbus->command_queue_empty); init_timer(&xbus->command_timer); @@ -1378,9 +1388,9 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv) goto nobus; } #endif - xframe_queue_init(&xbus->command_queue, 10, 500, "command_queue", xbus); + xframe_queue_init(&xbus->command_queue, 10, 200, "command_queue", xbus); xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus); - xframe_queue_init(&xbus->send_pool, 10, 200, "send_pool", xbus); + xframe_queue_init(&xbus->send_pool, 10, 100, "send_pool", xbus); xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus); xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus); tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus); @@ -1505,6 +1515,21 @@ out: } +static bool xpds_done(xbus_t *xbus) +{ + struct xbus_workqueue *worker; + + if(XBUS_IS(xbus, FAIL)) + return 1; /* Nothing to wait for */ + if(!XBUS_IS(xbus, RECVD_DESC)) + return 1; /* We are not in the initialization phase */ + worker = xbus->worker; + if(worker->xpds_init_done) + return 1; /* All good */ + /* Keep waiting */ + return 0; +} + int waitfor_xpds(xbus_t *xbus, char *buf) { struct xbus_workqueue *worker; @@ -1525,19 +1550,9 @@ int waitfor_xpds(xbus_t *xbus, char *buf) "Waiting for card initialization of %d XPD's max %d seconds\n", worker->num_units, INITIALIZATION_TIMEOUT/HZ); - /* - * when polling is finished xbus_poll(): - * - Unset worker->is_polling - * - Sets worker->count_xpds_to_initialize. - * So we wait until polling is finished (is_polling == 0) and: - * - No poll answers from Astribank (e.g: defective firmware). - * - Or no units to initialize (e.g: mini-AB with only main card). - * - Or we finished initializing all existing units. - * - Or A timeout passed. - */ ret = wait_event_interruptible_timeout( worker->wait_for_xpd_initialization, - !XBUS_IS(xbus, RECVD_DESC) || worker->xpds_init_done, + xpds_done(xbus), INITIALIZATION_TIMEOUT); if(ret == 0) { XBUS_ERR(xbus, "Card Initialization Timeout\n"); @@ -1552,11 +1567,15 @@ int waitfor_xpds(xbus_t *xbus, char *buf) "Finished initialization of %d XPD's in %d seconds.\n", worker->num_units_initialized, (INITIALIZATION_TIMEOUT - ret)/HZ); - spin_lock_irqsave(&xbus->lock, flags); - len += sprintf(buf, "XPDS_READY: %s: %d/%d\n", + if(XBUS_IS(xbus, FAIL)) { + len += sprintf(buf, "FAILED: %s\n", xbus->busname); + } else { + spin_lock_irqsave(&xbus->lock, flags); + len += sprintf(buf, "XPDS_READY: %s: %d/%d\n", xbus->busname, worker->num_units_initialized, worker->num_units); - spin_unlock_irqrestore(&xbus->lock, flags); + spin_unlock_irqrestore(&xbus->lock, flags); + } out: put_xbus(__FUNCTION__, xbus); /* from start of waitfor_xpds_show() */ return len; @@ -1566,10 +1585,7 @@ out: static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; - unsigned long flags; xbus_t *xbus = data; - struct xbus_workqueue *worker; - int ret; if(!xbus) goto out; @@ -1709,7 +1725,7 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int } #endif -static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv) +static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv) { BUG_ON(!xbus); BUG_ON(!ops); @@ -1719,6 +1735,7 @@ static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_s BUG_ON(!ops->free_xframe); xbus->transport.ops = ops; xbus->transport.max_send_size = max_send_size; + xbus->transport.transport_device = transport_device; xbus->transport.priv = priv; xbus->transport.xbus_state = XBUS_STATE_START; spin_lock_init(&xbus->transport.state_lock); diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h index 057e6cd..8cfb48c 100644 --- a/drivers/dahdi/xpp/xbus-core.h +++ b/drivers/dahdi/xpp/xbus-core.h @@ -103,6 +103,7 @@ const char *xbus_statename(enum xbus_state st); struct xbus_transport { struct xbus_ops *ops; void *priv; + struct device *transport_device; ushort max_send_size; enum xbus_state xbus_state; spinlock_t state_lock; @@ -297,7 +298,7 @@ xpacket_t *xframe_next_packet(xframe_t *xframe, int len); xpd_t *xpd_of(const xbus_t *xbus, int xpd_num); xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit); bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate); -xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv); +xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv); void xbus_free(xbus_t *xbus); int xbus_connect(xbus_t *xbus); int xbus_activate(xbus_t *xbus); diff --git a/drivers/dahdi/xpp/xbus-pcm.c b/drivers/dahdi/xpp/xbus-pcm.c index 9e6ce8d..d89991d 100644 --- a/drivers/dahdi/xpp/xbus-pcm.c +++ b/drivers/dahdi/xpp/xbus-pcm.c @@ -56,7 +56,7 @@ static struct xpp_ticker dahdi_ticker; */ static struct xpp_ticker *ref_ticker = NULL; static spinlock_t ref_ticker_lock = SPIN_LOCK_UNLOCKED; -static bool force_dahdi_sync = 0; /* from "/proc/xpp/sync" */ +static bool force_dahdi_sync = 0; /* from /sys/bus/astribanks/drivers/xppdrv/sync */ static xbus_t *global_ticker; static struct xpp_ticker global_ticks_series; @@ -170,9 +170,12 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv) driftinfo->delta_tick = new_delta_tick; if(lost_ticks) { + static int rate_limit; + driftinfo->lost_ticks++; driftinfo->lost_tick_count += abs(lost_ticks); - if(printk_ratelimit()) { + + if((rate_limit++ % 1003) == 0) { XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n", lost_ticks, (abs(lost_ticks) > 1) ? "s": ""); @@ -445,14 +448,8 @@ int dahdi_sync_tick(struct dahdi_span *span, int is_master) if(is_master) { static int rate_limit; - if(xpd->xbus != syncer && ((rate_limit % 1003) == 0)) { - XPD_ERR(xpd, - "Dahdi master, but syncer=%s\n", - xpd->xbus->busname); - } - if((rate_limit % 5003) == 0) - XPD_NOTICE(xpd, "Dahdi master: ignore DAHDI sync\n"); - rate_limit++; + if((rate_limit++ % 1003) == 0) + XPD_NOTICE(xpd, "Is a DAHDI sync master: ignore sync from DAHDI\n"); goto noop; } /* Now we know for sure someone else is dahdi sync master */ @@ -461,7 +458,7 @@ int dahdi_sync_tick(struct dahdi_span *span, int is_master) if((rate_limit++ % 5003) == 0) XBUS_DBG(SYNC, syncer, - "Already a syncer, ignore DAHDI sync\n"); + "is a SYNCer: ignore sync from DAHDI\n"); goto noop; } /* ignore duplicate calls from all our registered spans */ @@ -488,12 +485,15 @@ noop: * if new_syncer is NULL, than we move all to SYNC_MODE_PLL * for DAHDI sync. */ -static void update_sync_master(xbus_t *new_syncer) +static void update_sync_master(xbus_t *new_syncer, bool force_dahdi) { - const char *msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC"; + const char *msg; int i; unsigned long flags; + WARN_ON(new_syncer && force_dahdi); /* Ambigous */ + force_dahdi_sync = force_dahdi; + msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC"; DBG(SYNC, "%s => %s\n", (syncer) ? syncer->busname : msg, (new_syncer) ? new_syncer->busname : msg); @@ -545,9 +545,9 @@ void elect_syncer(const char *msg) xbus_t *xbus = xbus_num(i); if(!xbus) continue; - if(!the_xbus) - the_xbus = xbus; if(XBUS_IS(xbus, READY)) { + if(!the_xbus) + the_xbus = xbus; /* First candidate */ for(j = 0; j < MAX_XPDS; j++) { xpd_t *xpd = xpd_of(xbus, j); @@ -568,26 +568,25 @@ void elect_syncer(const char *msg) } else DBG(SYNC, "%s: No more syncers\n", msg); if(the_xbus != syncer) - update_sync_master(the_xbus); + update_sync_master(the_xbus, force_dahdi_sync); } /* * This function is used by FXS/FXO. The pcm_mask argument signifies * channels which should be *added* to the automatic calculation. * Normally, this argument is 0. - * - * The caller should spinlock the XPD before calling it. */ -void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) +void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask) { int i; int line_count = 0; + unsigned long flags; - XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask); + spin_lock_irqsave(&xpd->lock_recompute_pcm, flags); + //XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask); /* Add/remove all the trivial cases */ - pcm_mask |= xpd->offhook; - pcm_mask |= xpd->cid_on; - pcm_mask &= ~xpd->digital_signalling; /* No PCM in D-Channels */ + pcm_mask |= xpd->offhook_state; + pcm_mask |= xpd->oht_pcm_pass; pcm_mask &= ~xpd->digital_inputs; pcm_mask &= ~xpd->digital_outputs; for_each_line(xpd, i) @@ -605,18 +604,9 @@ void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE : 0L; xpd->wanted_pcm_mask = pcm_mask; -} - -/* - * A spinlocked version of __pcm_recompute() - */ -void pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) -{ - unsigned long flags; - - spin_lock_irqsave(&xpd->lock, flags); - __pcm_recompute(xpd, pcm_mask); - spin_unlock_irqrestore(&xpd->lock, flags); + XPD_DBG(SIGNAL, xpd, "pcm_len=%d wanted_pcm_mask=0x%X\n", + xpd->pcm_len, xpd->wanted_pcm_mask); + spin_unlock_irqrestore(&xpd->lock_recompute_pcm, flags); } void fill_beep(u_char *buf, int num, int duration) @@ -647,17 +637,18 @@ void fill_beep(u_char *buf, int num, int duration) static void do_ec(xpd_t *xpd) { - struct dahdi_chan **chans = xpd->span.chans; - int i; + int i; for (i = 0;i < xpd->span.channels; i++) { + struct dahdi_chan *chan = XPD_CHAN(xpd, i); + if(unlikely(IS_SET(xpd->digital_signalling, i))) /* Don't echo cancel BRI D-chans */ continue; if(!IS_SET(xpd->wanted_pcm_mask, i)) /* No ec for unwanted PCM */ continue; - dahdi_ec_chunk(chans[i], chans[i]->readchunk, xpd->ec_chunk2[i]); + dahdi_ec_chunk(chan, chan->readchunk, xpd->ec_chunk2[i]); memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], DAHDI_CHUNKSIZE); - memcpy(xpd->ec_chunk1[i], chans[i]->writechunk, DAHDI_CHUNKSIZE); + memcpy(xpd->ec_chunk1[i], chan->writechunk, DAHDI_CHUNKSIZE); } } @@ -761,31 +752,33 @@ dropit: * Generic implementations of card_pcmfromspan()/card_pcmtospan() * For FXS/FXO */ -void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack) +void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) { - byte *pcm; - struct dahdi_chan **chans; - unsigned long flags; - int i; + byte *pcm; + unsigned long flags; + xpp_line_t wanted_lines; + int i; BUG_ON(!xbus); BUG_ON(!xpd); BUG_ON(!pack); - RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines; + wanted_lines = xpd->wanted_pcm_mask; + RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = wanted_lines; pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); - chans = xpd->span.chans; for (i = 0; i < xpd->channels; i++) { - if(IS_SET(lines, i)) { + struct dahdi_chan *chan = XPD_CHAN(xpd, i); + + if(IS_SET(wanted_lines, i)) { if(SPAN_REGISTERED(xpd)) { #ifdef DEBUG_PCMTX - int channo = xpd->span.chans[i]->channo; + int channo = chan->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); + memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); } else memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; @@ -814,7 +807,7 @@ void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack) if(!SPAN_REGISTERED(xpd)) goto out; for (i = 0; i < xpd->channels; i++) { - volatile u_char *r = xpd->span.chans[i]->readchunk; + volatile u_char *r = XPD_CHAN(xpd, i)->readchunk; bool got_data = IS_SET(pcm_mask, i); if(got_data && !IS_SET(pcm_mute, i)) { @@ -914,7 +907,6 @@ static void xbus_tick(xbus_t *xbus) xpd_t *xpd; xframe_t *xframe = NULL; xpacket_t *pack = NULL; - size_t pcm_len; bool sent_sync_bit = 0; /* @@ -930,7 +922,7 @@ static void xbus_tick(xbus_t *xbus) xmit_mask |= xpd->silence_pcm; xmit_mask |= xpd->digital_signalling; for_each_line(xpd, j) { - xpd->chans[j].chanmute = (optimize_chanmute) + XPD_CHAN(xpd, j)->chanmute = (optimize_chanmute) ? !IS_SET(xmit_mask, j) : 0; } @@ -946,6 +938,8 @@ static void xbus_tick(xbus_t *xbus) * Fill xframes */ for(i = 0; i < MAX_XPDS; i++) { + size_t pcm_len; + if((xpd = xpd_of(xbus, i)) == NULL) continue; pcm_len = xpd->pcm_len; @@ -978,7 +972,7 @@ static void xbus_tick(xbus_t *xbus) XPACKET_ADDR_SYNC(pack) = 1; sent_sync_bit = 1; } - CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, xpd->wanted_pcm_mask, pack); + CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, pack); XBUS_COUNTER(xbus, TX_PACK_PCM)++; } } @@ -1070,7 +1064,50 @@ void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe) xbus->xbus_frag_count++; } -#ifdef CONFIG_PROC_FS +int exec_sync_command(const char *buf, size_t count) +{ + int ret = count; + int xbusno; + xbus_t *xbus; + + if(strncmp("DAHDI", buf, 6) == 0) { /* Ignore the newline */ + DBG(SYNC, "DAHDI\n"); + update_sync_master(NULL, 1); + } else if(sscanf(buf, "SYNC=%d\n", &xbusno) == 1) { + DBG(SYNC, "SYNC=%d\n", xbusno); + if((xbus = xbus_num(xbusno)) == NULL) { + ERR("No bus %d exists\n", xbusno); + return -ENXIO; + } + update_sync_master(xbus, 0); + } else if(sscanf(buf, "QUERY=%d\n", &xbusno) == 1) { + DBG(SYNC, "QUERY=%d\n", xbusno); + if((xbus = xbus_num(xbusno)) == NULL) { + ERR("No bus %d exists\n", xbusno); + return -ENXIO; + } + CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0); + } else { + ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf); + ret = -EINVAL; + } + return ret; +} + +int fill_sync_string(char *buf, size_t count) +{ + int len = 0; + + if(!syncer) { + len += snprintf(buf, count, "%s\n", + (force_dahdi_sync) ? "DAHDI" : "NO-SYNC"); + } else + len += snprintf(buf, count, "SYNC=%02d\n", syncer->num); + return len; +} + +#ifdef OLD_PROC +#ifdef CONFIG_PROC_FS static int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; @@ -1079,17 +1116,13 @@ static int proc_sync_read(char *page, char **start, off_t off, int count, int *e unsigned long usec; do_gettimeofday(&now); + NOTICE("%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n", + __FUNCTION__, current->comm, current->tgid); len += sprintf(page + len, "# To modify sync source write into this file:\n"); len += sprintf(page + len, "# DAHDI - Another dahdi device provide sync\n"); len += sprintf(page + len, "# SYNC=nn - XBUS-nn provide sync\n"); len += sprintf(page + len, "# QUERY=nn - Query XBUS-nn for sync information (DEBUG)\n"); - if(!syncer) { - if(force_dahdi_sync) - len += sprintf(page + len, "DAHDI\n"); - else - len += sprintf(page + len, "NO-SYNC\n"); - } else - len += sprintf(page + len, "SYNC=%02d\n", syncer->num); + len += fill_sync_string(page + len, PAGE_SIZE - len); #ifdef DAHDI_SYNC_TICK if(force_dahdi_sync) { len += sprintf(page + len, @@ -1123,68 +1156,26 @@ static int proc_sync_read(char *page, char **start, off_t off, int count, int *e static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { char buf[MAX_PROC_WRITE]; - int xbusno; - int xpd_num; - xbus_t *xbus; - xpd_t *xpd; // DBG(SYNC, "%s: count=%ld\n", __FUNCTION__, count); + NOTICE("%s: DEPRECATED: %s[%d] write to /proc interface instead of /sys\n", + __FUNCTION__, current->comm, current->tgid); if(count >= MAX_PROC_WRITE) return -EINVAL; if(copy_from_user(buf, buffer, count)) return -EFAULT; buf[count] = '\0'; - if(strncmp("DAHDI", buf, 5) == 0) { - DBG(SYNC, "DAHDI\n"); - force_dahdi_sync=1; - update_sync_master(NULL); - } else if(sscanf(buf, "SYNC=%d", &xbusno) == 1) { - DBG(SYNC, "SYNC=%d\n", xbusno); - if((xbus = xbus_num(xbusno)) == NULL) { - ERR("No bus %d exists\n", xbusno); - return -ENXIO; - } - update_sync_master(xbus); - } else if(sscanf(buf, "QUERY=%d", &xbusno) == 1) { - DBG(SYNC, "QUERY=%d\n", xbusno); - if((xbus = xbus_num(xbusno)) == NULL) { - ERR("No bus %d exists\n", xbusno); - return -ENXIO; - } - CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0); - } else if(sscanf(buf, "%d %d", &xbusno, &xpd_num) == 2) { - NOTICE("Using deprecated syntax to update %s file\n", - PROC_SYNC); - if(xpd_num != 0) { - ERR("Currently can only set sync for XPD #0\n"); - return -EINVAL; - } - if((xbus = xbus_num(xbusno)) == NULL) { - ERR("No bus %d exists\n", xbusno); - return -ENXIO; - } - if((xpd = xpd_of(xbus, xpd_num)) == NULL) { - XBUS_ERR(xbus, "No xpd %d exists\n", xpd_num); - return -ENXIO; - } - update_sync_master(xbus); - } else { - ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf); - count = -EINVAL; - } - return count; + return exec_sync_command(buf, count); } static struct proc_dir_entry *top; #endif +#endif /* OLD_PROC */ int xbus_pcm_init(struct proc_dir_entry *toplevel) { int ret = 0; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; -#endif #ifdef OPTIMIZE_CHANMUTE INFO("FEATURE: with CHANMUTE optimization (%sactivated)\n", @@ -1197,27 +1188,34 @@ int xbus_pcm_init(struct proc_dir_entry *toplevel) #endif xpp_ticker_init(&global_ticks_series); xpp_ticker_init(&dahdi_ticker); -#ifdef CONFIG_PROC_FS - top = toplevel; - ent = create_proc_entry(PROC_SYNC, 0644, top); - if(!ent) { - ret = -EFAULT; - goto err; +#ifdef OLD_PROC +#ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *ent; + + top = toplevel; + ent = create_proc_entry(PROC_SYNC, 0644, top); + if(ent) { + ent->read_proc = proc_sync_read; + ent->write_proc = proc_sync_write; + ent->data = NULL; + } else { + ret = -EFAULT; + } } - ent->read_proc = proc_sync_read; - ent->write_proc = proc_sync_write; - ent->data = NULL; #endif -err: +#endif /* OLD_PROC */ return ret; } void xbus_pcm_shutdown(void) { +#ifdef OLD_PROC #ifdef CONFIG_PROC_FS DBG(GENERAL, "Removing '%s' from proc\n", PROC_SYNC); remove_proc_entry(PROC_SYNC, top); #endif +#endif /* OLD_PROC */ } @@ -1227,8 +1225,7 @@ EXPORT_SYMBOL(elect_syncer); #ifdef DAHDI_SYNC_TICK EXPORT_SYMBOL(dahdi_sync_tick); #endif -EXPORT_SYMBOL(__pcm_recompute); -EXPORT_SYMBOL(pcm_recompute); +EXPORT_SYMBOL(generic_card_pcm_recompute); EXPORT_SYMBOL(generic_card_pcm_tospan); EXPORT_SYMBOL(generic_card_pcm_fromspan); #ifdef DEBUG_PCMTX diff --git a/drivers/dahdi/xpp/xbus-pcm.h b/drivers/dahdi/xpp/xbus-pcm.h index a7529c8..be33044 100644 --- a/drivers/dahdi/xpp/xbus-pcm.h +++ b/drivers/dahdi/xpp/xbus-pcm.h @@ -100,9 +100,9 @@ int xbus_pcm_init(struct proc_dir_entry *top); void xbus_pcm_shutdown(void); int send_pcm_frame(xbus_t *xbus, xframe_t *xframe); void pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); -void __pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); /* non locking */ void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe); -void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack); +void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask); +void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); void fill_beep(u_char *buf, int num, int duration); const char *sync_mode_name(enum sync_mode mode); @@ -112,6 +112,8 @@ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift); int xbus_command_queue_tick(xbus_t *xbus); void xbus_reset_counters(xbus_t *xbus); void elect_syncer(const char *msg); +int exec_sync_command(const char *buf, size_t count); +int fill_sync_string(char *buf, size_t count); #ifdef DAHDI_SYNC_TICK int dahdi_sync_tick(struct dahdi_span *span, int is_master); #endif diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c index 4dd0f0d..8d1f35a 100644 --- a/drivers/dahdi/xpp/xbus-sysfs.c +++ b/drivers/dahdi/xpp/xbus-sysfs.c @@ -38,7 +38,6 @@ #include "xpd.h" #include "xpp_dahdi.h" #include "xbus-core.h" -#include "card_global.h" #ifdef XPP_DEBUGFS #include "xpp_log.h" #endif @@ -49,6 +48,23 @@ static const char rcsid[] = "$Id$"; /* Command line parameters */ extern int debug; +/*--------- xpp driver attributes -*/ +static ssize_t sync_show(struct device_driver *driver, char *buf) +{ + DBG(SYNC, "\n"); + return fill_sync_string(buf, PAGE_SIZE); +} + +static ssize_t sync_store(struct device_driver *driver, const char *buf, size_t count) +{ + /* DBG(SYNC, "%s\n", buf); */ + return exec_sync_command(buf, count); +} + +static struct driver_attribute xpp_attrs[] = { + __ATTR(sync, S_IRUGO | S_IWUSR, sync_show, sync_store), +}; + /*--------- Sysfs Bus handling ----*/ static DEVICE_ATTR_READER(xbus_state_show, dev, buf) { @@ -320,19 +336,19 @@ void astribank_uevent_send(xbus_t *xbus, enum kobject_action act) xbus->astribank.bus_id, act); #if defined(OLD_HOTPLUG_SUPPORT_269) - { - /* Copy from new kernels lib/kobject_uevent.c */ - static const char *str[] = { - [KOBJ_ADD] "add", - [KOBJ_REMOVE] "remove", - [KOBJ_CHANGE] "change", - [KOBJ_MOUNT] "mount", - [KOBJ_UMOUNT] "umount", - [KOBJ_OFFLINE] "offline", - [KOBJ_ONLINE] "online" - }; - kobject_hotplug(str[act], kobj); - } + { + /* Copy from new kernels lib/kobject_uevent.c */ + static const char *str[] = { + [KOBJ_ADD] "add", + [KOBJ_REMOVE] "remove", + [KOBJ_CHANGE] "change", + [KOBJ_MOUNT] "mount", + [KOBJ_UMOUNT] "umount", + [KOBJ_OFFLINE] "offline", + [KOBJ_ONLINE] "online" + }; + kobject_hotplug(str[act], kobj); + } #elif defined(OLD_HOTPLUG_SUPPORT) kobject_hotplug(kobj, act); #else @@ -340,11 +356,6 @@ void astribank_uevent_send(xbus_t *xbus, enum kobject_action act) #endif } -static void xpp_release(struct device *dev) -{ - DBG(DEVICES, "SYSFS %s\n", dev->bus_id); -} - static void astribank_release(struct device *dev) { xbus_t *xbus; @@ -369,11 +380,7 @@ static struct bus_type toplevel_bus_type = { .uevent = astribank_uevent, #endif .dev_attrs = xbus_dev_attrs, -}; - -static struct device toplevel_device = { - .bus_id = "xpp", - .release = xpp_release + .drv_attrs = xpp_attrs, }; static int astribank_probe(struct device *dev) @@ -479,6 +486,9 @@ static DEVICE_ATTR_WRITER(chipregs_store, dev, buf, count) } } p += i + 1; + /* Don't flood command_queue */ + if(xframe_queue_count(&xpd->xbus->command_queue) > 5) + msleep(6); } return count; } @@ -559,6 +569,19 @@ static DEVICE_ATTR_WRITER(span_store, dev, buf, count) return (ret < 0) ? ret : count; } +static DEVICE_ATTR_READER(type_show, dev, buf) +{ + xpd_t *xpd; + int len = 0; + + BUG_ON(!dev); + xpd = dev_to_xpd(dev); + if(!xpd) + return -ENODEV; + len += sprintf(buf, "%s\n", xpd->type_name); + return len; +} + static int xpd_match(struct device *dev, struct device_driver *driver) { struct xpd_driver *xpd_driver; @@ -580,6 +603,7 @@ static struct device_attribute xpd_dev_attrs[] = { __ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store), __ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store), __ATTR(span, S_IRUGO | S_IWUSR, span_show, span_store), + __ATTR_RO(type), __ATTR_NULL, }; @@ -666,6 +690,7 @@ void xbus_sysfs_remove(xbus_t *xbus) XBUS_DBG(DEVICES, xbus, "\n"); astribank = &xbus->astribank; BUG_ON(!astribank); + sysfs_remove_link(&astribank->kobj, "transport"); if(!astribank->driver_data) return; BUG_ON(astribank->driver_data != xbus); @@ -682,7 +707,7 @@ int xbus_sysfs_create(xbus_t *xbus) BUG_ON(!astribank); XBUS_DBG(DEVICES, xbus, "\n"); astribank->bus = &toplevel_bus_type; - astribank->parent = &toplevel_device; + astribank->parent = xbus->transport.transport_device; snprintf(astribank->bus_id, BUS_ID_SIZE, "xbus-%02d", xbus->num); astribank->driver_data = xbus; astribank->release = astribank_release; @@ -690,7 +715,15 @@ int xbus_sysfs_create(xbus_t *xbus) if(ret) { XBUS_ERR(xbus, "%s: device_register failed: %d\n", __FUNCTION__, ret); astribank->driver_data = NULL; + goto out; } + ret = sysfs_create_link(&astribank->kobj, &astribank->parent->kobj, "transport"); + if(ret < 0) { + XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n", __FUNCTION__, ret); + astribank->driver_data = NULL; + goto out; + } +out: return ret; } @@ -704,11 +737,6 @@ int __init xpp_driver_init(void) __FUNCTION__, toplevel_bus_type.name, ret); goto failed_bus; } - if((ret = device_register(&toplevel_device)) < 0) { - ERR("%s: device_register(%s) failed. Error number %d", - __FUNCTION__, toplevel_device.bus_id, ret); - goto failed_busdevice; - } if((ret = driver_register(&xpp_driver)) < 0) { ERR("%s: driver_register(%s) failed. Error number %d", __FUNCTION__, xpp_driver.name, ret); @@ -723,8 +751,6 @@ int __init xpp_driver_init(void) failed_xpd_bus: driver_unregister(&xpp_driver); failed_xpp_driver: - device_unregister(&toplevel_device); -failed_busdevice: bus_unregister(&toplevel_bus_type); failed_bus: return ret; @@ -735,7 +761,6 @@ void xpp_driver_exit(void) DBG(DEVICES, "SYSFS\n"); bus_unregister(&xpd_type); driver_unregister(&xpp_driver); - device_unregister(&toplevel_device); bus_unregister(&toplevel_bus_type); } diff --git a/drivers/dahdi/xpp/xpd.h b/drivers/dahdi/xpp/xpd.h index 2e0363a..daf1954 100644 --- a/drivers/dahdi/xpp/xpd.h +++ b/drivers/dahdi/xpp/xpd.h @@ -156,6 +156,8 @@ struct xpd { char xpdname[XPD_NAMELEN]; struct dahdi_span span; struct dahdi_chan *chans[32]; +#define XPD_CHAN(xpd,chan) ((xpd)->chans[(chan)]) + int channels; xpd_type_t type; const char *type_name; @@ -163,8 +165,8 @@ struct xpd { xpd_direction_t direction; /* TO_PHONE, TO_PSTN */ int subunits; /* all siblings */ xpp_line_t no_pcm; /* Temporary: disable PCM (for USB-1) */ - xpp_line_t offhook; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */ - xpp_line_t cid_on; + xpp_line_t offhook_state; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */ + xpp_line_t oht_pcm_pass; /* Transfer on-hook PCM */ xpp_line_t msg_waiting; /* Voice Mail Waiting Indication */ xpp_line_t digital_outputs; /* 0 - no, 1 - yes */ xpp_line_t digital_inputs; /* 0 - no, 1 - yes */ @@ -175,6 +177,8 @@ struct xpd { struct device xpd_dev; #define dev_to_xpd(dev) container_of(dev, struct xpd, xpd_dev) + /* Assure atomicity of changes to pcm_len and wanted_pcm_mask */ + spinlock_t lock_recompute_pcm; /* maintained by card drivers */ uint pcm_len; /* allocation length of PCM packet (dynamic) */ xpp_line_t wanted_pcm_mask; @@ -187,7 +191,7 @@ struct xpd { spinlock_t lock; atomic_t dahdi_registered; /* Am I fully registered with dahdi */ - atomic_t open_counter; /* open channels */ + atomic_t open_counter; /* Number of open channels */ int flags; unsigned long blink_mode; /* bitmask of blinking ports */ diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c index 9c4963f..b1ec98c 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.c +++ b/drivers/dahdi/xpp/xpp_dahdi.c @@ -338,11 +338,11 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo } len += sprintf(page + len, "\n\t%-17s: ", "offhook"); for_each_line(xpd, i) { - len += sprintf(page + len, "%d ", IS_SET(xpd->offhook, i)); + len += sprintf(page + len, "%d ", IS_OFFHOOK(xpd, i)); } - len += sprintf(page + len, "\n\t%-17s: ", "cid_on"); + len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass"); for_each_line(xpd, i) { - len += sprintf(page + len, "%d ", IS_SET(xpd->cid_on, i)); + len += sprintf(page + len, "%d ", IS_SET(xpd->oht_pcm_pass, i)); } len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting"); for_each_line(xpd, i) { @@ -360,7 +360,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | W D"); for_each_line(xpd, i) { - struct dahdi_chan *chan = xpd->span.chans[i]; + struct dahdi_chan *chan = XPD_CHAN(xpd, i); byte rchunk[DAHDI_CHUNKSIZE]; byte wchunk[DAHDI_CHUNKSIZE]; byte *rp; @@ -396,7 +396,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nSignalling:\n"); for_each_line(xpd, i) { - struct dahdi_chan *chan = &xpd->span.chans[i]; + struct dahdi_chan *chan = XPD_CHAN(xpd, i); len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig); } } @@ -508,9 +508,10 @@ __must_check xpd_t *xpd_alloc(xbus_t *xbus, } xpd->priv = (byte *)xpd + sizeof(xpd_t); spin_lock_init(&xpd->lock); + spin_lock_init(&xpd->lock_recompute_pcm); xpd->channels = channels; xpd->card_present = 0; - xpd->offhook = 0x0; /* ONHOOK */ + xpd->offhook_state = 0x0; /* ONHOOK */ xpd->type = proto_table->type; xpd->xproto = proto_table; xpd->xops = &proto_table->xops; @@ -574,7 +575,7 @@ void xpd_unreg_request(xpd_t *xpd) /* TODO: Should this be done before releasing the spinlock? */ XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to close them\n"); for (i=0; i<xpd->span.channels; i++) { - dahdi_qevent_lock(xpd->chans[i],DAHDI_EVENT_REMOVED); + dahdi_qevent_lock(XPD_CHAN(xpd, i),DAHDI_EVENT_REMOVED); } } spin_unlock_irqrestore(&xpd->lock, flags); @@ -619,18 +620,64 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag) XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag); } -void update_line_status(xpd_t *xpd, int pos, bool to_offhook) +/* + * Used to block/pass PCM during onhook-transfers. E.g: + * - Playing FSK after FXS ONHOOK for MWI (non-neon style) + * - Playing DTFM/FSK for FXO Caller-ID detection. + */ +void oht_pcm(xpd_t *xpd, int pos, bool pass) { - enum dahdi_rxsig rxsig; + if(pass) { + LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: pass\n"); + BIT_SET(xpd->oht_pcm_pass, pos); + } else { + LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: block\n"); + BIT_CLR(xpd->oht_pcm_pass, pos); + } + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); +} - BUG_ON(!xpd); +/* + * Update our hookstate -- for PCM block/pass + */ +void mark_offhook(xpd_t *xpd, int pos, bool to_offhook) +{ if(to_offhook) { - BIT_SET(xpd->offhook, pos); - rxsig = DAHDI_RXSIG_OFFHOOK; + LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK\n"); + BIT_SET(xpd->offhook_state, pos); } else { - BIT_CLR(xpd->offhook, pos); - BIT_CLR(xpd->cid_on, pos); - rxsig = DAHDI_RXSIG_ONHOOK; + LINE_DBG(SIGNAL, xpd, pos, "ONHOOK\n"); + BIT_CLR(xpd->offhook_state, pos); + } + CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); +} + +/* + * Send a signalling notification to Asterisk + */ +void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig) +{ + /* + * We should not spinlock before calling dahdi_hooksig() as + * it may call back into our xpp_hooksig() and cause + * a nested spinlock scenario + */ + LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", rxsig2str(rxsig)); + if(SPAN_REGISTERED(xpd)) + dahdi_hooksig(XPD_CHAN(xpd, pos), rxsig); +} + +/* + * Called when hardware state changed: + * - FXS -- the phone was picked up or hanged-up. + * - FXO -- we answered the phone or handed-up. + */ +void hookstate_changed(xpd_t *xpd, int pos, bool to_offhook) +{ + BUG_ON(!xpd); + mark_offhook(xpd, pos, to_offhook); + if(!to_offhook) { + oht_pcm(xpd, pos, 0); /* * To prevent latest PCM to stay in buffers * indefinitely, mark this channel for a @@ -640,14 +687,7 @@ void update_line_status(xpd_t *xpd, int pos, bool to_offhook) */ BIT_SET(xpd->silence_pcm, pos); } - /* - * We should not spinlock before calling dahdi_hooksig() as - * it may call back into our xpp_hooksig() and cause - * a nested spinlock scenario - */ - LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", (rxsig == DAHDI_RXSIG_ONHOOK) ? "ONHOOK" : "OFFHOOK"); - if(SPAN_REGISTERED(xpd)) - dahdi_hooksig(xpd->chans[pos], rxsig); + notify_rxsig(xpd, pos, (to_offhook) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK); } #ifdef CONFIG_PROC_FS @@ -805,8 +845,6 @@ int xpp_open(struct dahdi_chan *chan) LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm, current->pid, atomic_read(&xpd->open_counter)); - if(IS_SET(xpd->digital_signalling, pos)) /* D-chan offhook */ - BIT_SET(xpd->offhook, pos); spin_unlock_irqrestore(&xbus->lock, flags); if(xpd->xops->card_open) xpd->xops->card_open(xpd, pos); @@ -821,8 +859,6 @@ int xpp_close(struct dahdi_chan *chan) unsigned long flags; spin_lock_irqsave(&xbus->lock, flags); - if(IS_SET(xpd->digital_signalling, pos)) /* D-chan onhook */ - BIT_CLR(xpd->offhook, pos); spin_unlock_irqrestore(&xbus->lock, flags); if(xpd->xops->card_close) xpd->xops->card_close(xpd, pos); @@ -1008,7 +1044,7 @@ int dahdi_register_xpd(xpd_t *xpd) XPD_DBG(DEVICES, xpd, "Initializing span: %d channels.\n", cn); memset(&xpd->span, 0, sizeof(struct dahdi_span)); for(i = 0; i < cn; i++) { - memset(xpd->chans[i], 0, sizeof(struct dahdi_chan)); + memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan)); } span = &xpd->span; @@ -1076,26 +1112,18 @@ int dahdi_register_xpd(xpd_t *xpd) atomic_inc(&xpd->dahdi_registered); xpd->xops->card_dahdi_postregistration(xpd, 1); /* - * Update dahdi about our state - */ -#if 0 - /* - * FIXME: since asterisk didn't open the channel yet, the report - * is discarded anyway. OTOH, we cannot report in xpp_open or - * xpp_chanconfig since dahdi call them with a spinlock on the channel - * and dahdi_hooksig tries to acquire the same spinlock, resulting in - * double spinlock deadlock (we are lucky that RH/Fedora kernel are - * compiled with spinlock debugging).... tough. + * Update dahdi about our state: + * - Since asterisk didn't open the channel yet, + * the report is discarded anyway. + * - Our FXS driver have another notification mechanism that + * is triggered (indirectly) by the open() of the channe. + * - The real fix should be in Asterisk (to get the correct state + * after open). */ for_each_line(xpd, cn) { - struct dahdi_chan *chans = xpd->span.chans; - - if(IS_SET(xpd->offhook, cn)) { - LINE_NOTICE(xpd, cn, "Report OFFHOOK to dahdi\n"); - dahdi_hooksig(&chans[cn], DAHDI_RXSIG_OFFHOOK); - } + if(IS_OFFHOOK(xpd, cn)) + notify_rxsig(xpd, cn, DAHDI_RXSIG_OFFHOOK); } -#endif return 0; } @@ -1163,7 +1191,10 @@ EXPORT_SYMBOL(xpd_alloc); EXPORT_SYMBOL(xpd_free); EXPORT_SYMBOL(xpd_unreg_request); EXPORT_SYMBOL(update_xpd_status); -EXPORT_SYMBOL(update_line_status); +EXPORT_SYMBOL(oht_pcm); +EXPORT_SYMBOL(mark_offhook); +EXPORT_SYMBOL(notify_rxsig); +EXPORT_SYMBOL(hookstate_changed); EXPORT_SYMBOL(xpp_open); EXPORT_SYMBOL(xpp_close); EXPORT_SYMBOL(xpp_ioctl); diff --git a/drivers/dahdi/xpp/xpp_dahdi.h b/drivers/dahdi/xpp/xpp_dahdi.h index 7b5695a..8bf471b 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.h +++ b/drivers/dahdi/xpp/xpp_dahdi.h @@ -35,13 +35,17 @@ xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits, void xpd_free(xpd_t *xpd); void xpd_remove(xpd_t *xpd); void update_xpd_status(xpd_t *xpd, int alarm_flag); -void update_line_status(xpd_t *xpd, int pos, bool good); +void hookstate_changed(xpd_t *xpd, int pos, bool good); int xpp_open(struct dahdi_chan *chan); int xpp_close(struct dahdi_chan *chan); int xpp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long arg); int xpp_maint(struct dahdi_span *span, int cmd); void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd); int total_registered_spans(void); +void oht_pcm(xpd_t *xpd, int pos, bool pass); +void mark_offhook(xpd_t *xpd, int pos, bool to_offhook); +#define IS_OFFHOOK(xpd,pos) IS_SET((xpd)->offhook_state, (pos)) +void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig); #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> diff --git a/drivers/dahdi/xpp/xpp_usb.c b/drivers/dahdi/xpp/xpp_usb.c index 2346fb4..2edec52 100644 --- a/drivers/dahdi/xpp/xpp_usb.c +++ b/drivers/dahdi/xpp/xpp_usb.c @@ -721,7 +721,7 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i /* let the user know what node this device is now attached to */ DBG(DEVICES, "USB XPP device now attached to minor %d\n", xusb->minor); - xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), xusb); + xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), &udev->dev, xusb); if(!xbus) { retval = -ENOMEM; goto probe_failed; diff --git a/drivers/dahdi/xpp/xproto.c b/drivers/dahdi/xpp/xproto.c index 53b6fce..3b454b1 100644 --- a/drivers/dahdi/xpp/xproto.c +++ b/drivers/dahdi/xpp/xproto.c @@ -437,6 +437,7 @@ int xproto_register(const xproto_table_t *proto_table) CHECK_XOP(card_init); CHECK_XOP(card_remove); CHECK_XOP(card_tick); + CHECK_XOP(card_pcm_recompute); CHECK_XOP(card_pcm_fromspan); CHECK_XOP(card_pcm_tospan); CHECK_XOP(card_dahdi_preregistration); diff --git a/drivers/dahdi/xpp/xproto.h b/drivers/dahdi/xpp/xproto.h index dbb720e..92eca4f 100644 --- a/drivers/dahdi/xpp/xproto.h +++ b/drivers/dahdi/xpp/xproto.h @@ -221,7 +221,8 @@ struct xops { int (*card_init)(xbus_t *xbus, xpd_t *xpd); int (*card_remove)(xbus_t *xbus, xpd_t *xpd); int (*card_tick)(xbus_t *xbus, xpd_t *xpd); - void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack); + void (*card_pcm_recompute)(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask); + void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); void (*card_pcm_tospan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack); int (*card_dahdi_preregistration)(xpd_t *xpd, bool on); int (*card_dahdi_postregistration)(xpd_t *xpd, bool on); |