summaryrefslogtreecommitdiff
path: root/xpp/card_fxo.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/card_fxo.c')
-rw-r--r--xpp/card_fxo.c341
1 files changed, 224 insertions, 117 deletions
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c
index 7187d08..70d6018 100644
--- a/xpp/card_fxo.c
+++ b/xpp/card_fxo.c
@@ -29,12 +29,13 @@
#include "xpp_zap.h"
#include "card_fxo.h"
#include "zap_debug.h"
+#include "xbus-core.h"
static const char rcsid[] = "$Id$";
-DEF_PARM(int, print_dbg, 0, "Print DBG statements");
-DEF_PARM(uint, poll_battery_interval, 100, "Poll battery interval in milliseconds (0 - disable)");
-DEF_PARM(bool, report_battery, 0, "Report battery status to zaptel");
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements");
+DEF_PARM(uint, poll_battery_interval, 100, 0600, "Poll battery interval in milliseconds (0 - disable)");
+DEF_PARM(int, ring_debounce, 50, 0600, "Number of ticks to debounce a false RING indication");
/* Signaling is opposite (fxs signalling for fxo card) */
#if 1
@@ -65,7 +66,6 @@ static /* 0x0F */ DECLARE_CMD(FXO, REGISTER_REQUEST, byte chipsel, bool writing,
/*---------------- FXO Protocol Commands ----------------------------------*/
static /* 0x0F */ DECLARE_CMD(FXO, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, lineno_t chan);
static /* 0x0F */ DECLARE_CMD(FXO, RING, lineno_t chan, bool on);
static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
@@ -79,33 +79,38 @@ static int handle_register_command(xpd_t *xpd, char *cmdline);
#define PROC_REGISTER_FNAME "slics"
#define PROC_FXO_INFO_FNAME "fxo_info"
+#define DAA_CURRENT_REGISTER 0x1C
#define DAA_RING_REGISTER 0x05
struct FXO_priv_data {
- struct proc_dir_entry *regfile;
- struct proc_dir_entry *fxo_info;
- uint poll_counter;
- xpp_line_t battery;
- ushort battery_debounce[CHANNELS_PERXPD];
- xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
- xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
- int blinking[NUM_LEDS][CHANNELS_PERXPD];
+ struct proc_dir_entry *regfile;
+ struct proc_dir_entry *fxo_info;
+ uint poll_counter;
+ xpp_line_t battery;
+ ushort battery_debounce[CHANNELS_PERXPD];
+ xpp_line_t polarity;
+ ushort polarity_counter[CHANNELS_PERXPD];
+ uint offhook_timestamp[CHANNELS_PERXPD];
+ ushort current_counter[CHANNELS_PERXPD];
+ xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ int led_counter[NUM_LEDS][CHANNELS_PERXPD];
+ atomic_t ring_debounce[CHANNELS_PERXPD];
};
-/*---------------- FXO: Static functions ----------------------------------*/
+/*
+ * LED counter values:
+ * n>1 : BLINK every n'th tick
+ */
+#define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos])
+#define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0)
+#define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t))
+#define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+#define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
-#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
-#define MARK_BLINK(priv,pos,color,val) ((priv)->blinking[color][pos] = (val))
+#define LED_BLINK_RING (1000/8) /* in ticks */
-void MARK_LED(xpd_t *xpd, lineno_t pos, byte color, bool on)
-{
- struct FXO_priv_data *priv = xpd->priv;
-
- if(on)
- BIT_SET(priv->ledcontrol[color], pos);
- else
- BIT_CLR(priv->ledcontrol[color], pos);
-}
+/*---------------- FXO: Static functions ----------------------------------*/
/*
* LED control is done via DAA register 0x20
@@ -152,9 +157,13 @@ static void handle_fxo_leds(xpd_t *xpd)
for_each_line(xpd, i) {
if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
continue;
- if(IS_BLINKING(priv,i,color)) {
+ if(xpd->blink_mode || IS_BLINKING(priv,i,color)) {
+ int mod_value = LED_COUNTER(priv, i, color);
+
+ if(!mod_value)
+ mod_value = DEFAULT_LED_PERIOD; /* safety value */
// led state is toggled
- if((timer_count % LED_BLINK_PERIOD) == 0) {
+ if((timer_count % mod_value) == 0) {
DBG("%s/%s/%d: ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
(IS_SET(priv->ledstate[color], i))?"ON":"OFF");
if(!IS_SET(priv->ledstate[color], i)) {
@@ -178,10 +187,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 */
if(on && !xpd->ringing[pos]) {
DBG("%s/%s/%d: START\n", xpd->xbus->busname, xpd->xpdname, pos);
xpd->ringing[pos] = 1;
- MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK);
+ MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK_RING);
if(update_zap)
update_zap_ring(xpd, pos, on);
} else if(!on && xpd->ringing[pos]) {
@@ -214,18 +224,19 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
mark_ring(xpd, pos, 0, 0); // No more rings
value = (to_offhook) ? 0x09 : 0x08; /* Bit 3 is for CID */
DBG("%s/%s/%d: SETHOOK: value=0x%02X %s\n", xbus->busname, xpd->xpdname, pos, value, (to_offhook)?"OFFHOOK":"ONHOOK");
- MARK_LED(xpd, pos, LED_GREEN, (to_offhook)?LED_ON:LED_OFF);
+ if(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);
if(to_offhook) {
BIT_SET(xpd->offhook, pos);
+ priv->offhook_timestamp[pos] = priv->poll_counter;
} else {
BIT_CLR(xpd->offhook, pos);
BIT_CLR(xpd->cid_on, pos);
- xpd->delay_until_dialtone[pos] = 0;
}
spin_unlock_irqrestore(&xpd->lock, flags);
- if(to_offhook)
- wake_up_interruptible(&xpd->txstateq[pos]);
return ret;
}
@@ -299,10 +310,20 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
goto err;
// Hanghup all lines
for_each_line(xpd, i) {
- init_waitqueue_head(&xpd->txstateq[i]);
do_sethook(xpd, i, 0);
}
DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 1);
+ msleep(50);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ msleep(50);
+ }
return 0;
err:
clean_proc(xbus, xpd);
@@ -343,10 +364,9 @@ static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on)
cur_chan->pvt = xpd;
cur_chan->sigcap = FXO_DEFAULT_SIGCAP;
}
- MARK_LED(xpd, ALL_LINES, LED_GREEN, LED_OFF);
for_each_line(xpd, i) {
- MARK_LED(xpd, i, LED_GREEN, LED_ON);
- msleep(50);
+ MARK_ON(priv, i, LED_GREEN);
+ msleep(4);
}
return 0;
}
@@ -364,8 +384,10 @@ static int FXO_card_zaptel_postregistration(xpd_t *xpd, bool on)
BUG_ON(!priv);
DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
for_each_line(xpd, i) {
- MARK_LED(xpd, i, LED_GREEN, LED_OFF);
- msleep(50);
+ MARK_OFF(priv, i, LED_GREEN);
+ msleep(2);
+ // MARK_OFF(priv, i, LED_RED);
+ msleep(2);
}
return 0;
}
@@ -404,6 +426,35 @@ static void poll_battery(xbus_t *xbus, xpd_t *xpd)
}
}
+static void poll_current(xbus_t *xbus, xpd_t *xpd)
+{
+ int i;
+
+ for_each_line(xpd, i) {
+ if (IS_SET(xpd->offhook, i))
+ DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_CURRENT_REGISTER, 0);
+ }
+}
+
+static void handle_fxo_ring(xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+ int i;
+
+ priv = xpd->priv;
+ for_each_line(xpd, i) {
+ if(atomic_read(&priv->ring_debounce[i]) > 0) {
+ /* Maybe start ring */
+ if(atomic_dec_and_test(&priv->ring_debounce[i]))
+ mark_ring(xpd, i, 1, 1);
+ } else if (atomic_read(&priv->ring_debounce[i]) < 0) {
+ /* Maybe stop ring */
+ if(atomic_inc_and_test(&priv->ring_debounce[i]))
+ mark_ring(xpd, i, 0, 1);
+ }
+ }
+}
+
static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
{
struct FXO_priv_data *priv;
@@ -413,54 +464,51 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!priv);
if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) {
poll_battery(xbus, xpd);
+ poll_current(xbus, xpd);
}
handle_fxo_leds(xpd);
+ handle_fxo_ring(xpd);
priv->poll_counter++;
return 0;
}
/* FIXME: based on data from from wctdm.h */
#include <wctdm.h>
-static const int echotune_reg[] = {30,45,46,47,58,49,50,51,52};
-union echotune {
- /* "coeff 0" is acim */
- unsigned char coeff[sizeof(echotune_reg)];
- struct wctdm_echo_coefs wctdm_struct;
-};
+/*
+ * The first register is the ACIM, the other are coefficient registers.
+ * We define the array size explicitly to track possible inconsistencies
+ * if the struct is modified.
+ */
+static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52};
static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
{
- union echotune echoregs;
- int i,ret;
+ int i,ret;
+ unsigned char echotune_data[ARRAY_SIZE(echotune_regs)];
BUG_ON(!xpd);
- DBG("cmd: 0x%X, expecting: 0x%X, pos=%d.\n", cmd, WCTDM_SET_ECHOTUNE, pos);
switch (cmd) {
case WCTDM_SET_ECHOTUNE:
DBG("-- Setting echo registers: \n");
/* first off: check if this span is fxs. If not: -EINVALID */
- if (copy_from_user(&echoregs.wctdm_struct,
- (struct wctdm_echo_coefs __user *)arg, sizeof(echoregs.wctdm_struct)))
+ if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data)))
return -EFAULT;
- /* Set the ACIM register */
- /* quick and dirty registers writing: */
- for (i=0; i<sizeof(echotune_reg); i++) {
- char buf[22];
- sprintf(buf, "%d WD %2X %2X",
- pos,echotune_reg[i],echoregs.coeff[i]
- );
- /* FIXME: code duplicated from proc_xpd_register_write */
- ret = handle_register_command(xpd, buf);
- if(ret < 0)
+ for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) {
+ DBG("Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]);
+ ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]);
+ if (ret < 0) {
+ NOTICE("%s/%s/%d: Couldn't write %0x02X to register %0x02X\n",
+ xpd->xbus->busname, xpd->xpdname, pos, echotune_data[i], echotune_regs[i]);
return ret;
+ }
msleep(1);
}
DBG("-- Set echo registers successfully\n");
-
break;
default:
+ DBG("%s/%s/%d: Unknown command 0x%X.\n", xpd->xbus->busname, xpd->xpdname, pos, cmd);
return -ENOTTY;
}
return 0;
@@ -471,6 +519,7 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
/* 0x0F */ HOSTCMD(FXO, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
{
int ret = 0;
+ xframe_t *xframe;
xpacket_t *pack;
reg_cmd_t *reg_cmd;
@@ -478,7 +527,7 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
DBG("NO XBUS\n");
return -EINVAL;
}
- XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
+ XFRAME_NEW(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
#if 0
DBG("%s/%s/%d: %c%c R%02X S%02X %02X %02X\n",
xbus->busname, xpd->xpdname, chipsel,
@@ -487,7 +536,6 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
regnum, subreg, data_low, data_high);
#endif
reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
- pack->datalen = sizeof(*reg_cmd);
reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
REG_FIELD(reg_cmd, chipsel) = chipsel;
REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
@@ -496,42 +544,23 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
REG_FIELD(reg_cmd, subreg) = subreg;
REG_FIELD(reg_cmd, data_low) = data_low;
REG_FIELD(reg_cmd, data_high) = data_high;
- ret = packet_send(xbus, pack);
+ ret = xframe_send(xbus, xframe);
return ret;
}
static /* 0x0F */ HOSTCMD(FXO, XPD_STATE, bool on)
{
- int ret = 0;
- int i;
+ int ret = 0;
+ struct FXO_priv_data *priv;
BUG_ON(!xbus);
BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
DBG("%s/%s: %s\n", xbus->busname, xpd->xpdname, (on) ? "on" : "off");
- if(on) {
- for_each_line(xpd, i) {
- MARK_LED(xpd, i, LED_GREEN, LED_ON);
- msleep(20);
- }
- for_each_line(xpd, i) {
- MARK_LED(xpd, i, LED_GREEN, LED_OFF);
- msleep(20);
- }
- }
return ret;
}
-static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, lineno_t chan)
-{
- int ret = 0;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
- return ret;
-}
-
-
static /* 0x0F */ HOSTCMD(FXO, RING, lineno_t chan, bool on)
{
BUG_ON(!xbus);
@@ -557,7 +586,7 @@ HANDLER_DEF(FXO, SIG_CHANGED)
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ __FUNCTION__, cmd->name, XPD_NUM(pack->addr));
return -EPROTO;
}
priv = xpd->priv;
@@ -565,19 +594,109 @@ HANDLER_DEF(FXO, SIG_CHANGED)
DBG("%s/%s: (PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", xpd->xbus->busname, xpd->xpdname, sig_toggles, sig_status);
spin_lock_irqsave(&xpd->lock, flags);
for_each_line(xpd, i) {
+ int debounce;
+
if(IS_SET(sig_toggles, i)) {
if(!IS_SET(priv->battery, i)) {
- DBG("%s/%s/%d: battery is off. ignore false alarm.\n",
+ DBG("%s/%s/%d: SIG_CHANGED while battery is off.\n",
xbus->busname, xpd->xpdname, i);
- continue;
+ // FIXME: allow dialing without battery polling...
+ // continue;
}
- mark_ring(xpd, i, IS_SET(sig_status, i), 1);
+ /* First report false ring alarms */
+ debounce = atomic_read(&priv->ring_debounce[i]);
+ if(debounce)
+ NOTICE("%s/%s/%d: debounced %d ticks\n", xbus->busname, xpd->xpdname, i, debounce);
+ /*
+ * Now set a new ring alarm.
+ * It will be checked in handle_fxo_ring()
+ */
+ debounce = (IS_SET(sig_status, i)) ? ring_debounce : -ring_debounce;
+ atomic_set(&priv->ring_debounce[i], debounce);
}
}
spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
}
+static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel)
+{
+ struct FXO_priv_data *priv;
+ byte bat = abs((signed char)data_low);
+ byte pol = IS_SET(data_low, 7);
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(bat < BAT_THRESHOLD) {
+ /*
+ * Check for battery voltage fluctuations
+ */
+ if(IS_SET(priv->battery, chipsel) && priv->battery_debounce[chipsel]++ > BAT_DEBOUNCE) {
+ DBG("%s/%s/%d: BATTERY OFF voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
+ BIT_CLR(priv->battery, chipsel);
+ update_line_status(xpd, chipsel, 0);
+ }
+ } else {
+ priv->battery_debounce[chipsel] = 0;
+ if(!IS_SET(priv->battery, chipsel)) {
+ DBG("%s/%s/%d: BATTERY ON voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
+ BIT_SET(priv->battery, chipsel);
+ }
+ }
+ /*
+ * Handle reverse polarity
+ */
+ if (IS_SET(xpd->offhook, chipsel)) { /* Learn the current polarity */
+ if (priv->poll_counter - priv->offhook_timestamp[chipsel] < 3) {
+ 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) {
+ if (pol)
+ BIT_SET(priv->polarity, chipsel);
+ else
+ BIT_CLR(priv->polarity, chipsel);
+ priv->polarity_counter[chipsel] = 0;
+ /* Inform Zaptel */
+ zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_POLARITY);
+#if 0
+ /*
+ * These two lines hangup the channel (by sending a message to
+ * the firmware), and inform Zaptel that the line has been hung-up.
+ * They are not needed if Asterisk does the hangup after receiving
+ * a notification from Zaptel (which is sent by the above zt_qevent_lock().
+ * Asterisk does that if it has "hanguponpolarityswitch=1" in zapata.conf.
+ */
+ do_sethook(xpd, chipsel, 0);
+ update_line_status(xpd, chipsel, 0);
+#endif
+ }
+ }
+ }
+}
+
+static void update_power_denial(xpd_t *xpd, byte data_low, lineno_t chipsel)
+{
+ struct FXO_priv_data *priv;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if (IS_SET(xpd->offhook, chipsel) && data_low < 3) {
+ priv->current_counter[chipsel]++;
+ if (priv->current_counter[chipsel] >= 10) {
+ priv->current_counter[chipsel] = 0;
+ do_sethook(xpd, chipsel, 0);
+ update_line_status(xpd, chipsel, 0);
+ }
+ } else
+ priv->current_counter[chipsel] = 0;
+}
+
HANDLER_DEF(FXO, DAA_REPLY)
{
reg_cmd_t *info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, regcmd);
@@ -587,36 +706,20 @@ HANDLER_DEF(FXO, DAA_REPLY)
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ __FUNCTION__, cmd->name, XPD_NUM(pack->addr));
return -EPROTO;
}
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
chipsel = REG_FIELD(info, chipsel);
-
- /*
- * Update battery status
- */
- if(REG_FIELD(info, regnum) == DAA_VBAT_REGISTER) {
- byte bat = abs((signed char)REG_FIELD(info, data_low));
-
- if(bat < BAT_THRESHOLD) {
- /*
- * Check for battery voltage fluctuations
- */
- if(IS_SET(priv->battery, chipsel) && priv->battery_debounce[chipsel]++ > BAT_DEBOUNCE) {
- DBG("%s/%s/%d: BATTERY OFF voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
- BIT_CLR(priv->battery, chipsel);
- update_line_status(xpd, chipsel, 0);
- }
- } else {
- priv->battery_debounce[chipsel] = 0;
- if(!IS_SET(priv->battery, chipsel)) {
- DBG("%s/%s/%d: BATTERY ON voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
- BIT_SET(priv->battery, chipsel);
- }
- }
+ switch(REG_FIELD(info, regnum)) {
+ case DAA_VBAT_REGISTER:
+ update_battery_status(xpd, REG_FIELD(info, data_low), chipsel);
+ break;
+ case DAA_CURRENT_REGISTER:
+ update_power_denial(xpd, REG_FIELD(info, data_low), chipsel);
+ break;
}
#if 0
DBG("DAA_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
@@ -658,10 +761,8 @@ xproto_table_t PROTO_TABLE(FXO) = {
.RING = XPROTO_CALLER(FXO, RING),
.RELAY_OUT = XPROTO_CALLER(FXO, RELAY_OUT),
.XPD_STATE = XPROTO_CALLER(FXO, XPD_STATE),
- .CHAN_CID = XPROTO_CALLER(FXO, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
- .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
},
.packet_is_valid = fxo_packet_is_valid,
.packet_dump = fxo_packet_dump,
@@ -672,7 +773,7 @@ static bool fxo_packet_is_valid(xpacket_t *pack)
const xproto_entry_t *xe;
//DBG("\n");
- xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->content.opcode);
+ xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->opcode);
return xe != NULL;
}
@@ -896,7 +997,12 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
int __init card_fxo_startup(void)
{
- INFO("%s\n", THIS_MODULE->name);
+ if(ring_debounce <= 0) {
+ ERR("%s: ring_debounce=%d. Must be positive number of ticks\n",
+ THIS_MODULE->name, ring_debounce);
+ return -EINVAL;
+ }
+ INFO("%s revision %s\n", THIS_MODULE->name, XPP_VERSION);
xproto_register(&PROTO_TABLE(FXO));
return 0;
}
@@ -909,6 +1015,7 @@ void __exit card_fxo_cleanup(void)
MODULE_DESCRIPTION("XPP FXO Card Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
MODULE_ALIAS_XPD(XPD_TYPE_FXO);
module_init(card_fxo_startup);