diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-07 20:58:46 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-07 20:58:46 +0000 |
commit | 8953e09799d8995e3667e5766a362d282700af20 (patch) | |
tree | 8ce49c141cdccd5b1398979e809a3bdeeff0e9d8 | |
parent | 237daca586a95a8f46c5e3326acf9015a004bf1b (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/Makefile | 33 | ||||
-rw-r--r-- | xpp/card_fxo.c | 265 | ||||
-rw-r--r-- | xpp/card_fxs.c | 90 | ||||
-rw-r--r-- | xpp/card_global.c | 27 | ||||
-rwxr-xr-x | xpp/init_card_4_24 | 6 | ||||
-rwxr-xr-x | xpp/init_card_6_24 | 47 | ||||
-rwxr-xr-x | xpp/init_card_7_24 | 43 | ||||
-rw-r--r-- | xpp/utils/Makefile | 4 | ||||
-rwxr-xr-x | xpp/utils/genzaptelconf | 32 | ||||
-rw-r--r-- | xpp/utils/xpp.rules | 8 | ||||
-rw-r--r-- | xpp/utils/xpp_fxloader | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | xpp/utils/zaptel-helper (renamed from xpp/zaptel-helper) | 30 | ||||
-rw-r--r-- | xpp/xbus-core.c | 39 | ||||
-rw-r--r-- | xpp/xdefs.h | 4 | ||||
-rw-r--r-- | xpp/xpd.h | 30 | ||||
-rw-r--r-- | xpp/xpp_usb.c | 17 | ||||
-rw-r--r-- | xpp/xpp_zap.c | 149 |
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__ @@ -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; } |