[zaptel-commits] tzafrir: branch 1.4 r2123 - in /branches/1.4/xpp: ./ firmwares/ utils/

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Wed Feb 7 17:05:18 MST 2007


Author: tzafrir
Date: Wed Feb  7 18:05:17 2007
New Revision: 2123

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2123
Log:
Branch 1.4 is back in sync (currently: xorcom rev. 3332):
* Performance improvements for multi-XPD (span) devices.
* Astribank BRI driver (in next commit).
* Changes under /proc:
  - XBUS and XPD numbers have two digits.
  - Every script wildcard should be replaced from XBUS-? to XBUS-[0-9]*
  - Added /proc/xpp/XBUS-*/XPD-*/blink: echo 1 to start and 0 to stop.
* Several countries (South Africa, UAE, anybody else) require a shorter
  ring delay. Adjust FXO reg 0x17 (23)'s bits 0:2 to 011.
* Use tasklets to move most of the interrupt PCM copying out of the interrupt.
* Debugfs-based code to dump data to userspace (used to debug BRI D channel).
* Pretend every 2.6.9 actually has later RHEL's typedefs.
* fpga_load supports /dev/bus/usb .
* Fixed physical order sorting in genzaptelconf.
* 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. Moved to xpp/utils .
* Xbus protocol version: 2.4 (Zaptel 1.2.12/1.4.0 had 2.3).
 XPS Init scripts renamed accordingly.

Added:
    branches/1.4/xpp/firmwares/FPGA_1141.hex   (with props)
    branches/1.4/xpp/firmwares/USB_1140.hex   (with props)
    branches/1.4/xpp/init_card_3_24   (with props)
    branches/1.4/xpp/init_card_4_24   (with props)
    branches/1.4/xpp/init_card_6_24   (with props)
    branches/1.4/xpp/init_card_7_24   (with props)
    branches/1.4/xpp/utils/xpp.rules   (with props)
    branches/1.4/xpp/utils/zaptel-helper   (with props)
    branches/1.4/xpp/xpp_log.h   (with props)
Removed:
    branches/1.4/xpp/init_card_3_23
    branches/1.4/xpp/init_card_4_23
    branches/1.4/xpp/zaptel-helper
Modified:
    branches/1.4/xpp/   (props changed)
    branches/1.4/xpp/Makefile
    branches/1.4/xpp/README.Astribank
    branches/1.4/xpp/card_fxo.c
    branches/1.4/xpp/card_fxs.c
    branches/1.4/xpp/card_global.c
    branches/1.4/xpp/firmwares/FPGA_1151.hex
    branches/1.4/xpp/firmwares/FPGA_FXS.hex   (contents, props changed)
    branches/1.4/xpp/utils/Makefile
    branches/1.4/xpp/utils/adj_clock.8   (props changed)
    branches/1.4/xpp/utils/adj_clock.c   (props changed)
    branches/1.4/xpp/utils/fpga_load.8
    branches/1.4/xpp/utils/fpga_load.c
    branches/1.4/xpp/utils/genzaptelconf
    branches/1.4/xpp/utils/xpp_fxloader
    branches/1.4/xpp/xbus-core.c
    branches/1.4/xpp/xbus-core.h
    branches/1.4/xpp/xdefs.h
    branches/1.4/xpp/xpd.h
    branches/1.4/xpp/xpp_usb.c
    branches/1.4/xpp/xpp_zap.c
    branches/1.4/xpp/xpp_zap.h
    branches/1.4/xpp/xproto.c
    branches/1.4/xpp/xproto.h
    branches/1.4/xpp/zap_debug.c
    branches/1.4/xpp/zap_debug.h

Propchange: branches/1.4/xpp/
------------------------------------------------------------------------------
--- svk:merge (original)
+++ svk:merge Wed Feb  7 18:05:17 2007
@@ -1,5 +1,5 @@
-283159da-0705-0410-b60c-f2062b4bb6ad:/components/xpp-zaptel/branches/RELEASE-1.2.0/xpp:2933
-283159da-0705-0410-b60c-f2062b4bb6ad:/components/xpp-zaptel/trunk/xpp:2830
-f558416c-6c06-0410-9f27-dde2687782d0:/branches/1.2/xpp:1724
+283159da-0705-0410-b60c-f2062b4bb6ad:/components/xpp-zaptel/branches/RELEASE-1.2.0/xpp:2948
+283159da-0705-0410-b60c-f2062b4bb6ad:/components/xpp-zaptel/trunk/xpp:3332
+f558416c-6c06-0410-9f27-dde2687782d0:/branches/1.2/xpp:2122
 f558416c-6c06-0410-9f27-dde2687782d0:/team/tzafrir/xpp_1.2/xpp:1554
 f558416c-6c06-0410-9f27-dde2687782d0:/trunk/xpp:1453

