diff options
Diffstat (limited to 'xpp/card_fxo.c')
-rw-r--r-- | xpp/card_fxo.c | 119 |
1 files changed, 74 insertions, 45 deletions
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c index 404407f..513cd5b 100644 --- a/xpp/card_fxo.c +++ b/xpp/card_fxo.c @@ -34,7 +34,8 @@ static const char rcsid[] = "$Id$"; DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); -DEF_PARM(uint, poll_battery_interval, 40, 0644, "Poll battery interval in milliseconds (0 - disable)"); +DEF_PARM(uint, poll_battery_interval, 500, 0644, "Poll battery interval in milliseconds (0 - disable)"); +DEF_PARM(uint, poll_power_denial_interval, 40, 0644, "Power denial detection poll interval in milliseconds (0 - disable)"); #ifdef WITH_METERING DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval in milliseconds (0 - disable)"); #endif @@ -54,8 +55,10 @@ enum fxo_leds { #define NUM_LEDS 1 #define DELAY_UNTIL_DIALTONE 3000 +#define POLREV_START 3 /* time after offhook to ignore polarity reversals (in ticks) */ +#define POLREV_THRESHOLD 1000 /* minimum duration for polarity reversal detection (in ticks) */ #define BAT_THRESHOLD 3 -#define BAT_DEBOUNCE 3 /* compensate for battery voltage fluctuation (in poll_battery_interval's) */ +#define BAT_DEBOUNCE 1000 /* compensate for battery voltage fluctuation (in ticks) */ /* Shortcuts */ #define DAA_WRITE 1 @@ -87,9 +90,10 @@ static int handle_register_command(xpd_t *xpd, char *cmdline); #define PROC_METERING_FNAME "metering_read" #endif -#define DAA_RING_REGISTER 0x05 -#define DAA_METERING_REGISTER 0x11 /* 17 */ -#define DAA_CURRENT_REGISTER 0x1C /* 28 */ +#define DAA_REG_RING 0x05 +#define DAA_REG_METERING 0x11 /* 17 */ +#define DAA_REG_CURRENT 0x1C /* 28 */ +#define DAA_REG_VBAT 0x1D /* 29 */ #define POWER_DENIAL_CURRENT 3 #define POWER_DENIAL_TIME 80 /* ticks */ @@ -211,7 +215,7 @@ static void update_zap_ring(xpd_t *xpd, int pos, bool on) BIT_SET(xpd->cid_on, pos); rxsig = ZT_RXSIG_OFFHOOK; } - pcm_recompute(xpd, xpd->offhook | xpd->cid_on); + pcm_recompute(xpd, 0); /* * We should not spinlock before calling zt_hooksig() as * it may call back into our xpp_hooksig() and cause @@ -228,6 +232,11 @@ static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_zap) priv = xpd->priv; BUG_ON(!priv); atomic_set(&priv->ring_debounce[pos], 0); /* Stop debouncing */ + /* + * We don't want to check battery during ringing + * due to voltage fluctuations. + */ + priv->battery_debounce[pos] = 0; if(on && !xpd->ringing[pos]) { LINE_DBG(SIGNAL, xpd, pos, "START\n"); xpd->ringing[pos] = 1; @@ -268,7 +277,7 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) MARK_ON(priv, pos, LED_GREEN); else MARK_OFF(priv, pos, LED_GREEN); - ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_RING_REGISTER, value); + ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_RING, value); if(to_offhook) { BIT_SET(xpd->offhook, pos); priv->offhook_timestamp[pos] = priv->poll_counter; @@ -279,7 +288,7 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) #ifdef WITH_METERING priv->metering_count[pos] = 0; priv->metering_tone_state = 0L; - DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_METERING_REGISTER, 0x2D); + DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_METERING, 0x2D); #endif spin_unlock_irqrestore(&xpd->lock, flags); return ret; @@ -393,7 +402,7 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) do_led(xpd, i, LED_GREEN, 0); msleep(50); } - pcm_recompute(xpd, xpd->offhook | xpd->cid_on); + pcm_recompute(xpd, 0); return 0; err: clean_proc(xbus, xpd); @@ -485,7 +494,7 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig) txsig2str(txsig), txsig); return -EINVAL; } - pcm_recompute(xpd, xpd->offhook | xpd->cid_on); + pcm_recompute(xpd, 0); return 0; } @@ -511,7 +520,7 @@ static void poll_battery(xbus_t *xbus, xpd_t *xpd) int i; for_each_line(xpd, i) { - DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_VBAT_REGISTER, 0); + DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_VBAT, 0); } } @@ -521,7 +530,7 @@ static void poll_current(xbus_t *xbus, xpd_t *xpd) for_each_line(xpd, i) { if (IS_SET(xpd->offhook, i)) - DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_CURRENT_REGISTER, 0); + DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0); } } @@ -532,7 +541,7 @@ static void poll_metering(xbus_t *xbus, xpd_t *xpd) for_each_line(xpd, i) { if (IS_SET(xpd->offhook, i)) - DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_METERING_REGISTER, 0); + DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0); } } #endif @@ -563,10 +572,10 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); - if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) { + if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) poll_battery(xbus, xpd); + if(poll_power_denial_interval != 0 && (priv->poll_counter % poll_power_denial_interval) == 0) poll_current(xbus, xpd); - } #ifdef WITH_METERING if(poll_metering_interval != 0 && (priv->poll_counter % poll_metering_interval) == 0) poll_metering(xbus, xpd); @@ -592,7 +601,7 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a unsigned char echotune_data[ARRAY_SIZE(echotune_regs)]; BUG_ON(!xpd); - if(!xpd->xbus->hardware_exists) + if(!TRANSPORT_RUNNING(xpd->xbus)) return -ENODEV; switch (cmd) { case WCTDM_SET_ECHOTUNE: @@ -614,8 +623,16 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a XPD_DBG(GENERAL, xpd, "-- Set echo registers successfully\n"); break; + case ZT_TONEDETECT: + /* + * Asterisk call all span types with this (FXS specific) + * call. Silently ignore it. + */ + LINE_DBG(GENERAL, xpd, pos, + "ZT_TONEDETECT (FXO: NOTIMPLEMENTED)\n"); + return -ENOTTY; default: - LINE_DBG(GENERAL, xpd, pos, "Unknown command 0x%X.\n", cmd); + report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); return -ENOTTY; } return 0; @@ -704,11 +721,17 @@ static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel) /* * Check for battery voltage fluctuations */ - if(IS_SET(priv->battery, chipsel) && priv->battery_debounce[chipsel]++ > BAT_DEBOUNCE) { - LINE_DBG(SIGNAL, xpd, chipsel, "BATTERY OFF voltage=%d\n", bat); - BIT_CLR(priv->battery, chipsel); - if(SPAN_REGISTERED(xpd)) - zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_ALARM); + if(IS_SET(priv->battery, chipsel)) { + int milliseconds; + + milliseconds = priv->battery_debounce[chipsel]++ * + poll_battery_interval; + if(milliseconds > BAT_DEBOUNCE) { + LINE_DBG(SIGNAL, xpd, chipsel, "BATTERY OFF voltage=%d\n", bat); + BIT_CLR(priv->battery, chipsel); + if(SPAN_REGISTERED(xpd)) + zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_ALARM); + } } } else { @@ -724,23 +747,24 @@ static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel) * Handle reverse polarity */ if (IS_SET(xpd->offhook, chipsel)) { /* Learn the current polarity */ - if (priv->poll_counter - priv->offhook_timestamp[chipsel] < 3) { + if (priv->poll_counter - priv->offhook_timestamp[chipsel] < POLREV_START) { priv->polarity_counter[chipsel] = 0; if (pol) BIT_SET(priv->polarity, chipsel); else BIT_CLR(priv->polarity, chipsel); - } - else if (IS_SET(priv->polarity, chipsel) != pol) { /* Polarity has reversed */ - priv->polarity_counter[chipsel]++; - if (priv->polarity_counter[chipsel] >= 2) { + } else if (IS_SET(priv->polarity, chipsel) != pol) { /* Polarity has reversed */ + int milliseconds; + + milliseconds = priv->polarity_counter[chipsel]++ * poll_battery_interval; + if (milliseconds >= POLREV_THRESHOLD) { if (pol) BIT_SET(priv->polarity, chipsel); else BIT_CLR(priv->polarity, chipsel); priv->polarity_counter[chipsel] = 0; /* Inform Zaptel */ - LINE_DBG(GENERAL, xpd, chipsel, "Send ZT_EVENT_POLARITY\n"); + LINE_DBG(SIGNAL, xpd, chipsel, "Send ZT_EVENT_POLARITY\n"); zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_POLARITY); #if 0 /* @@ -752,7 +776,7 @@ static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel) */ do_sethook(xpd, chipsel, 0); update_line_status(xpd, chipsel, 0); - pcm_recompute(xpd, xpd->offhook | xpd->cid_on); + pcm_recompute(xpd, 0); #endif } } @@ -773,7 +797,7 @@ static void update_power_denial(xpd_t *xpd, byte data_low, lineno_t chipsel) priv->current_counter[chipsel] = 0; do_sethook(xpd, chipsel, 0); update_line_status(xpd, chipsel, 0); - pcm_recompute(xpd, xpd->offhook | xpd->cid_on); + pcm_recompute(xpd, 0); } } else priv->current_counter[chipsel] = 0; @@ -803,7 +827,7 @@ static void update_metering_state(xpd_t *xpd, byte data_low, lineno_t chipsel) if(metering_tone) { /* Clear the BTD bit */ data_low &= ~BTD_BIT; - DAA_DIRECT_REQUEST(xpd->xbus, xpd, chipsel, DAA_WRITE, DAA_METERING_REGISTER, data_low); + DAA_DIRECT_REQUEST(xpd->xbus, xpd, chipsel, DAA_WRITE, DAA_REG_METERING, data_low); } } #endif @@ -817,14 +841,14 @@ static int FXO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) BUG_ON(!priv); chipsel = REG_FIELD(info, chipsel); switch(REG_FIELD(info, regnum)) { - case DAA_VBAT_REGISTER: + case DAA_REG_VBAT: update_battery_status(xpd, REG_FIELD(info, data_low), chipsel); break; - case DAA_CURRENT_REGISTER: + case DAA_REG_CURRENT: update_power_denial(xpd, REG_FIELD(info, data_low), chipsel); break; #ifdef WITH_METERING - case DAA_METERING_REGISTER: + case DAA_REG_METERING: update_metering_state(xpd, REG_FIELD(info, data_low), chipsel); break; #endif @@ -927,6 +951,10 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in for_each_line(xpd, i) { len += sprintf(page + len, "%2d ", IS_SET(priv->polarity, i)); } + len += sprintf(page + len, "\n\t%-17s: ", "polarity_counter"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%2d ", priv->polarity_counter[i]); + } #ifdef WITH_METERING len += sprintf(page + len, "\n\t%-17s: ", "metering"); for_each_line(xpd, i) { @@ -976,7 +1004,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; BUG_ON(!xpd); xbus = xpd->xbus; @@ -989,6 +1017,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; + } elements = sscanf(cmdline, "%d %c%c %x %x", &chipsel, &op, ®_type, ®_num, @@ -996,11 +1028,11 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) XPD_DBG(PROC, xpd, "'%s': %d %c%c %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, data_low); if(elements < 4) { // 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 chipsel number: %d\n", chipsel); - return -EINVAL; + goto out; } REG_FIELD(®cmd, chipsel) = chipsel; REG_FIELD(®cmd, do_subreg) = 0; @@ -1013,7 +1045,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) break; default: ERR("Unkown operation type '%c'\n", op); - return -EINVAL; + goto out; } switch(reg_type) { case 'D': @@ -1022,7 +1054,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) break; default: ERR("Unkown register type '%c'\n", reg_type); - return -EINVAL; + goto out; } if( (op == 'W' && reg_type == 'D' && elements != 5) || @@ -1031,21 +1063,18 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) ERR("%s: '%s' (%d elements): %d %c%c %02X %02X\n", __FUNCTION__, cmdline, elements, chipsel, op, reg_type, reg_num, data_low); - return -EINVAL; + goto out; } regcmd.bytes = sizeof(regcmd) - 1; REG_FIELD(®cmd, data_low) = data_low; REG_FIELD(®cmd, data_high) = 0; REG_FIELD(®cmd, read_request) = writing; - if(!down_read_trylock(&xbus->in_use)) { - XBUS_DBG(GENERAL, xbus, "Dropped packet. Is in_use\n"); - return -EBUSY; - } xpd->requested_reply = regcmd; if(print_dbg) dump_reg_cmd("FXO", ®cmd, 1); ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, REG_FIELD(®cmd, chipsel), writing, REG_FIELD(®cmd, regnum), REG_FIELD(®cmd, data_low)); - up_read(&xbus->in_use); +out: + XBUS_PUT(xbus); return ret; } |