summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-07 20:58:46 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-07 20:58:46 +0000
commit8953e09799d8995e3667e5766a362d282700af20 (patch)
tree8ce49c141cdccd5b1398979e809a3bdeeff0e9d8
parent237daca586a95a8f46c5e3326acf9015a004bf1b (diff)
xpp driver rev. 3332:
* Reverse polarity and power denial detection. * A short led flash at registration time. * Add a real version of the xpp modules to them (independent of the Zaptel version). * Update our line status even when not registered. * Fixed a false SIG_CHANGED when inserting or removing cable to FXO. * Fixed compilation fixes for 2.6.20 (Bug #8982) * A cleaner fix for the bool changes of 2.6.19 . * Automatically detect echo_can_state_t at debug time. * Automaitcally set XPP_DEBUGFS (depending on debugfs) at compile time. * Bug-fixes to zaptel-helper. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@2113 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--xpp/Makefile33
-rw-r--r--xpp/card_fxo.c265
-rw-r--r--xpp/card_fxs.c90
-rw-r--r--xpp/card_global.c27
-rwxr-xr-xxpp/init_card_4_246
-rwxr-xr-xxpp/init_card_6_2447
-rwxr-xr-xxpp/init_card_7_2443
-rw-r--r--xpp/utils/Makefile4
-rwxr-xr-xxpp/utils/genzaptelconf32
-rw-r--r--xpp/utils/xpp.rules8
-rw-r--r--xpp/utils/xpp_fxloader2
-rw-r--r--[-rwxr-xr-x]xpp/utils/zaptel-helper (renamed from xpp/zaptel-helper)30
-rw-r--r--xpp/xbus-core.c39
-rw-r--r--xpp/xdefs.h4
-rw-r--r--xpp/xpd.h30
-rw-r--r--xpp/xpp_usb.c17
-rw-r--r--xpp/xpp_zap.c149
17 files changed, 527 insertions, 299 deletions
diff --git a/xpp/Makefile b/xpp/Makefile
index deaadcf..1588416 100644
--- a/xpp/Makefile
+++ b/xpp/Makefile
@@ -3,18 +3,20 @@ EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \
-DDEBUG \
-DPOLL_DIGITAL_INPUTS \
-DWITH_ECHO_SUPPRESSION \
- -DPROTOCOL_DEBUG \
- -DZAPTEL_EC_TYPEDEF \
+ -DPROTOCOL_DEBUG
-# Useful for Astribank-BRI debugging, and maybe more later on.
-# Requires debugfs support in the kernel.
-# -DXPP_DEBUGFS
+ifneq (,$(filter y m,$(CONFIG_DEBUG_FS)))
+EXTRA_CFLAGS += -DXPP_DEBUGFS
+endif
+ifneq (,$(shell grep -w echo_can_state_t $(ZAPTEL_DIR)/zaptel.h))
+EXTRA_CFLAGS += -DZAPTEL_EC_TYPEDEF
+endif
-DRIVER_DIR = $(SUBDIRS)
+ZAPTEL_DIR = $(SUBDIRS)
obj-m += xpp.o xpd_fxs.o xpd_fxo.o
-HAS_BRISTUFF := $(shell cpp $(CPPFLAGS) -dM $(DRIVER_DIR)/zconfig.h | sed -n 's/^.*CONFIG_ZAPATA_BRI_DCHANS/y/p')
+HAS_BRISTUFF := $(shell cpp $(CPPFLAGS) -dM $(ZAPTEL_DIR)/zconfig.h | sed -n 's/^.*CONFIG_ZAPATA_BRI_DCHANS/y/p')
# Build only supported modules
ifneq (,$(filter y m,$(CONFIG_USB)))
@@ -31,3 +33,20 @@ xpd_bri-y += card_bri.o
ctags:
ctags *.[ch]
+
+# Handle versioning
+XPP_VERSION_STR ?= $(shell if [ -r $(obj)/.version ]; then echo "\"`cat $(obj)/.version`\""; else echo '"Unknown"'; fi)
+clean-files := xpp_version.h
+
+$(obj)/card_fxs.o $(obj)/card_fxo.o $(obj)/card_bri.o $(obj)/xpp_usb.o $(obj)/xpp.o: $(obj)/xpp_version.h
+
+$(obj)/xpp_version.h: FORCE
+ $(Q)echo "Compile for $(XPP_VERSION_STR)"
+ $(Q)echo '#define XPP_VERSION $(XPP_VERSION_STR)' > $@.tmp
+ $(Q)if cmp -s $@.tmp $@ ; then echo; else \
+ mv $@.tmp $@ ; \
+ fi
+ $(Q)rm -f $@.tmp
+
+.PHONY: FORCE
+FORCE:
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c
index 5d5bdc5..70d6018 100644
--- a/xpp/card_fxo.c
+++ b/xpp/card_fxo.c
@@ -33,9 +33,9 @@
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
@@ -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 ----------------------------------*/
-
-#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
-#define MARK_BLINK(priv,pos,color,val) ((priv)->blinking[color][pos] = (val))
+/*
+ * 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)
-void MARK_LED(xpd_t *xpd, lineno_t pos, byte color, bool on)
-{
- struct FXO_priv_data *priv = xpd->priv;
+#define LED_BLINK_RING (1000/8) /* in ticks */
- 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
@@ -153,8 +158,12 @@ static void handle_fxo_leds(xpd_t *xpd)
if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
continue;
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,8 +464,10 @@ 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;
}
@@ -497,22 +550,14 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
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;
}
@@ -549,6 +594,8 @@ 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: SIG_CHANGED while battery is off.\n",
@@ -556,13 +603,100 @@ HANDLER_DEF(FXO, SIG_CHANGED)
// 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);
@@ -579,29 +713,13 @@ HANDLER_DEF(FXO, DAA_REPLY)
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",
@@ -879,6 +997,11 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
int __init card_fxo_startup(void)
{
+ 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;
diff --git a/xpp/card_fxs.c b/xpp/card_fxs.c
index 5177f81..af12cd2 100644
--- a/xpp/card_fxs.c
+++ b/xpp/card_fxs.c
@@ -33,8 +33,8 @@
static const char rcsid[] = "$Id$";
-DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
-DEF_PARM(bool, poll_digital_inputs, 1, "Poll Digital Inputs"); /* must be before zap_debug.h */
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements"); /* must be before zap_debug.h */
+DEF_PARM_BOOL(poll_digital_inputs, 1, 0600, "Poll Digital Inputs"); /* must be before zap_debug.h */
/* Signaling is opposite (fxo signalling for fxs card) */
#if 1
@@ -92,9 +92,21 @@ struct FXS_priv_data {
xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
xpp_line_t found_fsk_pattern;
xpp_line_t msg_waiting;
- int blinking[NUM_LEDS][CHANNELS_PERXPD];
+ int led_counter[NUM_LEDS][CHANNELS_PERXPD];
};
+/*
+ * 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 LED_BLINK_RING (1000/8) /* in ticks */
+
/*---------------- FXS: Static functions ----------------------------------*/
static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
{
@@ -106,10 +118,6 @@ 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, 0x42, value);
}
-#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
-#define MARK_BLINK(priv,pos,color,val) ((priv)->blinking[color][pos] = (val))
-#define MARK_LED(priv,pos,color,val) ((val)?BIT_SET((priv)->ledcontrol[color],(pos)):BIT_CLR((priv)->ledcontrol[color],(pos)))
-
/*
* LED and RELAY control is done via SLIC register 0x06:
* 7 6 5 4 3 2 1 0
@@ -191,8 +199,12 @@ static void handle_fxs_leds(xpd_t *xpd)
if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
continue;
if(xpd->blink_mode || IS_BLINKING(priv, i, color)) { // Blinking
+ 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)) {
@@ -273,6 +285,7 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
{
struct FXS_priv_data *priv;
int ret = 0;
+ int i;
BUG_ON(!xpd);
priv = xpd->priv;
@@ -308,6 +321,18 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
if(ret < 0)
goto err;
DBG("%s/%s: done\n", xbus->busname, xpd->xpdname);
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ do_led(xpd, i, LED_RED, 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);
@@ -331,8 +356,6 @@ static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
xbus_t *xbus;
struct FXS_priv_data *priv;
int i;
- unsigned long flags;
- const enum fxs_leds color = (on) ? LED_GREEN : LED_RED;
BUG_ON(!xpd);
xbus = xpd->xbus;
@@ -357,13 +380,8 @@ static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
cur_chan->sigcap = FXS_DEFAULT_SIGCAP;
}
for_each_line(xpd, i) {
- spin_lock_irqsave(&xpd->lock, flags);
- do_led(xpd, i, color, LED_OFF);
- spin_unlock_irqrestore(&xpd->lock, flags);
- }
- for_each_line(xpd, i) {
- MARK_LED(priv, i, color, LED_ON);
- msleep(50);
+ MARK_ON(priv, i, LED_GREEN);
+ msleep(4);
}
return 0;
}
@@ -373,7 +391,6 @@ static int FXS_card_zaptel_postregistration(xpd_t *xpd, bool on)
xbus_t *xbus;
struct FXS_priv_data *priv;
int i;
- const enum fxs_leds color = (on) ? LED_GREEN : LED_RED;
BUG_ON(!xpd);
xbus = xpd->xbus;
@@ -382,8 +399,10 @@ static int FXS_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(priv, i, color, LED_OFF);
- msleep(50);
+ MARK_OFF(priv, i, LED_GREEN);
+ msleep(2);
+ MARK_OFF(priv, i, LED_RED);
+ msleep(2);
}
return 0;
}
@@ -717,9 +736,9 @@ static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on)
for_each_line(xpd, i)
xpd->lasttxhook[i] = value;
if(on) {
- MARK_LED(priv, ALL_CHANS, LED_GREEN, LED_ON);
+ MARK_ON(priv, ALL_CHANS, LED_GREEN);
} else {
- MARK_LED(priv, ALL_CHANS, LED_GREEN, LED_OFF);
+ MARK_OFF(priv, ALL_CHANS, LED_GREEN);
}
spin_unlock_irqrestore(&xpd->lock, flags);
return ret;
@@ -740,10 +759,10 @@ static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, value);
xpd->lasttxhook[chan] = value;
if(on) {
- MARK_BLINK(priv,chan,LED_GREEN,LED_BLINK);
+ MARK_BLINK(priv, chan, LED_GREEN, LED_BLINK_RING);
} else {
if(IS_BLINKING(priv, chan, LED_GREEN))
- MARK_BLINK(priv,chan,LED_GREEN,0);
+ MARK_BLINK(priv, chan, LED_GREEN, 0);
}
return ret;
}
@@ -779,19 +798,6 @@ HANDLER_DEF(FXS, SIG_CHANGED)
priv = xpd->priv;
DBG("%s/%s: (PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", xbus->busname, xpd->xpdname, sig_toggles, sig_status);
#if 0
- /*
- * Not needed anymore. update_line_status() returns immediately
- * if !SPAN_REGISTERED(). Now we maintain good status even if
- * we are not registered.
- *
- * FIXME: Need to notify zaptel later (when registering).
- */
- if(!SPAN_REGISTERED(xpd)) {
- NOTICE("%s: %s/%s is not registered. Skipping.\n", __FUNCTION__, xbus->busname, xpd->xpdname);
- return -ENODEV;
- }
-#endif
-#if 0
Is this needed?
for_each_line(xpd, i) {
if(IS_SET(sig_toggles, i))
@@ -804,14 +810,14 @@ HANDLER_DEF(FXS, SIG_CHANGED)
continue;
if(IS_SET(sig_toggles, i)) {
xpd->ringing[i] = 0; // No more ringing...
- MARK_BLINK(priv,i,LED_GREEN,0);
+ MARK_BLINK(priv, i, LED_GREEN, 0);
if(IS_SET(sig_status, i)) {
DBG("%s/%s/%d: OFFHOOK\n", xbus->busname, xpd->xpdname, i);
- MARK_LED(priv,i,LED_GREEN,LED_ON);
+ MARK_ON(priv, i, LED_GREEN);
update_line_status(xpd, i, 1);
} else {
DBG("%s/%s/%d: ONHOOK\n", xbus->busname, xpd->xpdname, i);
- MARK_LED(priv,i,LED_GREEN,LED_OFF);
+ MARK_OFF(priv, i, LED_GREEN);
update_line_status(xpd, i, 0);
start_stop_vm_led(xbus, xpd, i);
}
@@ -966,10 +972,10 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
len += sprintf(page + len, "%d ", IS_SET(priv->ledcontrol[led], i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "blinking");
+ len += sprintf(page + len, "\n\t%-17s: ", "led_counter");
for_each_line(xpd, i) {
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
- len += sprintf(page + len, "%d ", IS_BLINKING(priv,i,led));
+ len += sprintf(page + len, "%d ", LED_COUNTER(priv,i,led));
}
len += sprintf(page + len, "\n");
}
diff --git a/xpp/card_global.c b/xpp/card_global.c
index 17e94ef..c2c7022 100644
--- a/xpp/card_global.c
+++ b/xpp/card_global.c
@@ -30,7 +30,7 @@
static const char rcsid[] = "$Id$";
-DEF_PARM(charp,initdir, "/usr/share/zaptel", "The directory of card initialization scripts");
+DEF_PARM(charp,initdir, "/usr/share/zaptel", 0600, "The directory of card initialization scripts");
extern int print_dbg;
static bool pcm_valid(xpd_t *xpd, xpacket_t *pack);
@@ -226,27 +226,32 @@ HANDLER_DEF(GLOBAL, SYNC_REPLY)
HANDLER_DEF(GLOBAL, ERROR_CODE)
{
- byte errorcode = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode);
- reg_cmd_t *bad_cmd;
- char xpdname[XPD_NAMELEN];
+ byte errorcode = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode);
+ reg_cmd_t *bad_cmd;
+ char tmp_xpdname[XPD_NAMELEN];
+ static long rate_limit;
BUG_ON(!xbus);
+ if((rate_limit++ % 5003) > 200)
+ return 0;
if(!xpd) {
int xpd_num = XPD_NUM(pack->addr);
- snprintf(xpdname, XPD_NAMELEN, "#%d", xpd_num);
+ snprintf(tmp_xpdname, XPD_NAMELEN, "#%d", xpd_num);
} else {
- snprintf(xpdname, XPD_NAMELEN, "%s", xpd->xpdname);
+ snprintf(tmp_xpdname, XPD_NAMELEN, "%s", xpd->xpdname);
}
- if(!printk_ratelimit())
- return 0;
- NOTICE("%s/%s: %s CODE = 0x%X\n", xbus->busname, xpdname, cmd->name, errorcode);
+ NOTICE("%s/%s: FIRMWARE: %s CODE = 0x%X (rate_limit=%ld)\n",
+ xbus->busname, tmp_xpdname, cmd->name, errorcode, rate_limit);
switch(errorcode) {
case 1:
bad_cmd = &RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, info.bad_spi_cmd);
- dump_packet("BAD_SPI_CMD", pack, 1);
+ dump_packet("FIRMWARE: BAD_SPI_CMD", pack, 1);
+ break;
+ case 0xAB:
+ dump_packet("FIRMWARE: BAD_PACKET_LEN", pack, 1);
break;
default:
- NOTICE("%s/%s: %s UNKNOWN CODE = 0x%X\n", xbus->busname, xpdname, cmd->name, errorcode);
+ NOTICE("%s/%s: FIRMWARE: %s UNKNOWN CODE = 0x%X\n", xbus->busname, tmp_xpdname, cmd->name, errorcode);
dump_packet("PACKET", pack, 1);
}
/*
diff --git a/xpp/init_card_4_24 b/xpp/init_card_4_24
index b766804..884923e 100755
--- a/xpp/init_card_4_24
+++ b/xpp/init_card_4_24
@@ -160,6 +160,12 @@ echo "
31 WD 1A C0
" | sed -e 's/[;#].*$//' -e '/^[ ]*$/d'
+# Turning off red LEDs
+# Warning: do not send WD 31 20 A0 !
+for i in `seq 0 7`; do
+ echo "$i WD 20 A0";
+done;
+
set_daa_country_params "$opermode"
$LOGGER -p kern.info "$XPD_BUS/$XPD_NAME: Ending '$0'"
diff --git a/xpp/init_card_6_24 b/xpp/init_card_6_24
index b300d60..7219707 100755
--- a/xpp/init_card_6_24
+++ b/xpp/init_card_6_24
@@ -52,14 +52,31 @@ use strict;
#
package main;
+use File::Basename;
+
+my $program = basename("$0");
+my $init_dir = dirname("$0");
+my $unit_id;
+
sub logit {
- print STDERR "@_\n";
+ print STDERR "$unit_id: @_\n";
+}
+
+# Arrange for error logging
+if (-t STDERR) {
+ $unit_id = 'Interactive';
+ logit "Interactive startup\n";
+} else {
+ $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}";
+ open (STDERR, "| /usr/bin/logger -t $program -p kern.info") || die;
+ logit "Non Interactive startup\n";
}
package BRI;
sub gen {
my $fmt = shift;
+ $| = 1;
printf "$fmt\n", @_;
}
@@ -274,44 +291,27 @@ sub zthfc_startup {
package main;
-
-use File::Basename;
use Getopt::Std;
-my $program = basename("$0");
-my $init_dir = dirname("$0");
-
-# Arrange for error logging
-if (-t STDERR) {
- logit "Interactive\n";
-} else {
- open (STDERR, "| logger -s -t $program -p kern.info") || die;
- logit "Non Interactive\n";
-}
-
my %opts;
getopts('o:', \%opts);
$ENV{XPP_BASE} = '/proc/xpp';
my $output;
-my $unit_id;
if ($opts{o}) {
$output = $opts{o};
- $unit_id = 'Interactive';
} else {
$ENV{XPD_BUS} || die "Missing XPD_BUS environment variable\n";
$ENV{XPD_NAME} || die "Missing XPD_NAME environment variable\n";
$ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n";
$ENV{XPD_REVISION} || die "Missing XPD_REVISION environment variable\n";
$output = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics";
- $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}";
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
select REG;
-
-#logit "$unit_id: Starting '$0'";
+logit "Starting '$0'";
#------------------------------------------- Instance detection
@@ -361,7 +361,7 @@ my %port_type = (
# zap_xhfc_su.c:175
sub main() {
- #logit "main()";
+ #logit "main(): XPD_TYPE=$ENV{XPD_TYPE}";
$ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n";
my $type = $port_type{$ENV{XPD_TYPE}};
@@ -372,9 +372,9 @@ sub main() {
#
# Otherwise we mess with registers while the FPGA firmware tries to
# send us packets.
-
- # Common initialization
+ BRI::gen "0 Wm";
+ # Common initialization
if($ENV{XPD_SUBUNIT} eq '0') {
# Turn off multi-byte packet reception before initialization started
system("/bin/echo \"0A 00 0F 00 C0 00 00 00 00 00\" >/proc/xpp/$ENV{XPD_BUS}/command");
@@ -408,7 +408,8 @@ sub main() {
main;
-#logit "$unit_id: Ending '$0'";
+logit "Ending '$0'";
close REG;
+close STDERR;
exit 0;
diff --git a/xpp/init_card_7_24 b/xpp/init_card_7_24
index e06e8b0..7219707 100755
--- a/xpp/init_card_7_24
+++ b/xpp/init_card_7_24
@@ -52,14 +52,31 @@ use strict;
#
package main;
+use File::Basename;
+
+my $program = basename("$0");
+my $init_dir = dirname("$0");
+my $unit_id;
+
sub logit {
- print STDERR "@_\n";
+ print STDERR "$unit_id: @_\n";
+}
+
+# Arrange for error logging
+if (-t STDERR) {
+ $unit_id = 'Interactive';
+ logit "Interactive startup\n";
+} else {
+ $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}";
+ open (STDERR, "| /usr/bin/logger -t $program -p kern.info") || die;
+ logit "Non Interactive startup\n";
}
package BRI;
sub gen {
my $fmt = shift;
+ $| = 1;
printf "$fmt\n", @_;
}
@@ -274,44 +291,27 @@ sub zthfc_startup {
package main;
-
-use File::Basename;
use Getopt::Std;
-my $program = basename("$0");
-my $init_dir = dirname("$0");
-
-# Arrange for error logging
-if (-t STDERR) {
- logit "Interactive\n";
-} else {
- open (STDERR, "| logger -s -t $program -p kern.info") || die;
- logit "Non Interactive\n";
-}
-
my %opts;
getopts('o:', \%opts);
$ENV{XPP_BASE} = '/proc/xpp';
my $output;
-my $unit_id;
if ($opts{o}) {
$output = $opts{o};
- $unit_id = 'Interactive';
} else {
$ENV{XPD_BUS} || die "Missing XPD_BUS environment variable\n";
$ENV{XPD_NAME} || die "Missing XPD_NAME environment variable\n";
$ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n";
$ENV{XPD_REVISION} || die "Missing XPD_REVISION environment variable\n";
$output = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics";
- $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}";
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
select REG;
-
-#logit "$unit_id: Starting '$0'";
+logit "Starting '$0'";
#------------------------------------------- Instance detection
@@ -361,7 +361,7 @@ my %port_type = (
# zap_xhfc_su.c:175
sub main() {
- #logit "main()";
+ #logit "main(): XPD_TYPE=$ENV{XPD_TYPE}";
$ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n";
my $type = $port_type{$ENV{XPD_TYPE}};
@@ -408,7 +408,8 @@ sub main() {
main;
-#logit "$unit_id: Ending '$0'";
+logit "Ending '$0'";
close REG;
+close STDERR;
exit 0;
diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile
index 4934b21..db93ded 100644
--- a/xpp/utils/Makefile
+++ b/xpp/utils/Makefile
@@ -20,9 +20,9 @@ XPD_INIT = $(wildcard ../init_card_?_*) ../calibrate_slics
# FIXME: Are those values really sane?
HOSTCC ?= $(CC)
CONFIG_USB ?= y
-DRIVER_DIR ?= ../..
+ZAPTEL_DIR ?= ../..
-WCTDM=$(DRIVER_DIR)/wctdm.c
+WCTDM=$(ZAPTEL_DIR)/wctdm.c
CFLAGS = -g -Wall $(EXTRA_CFLAGS)
diff --git a/xpp/utils/genzaptelconf b/xpp/utils/genzaptelconf
index 03c28be..a5fb0b0 100755
--- a/xpp/utils/genzaptelconf
+++ b/xpp/utils/genzaptelconf
@@ -50,10 +50,6 @@ context_output=astbank-output # useless, but helps marking the channels :-)
#group_manual=yes
group_phones=5 # group for phones
group_lines=0 # group for lines
-# set 'immediate=yes' for Asteribank input channels and 'immediate=no'
-# for others. Note that if an Astribank is not detected, the script
-# will set this to "no", so you can safely leave it as "yes".
-set_immediate=yes
# Set fxs_immediate to 'yes' to make all FXS lines answer immediately.
fxs_immediate=no
@@ -231,15 +227,6 @@ zap_reg_xpp() {
}
-check_for_astribank(){
- if ! grep -q XPP_IN/ /proc/zaptel/* 2>/dev/null
- then
- # we only get here is if we find no Astribank input channels
- # in /proc/zaptel . Hence we can safely disable their special settings:
- set_immediate=no
- fi
-}
-
usage() {
program=`basename $0`
@@ -395,14 +382,11 @@ print_pattern() {
fi
fi
- if [ "$set_immediate" = 'yes' ]
- then
- if [ "$astbank_type" = 'input' ] || \
- ( [ "$fxs_immediate" = 'yes' ] && [ "$sig" = "fxo" ] )
- then
- echo 'immediate=yes' >> $zapata_file
- reset_values="$reset_values immediate"
- fi
+ if [ "$astbank_type" = 'input' ] || \
+ ( [ "$fxs_immediate" = 'yes' ] && [ "$sig" = "fxo" ] )
+ then
+ echo 'immediate=yes' >> $zapata_file
+ reset_values="$reset_values immediate"
fi
echo "channel => $chan" >> $zapata_file
reset_zapata_entry $zapata_file $reset_values
@@ -1028,14 +1012,10 @@ if [ "$mode" = list ]; then
genconf list
else
zap_reg_xpp
- check_for_astribank
wait_for_zapctl
say "Generating '${ZAPCONF_FILE} and ${ZAPATA_FILE}'"
genconf files
- if [ "$set_immediate" = 'yes' ] && [ -x /etc/init.d/zaptel ]
- then /etc/init.d/zaptel start
- else run_ztcfg
- fi
+ run_ztcfg
fi
if [ "$tmp_dir" != '' ]
diff --git a/xpp/utils/xpp.rules b/xpp/utils/xpp.rules
new file mode 100644
index 0000000..8a669b1
--- /dev/null
+++ b/xpp/utils/xpp.rules
@@ -0,0 +1,8 @@
+BUS!="usb", ACTION!="add", GOTO="xpp_usb_add_end"
+
+# Load firmware into the Xorcom Astribank device:
+SYSFS{idVendor}=="e4e4", SYSFS{idProduct}=="11[345][01]", \
+ RUN+="/etc/hotplug/usb/xpp_fxloader udev $sysfs{idVendor}/$sysfs{idProduct}/$sysfs{bcdDevice}"
+
+LABEL="xpp_usb_add_end"
+
diff --git a/xpp/utils/xpp_fxloader b/xpp/utils/xpp_fxloader
index 5fd4ad5..918a712 100644
--- a/xpp/utils/xpp_fxloader
+++ b/xpp/utils/xpp_fxloader
@@ -195,7 +195,7 @@ esac
## Hotplug run
##
-if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ]
+if [ "$ACTION" = "add" ] && [ -w "$DEVICE" ]
then
$LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE"
prod_id=`echo "$PRODUCT" | cut -d/ -f2`
diff --git a/xpp/zaptel-helper b/xpp/utils/zaptel-helper
index 5b17d22..1b2ca45 100755..100644
--- a/xpp/zaptel-helper
+++ b/xpp/utils/zaptel-helper
@@ -1,6 +1,25 @@
#!/bin/sh
-# zaptel-helper: helper script/functions for Zaptel .
+# zaptel-helper: helper script/functions for Zaptel
+
+# Wrriten by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+# Copyright (C) 2006-2007, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# Should be possible to run with -e set. This is also recommended.
@@ -20,6 +39,10 @@ MODLIST_FILE_REDHAT=${MODLIST_FILE_REDHAT:-/etc/sysconfig/zaptel}
FXOTUNE="${FXOTUNE:-/usr/sbin/fxotune}"
FXOTUNE_CONF="${FXOTUNE_CONF:-/etc/fxotune.conf}"
+# this is the context FXO zaptel channels are in.
+# See run_fxotune.
+FXO_CONTEXT=${FXO_CONTEXT:-from-pstn}
+
ZTCFG="${ZTCFG:-/sbin/ztcfg}"
# TODO: this may not be appropriate for a general-purpose script.
@@ -246,11 +269,12 @@ debian_start() {
# or rather: all tunable FXO channels are in the context from-pstn are
# not defined by zaptel.
run_fxotune() {
+ zap_fxo_chans=`asterisk -rx "zap show channels" | awk "/$FXO_CONTEXT/{print \$1}"`
xpp_fxo_chans=`cat /proc/zaptel/* | awk '/XPP_FXO/{print $1}'`
- for chan in $xpp_fxo_chans; do
+ for chan in $xpp_fxo_chans $zap_fxo_chans; do
asterisk -rx "zap destroy channel $chan"
done
- $FXOTUNE
+ $FXOTUNE -i
asterisk -rx "zap restart"
}
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c
index ca14b38..dc5c812 100644
--- a/xpp/xbus-core.c
+++ b/xpp/xbus-core.c
@@ -58,7 +58,7 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
/* Command line parameters */
extern int print_dbg;
-DEF_PARM(uint, poll_timeout, POLL_TIMEOUT,"Timeout (in jiffies) waiting for units to reply (default " __stringify(POLL_TIMEOUT) ")");
+DEF_PARM(uint, poll_timeout, POLL_TIMEOUT, 0600, "Timeout (in jiffies) waiting for units to reply (default " __stringify(POLL_TIMEOUT) ")");
/* Forward declarations */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
@@ -237,8 +237,12 @@ static int debugfs_release(struct inode *inode, struct file *file)
#endif
/*------------------------- Frame Handling ------------------------*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static kmem_cache_t *xframes_cache = NULL;
+#else
+static struct kmem_cache *xframes_cache = NULL;
+#endif
-static kmem_cache_t *xframes_cache = NULL;
xframe_t *xbus_xframe_new(xbus_t *xbus, gfp_t flags)
{
xframe_t *frm;
@@ -424,12 +428,24 @@ out:
}
/*
+ * Workqueue API change in kernel 2.6.20
+ * The work function always receives the work_struct as parameter
+ * and not an arbitrary pointer.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#define WORK_DATA void
+#define XBUS_WORK(xbus) INIT_WORK(&(xbus)->xpds_init_work, (void (*)(void *))xbus_poll, (void *)(xbus))
+#else
+#define WORK_DATA struct work_struct
+#define XBUS_WORK(xbus) INIT_WORK(&(xbus)->xpds_init_work, (work_func_t)xbus_poll)
+#endif
+
+/*
* This must be called from synchronous (non-interrupt) context
* it returns only when all XPD's on the bus are detected and
* initialized.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-static void xbus_poll(struct work_struct *work)
+static int xbus_poll(WORK_DATA *data)
{
xbus_t *xbus = container_of(work, xbus_t, xpds_init_work);
#else
@@ -447,7 +463,13 @@ static void xbus_poll(void *data)
struct list_head additions_list;
int count_removed;
int count_added;
+ xbus_t *xbus;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ xbus = data;
+#else
+ xbus = container_of(data, xbus_t, xpds_init_work);
+#endif
if(!down_read_trylock(&xbus->in_use)) {
ERR("%s is being removed...\n", xbus->busname);
return;
@@ -565,11 +587,7 @@ void xbus_activate(xbus_t *xbus)
xbus->hardware_exists = 1;
DBG("Activating: %s\n", xbus->busname);
/* Poll it */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
- INIT_WORK(&xbus->xpds_init_work, xbus_poll);
-#else
- INIT_WORK(&xbus->xpds_init_work, xbus_poll, xbus);
-#endif
+ XBUS_WORK(xbus);
if(!queue_work(xpp_worker, &xbus->xpds_init_work)) {
ERR("Failed to queue xpd initialization work\n");
/* FIXME: need to return error */
@@ -1127,6 +1145,9 @@ int __init xbus_core_init(void)
#ifdef PROTOCOL_DEBUG
INFO("FEATURE: %s with PROTOCOL_DEBUG\n", THIS_MODULE->name);
#endif
+#ifdef XPP_DEBUGFS
+ INFO("FEATURE: %s with XPP_DEBUGFS support\n", THIS_MODULE->name);
+#endif
xframes_cache = kmem_cache_create("xpp_frames",
sizeof(xframe_t) + XFRAME_DATASIZE,
0, 0,
diff --git a/xpp/xdefs.h b/xpp/xdefs.h
index fccec23..e6e48f6 100644
--- a/xpp/xdefs.h
+++ b/xpp/xdefs.h
@@ -22,9 +22,7 @@
*
*/
-#ifndef XPP_VERSION
-#define XPP_VERSION "external-compile"
-#endif
+#include "xpp_version.h"
#ifdef __KERNEL__
diff --git a/xpp/xpd.h b/xpp/xpd.h
index fcdbf8a..40a6a20 100644
--- a/xpp/xpd.h
+++ b/xpp/xpd.h
@@ -51,13 +51,20 @@
typedef unsigned gfp_t; /* Added in 2.6.14 */
#endif
#endif
-#define DEF_PARM(type,name,init,desc) \
- type name = init; \
- module_param(name, type, 0600); \
+
+/*
+ * FIXME: Kludge for 2.6.19
+ * bool is now defined as a proper boolean type (gcc _Bool)
+ * but the command line parsing framework handles it as int.
+ */
+#define DEF_PARM_BOOL(name,init,perm,desc) \
+ int name = init; \
+ module_param(name, bool, perm); \
MODULE_PARM_DESC(name, desc)
-#define DEF_PARM_RO(type,name,init,desc) \
+
+#define DEF_PARM(type,name,init,perm,desc) \
type name = init; \
- module_param(name, type, 0400); \
+ module_param(name, type, perm); \
MODULE_PARM_DESC(name, desc)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
@@ -248,12 +255,6 @@ static struct xpd_counters {
#define XPD_COUNTER_MAX (sizeof(xpd_counters)/sizeof(xpd_counters[0]))
-#define LED_BLINK_PERIOD (HZ/8)
-
-#define LED_ON 1
-#define LED_OFF 0
-#define LED_BLINK (-LED_BLINK_PERIOD)
-
/* Values of SLIC register 0x40 */
enum fxs_state {
FXS_LINE_DISABLED = 0x00,
@@ -282,11 +283,7 @@ struct xpd {
xpp_line_t digital_inputs; /* 0 - no, 1 - yes */
xpp_line_t digital_signalling; /* PRI/BRI signalling channels */
- int ringing[CHANNELS_PERXPD];
- bool ringer_on[CHANNELS_PERXPD]; /* For ring toggling */
-
- wait_queue_head_t txstateq[CHANNELS_PERXPD]; /* waiting on the tx state to change */
- int delay_until_dialtone[CHANNELS_PERXPD];
+ bool ringing[CHANNELS_PERXPD];
enum fxs_state lasttxhook[CHANNELS_PERXPD];
int idletxhookstate[CHANNELS_PERXPD]; /* IDLE changing hook state */
@@ -300,6 +297,7 @@ struct xpd {
int flags;
bool blink_mode; /* for visual identification */
+#define DEFAULT_LED_PERIOD (1000/8) /* in tick */
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_xpd_dir;
diff --git a/xpp/xpp_usb.c b/xpp/xpp_usb.c
index 5e9d7d1..3325f59 100644
--- a/xpp/xpp_usb.c
+++ b/xpp/xpp_usb.c
@@ -48,7 +48,7 @@
static const char rcsid[] = "$Id$";
-DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements"); /* must be before zap_debug.h */
#include "zap_debug.h"
@@ -158,10 +158,17 @@ static int xusb_open (struct inode *inode, struct file *file);
static int xusb_release (struct inode *inode, struct file *file);
static void xusb_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#define USB_PASS_CB(u) struct urb *u, struct pt_regs *regs
+#else
+#define USB_PASS_CB(u) struct urb *u
+#endif
+
static void xpp_urb_delete(struct urb *urb);
static struct urb *xpp_urb_new(xusb_t *dev, enum xusb_dir dir, size_t size);
-static void xpp_send_callback(struct urb *urb, struct pt_regs *regs);
-static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs);
+static void xpp_send_callback(USB_PASS_CB(urb));
+static void xpp_receive_callback(USB_PASS_CB(urb));
static int xusb_probe (struct usb_interface *interface, const struct usb_device_id *id);
static void xusb_disconnect (struct usb_interface *interface);
@@ -708,7 +715,7 @@ static void xusb_disconnect(struct usb_interface *interface)
INFO("XUSB #%d now disconnected\n", minor);
}
-static void xpp_send_callback(struct urb *urb, struct pt_regs *regs)
+static void xpp_send_callback(USB_PASS_CB(urb))
{
xusb_t *xusb = (xusb_t *)urb->context;
xbus_t *xbus = xusb->xbus;
@@ -731,7 +738,7 @@ static void xpp_send_callback(struct urb *urb, struct pt_regs *regs)
XUSB_COUNTER(xusb, TX_FRAMES)++;
}
-static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
+static void xpp_receive_callback(USB_PASS_CB(urb))
{
xusb_t *xusb = (xusb_t *)urb->context;
xbus_t *xbus;
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index cd10ff4..b3e7017 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -64,13 +64,13 @@ static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
-DEF_PARM(bool, pcm_tasklet, 0, "Handle PCM in a tasklet (lower interrupt load)");
-DEF_PARM(int, disable_pcm, 0, "Disable all PCM transmissions");
-DEF_PARM(int, print_dbg, 0, "Print DBG statements");
-DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)");
-DEF_PARM(bool, prefmaster, 1, "Do we want to be zaptel preferred sync master");
+DEF_PARM_BOOL(pcm_tasklet, 0, 0600, "Handle PCM in a tasklet (lower interrupt load)");
+DEF_PARM(int, disable_pcm, 0, 0600, "Disable all PCM transmissions");
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements");
+DEF_PARM_BOOL(zap_autoreg, 1, 0600, "Register spans automatically (1) or not (0)");
+DEF_PARM_BOOL(prefmaster, 1, 0600, "Do we want to be zaptel preferred sync master");
#ifdef XPP_EC_CHUNK
-DEF_PARM_RO(bool, xpp_ec, 1, "Do we use our own (1) or Zaptel's (0) echo canceller");
+DEF_PARM_BOOL(xpp_ec, 1, 0400, "Do we use our own (1) or Zaptel's (0) echo canceller");
#else
static int xpp_ec = 0;
#endif
@@ -166,44 +166,54 @@ static inline void send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
* - Takes into account BRI subunits
* - Returns an XPD pointer if we should transmit, NULL otherwise
*/
-static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, int *pline_count, xpp_line_t *plines)
+static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, size_t *pcm_len, xpp_line_t *plines)
{
bool is_bri;
bool digital_telephony;
int line_count = 0;
xpp_line_t lines;
xpd_t *xpd;
+ unsigned long flags;
+ int i;
xpd = xpd_by_addr(xbus, unit, 0);
if(!xpd || !xpd->card_present)
return NULL;
+ spin_lock_irqsave(&xpd->lock, flags);
is_bri = (xpd->type == XPD_TYPE_BRI_NT) || (xpd->type == XPD_TYPE_BRI_TE);
- digital_telephony = is_bri;
+ digital_telephony = is_bri; /* or PRI */
if(digital_telephony) {
- xpd_t *tmp_xpd;
int subunit;
+ /* without D-Channel */
lines = xpd->offhook & ~xpd->digital_signalling;
- line_count = xpd->channels - 1; /* without D-Channel */
+ for_each_line(xpd, i)
+ if(IS_SET(lines, i))
+ line_count++;
if(is_bri) {
+ /*
+ * BRI has a single PCM highway for all subunits, so
+ * we agregate the next subunits into the same
+ * transmition.
+ */
for(subunit = 1; subunit < MAX_SUBUNIT; subunit++) {
- tmp_xpd = xpd_by_addr(xbus, unit, subunit);
+ xpd_t *tmp_xpd = xpd_by_addr(xbus, unit, subunit);
+ xpp_line_t tmp_lines;
+
if(!tmp_xpd || !tmp_xpd->card_present)
continue;
- lines <<= SUBUNIT_PCM_SHIFT; /* B1, B2, D, E */
- lines |= tmp_xpd->offhook;
- lines &= ~(tmp_xpd->digital_signalling);
- line_count += tmp_xpd->channels - 1; /* Without D-channel */
+ tmp_lines = xpd->offhook & ~xpd->digital_signalling; /* Without D-channel */
+ for_each_line(tmp_xpd, i)
+ if(IS_SET(tmp_lines, i))
+ line_count++;
+ lines = (lines << SUBUNIT_PCM_SHIFT) | tmp_lines; /* B1, B2, D, E */
}
}
} else {
- int i;
-
lines = (xpd->offhook | xpd->cid_on);
- for_each_line(xpd, i) {
+ for_each_line(xpd, i)
if(IS_SET(lines, i))
line_count++;
- }
}
/*
* FIXME: Workaround a bug in sync code of the Astribank.
@@ -213,8 +223,9 @@ static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, int *pline_count, xpp_
lines = BIT(0);
line_count = 1;
}
- *pline_count = line_count;
+ *pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE;
*plines = lines;
+ spin_unlock_irqrestore(&xpd->lock, flags);
return xpd;
}
@@ -223,16 +234,15 @@ static void xbus_tick(xbus_t *xbus)
int unit;
int i;
xpp_line_t lines;
- int line_count;
xpd_t *xpd;
xframe_t *xframe = NULL;
xpacket_t *pack = NULL;
+ size_t pcm_len;
for(unit = 0; unit < MAX_UNIT; unit++) {
- if((xpd = unit_pcm_calc(xbus, unit, &line_count, &lines)) == NULL)
+ if((xpd = unit_pcm_calc(xbus, unit, &pcm_len, &lines)) == NULL)
continue;
if(lines && SPAN_REGISTERED(xpd)) {
- int pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE;
do {
// pack = NULL; /* FORCE single packet frames */
if(xframe && !pack) { /* FULL frame */
@@ -619,7 +629,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
for(j = 0; j < ZT_CHUNKSIZE; j++) {
len += sprintf(page + len, "%02X ", wchunk[j]);
}
- len += sprintf(page + len, " | %d ", xpd->delay_until_dialtone[i]);
+ len += sprintf(page + len, " | ");
}
}
#endif
@@ -778,7 +788,7 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
struct zt_span *span = &xpd->span;
if(!SPAN_REGISTERED(xpd)) {
- NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
+ // NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
return;
}
switch (alarm_flag) {
@@ -798,47 +808,45 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
{
- struct zt_chan *chan;
+ zt_rxsig_t rxsig;
BUG_ON(!xpd);
- if(!SPAN_REGISTERED(xpd))
- return;
- chan = &xpd->chans[pos];
- /*
- * We should not spinlock before calling zt_hooksig() as
- * it may call back into our xpp_hooksig() and cause
- * a nested spinlock scenario
- */
if(to_offhook) {
BIT_SET(xpd->offhook, pos);
- zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
+ rxsig = ZT_RXSIG_OFFHOOK;
} else {
BIT_CLR(xpd->offhook, pos);
BIT_CLR(xpd->cid_on, pos);
- zt_hooksig(chan, ZT_RXSIG_ONHOOK);
+ rxsig = ZT_RXSIG_ONHOOK;
}
+ /*
+ * We should not spinlock before calling zt_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ if(SPAN_REGISTERED(xpd))
+ zt_hooksig(&xpd->chans[pos], rxsig);
}
void update_zap_ring(xpd_t *xpd, int pos, bool on)
{
- struct zt_chan *chan;
+ zt_rxsig_t rxsig;
BUG_ON(!xpd);
- if(!SPAN_REGISTERED(xpd))
- return;
- chan = &xpd->chans[pos];
- /*
- * We should not spinlock before calling zt_hooksig() as
- * it may call back into our xpp_hooksig() and cause
- * a nested spinlock scenario
- */
if(on) {
BIT_CLR(xpd->cid_on, pos);
- zt_hooksig(chan, ZT_RXSIG_RING);
+ rxsig = ZT_RXSIG_RING;
} else {
BIT_SET(xpd->cid_on, pos);
- zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
+ rxsig = ZT_RXSIG_OFFHOOK;
}
+ /*
+ * We should not spinlock before calling zt_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ if(SPAN_REGISTERED(xpd))
+ zt_hooksig(&xpd->chans[pos], rxsig);
}
#ifdef CONFIG_PROC_FS
@@ -886,7 +894,7 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
xbus_t *xbus;
xpd_t *xpd;
int ret;
- bool setit;
+ int setit;
// DBG("%s: count=%ld\n", __FUNCTION__, count);
if(count >= MAX_PROC_WRITE)
@@ -958,7 +966,7 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe
{
xpd_t *xpd = data;
char buf[MAX_PROC_WRITE];
- bool zt_reg;
+ int zt_reg;
int ret;
BUG_ON(!xpd);
@@ -1005,7 +1013,7 @@ static int proc_xpd_blink_write(struct file *file, const char __user *buffer, un
{
xpd_t *xpd = data;
char buf[MAX_PROC_WRITE];
- bool blink;
+ int blink;
int ret;
BUG_ON(!xpd);
@@ -1093,13 +1101,6 @@ static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
channels = tmp_xpd->channels;
chans = tmp_xpd->span.chans;
for (i = 0; i < channels; i++) {
- if (tmp_xpd->delay_until_dialtone[i] > 0) {
- tmp_xpd->delay_until_dialtone[i]--;
- if (tmp_xpd->delay_until_dialtone[i] <= 0) {
- tmp_xpd->delay_until_dialtone[i] = 0;
- wake_up_interruptible(&tmp_xpd->txstateq[i]);
- }
- }
if(IS_SET(lines, i)) {
if(SPAN_REGISTERED(tmp_xpd)) {
memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
@@ -1118,7 +1119,7 @@ static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
void fill_beep(u_char *buf, int num, int duration)
{
- bool alternate = (duration) ? (jiffies/(duration*HZ)) & 0x1 : 0;
+ bool alternate = (duration) ? (jiffies/(duration*1000)) & 0x1 : 0;
int which;
u_char *snd;
@@ -1272,6 +1273,10 @@ static int xpp_shutdown(struct zt_span *span)
return xpd->xops->span_shutdown(xpd);
}
+/*
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
int xpp_open(struct zt_chan *chan)
{
xpd_t *xpd = chan->pvt;
@@ -1420,7 +1425,11 @@ int xpp_maint(struct zt_span *span, int cmd)
return ret;
}
-/* Set signalling type (if appropriate) */
+/*
+ * Set signalling type (if appropriate)
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
{
DBG("channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
@@ -1586,6 +1595,28 @@ static int zaptel_register_xpd(xpd_t *xpd)
}
atomic_inc(&xpd->zt_registered);
xpd->xops->card_zaptel_postregistration(xpd, 1);
+ /*
+ * Update zaptel 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 zaptel call them with a spinlock on the channel
+ * and zt_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.
+ */
+ for_each_line(xpd, cn) {
+ struct zt_chan *chans = xpd->span.chans;
+
+ if(IS_SET(xpd->offhook, cn)) {
+ NOTICE("%s/%s/%d: Report OFFHOOK to zaptel\n",
+ xbus->busname, xpd->xpdname, cn);
+ zt_hooksig(&chans[cn], ZT_RXSIG_OFFHOOK);
+ }
+ }
+#endif
return 0;
}