Propchange: branches/1.4/xpp/
------------------------------------------------------------------------------
--- svn:executable (original)
+++ svn:executable Wed Feb  7 18:05:17 2007
@@ -1,1 +1,1 @@
-calibrate_slics
+utils/zaptel-helper

Propchange: branches/1.4/xpp/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Feb  7 18:05:17 2007
@@ -5,3 +5,4 @@
 *.mod.c
 .tmp_versions
 .*.swp
+xpp_version.h

Modified: branches/1.4/xpp/Makefile
URL: http://svn.digium.com/view/zaptel/branches/1.4/xpp/Makefile?view=diff&rev=2123&r1=2122&r2=2123
==============================================================================
--- branches/1.4/xpp/Makefile (original)
+++ branches/1.4/xpp/Makefile Wed Feb  7 18:05:17 2007
@@ -1,15 +1,52 @@
-EXTRA_CFLAGS	= -g3 -I$(SUBDIRS) -DDEBUG -DPOLL_DIGITAL_INPUTS -DWITH_ECHO_SUPPRESSION
+EXTRA_CFLAGS	=	$(XPP_LOCAL_CFLAGS)	\
+			-g3 -I$(SUBDIRS)	\
+			-DDEBUG			\
+			-DPOLL_DIGITAL_INPUTS	\
+			-DWITH_ECHO_SUPPRESSION	\
+			-DPROTOCOL_DEBUG
+
+ifneq	(,$(filter y m,$(CONFIG_DEBUG_FS)))
+EXTRA_CFLAGS	+=	-DXPP_DEBUGFS
+endif
+
+ZAPTEL_DIR	= $(SUBDIRS)
+
+ifneq	(,$(shell grep -w echo_can_state_t $(ZAPTEL_DIR)/zaptel.h))
+EXTRA_CFLAGS	+=	-DZAPTEL_EC_TYPEDEF
+endif
 
 obj-m		+= xpp.o xpd_fxs.o xpd_fxo.o
+
+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)))
 obj-m		+= xpp_usb.o
 endif
+ifneq	(,$(HAS_BRISTUFF))
+obj-m		+= xpd_bri.o
+endif
 
 xpp-y		+= xbus-core.o xpp_zap.o xproto.o card_global.o
 xpd_fxs-y	+= card_fxs.o
 xpd_fxo-y	+= card_fxo.o
+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 '#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:

Modified: branches/1.4/xpp/README.Astribank
URL: http://svn.digium.com/view/zaptel/branches/1.4/xpp/README.Astribank?view=diff&rev=2123&r1=2122&r2=2123
==============================================================================
--- branches/1.4/xpp/README.Astribank (original)
+++ branches/1.4/xpp/README.Astribank Wed Feb  7 18:05:17 2007
@@ -22,9 +22,10 @@
 
   make -C xpp/utils
   
-In order to build the user space utilities, you will need the libusb-dev 
-package on Debian (and derivatives like ubuntu) or libusb-devel on RedHat 
+In order to build the user space utilities, you will need the libusb-dev
+package on Debian (and derivatives like ubuntu) or libusb-devel on RedHat
 (and derivatives like Centox/Trixbox).
+  
 
 INSTALLATION:
 """"""""""""
@@ -130,11 +131,54 @@
 this will be the old value + 1.
 
 
