summaryrefslogtreecommitdiff
path: root/drivers/dahdi/xpp/card_fxo.c
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2009-01-18 09:55:48 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2009-01-18 09:55:48 +0000
commitf89c302cbde0ea699009df9e5286be5001f16c20 (patch)
tree41fa4bf87faacf1979e54ac579c5dcc65e1c62aa /drivers/dahdi/xpp/card_fxo.c
parent7d1e606f63ae5ce4c4932f3d65e18adf519b9aee (diff)
xpp.r6616: More sysfs migration, FXO enhancements, BRI fixes
* Fix cases where the command_queue overflowed during initialization. * More migrations to sysfs: - Add a 'transport' attribute to our astribank devices which points to the usb device we use. E.g: /sys/bus/astribanks/devices/xbus-00/transport is symlinked to ../../../../../../devices/pci0000:00/0000:00:10.4/usb5/5-4 - Move /proc/xpp/XBUS-??/XPD-??/span to /sys/bus/xpds/devices/??:?:?/span - Migrate from /proc/xpp/sync to: /sys/bus/astribanks/drivers/xppdrv/sync * PRI: change the "timing" priority to match the convention used by other PRI cards -- I.e: lower numbers (not 0) have higher priority. * FXO: - Power denial: create two module parameters instead of hard-coded constants (power_denial_safezone, power_denial_minlen). For sites that get non-standard power-denial signals from central office on offhook. - Don't hangup on power-denial, just notify Dahdi and wait for - Fix caller-id detection for the case central office sends it before first ring without any indication before. Asterisk's desicion. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@5663 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/xpp/card_fxo.c')
-rw-r--r--drivers/dahdi/xpp/card_fxo.c190
1 files changed, 93 insertions, 97 deletions
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]);