summaryrefslogtreecommitdiff
path: root/kernel/xpp/card_fxo.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/card_fxo.c')
-rw-r--r--kernel/xpp/card_fxo.c176
1 files changed, 124 insertions, 52 deletions
diff --git a/kernel/xpp/card_fxo.c b/kernel/xpp/card_fxo.c
index 2090773..bddfa0c 100644
--- a/kernel/xpp/card_fxo.c
+++ b/kernel/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)");
/* Backward compatibility plug */
#ifndef ZT_GET_PARAMS_V1
@@ -77,8 +79,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 */
@@ -144,10 +144,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];
@@ -201,9 +199,8 @@ 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);
+ power_change(xpd, pos, POWER_UNKNOWN);
}
static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) };
@@ -364,9 +361,12 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
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)
- power_change(xpd, pos, POWER_UNKNOWN);
+ if(to_offhook) {
+ priv->power_denial_safezone[pos] = power_denial_safezone;
+ } else {
+ 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;
@@ -443,13 +443,11 @@ static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
channels = min(2, CHANNELS_PERXPD);
else
channels = min(8, CHANNELS_PERXPD);
- xpd = xpd_alloc(sizeof(struct FXO_priv_data), proto_table, channels);
+ xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct FXO_priv_data), proto_table, channels);
if(!xpd)
return NULL;
xpd->direction = TO_PSTN;
xpd->type_name = "FXO";
- if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
- goto err;
if(fxo_proc_create(xbus, xpd) < 0)
goto err;
return xpd;
@@ -574,7 +572,6 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
/* XXX Enable hooksig for FXO XXX */
switch(txsig) {
case ZT_TXSIG_START:
- break;
case ZT_TXSIG_OFFHOOK:
ret = do_sethook(xpd, pos, 1);
break;
@@ -666,48 +663,51 @@ 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]) {
+ if(--priv->power_denial_safezone[i] == 0) {
/*
* Poll current, previous answers are meaningless
*/
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_OFFHOOK(xpd, 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);
/*
* Let Asterisk decide what to do
*/
notify_rxsig(xpd, i, ZT_RXSIG_ONHOOK);
}
- } else {
- priv->power_denial_delay[i] = 0;
- BIT_CLR(priv->maybe_power_denial, i);
}
}
}
@@ -784,7 +784,6 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
return 0;
}
-/* FIXME: based on data from from wctdm.h */
#include <wctdm.h>
/*
* The first register is the ACIM, the other are coefficient registers.
@@ -799,7 +798,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(!TRANSPORT_RUNNING(xpd->xbus))
+ if(!XBUS_IS(xpd->xbus, READY))
return -ENODEV;
switch (cmd) {
case WCTDM_SET_ECHOTUNE:
@@ -921,8 +920,7 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno)
if(milliseconds > BAT_DEBOUNCE) {
LINE_DBG(SIGNAL, xpd, portno, "BATTERY OFF voltage=%d\n", volts);
priv->battery[portno] = BATTERY_OFF;
- if(SPAN_REGISTERED(xpd))
- zap_report_battery(xpd, portno);
+ zap_report_battery(xpd, portno);
/* What's the polarity ? */
priv->polarity[portno] = POL_UNKNOWN;
priv->polarity_debounce[portno] = 0;
@@ -940,8 +938,7 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno)
if(priv->battery[portno] != BATTERY_ON) {
LINE_DBG(SIGNAL, xpd, portno, "BATTERY ON voltage=%d\n", volts);
priv->battery[portno] = BATTERY_ON;
- if(SPAN_REGISTERED(xpd))
- zap_report_battery(xpd, portno);
+ zap_report_battery(xpd, portno);
}
}
#if 0
@@ -1039,20 +1036,19 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno)
if(data_low < POWER_DENIAL_CURRENT) {
if(priv->power[portno] == POWER_ON) {
power_change(xpd, portno, POWER_OFF);
- priv->power_denial_minimum[portno] = POWER_DENIAL_TIME;
+ priv->power_denial_length[portno] = power_denial_minlen;
}
} else {
if(priv->power[portno] != POWER_ON) {
power_change(xpd, portno, POWER_ON);
- priv->power_denial_minimum[portno] = 0;
+ 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
@@ -1256,14 +1252,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]);
@@ -1327,12 +1315,95 @@ static int proc_xpd_metering_read(char *page, char **start, off_t off, int count
}
#endif
+static DEVICE_ATTR_READER(fxo_battery_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct FXO_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+ int i;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ for_each_line(xpd, i) {
+ char bat;
+
+ if(priv->battery[i] == BATTERY_ON)
+ bat = '+';
+ else if(priv->battery[i] == BATTERY_OFF)
+ bat = '-';
+ else
+ bat = '.';
+ len += sprintf(buf + len, "%c ", bat);
+ }
+ len += sprintf(buf + len, "\n");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR(fxo_battery, S_IRUGO, fxo_battery_show, NULL);
+
+
+static int fxo_xpd_probe(struct device *dev)
+{
+ xpd_t *xpd;
+ int ret;
+
+ xpd = dev_to_xpd(dev);
+ /* Is it our device? */
+ if(xpd->type != XPD_TYPE_FXO) {
+ XPD_ERR(xpd, "drop suggestion for %s (%d)\n",
+ dev->bus_id, xpd->type);
+ return -EINVAL;
+ }
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ ret = device_create_file(dev, &dev_attr_fxo_battery);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(fxo_battery) failed: %d\n", __FUNCTION__, ret);
+ goto fail_fxo_battery;
+ }
+ return 0;
+fail_fxo_battery:
+ return ret;
+}
+
+static int fxo_xpd_remove(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ device_remove_file(dev, &dev_attr_fxo_battery);
+ return 0;
+}
+
+static struct xpd_driver fxo_driver = {
+ .type = XPD_TYPE_FXO,
+ .driver = {
+ .name = "fxo",
+#ifndef OLD_HOTPLUG_SUPPORT
+ .owner = THIS_MODULE,
+#endif
+ .probe = fxo_xpd_probe,
+ .remove = fxo_xpd_remove
+ }
+};
+
static int __init card_fxo_startup(void)
{
+ int ret;
+
if(ring_debounce <= 0) {
ERR("ring_debounce=%d. Must be positive number of ticks\n", ring_debounce);
return -EINVAL;
}
+ if((ret = xpd_driver_register(&fxo_driver.driver)) < 0)
+ return ret;
INFO("revision %s\n", XPP_VERSION);
#ifdef WITH_METERING
INFO("FEATURE: WITH METERING Detection\n");
@@ -1346,6 +1417,7 @@ static int __init card_fxo_startup(void)
static void __exit card_fxo_cleanup(void)
{
xproto_unregister(&PROTO_TABLE(FXO));
+ xpd_driver_unregister(&fxo_driver.driver);
}
MODULE_DESCRIPTION("XPP FXO Card Driver");