+Firmware Loading with Hotplug:
+"""""""""""""""""""""""""""""
+The Hotplug framework was popular for hotplugging and usually also 
+autoloading drivers. If it is used on your system, you'll see 
+/etc/hotplug with many files under it. Hotplug will automatically load
+most relevant USB and PCI kernel modules by the relevant USB and PCI
+IDs. Again: if the framework is in place and the proper configuration
+files are in place, the firmware should be loaded automatically.
+
+In order to get hotplug to autoload the firmware into the Astribank, 
+the configuration file xpp_fxloader.usermap and the script xpp_fxloader 
+should be copied into /etc/hotplug/usb/ . This is done by 'make -C
+xpp/utils install' .
+
+xpp_fxloader.usermap includes a map of USB IDs and the command to run 
+when they are encountered. It instructs hotplug to run the script 
+xpp_fxloader from that directory. This is done by 'make -C
+xpp/utils install' .
+
+When xpp_fxloader is run without any parameters it assumes that it was
+run by the hotplug scripts. It will then check if the even is an "add"
+event (and not a "remove" event), and if so, install the required
+firmware file. It will be called twice, as after the load of the USB
+firmware the device will reenumerate itself and thus "unplug" and
+"replug" to load the FPGA firmware.
+
+
 Firmware Loading with UDEV:
 """"""""""""""""""""""""""
-Firmware loading with udev should work but is not installed 
-automatically, yet. See the comments in the beginning of the script
-/etc/hotplug/usb/xpp_fxloader .
+The UDEV framework has replaced Hotplug in most recent systems. If you
+have a recent 2.6 system with no Hotplug and files under /etc/udev,
+chances are you ude udev. udev does quite a few nice things.
+Again: if the framework is in place and the proper configuration
+files are in place, the firmware should be loaded automatically.
+
+In order to get hotplug to autoload the firmware into the Astribank, 
+the configuration file xpp.rules should be copied into /etc/udev/rules.d 
+and the script xpp_fxloader should be copied into /etc/hotplug/usb/ . 
+This is done by 'make -C xpp/utils install' .
+
+xpp.rules instructs udevd to run xpp_fxloader with the option udev and
+the USB ID when an Astribank is plugged and needs loading firmware.
+When xpp_fxloader is run with the option udev it assumes that it was
+run by udevd scripts. It will then install the required firmware file. 
+It will be called twice, as after the load of the USB firmware the
+device will reenumerate itself and thus "unplug" and "replug" to load 
+the FPGA firmware.
+
 
 Loading The Modules:
 """""""""""""""""""
@@ -301,6 +345,47 @@
           13 XPP_IN/0-12 FXOKS (In use) 
           14 XPP_IN/0-13 FXOKS (In use) 
 
+Sample dialplan (extentions.conf) for all the above:
+
+[phones-zap] 
+; 401 will dial to channel 1, 420, to zaptel channel 20, etc. 
+exten => _4XX,1,Dial(ZAP/${EXTEN:1}) 
+ 
+[trunk-9] 
+; Dial through the first FXO port availble.  
+; This assumes that all FXO ports are in group 0 and all others are not,  
+; as in the sample zapata.conf for 8FXS/8FXO below, and as is generated 
+; by genzaptelconf by default. 
+exten => 9.,Dial(Zap/g0/${EXTEN:1}) 
+ 
+[from-internal] 
+;  The context of FXS ports: analog phones.  
+; They are allowed to dial to all other phones 
+include => phones-zap 
+; They are also allowed to call through the trunk: 
+include => trunk-9 
+ 
+[from-pstn] 
+; Calls from the PSTN enter here. Redirect calls to an IVR 
+; or a default extension in the s context here. In this case we  
+; redirect calls to Zaptel channel 1: 
+exten => s,1,Dial(Zap/1) 
+ 
+[astribank-inputs] 
+exten => s,1,Set(ZAP_CHAN=Cut(${CHANNEL},-,1)) 
+exten => s,n,Set(ZAP_CHAN=Cut(${ZAP_CHAN},/,2)) 
+; 11 is the number of the first input port. At least in the sample 
+; configuration below. 
+exten => s,n,Set(INPUT_NUM=Math(${ZAP_CHAN}-11)) 
+; The sample below just logs the signal.  
+exten => s,n,NoOp(Got signal from input port number ${INPUT_NUM}) 
+; Alternatively: 
+;exten => s,n,System(run something) 
+ 
+; No. We did not forget the context astribank-outputs. Output 
+; ports only get calls from the PBX. Thus they don't need a context 
+; of their own. 
+
 
 /proc Interface
 """""""""""""""

Modified: branches/1.4/xpp/card_fxo.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/xpp/card_fxo.c?view=diff&rev=2123&r1=2122&r2=2123
==============================================================================
--- branches/1.4/xpp/card_fxo.c (original)
+++ branches/1.4/xpp/card_fxo.c Wed Feb  7 18:05:17 2007
@@ -29,12 +29,13 @@
 #include "xpp_zap.h"
 #include "card_fxo.h"
 #include "zap_debug.h"
+#include "xbus-core.h"
 
 static const char rcsid[] = "$Id$";
 
-DEF_PARM(int, print_dbg, 0, "Print DBG statements");
-DEF_PARM(uint, poll_battery_interval, 100, "Poll battery interval in milliseconds (0 - disable)");
-DEF_PARM(bool, report_battery, 0, "Report battery status to zaptel");
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements");
+DEF_PARM(uint, poll_battery_interval, 100, 0600, "Poll battery interval in milliseconds (0 - disable)");
+DEF_PARM(int, ring_debounce, 50, 0600, "Number of ticks to debounce a false RING indication");
 
 /* Signaling is opposite (fxs signalling for fxo card) */
 #if 1
@@ -65,7 +66,6 @@
 /*---------------- FXO Protocol Commands ----------------------------------*/
 
 static /* 0x0F */ DECLARE_CMD(FXO, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, lineno_t chan);
 static /* 0x0F */ DECLARE_CMD(FXO, RING, lineno_t chan, bool on);
 static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
 
@@ -79,33 +79,38 @@
 #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];
 };
 
+/*
+ * 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 */
+
 /*---------------- 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))
-
-void MARK_LED(xpd_t *xpd, lineno_t pos, byte color, bool on)
-{
-	struct FXO_priv_data *priv = xpd->priv;
-
-	if(on)
-		BIT_SET(priv->ledcontrol[color], pos);
-	else
-		BIT_CLR(priv->ledcontrol[color], pos);
-}
 
 /*
  * LED control is done via DAA register 0x20
@@ -152,9 +157,13 @@
 	for_each_line(xpd, i) {
 		if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
 			continue;
-		if(IS_BLINKING(priv,i,color)) {
+		if(xpd->blink_mode || IS_BLINKING(priv,i,color)) {
+			int	mod_value = LED_COUNTER(priv, i, color);
+
+			if(!mod_value)
+				mod_value = DEFAULT_LED_PERIOD;		/* safety value */
 			// led state is toggled
-			if((timer_count % LED_BLINK_PERIOD) == 0) {
+			if((timer_count % mod_value) == 0) {
 				DBG("%s/%s/%d: ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
 						(IS_SET(priv->ledstate[color], i))?"ON":"OFF");
 				if(!IS_SET(priv->ledstate[color], i)) {
@@ -178,10 +187,11 @@
 
 	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 @@
 	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 @@
 		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 @@
 		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);
+	for_each_line(xpd, i) {
+		MARK_ON(priv, i, LED_GREEN);
+		msleep(4);
 	}
 	return 0;
 }
@@ -364,8 +384,10 @@
 	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_current(xbus_t *xbus, xpd_t *xpd)
+{
+	int	i;
+
+	for_each_line(xpd, i) {
+		if (IS_SET(xpd->offhook, i))
+			DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_CURRENT_REGISTER, 0);
+	}
+}
+
+static void handle_fxo_ring(xpd_t *xpd)
+{
+	struct FXO_priv_data	*priv;
+	int			i;
+
+	priv = xpd->priv;
+	for_each_line(xpd, i) {
+		if(atomic_read(&priv->ring_debounce[i]) > 0) {
+			/* Maybe start ring */
+			if(atomic_dec_and_test(&priv->ring_debounce[i]))
+				mark_ring(xpd, i, 1, 1);
+		} else if (atomic_read(&priv->ring_debounce[i]) < 0) {
+			/* Maybe stop ring */
+			if(atomic_inc_and_test(&priv->ring_debounce[i]))
+				mark_ring(xpd, i, 0, 1);
+		}
+	}
+}
+
 static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
 {
 	struct FXO_priv_data	*priv;
@@ -413,54 +464,51 @@
 	BUG_ON(!priv);
 	if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) {
 		poll_battery(xbus, xpd);
+		poll_current(xbus, xpd);
 	}
 	handle_fxo_leds(xpd);
+	handle_fxo_ring(xpd);
 	priv->poll_counter++;
 	return 0;
 }
 
 /* FIXME: based on data from from wctdm.h */
 #include <wctdm.h>
-static const int echotune_reg[] = {30,45,46,47,58,49,50,51,52};
-union echotune {
-	/* "coeff 0" is acim */
-	unsigned char		coeff[sizeof(echotune_reg)];
-	struct wctdm_echo_coefs	wctdm_struct;
-};
+/*
+ * The first register is the ACIM, the other are coefficient registers.
+ * We define the array size explicitly to track possible inconsistencies
+ * if the struct is modified.
+ */
+static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52};
 
 static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
 {
-	union echotune	echoregs;
-	int 		i,ret;
-
-	BUG_ON(!xpd);
-	DBG("cmd: 0x%X, expecting: 0x%X, pos=%d.\n", cmd, WCTDM_SET_ECHOTUNE, pos);
+	int 			i,ret;
+	unsigned char		echotune_data[ARRAY_SIZE(echotune_regs)];
+
+	BUG_ON(!xpd);
 	switch (cmd) {
 		case WCTDM_SET_ECHOTUNE:
 			DBG("-- Setting echo registers: \n");
 			/* first off: check if this span is fxs. If not: -EINVALID */
-			if (copy_from_user(&echoregs.wctdm_struct, 
-				(struct wctdm_echo_coefs __user *)arg, sizeof(echoregs.wctdm_struct)))
+			if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data)))
 				return -EFAULT;
 
-			/* Set the ACIM register */
-			/* quick and dirty registers writing: */
-			for (i=0; i<sizeof(echotune_reg); i++) {
-				char buf[22];
-				sprintf(buf, "%d WD %2X %2X",
-					pos,echotune_reg[i],echoregs.coeff[i]
-				);
-				/* FIXME: code duplicated from proc_xpd_register_write */
-				ret = handle_register_command(xpd, buf);
-				if(ret < 0)
+			for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) {
+				DBG("Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]);
+				ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]);
+				if (ret < 0) {
+					NOTICE("%s/%s/%d: Couldn't write %0x02X to register %0x02X\n",
+							xpd->xbus->busname, xpd->xpdname, pos, echotune_data[i], echotune_regs[i]);
 					return ret;
+				}
 				msleep(1);
 			}
 
 			DBG("-- Set echo registers successfully\n");
-
 			break;
 		default:
+			DBG("%s/%s/%d: Unknown command 0x%X.\n", xpd->xbus->busname, xpd->xpdname, pos, cmd);
 			return -ENOTTY;
 	}
 	return 0;
@@ -471,6 +519,7 @@
 /* 0x0F */ HOSTCMD(FXO, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
 {
 	int		ret = 0;
+	xframe_t	*xframe;
 	xpacket_t	*pack;
 	reg_cmd_t	*reg_cmd;
 
@@ -478,7 +527,7 @@
 		DBG("NO XBUS\n");
 		return -EINVAL;
 	}
-	XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
+	XFRAME_NEW(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
 #if 0
 	DBG("%s/%s/%d: %c%c R%02X S%02X %02X %02X\n",
 			xbus->busname, xpd->xpdname, chipsel,
@@ -487,7 +536,6 @@
 			regnum, subreg, data_low, data_high);
 #endif
 	reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
-	pack->datalen = sizeof(*reg_cmd);
 	reg_cmd->bytes = sizeof(*reg_cmd) - 1;	// do not count the 'bytes' field
 	REG_FIELD(reg_cmd, chipsel) = chipsel;
 	REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
@@ -496,41 +544,22 @@
 	REG_FIELD(reg_cmd, subreg) = subreg;
 	REG_FIELD(reg_cmd, data_low) = data_low;
 	REG_FIELD(reg_cmd, data_high) = data_high;
-	ret = packet_send(xbus, pack);
+	ret = xframe_send(xbus, xframe);
 	return ret;
 }
 
 static /* 0x0F */ HOSTCMD(FXO, XPD_STATE, bool on)
 {
-	int	ret = 0;
-	int	i;
+	int			ret = 0;
+	struct FXO_priv_data	*priv;
 
 	BUG_ON(!xbus);
 	BUG_ON(!xpd);
+	priv = xpd->priv;
+	BUG_ON(!priv);
 	DBG("%s/%s: %s\n", xbus->busname, xpd->xpdname, (on) ? "on" : "off");
-	if(on) {
-		for_each_line(xpd, i) {
-			MARK_LED(xpd, i, LED_GREEN, LED_ON);
-			msleep(20);
-		}
-		for_each_line(xpd, i) {
-			MARK_LED(xpd, i, LED_GREEN, LED_OFF);
-			msleep(20);
-		}
-	}
 	return ret;
 }
-
-static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, lineno_t chan)
-{
-	int		ret = 0;
-
-	BUG_ON(!xbus);
-	BUG_ON(!xpd);
-	DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
-	return ret;
-}
-
 
 static /* 0x0F */ HOSTCMD(FXO, RING, lineno_t chan, bool on)
 {
@@ -557,7 +586,7 @@
 
 	if(!xpd) {
 		NOTICE("%s: received %s for non-existing xpd: %d\n",
-				__FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+				__FUNCTION__, cmd->name, XPD_NUM(pack->addr));
 		return -EPROTO;
 	}
 	priv = xpd->priv;
@@ -565,19 +594,109 @@
 	DBG("%s/%s: (PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", xpd->xbus->busname, xpd->xpdname, sig_toggles, sig_status);
 	spin_lock_irqsave(&xpd->lock, flags);
 	for_each_line(xpd, i) {
+		int	debounce;
+
 		if(IS_SET(sig_toggles, i)) {
 			if(!IS_SET(priv->battery, i)) {
-				DBG("%s/%s/%d: battery is off. ignore false alarm.\n",
+				DBG("%s/%s/%d: SIG_CHANGED while battery is off.\n",
 					xbus->busname, xpd->xpdname, i);
-				continue;
+				// FIXME: allow dialing without battery polling...
+				// continue;
 			}
-			mark_ring(xpd, i, IS_SET(sig_status, i), 1);
+			/* First report false ring alarms */
+			debounce = atomic_read(&priv->ring_debounce[i]);
+			if(debounce)
+				NOTICE("%s/%s/%d: debounced %d ticks\n", xbus->busname, xpd->xpdname, i, debounce);
+			/*
+			 * Now set a new ring alarm.
+			 * It will be checked in handle_fxo_ring()
+			 */
+			debounce = (IS_SET(sig_status, i)) ? ring_debounce : -ring_debounce;
+			atomic_set(&priv->ring_debounce[i], debounce);
 		}
 	}
 	spin_unlock_irqrestore(&xpd->lock, flags);
 	return 0;
 }
 
+static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel)
+{
+	struct FXO_priv_data	*priv;
+	byte			bat = abs((signed char)data_low);
+	byte			pol = IS_SET(data_low, 7);
+
+	priv = xpd->priv;
+	BUG_ON(!priv);
+	if(bat < BAT_THRESHOLD) {
+		/*
+		 * Check for battery voltage fluctuations
+		 */
+		if(IS_SET(priv->battery, chipsel) && priv->battery_debounce[chipsel]++ > BAT_DEBOUNCE) {
+			DBG("%s/%s/%d: BATTERY OFF voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
+			BIT_CLR(priv->battery, chipsel);
+			update_line_status(xpd, chipsel, 0);
+		}
+	} else {
+		priv->battery_debounce[chipsel] = 0;
+		if(!IS_SET(priv->battery, chipsel)) {
+			DBG("%s/%s/%d: BATTERY ON voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
+			BIT_SET(priv->battery, chipsel);
+		}
+	}
+	/*
+	 * Handle reverse polarity
+	 */
+	if (IS_SET(xpd->offhook, chipsel)) {				/* Learn the current polarity */
+		if (priv->poll_counter - priv->offhook_timestamp[chipsel] < 3) {
+			priv->polarity_counter[chipsel] = 0;
+			if (pol)
+				BIT_SET(priv->polarity, chipsel);
+			else
+				BIT_CLR(priv->polarity, chipsel);
+		}
+		else if (IS_SET(priv->polarity, chipsel) != pol) {	/* Polarity has reversed */
+			priv->polarity_counter[chipsel]++;
+			if (priv->polarity_counter[chipsel] >= 2) {
+				if (pol)
+					BIT_SET(priv->polarity, chipsel);
+				else
+					BIT_CLR(priv->polarity, chipsel);
+				priv->polarity_counter[chipsel] = 0;
+				/* Inform Zaptel */
+				zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_POLARITY);
+#if 0
+				/*
+				 * These two lines hangup the channel (by sending a message to
+				 * the firmware), and inform Zaptel that the line has been hung-up.
+				 * They are not needed if Asterisk does the hangup after receiving
+				 * a notification from Zaptel (which is sent by the above zt_qevent_lock().
+				 * Asterisk does that if it has "hanguponpolarityswitch=1" in zapata.conf.
+				 */
+				do_sethook(xpd, chipsel, 0);
+				update_line_status(xpd, chipsel, 0);
+#endif
+			}
+		}
+	}
+}
+
+static void update_power_denial(xpd_t *xpd, byte data_low, lineno_t chipsel)
+{
+	struct FXO_priv_data	*priv;
+
+	priv = xpd->priv;
+	BUG_ON(!priv);
+	if (IS_SET(xpd->offhook, chipsel) && data_low < 3) {
+		priv->current_counter[chipsel]++;
+		if (priv->current_counter[chipsel] >= 10) {
+			priv->current_counter[chipsel] = 0;
+			do_sethook(xpd, chipsel, 0);
+			update_line_status(xpd, chipsel, 0);
+		}
+	} else
+		priv->current_counter[chipsel] = 0;
+}
+
 HANDLER_DEF(FXO, DAA_REPLY)
 {
 	reg_cmd_t		*info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, regcmd);
@@ -587,36 +706,20 @@
 
 	if(!xpd) {
 		NOTICE("%s: received %s for non-existing xpd: %d\n",
-				__FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+				__FUNCTION__, cmd->name, XPD_NUM(pack->addr));
 		return -EPROTO;
 	}
 	spin_lock_irqsave(&xpd->lock, flags);
 	priv = xpd->priv;
 	BUG_ON(!priv);
 	chipsel = REG_FIELD(info, chipsel);
-
-	/*
-	 * Update battery status
-	 */
-	if(REG_FIELD(info, regnum) == DAA_VBAT_REGISTER) {
-		byte		bat = abs((signed char)REG_FIELD(info, data_low));
-
-		if(bat < BAT_THRESHOLD) {
-			/*
-			 * Check for battery voltage fluctuations
-			 */
-			if(IS_SET(priv->battery, chipsel) && priv->battery_debounce[chipsel]++ > BAT_DEBOUNCE) {
-				DBG("%s/%s/%d: BATTERY OFF voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
-				BIT_CLR(priv->battery, chipsel);
-				update_line_status(xpd, chipsel, 0);
-			}
-		} else {
-			priv->battery_debounce[chipsel] = 0;
-			if(!IS_SET(priv->battery, chipsel)) {
-				DBG("%s/%s/%d: BATTERY ON voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
-				BIT_SET(priv->battery, chipsel);
-			}
-		}
+	switch(REG_FIELD(info, regnum)) {
+		case DAA_VBAT_REGISTER:
+			update_battery_status(xpd, REG_FIELD(info, data_low), chipsel);
+			break;
+		case DAA_CURRENT_REGISTER:
+			update_power_denial(xpd, REG_FIELD(info, data_low), chipsel);
+			break;
 	}
 #if 0
 	DBG("DAA_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
@@ -658,10 +761,8 @@
 		.RING		= XPROTO_CALLER(FXO, RING),
 		.RELAY_OUT	= XPROTO_CALLER(FXO, RELAY_OUT),
 		.XPD_STATE	= XPROTO_CALLER(FXO, XPD_STATE),
-		.CHAN_CID	= XPROTO_CALLER(FXO, CHAN_CID),
 
 		.SYNC_SOURCE	= XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
-		.PCM_WRITE	= XPROTO_CALLER(GLOBAL, PCM_WRITE),
 	},
 	.packet_is_valid = fxo_packet_is_valid,
 	.packet_dump = fxo_packet_dump,
@@ -672,7 +773,7 @@
 	const xproto_entry_t	*xe;
 
 	//DBG("\n");
-	xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->content.opcode);
+	xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->opcode);
 	return xe != NULL;
 }
 
@@ -896,7 +997,12 @@
 
 int __init card_fxo_startup(void)
 {
-	INFO("%s\n", THIS_MODULE->name);
+	if(ring_debounce <= 0) {
+		ERR("%s: ring_debounce=%d. Must be positive number of ticks\n",
+				THIS_MODULE->name, ring_debounce);
+		return -EINVAL;
+	}
+	INFO("%s revision %s\n", THIS_MODULE->name, XPP_VERSION);
 	xproto_register(&PROTO_TABLE(FXO));
 	return 0;
 }
@@ -909,6 +1015,7 @@
 MODULE_DESCRIPTION("XPP FXO Card Driver");
 MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
 MODULE_ALIAS_XPD(XPD_TYPE_FXO);
 
 module_init(card_fxo_startup);

Modified: branches/1.4/xpp/card_fxs.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/xpp/card_fxs.c?view=diff&rev=2123&r1=2122&r2=2123
==============================================================================
--- branches/1.4/xpp/card_fxs.c (original)
+++ branches/1.4/xpp/card_fxs.c Wed Feb  7 18:05:17 2007
@@ -29,11 +29,12 @@
 #include "xpp_zap.h"
 #include "card_fxo.h"
 #include "zap_debug.h"
+#include "xbus-core.h"
 
 static const char rcsid[] = "$Id$";
 
-DEF_PARM(int, print_dbg, 0, "Print DBG statements");	/* 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
@@ -64,14 +65,13 @@
 #define	SLIC_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL)	\
 	CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0)
 #define	SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH)	\
-	PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, (reg), 0, (dL), (dH))
+	CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH))
 
 #define	VALID_CHIPSEL(x)	(((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS)
 
 /*---------------- FXS Protocol Commands ----------------------------------*/
 
 static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, lineno_t chan);
 static /* 0x0F */ DECLARE_CMD(FXS, RING, lineno_t chan, bool on);
 static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
 
@@ -80,6 +80,7 @@
 static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
 static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data);
 static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
 
 #define	PROC_REGISTER_FNAME	"slics"
 #define	PROC_FXS_INFO_FNAME	"fxs_info"
@@ -89,8 +90,22 @@
 	struct proc_dir_entry		*fxs_info;
 	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];
+	xpp_line_t			found_fsk_pattern;
+	xpp_line_t			msg_waiting;
+	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)
@@ -102,10 +117,6 @@
 	DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, chan, (on) ? "up" : "down");
 	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:
@@ -137,7 +148,7 @@
 /*
  * pos can be:
  * 	- A line number
- * 	- ALL_LINES
+ * 	- ALL_LINES. This is not valid anymore since 8-Jan-2007.
  */
 static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
 {
@@ -147,6 +158,7 @@
 	xbus_t			*xbus;
 
 	BUG_ON(!xpd);
+	BUG_ON(chan == ALL_LINES);
 	xbus = xpd->xbus;
 	priv = xpd->priv;
 	which = which % NUM_LEDS;
@@ -186,9 +198,13 @@
 		for_each_line(xpd, i) {
 			if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
 				continue;
-			if(IS_BLINKING(priv, i, color)) {		// Blinking
+			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)) {
@@ -207,6 +223,21 @@
 	}
 }
 
+static int do_callerid(xbus_t *xbus, xpd_t *xpd, lineno_t chan)
+{
+	int		ret = 0;
+	int		i;
+
+	BUG_ON(!xbus);
+	BUG_ON(!xpd);
+	DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
+	ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, FXS_LINE_CID);
+	for_each_line(xpd, i)
+		xpd->lasttxhook[i] = FXS_LINE_CID;
+	return ret;
+}
+
+
 /*---------------- FXS: Methods -------------------------------------------*/
 
 static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
@@ -254,6 +285,7 @@
 {
 	struct FXS_priv_data	*priv;
 	int			ret = 0;
+	int			i;
 
 	BUG_ON(!xpd);
 	priv = xpd->priv;
@@ -289,6 +321,18 @@
 	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);
@@ -312,8 +356,6 @@
 	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;
@@ -337,12 +379,9 @@
 		cur_chan->pvt = xpd;
 		cur_chan->sigcap = FXS_DEFAULT_SIGCAP;
 	}
-	spin_lock_irqsave(&xpd->lock, flags);
-	do_led(xpd, ALL_LINES, 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;
 }
@@ -352,7 +391,6 @@
 	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;
@@ -361,8 +399,10 @@
 	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;
 }
@@ -387,6 +427,8 @@
 				return ret;
 			}
 			ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0);			// RING off
+			if (!IS_SET(xpd->offhook, pos))
+				start_stop_vm_led(xbus, xpd, pos);
 #if 0
 			switch(chan->sig) {
 				case ZT_SIG_EM:
@@ -403,7 +445,7 @@
 		case ZT_TXSIG_OFFHOOK:
 			if(xpd->ringing[pos]) {
 				BIT_SET(xpd->cid_on, pos);
-				ret = CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos);		// CALLER ID
+				ret = do_callerid(xpd->xbus, xpd, pos);		// CALLER ID
 			}
 			xpd->ringing[pos] = 0;
 #if 0
@@ -438,6 +480,107 @@
 	return ret;
 }
 
+#ifdef	VMWI_IOCTL
+/*
+ * Private ioctl()
+ * We don't need it now, since we detect vmwi via FSK patterns
+ */
+static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+	struct FXS_priv_data *priv;
+	xbus_t *xbus;
+	
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	BUG_ON(!priv);
+	xbus = xpd->xbus;
+	BUG_ON(!xbus);
+	
+	if (pos < 0 || pos >= xpd->channels) {
+		NOTICE("%s/%s: Bad channel number %d in %s(), cmd=%u\n", xbus->busname, xpd->xpdname, pos, __FUNCTION__, cmd);
+		return -EINVAL;
+	}
+	
+	switch (cmd) {
+		case _IOW(ZT_CODE, 60, int):		/* message-waiting led control */
+			/* Digital inputs/outputs don't have VM leds */
+			if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
+				return 0;
+			if (arg)
+				BIT_SET(priv->msg_waiting, pos);
+			else
+				BIT_CLR(priv->msg_waiting, pos);
+			return 0;
+	}
+	return -ENOTTY;
+}
+#endif
+
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+{
+	int	ret = 0;
+	BUG_ON(!xbus);
+	BUG_ON(!xpd);
+
+	if (on) {
+		/* A write to register 0x40 will now turn on/off the VM led */
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
+	} else {
+		/* A write to register 0x40 will now turn on/off the ringer */
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
+		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
+		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
+	}
+
+	return (ret ? -EPROTO : 0);
+}
+
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
+{
+	bool		on;
+

[... 9691 lines stripped ...]


More information about the zaptel-commits mailing list