[Pkg-voip-commits] r2024 - in zaptel/trunk/debian: . patches

Tzafrir Cohen tzafrir-guest at costa.debian.org
Sat Jul 8 01:56:15 UTC 2006


Author: tzafrir-guest
Date: 2006-07-08 01:56:10 +0000 (Sat, 08 Jul 2006)
New Revision: 2024

Modified:
   zaptel/trunk/debian/changelog
   zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch
Log:
* xpp revision r1588 (branches/RELEASE-1.1.0). Changes vs. 1473:
- Generate ZT_EVENT_REMOVED in the right place: hinting asterisk to
  disconnect
- Add support for fxotune ioctls
- Remove old cmd2inc et al.

Modified: zaptel/trunk/debian/changelog
===================================================================
--- zaptel/trunk/debian/changelog	2006-07-07 06:24:41 UTC (rev 2023)
+++ zaptel/trunk/debian/changelog	2006-07-08 01:56:10 UTC (rev 2024)
@@ -11,12 +11,16 @@
   * Removing some unneeded dirs from zaptel-source
   * debian/patches/Makefile_kbuild: a small part of the original one.
     Fixes building on Sarge
-  * xpp revision r1473 (branches/RELEASE-1.1.0):
+  * xpp revision r1588 (branches/RELEASE-1.1.0)
   - With EC
   - FXS caller ID working
   - Improved FXO
   - Back to RBS
   - genzaptelconf is now in zaptel
+  - Generate ZT_EVENT_REMOVED in the right place: hinting asterisk to
+    disconnect
+  - Add support for fxotune ioctls
+  - Remove old cmd2inc et al.
   * xpp/utils/Makefile has a decent install target
   * debian/rules: Use CURDIR
   * debian/modulestest: Building modules for -3 kernels

Modified: zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch
===================================================================
--- zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch	2006-07-07 06:24:41 UTC (rev 2023)
+++ zaptel/trunk/debian/patches/xpp_xorcom_debian.dpatch	2006-07-08 01:56:10 UTC (rev 2024)
@@ -2,16 +2,18 @@
 ## xpp_xorcom_debian.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
 ##
 ## DP: Up-to-date zaptel drivers for the Xorcom Astribank and friends.
-## DP: Revision r1473 (branches/RELEASE-1.1.0)
+## DP: Revision r1588 (branches/RELEASE-1.1.0)
 
 ## DP: This version omites the .version file and the firmware files.
+## DP: This patch has been merged into trunk and branch 1.2 and is expected
+## DP: to be included in zaptel 1.2.7
 
 @DPATCH@
-diff -uNr -x .svn -x debian zaptel-1.2.6/.version zaptel-xpp-8WuH7d_dist/.version
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxo.c zaptel-xpp-8WuH7d_dist/xpp/card_fxo.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/.version zaptel-xpp-oaIQ8i_dist/.version
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxo.c zaptel-xpp-oaIQ8i_dist/xpp/card_fxo.c
 --- zaptel-1.2.6/xpp/card_fxo.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/card_fxo.c	2006-06-22 11:31:28.427315000 +0300
-@@ -0,0 +1,926 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/card_fxo.c	2006-07-05 16:28:42.355959000 +0300
+@@ -0,0 +1,946 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2006, Xorcom
@@ -45,10 +47,19 @@
 +#include "card_fxo.h"
 +#include "zap_debug.h"
 +
-+static const char rcsid[] = "$Id: card_fxo.c 1431 2006-06-22 08:31:28Z oron $";
++static const char rcsid[] = "$Id: card_fxo.c 1584 2006-07-05 13:28:42Z tzafrir $";
 +
 +DEF_PARM(int, print_dbg, 0, "Print DBG statements");	/* must be before zap_debug.h */
++DEF_PARM(uint, poll_battery_interval, 100, "Poll battery interval in milliseconds");
++DEF_PARM(bool, report_battery, 0, "Report battery status to zaptel");
 +
++/* Signaling is opposite (fxs signalling for fxo card) */
++#if 1
++#define	FXO_DEFAULT_SIGCAP	(ZT_SIG_FXSKS | ZT_SIG_FXSLS)
++#else
++#define	FXO_DEFAULT_SIGCAP	(ZT_SIG_SF)
++#endif
++
 +enum fxo_leds {
 +	LED_GREEN,
 +};
@@ -58,40 +69,20 @@
 +
 +/*---------------- FXO Protocol Commands ----------------------------------*/
 +
-+/* 0x0F */ DECLARE_CMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on);
-+/* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, int pos);
-+/* 0x0F */ DECLARE_CMD(FXO, RING, int pos, bool on);
-+/* 0x0F */ DECLARE_CMD(FXO, SETHOOK, int pos, bool offhook);
-+/* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
-+/* 0x0F */ DECLARE_CMD(FXO, DAA_INIT);
-+/* 0x0F */ DECLARE_CMD(FXO, DAA_QUERY, int pos, byte reg_num);
++static /* 0x0F */ DECLARE_CMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on);
++static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, int pos);
++static /* 0x0F */ DECLARE_CMD(FXO, RING, int pos, bool on);
++static /* 0x0F */ DECLARE_CMD(FXO, SETHOOK, int pos, bool offhook);
++static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
++static /* 0x0F */ DECLARE_CMD(FXO, DAA_QUERY, int pos, byte reg_num);
 +
 +static bool fxo_packet_is_valid(xpacket_t *pack);
 +static void fxo_packet_dump(xpacket_t *pack);
 +static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
 +static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
 +static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
++static int process_slic_cmdline(xpd_t *xpd, char *cmdline);
 +
-+#define	S_(s,l,...)					\
-+	{						\
-+		.lines = s,				\
-+		{					\
-+			.len = l,			\
-+			.data = { __VA_ARGS__ },	\
-+		}					\
-+	}
-+struct slic_init_data {
-+	xpp_line_t	lines;
-+	slic_data_t	slic_data;
-+} slic_init_data[] = {
-+#ifdef	OLD_CARD
-+#include "init_data_4_19.inc"
-+#else
-+#include "init_data_4_20.inc"
-+#endif
-+};
-+#undef	S_
-+
 +#define	PROC_DAA_FNAME		"slics"
 +#define	PROC_FXO_INFO_FNAME	"fxo_info"
 +
@@ -140,7 +131,7 @@
 +			BIT_CLR(priv->ledstate[which], pos);
 +		}
 +	}
-+	if(!(lines & xpd->enabled_chans))	// Ignore disabled channels
++	if(!lines)	// Nothing to do
 +		goto out;
 +	DBG("%s/%s: LED: lines=0x%04X which=%d -- %s\n", xbus->busname, xpd->xpdname, lines, which, (on) ? "on" : "off");
 +	XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
@@ -165,7 +156,7 @@
 +	spin_lock_irqsave(&xpd->lock, flags);
 +	priv = xpd->priv;
 +	timer_count = xpd->timer_count;
-+	for_each_enabled_line(xpd, i) {
++	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)) {
@@ -186,10 +177,16 @@
 +
 +static void do_sethook(xpd_t *xpd, int pos, bool offhook)
 +{
-+	unsigned long	flags;
++	unsigned long		flags;
++	struct FXO_priv_data	*priv;
 +
 +	BUG_ON(!xpd);
 +	BUG_ON(xpd->direction == TO_PHONE);		// We can SETHOOK state only on PSTN
++	priv = xpd->priv;
++	BUG_ON(!priv);
++	if(!IS_SET(priv->battery, pos)) {
++		DBG("%s/%s/%d: WARNING: called while battery is off\n", xpd->xbus->busname, xpd->xpdname, pos);
++	}
 +	spin_lock_irqsave(&xpd->lock, flags);
 +	xpd->ringing[pos] = 0;				// No more rings
 +	CALL_XMETHOD(SETHOOK, xpd->xbus, xpd, pos, offhook);
@@ -242,6 +239,7 @@
 +{
 +	struct FXO_priv_data	*priv;
 +	int			ret = 0;
++	int			i;
 +
 +	BUG_ON(!xpd);
 +	priv = xpd->priv;
@@ -251,41 +249,34 @@
 +	if(!priv->fxo_info) {
 +		ERR("Failed to create proc '%s' for %s/%s\n", PROC_FXO_INFO_FNAME, xbus->busname, xpd->xpdname);
 +		ret = -ENOENT;
-+		goto out;
++		goto err;
 +	}
++	priv->fxo_info->owner = THIS_MODULE;
 +	DBG("Creating DAAs file for %s/%s\n", xbus->busname, xpd->xpdname);
 +	priv->xpd_slic = create_proc_entry(PROC_DAA_FNAME, 0644, xpd->proc_xpd_dir);
 +	if(!priv->xpd_slic) {
 +		ERR("Failed to create proc file for DAAs of %s/%s\n", xbus->busname, xpd->xpdname);
-+		goto out;
++		ret = -ENOENT;
++		goto err;
 +	}
++	priv->xpd_slic->owner = THIS_MODULE;
 +	priv->xpd_slic->write_proc = proc_xpd_slic_write;
 +	priv->xpd_slic->read_proc = proc_xpd_slic_read;
 +	priv->xpd_slic->data = xpd;
 +#endif
-+#ifdef HARD_CODED_INIT
-+	CALL_PROTO(FXO, DAA_INIT, xbus, xpd);
-+#else
 +	ret = run_initialize_registers(xpd);
 +	if(ret < 0)
-+		goto out;
-+#endif
-+	if(xpd->direction == TO_PSTN) {
-+		int	i;
-+
-+		// Hanghup all lines
-+		for_each_enabled_line(xpd, i) {
-+			init_waitqueue_head(&xpd->txstateq[i]);
-+			do_sethook(xpd, i, 0);
-+		}
++		goto err;
++	// Hanghup all lines
++	for_each_line(xpd, i) {
++		init_waitqueue_head(&xpd->txstateq[i]);
++		do_sethook(xpd, i, 0);
 +	}
-+out:
-+	if(ret < 0) {
-+		clean_proc(xbus, xpd);
-+		ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
-+	} else {
-+		DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
-+	}
++	DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
++	return 0;
++err:
++	clean_proc(xbus, xpd);
++	ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
 +	return ret;
 +}
 +
@@ -300,11 +291,43 @@
 +	return 0;
 +}
 +
-+static int FXO_card_zaptel_registration(xpd_t *xpd, bool on)
++static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on)
 +{
 +	xbus_t			*xbus;
 +	struct FXO_priv_data	*priv;
++	int			i;
 +	unsigned long		flags;
++
++	BUG_ON(!xpd);
++	xbus = xpd->xbus;
++	BUG_ON(!xbus);
++	priv = xpd->priv;
++	BUG_ON(!priv);
++	DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
++	snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: FXO", xbus->num, xpd->id);
++	for_each_line(xpd, i) {
++		struct zt_chan	*cur_chan = &xpd->chans[i];
++
++		DBG("setting FXO channel %d\n", i);
++		snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%d/%d/%d", xbus->num, xpd->id, i);
++		cur_chan->chanpos = i + 1;
++		cur_chan->pvt = xpd;
++		cur_chan->sigcap = FXO_DEFAULT_SIGCAP;
++	}
++	spin_lock_irqsave(&xpd->lock, flags);
++	do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
++	spin_unlock_irqrestore(&xpd->lock, flags);
++	for_each_line(xpd, i) {
++		do_led(xpd, i, LED_GREEN, LED_ON);
++		mdelay(50);
++	}
++	return 0;
++}
++
++static int FXO_card_zaptel_postregistration(xpd_t *xpd, bool on)
++{
++	xbus_t			*xbus;
++	struct FXO_priv_data	*priv;
 +	int			i;
 +
 +	BUG_ON(!xpd);
@@ -313,29 +336,9 @@
 +	priv = xpd->priv;
 +	BUG_ON(!priv);
 +	DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
-+	if(on) {
-+		for_each_line(xpd, i) {
-+			spin_lock_irqsave(&xpd->lock, flags);
-+			do_led(xpd, i, LED_GREEN, LED_ON);
-+			spin_unlock_irqrestore(&xpd->lock, flags);
-+			mdelay(50);
-+		}
-+		for_each_line(xpd, i) {
-+			spin_lock_irqsave(&xpd->lock, flags);
-+			do_led(xpd, i, LED_GREEN, LED_OFF);
-+			spin_unlock_irqrestore(&xpd->lock, flags);
-+			mdelay(50);
-+		}
-+	} else {
-+		for_each_line(xpd, i) {
-+			spin_lock_irqsave(&xpd->lock, flags);
-+			do_led(xpd, i, LED_GREEN, LED_ON);
-+			spin_unlock_irqrestore(&xpd->lock, flags);
-+			mdelay(100);
-+			spin_lock_irqsave(&xpd->lock, flags);
-+			do_led(xpd, i, LED_GREEN, LED_OFF);
-+			spin_unlock_irqrestore(&xpd->lock, flags);
-+		}
++	for_each_line(xpd, i) {
++		do_led(xpd, i, LED_GREEN, LED_OFF);
++		mdelay(50);
 +	}
 +	return 0;
 +}
@@ -343,6 +346,10 @@
 +#ifdef WITH_RBS
 +int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
 +{
++	struct FXO_priv_data	*priv;
++
++	priv = xpd->priv;
++	BUG_ON(!priv);
 +	DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, txsig2str(txsig));
 +	BUG_ON(xpd->direction != TO_PSTN);
 +	/* XXX Enable hooksig for FXO XXX */
@@ -365,13 +372,12 @@
 +#else
 +int FXO_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate)
 +{
-+	int	ret = 0;
++	int			ret = 0;
++	struct FXO_priv_data	*priv;
 +
 +	DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, hookstate2str(hookstate));
 +	switch(hookstate) {
-+		/* On-hook, off-hook: The PBX is playing a phone on an FXO line. 
-+		 * Can be ignored for an FXS line
-+		 */
++		/* On-hook, off-hook: The PBX is playing a phone on an FXO line.  */
 +		case ZT_ONHOOK:
 +			do_sethook(xpd, pos, 0);
 +			break;
@@ -390,7 +396,7 @@
 +			WARN("No code yet\n");
 +			break;
 +		case ZT_RING:
-+			DBG("%s/%s/%d: (ringing[%d]=%d)\n", xbus->busname, xpd->xpdname, pos, pos, xpd->ringing[pos]);
++			DBG("%s/%s/%d: ZT_RING: %d\n", xbus->busname, xpd->xpdname, pos, xpd->ringing[pos]);
 +			break;
 +		case ZT_RINGOFF:
 +			WARN("No code yet\n");
@@ -404,7 +410,7 @@
 +{
 +	int	i;
 +
-+	for_each_enabled_line(xpd, i) {
++	for_each_line(xpd, i) {
 +		CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_VBAT_REGISTER);
 +	}
 +}
@@ -412,23 +418,75 @@
 +
 +static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
 +{
-+	static int		rate_limit = 0;
++	static unsigned		rate_limit = 0;
 +	struct FXO_priv_data	*priv;
 +
 +	BUG_ON(!xpd);
 +	priv = xpd->priv;
 +	BUG_ON(!priv);
 +	rate_limit++;
-+	if((rate_limit % 100) == 0) {
++	if(poll_battery_interval != 0 && (rate_limit % poll_battery_interval) == 0) {
 +		poll_battery(xbus, xpd);
 +	}
 +	handle_fxo_leds(xpd);
 +	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;
++};
++
++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);
++	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*)arg, sizeof(echoregs.wctdm_struct)))
++				return -EFAULT;
++
++			/* Set the ACIM register */
++			/* quick and dirty registers writing: */
++			for (i=0; i<sizeof(echotune_reg); i++) {
++				char buf[22];
++				xpp_line_t	lines = BIT(pos);
++				sprintf(buf, "%02X %02X %02X %02X WD %2X %2X",
++					(lines & 0xFF),
++					((lines >> 8) & 0xFF),
++					((lines >> 16) & 0xFF),
++					((lines >> 24) & 0xFF),
++					echotune_reg[i],echoregs.coeff[i]
++				);
++				/* FIXME: code duplicated from proc_xpd_register_write */
++				ret = process_slic_cmdline(xpd, buf);
++				if(ret < 0)
++					return ret;
++				mdelay(1);
++			}
++
++			DBG("-- Set echo registers successfully\n");
++
++			break;
++		default:
++			return -ENOTTY;
++	}
++	return 0;
++}
++
 +/*---------------- FXO: HOST COMMANDS -------------------------------------*/
 +
-+/* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
++static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
 +{
 +	unsigned long		flags;
 +	int	ret = 0;
@@ -436,19 +494,18 @@
 +
 +	BUG_ON(!xbus);
 +	BUG_ON(!xpd);
-+	lines &= xpd->enabled_chans;	// Ignore disabled channels
 +	if(!lines) {
 +		return 0;
 +	}
 +	DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
 +	if(on) {
-+		for_each_enabled_line(xpd, i) {
++		for_each_line(xpd, i) {
 +			spin_lock_irqsave(&xpd->lock, flags);
 +			do_led(xpd, i, LED_GREEN, LED_ON);
 +			spin_unlock_irqrestore(&xpd->lock, flags);
 +			mdelay(20);
 +		}
-+		for_each_enabled_line(xpd, i) {
++		for_each_line(xpd, i) {
 +			spin_lock_irqsave(&xpd->lock, flags);
 +			do_led(xpd, i, LED_GREEN, LED_OFF);
 +			spin_unlock_irqrestore(&xpd->lock, flags);
@@ -458,14 +515,13 @@
 +	return ret;
 +}
 +
-+/* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos)
++static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos)
 +{
 +	int		ret = 0;
 +	xpp_line_t	lines = BIT(pos);
 +
 +	BUG_ON(!xbus);
 +	BUG_ON(!xpd);
-+	lines &= xpd->enabled_chans;	// Ignore disabled channels
 +	if(!lines) {
 +		return 0;
 +	}
@@ -474,17 +530,16 @@
 +}
 +
 +
-+/* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
++static /* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
 +{
 +	int		ret = 0;
 +	xpacket_t	*pack;
 +	slic_cmd_t	*sc;
-+	xpp_line_t	mask = (1 << pos);
++	xpp_line_t	mask = BIT(pos);
 +	int		len;
 +
 +	BUG_ON(!xbus);
 +	BUG_ON(!xpd);
-+	mask &= xpd->enabled_chans;	// Ignore disabled channels
 +	if(!mask) {
 +		return 0;
 +	}
@@ -498,7 +553,7 @@
 +	return ret;
 +}
 +
-+/* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook)
++static /* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook)
 +{
 +	int		ret = 0;
 +	xpacket_t	*pack;
@@ -509,58 +564,28 @@
 +
 +	BUG_ON(!xbus);
 +	BUG_ON(!xpd);
-+	value = (offhook) ? 0x01 : 0x00;
++	value = (offhook) ? 0x09 : 0x08;
 +	// value |= BIT(3);	/* Bit 3 is for CID */
 +	DBG("%s/%s/%d: SETHOOK: value=0x%02X %s\n", xbus->busname, xpd->xpdname, pos, value, (offhook)?"OFFHOOK":"ONHOOK");
 +	spin_lock_irqsave(&xpd->lock, flags);
-+	if(!IS_SET(xpd->enabled_chans, pos))
-+		goto out;
 +	XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
 +	sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
 +	len = slic_cmd_direct_write(sc, BIT(pos), 0x05, value);
 +	pack->datalen = len;
 +	packet_send(xbus, pack);
 +	do_led(xpd, pos, LED_GREEN, (offhook)?LED_ON:LED_OFF);
-+out:
 +	spin_unlock_irqrestore(&xpd->lock, flags);
 +	return ret;
 +}
 +
-+/* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
++static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
 +{
 +	return -ENOSYS;
 +}
 +
-+/* 0x0F */ HOSTCMD(FXO, DAA_INIT)
++static /* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num)
 +{
 +	int	ret = 0;
-+	xpacket_t		*pack;
-+	slic_data_t		*slic;
-+	struct slic_init_data	*source;
-+	int			i;
-+
-+	BUG_ON(!xbus);
-+	BUG_ON(!xpd);
-+	DBG("INITIALIZING DAA\n");
-+	for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
-+		source = &slic_init_data[i];
-+		XPACKET_NEW(pack, xbus, FXO, DAA_INIT, xpd->id);
-+		RPACKET_FIELD(pack, FXO, DAA_INIT, lines) = source->lines;
-+
-+		slic = &RPACKET_FIELD(pack, FXO, DAA_INIT, slic_data);
-+		slic->len = source->slic_data.len;
-+		memcpy(slic->data, source->slic_data.data, source->slic_data.len);
-+		pack->datalen = sizeof(xpp_line_t) + slic->len + 1;
-+//		dump_packet("DAA", pack, print_dbg);
-+		packet_send(xbus, pack);
-+		mdelay(1);	// FIXME: check with Dima
-+	}
-+	return ret;
-+}
-+
-+/* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num)
-+{
-+	int	ret = 0;
 +	xpacket_t	*pack;
 +	slic_cmd_t	*sc;
 +	int		len;
@@ -627,22 +652,16 @@
 +
 +		if(abs(info->data_low) < BAT_THRESHOLD) {
 +			priv->battery &= ~lines;
-+			// DBG("BATTERY OFF (%04X) = %d\n", lines, info->data_low);
++			// DBG("%s/%s: BATTERY OFF (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low);
 +		} else {
 +			priv->battery |= lines;
-+			// DBG("BATTERY ON  (%04X) = %d\n", lines, info->data_low);
++			// DBG("%s/%s: BATTERY ON (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low);
 +		}
 +		changed_lines = last_batt_on ^ priv->battery;
 +		for_each_line(xpd, i) {
-+			if(!IS_SET(changed_lines, i) || IS_SET(xpd->hookstate, i))
-+				continue;
-+#if 0
-+			/* FIXME: We don't want to affect the whole span */
-+			if(IS_SET(priv->battery, i))
-+				update_xpd_status(xpd, ZT_ALARM_NONE);
-+			else
-+				update_xpd_status(xpd, ZT_ALARM_RED);
-+#endif
++			if(IS_SET(changed_lines, i)) {
++				update_line_status(xpd, i, IS_SET(priv->battery, i));
++			}
 +		}
 +	}
 +#if 0
@@ -674,13 +693,15 @@
 +		.card_new	= FXO_card_new,
 +		.card_init	= FXO_card_init,
 +		.card_remove	= FXO_card_remove,
-+		.card_zaptel_registration	= FXO_card_zaptel_registration,
++		.card_zaptel_preregistration	= FXO_card_zaptel_preregistration,
++		.card_zaptel_postregistration	= FXO_card_zaptel_postregistration,
 +#ifdef WITH_RBS
 +		.card_hooksig	= FXO_card_hooksig,
 +#else
 +		.card_sethook	= FXO_card_sethook,
 +#endif
 +		.card_tick	= FXO_card_tick,
++		.card_ioctl	= FXO_card_ioctl,
 +
 +		.RING		= XPROTO_CALLER(FXO, RING),
 +		.SETHOOK	= XPROTO_CALLER(FXO, SETHOOK),
@@ -719,7 +740,8 @@
 +	struct FXO_priv_data	*priv;
 +	int			i;
 +
-+	BUG_ON(!xpd);
++	if(!xpd)
++		return -ENODEV;
 +	spin_lock_irqsave(&xpd->lock, flags);
 +	priv = xpd->priv;
 +	BUG_ON(!priv);
@@ -873,9 +895,8 @@
 +	len = parse_slic_cmd(p, &sc, &priv->requested_reply);
 +	if(len < 0)
 +		return len;
-+	sc.lines &= xpd->enabled_chans;	// Ignore disabled channels
 +	if(!sc.lines) {
-+		NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__);
++		NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__);
 +		return 0;
 +	}
 +	dump_slic_cmd("WRITE_DAA", &sc);
@@ -895,7 +916,8 @@
 +	int		i;
 +	int		ret;
 +
-+	BUG_ON(!xpd);
++	if(!xpd)
++		return -ENODEV;
 +	for(i = 0; i < count; /* noop */) {
 +		for(p = buf; p < buf + LINE_LEN; p++) {	/* read a line */
 +			if(i >= count)
@@ -938,10 +960,10 @@
 +
 +module_init(card_fxo_startup);
 +module_exit(card_fxo_cleanup);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxo.h zaptel-xpp-8WuH7d_dist/xpp/card_fxo.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxo.h zaptel-xpp-oaIQ8i_dist/xpp/card_fxo.h
 --- zaptel-1.2.6/xpp/card_fxo.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/card_fxo.h	2006-03-30 12:42:46.619481000 +0200
-@@ -0,0 +1,65 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/card_fxo.h	2006-07-02 17:17:18.812352000 +0300
+@@ -0,0 +1,61 @@
 +#ifndef	CARD_FXO_H
 +#define	CARD_FXO_H
 +/*
@@ -995,10 +1017,6 @@
 +	xpp_line_t	lines;
 +	slic_reply_t	info;
 +	);
-+DEF_RPACKET_DATA(FXO, DAA_INIT,
-+	xpp_line_t      lines;
-+	slic_data_t     slic_data;
-+	);
 +DEF_RPACKET_DATA(FXO, DAA_WRITE,
 +	slic_cmd_t	slic_cmd;
 +	);
@@ -1007,9 +1025,9 @@
 +#define	BAT_THRESHOLD		3
 +
 +#endif	/* CARD_FXO_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxs.c zaptel-xpp-8WuH7d_dist/xpp/card_fxs.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxs.c zaptel-xpp-oaIQ8i_dist/xpp/card_fxs.c
 --- zaptel-1.2.6/xpp/card_fxs.c	2006-04-03 10:08:13.000000000 +0300
-+++ zaptel-xpp-8WuH7d_dist/xpp/card_fxs.c	2006-06-27 19:12:14.132258000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/card_fxs.c	2006-07-04 10:42:50.607003000 +0300
 @@ -1,6 +1,6 @@
  /*
   * Written by Oron Peled <oron at actcom.co.il>
@@ -1018,7 +1036,7 @@
   *
   * All rights reserved.
   *
-@@ -23,13 +23,15 @@
+@@ -23,65 +23,232 @@
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/fs.h>
@@ -1033,20 +1051,34 @@
  
 -static const char rcsid[] = "$Id: card_fxs.c 995 2006-04-03 07:08:13Z tzafrir $";
 -static const char revision[] = "$Revision: 995 $";
-+static const char rcsid[] = "$Id: card_fxs.c 1473 2006-06-27 16:12:14Z tzafrir $";
++static const char rcsid[] = "$Id: card_fxs.c 1564 2006-07-04 07:42:50Z oron $";
  
  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 */
++
++/* Signaling is opposite (fxo signalling for fxs card) */
++#if 1
++#define	FXS_DEFAULT_SIGCAP	(ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS)
++#else
++#define	FXS_DEFAULT_SIGCAP	(ZT_SIG_SF | ZT_SIG_EM)
++#endif
  
-@@ -42,20 +44,41 @@
- #define	MASK_DIGI_OUT	(MASK_BITS(LINES_DIGI_OUT) << LINES_REGULAR)
- #define	MASK_DIGI_INP	(MASK_BITS(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
+ #define	LINES_REGULAR	8
+ #define	LINES_DIGI_OUT	2
+ #define	LINES_DIGI_INP	4
  
+-#define	MASK_BITS(b)		((1U << (b)) - 1)
++#define	MASK_DIGI_OUT	(BITMASK(LINES_DIGI_OUT) << LINES_REGULAR)
++#define	MASK_DIGI_INP	(BITMASK(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
++
 +enum fxs_leds {
 +	LED_GREEN,
 +	LED_RED,
 +	OUTPUT_RELAY,
 +};
-+
+ 
+-#define	MASK_DIGI_OUT	(MASK_BITS(LINES_DIGI_OUT) << LINES_REGULAR)
+-#define	MASK_DIGI_INP	(MASK_BITS(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
 +#define	NUM_LEDS	2
 +
 +static int SLIC_DIRECT_REQUEST(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, byte reg, byte dL)
@@ -1062,7 +1094,7 @@
 +	packet_send(xbus, pack);
 +	return 0;
 +}
-+
+ 
  /*---------------- FXS Protocol Commands ----------------------------------*/
  
 -/* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
@@ -1079,7 +1111,6 @@
 +static /* 0x0F */ DECLARE_CMD(FXS, RING, int pos, bool on);
 +static /* 0x0F */ DECLARE_CMD(FXS, SETHOOK, int pos, bool offhook);
 +static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
-+static /* 0x0F */ DECLARE_CMD(FXS, SLIC_INIT);
 +static /* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
  
  static bool fxs_packet_is_valid(xpacket_t *pack);
@@ -1088,19 +1119,22 @@
  static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
  static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
  
-@@ -71,17 +94,177 @@
- 	xpp_line_t	lines;
- 	slic_data_t	slic_data;
- } slic_init_data[] = {
+-#define	S_(s,l,...)					\
+-	{						\
+-		.lines = s,				\
+-		{					\
+-			.len = l,			\
+-			.data = { __VA_ARGS__ },	\
+-		}					\
+-	}
+-struct slic_init_data {
+-	xpp_line_t	lines;
+-	slic_data_t	slic_data;
+-} slic_init_data[] = {
 -#include "slic_init.inc"
-+#ifdef	OLD_CARD
-+#include "init_data_3_19.inc"
-+#else
-+#include "init_data_3_20.inc"
-+#endif
- };
- #undef	S_
- 
+-};
+-#undef	S_
+-
  #define	PROC_SLIC_FNAME		"slics"
 +#define	PROC_FXS_INFO_FNAME	"fxs_info"
  
@@ -1126,7 +1160,6 @@
 +
 +	BUG_ON(!xbus);
 +	BUG_ON(!xpd);
-+	lines &= xpd->enabled_chans;	// Ignore disabled channels
 +	if(!lines) {
 +		return 0;
 +	}
@@ -1147,8 +1180,8 @@
 +}
 +
 +#define	IS_BLINKING(priv,pos,color)	((priv)->blinking[color][pos] != 0)
-+#define	DO_BLINK(priv,pos,color,val)	((priv)->blinking[color][pos] = (val))
-+#define	DO_LED(priv,pos,color,val)	((val)?BIT_SET((priv)->ledcontrol[color],(pos)):BIT_CLR((priv)->ledcontrol[color],(pos)))
++#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:
@@ -1210,7 +1243,7 @@
 +			BIT_CLR(priv->ledstate[which], pos);
 +		}
 +	}
-+	if(!(lines & xpd->enabled_chans))	// Ignore disabled channels
++	if(!lines)	// Nothing to do
 +		goto out;
 +	DBG("%s/%s: LED: lines=0x%04X which=%d -- %s\n", xbus->busname, xpd->xpdname, lines, which, (on) ? "on" : "off");
 +	value = BIT(2) | BIT(3);
@@ -1237,11 +1270,11 @@
 +	struct FXS_priv_data	*priv;
 +
 +	BUG_ON(!xpd);
++	spin_lock_irqsave(&xpd->lock, flags);
 +	priv = xpd->priv;
-+	spin_lock_irqsave(&xpd->lock, flags);
 +	timer_count = xpd->timer_count;
 +	for(color = 0; color < ARRAY_SIZE(colors); color++) {
-+		for_each_enabled_line(xpd, i) {
++		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
@@ -1269,7 +1302,7 @@
  /*---------------- FXS: Methods -------------------------------------------*/
  
  static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
-@@ -100,29 +283,83 @@
+@@ -100,29 +267,82 @@
  		xpd->digital_inputs = MASK_DIGI_INP;
  	}
  	xpd->direction = TO_PHONE;
@@ -1286,6 +1319,7 @@
 +#ifdef	CONFIG_PROC_FS
 +	if(priv->xpd_slic) {
 +		DBG("Removing xpd SLIC file %s/%s\n", xbus->busname, xpd->xpdname);
++		priv->xpd_slic->data = NULL;
 +		remove_proc_entry(PROC_SLIC_FNAME, xpd->proc_xpd_dir);
 +	}
 +	if(priv->fxs_info) {
@@ -1309,28 +1343,26 @@
 +	if(!priv->fxs_info) {
 +		ERR("Failed to create proc '%s' for %s/%s\n", PROC_FXS_INFO_FNAME, xbus->busname, xpd->xpdname);
 +		ret = -ENOENT;
-+		goto out;
++		goto err;
 +	}
++	priv->fxs_info->owner = THIS_MODULE;
  	DBG("Creating SLICs file for %s/%s\n", xbus->busname, xpd->xpdname);
  	priv->xpd_slic = create_proc_entry(PROC_SLIC_FNAME, 0644, xpd->proc_xpd_dir);
  	if(!priv->xpd_slic) {
  		ERR("Failed to create proc file for SLICs of %s/%s\n", xbus->busname, xpd->xpdname);
+-		goto out;
 +		ret = -ENOENT;
- 		goto out;
++		goto err;
  	}
++	priv->xpd_slic->owner = THIS_MODULE;
  	priv->xpd_slic->write_proc = proc_xpd_slic_write;
  	priv->xpd_slic->read_proc = proc_xpd_slic_read;
  	priv->xpd_slic->data = xpd;
 -out:
  #endif
--	return 0;
-+#ifdef HARD_CODED_INIT
-+	CALL_PROTO(FXS, SLIC_INIT, xbus, xpd);
-+#else
 +	ret = run_initialize_registers(xpd);
-+#endif
 +	if(ret < 0)
-+		goto out;
++		goto err;
 +	/*
 +	 * Setup ring timers
 +	 */
@@ -1345,18 +1377,18 @@
 +	ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x33, 0x3E);	/* Inactive timer high byte */
 +	ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x22, 0x18);	/* Ringing Oscilator Control */
 +#endif
-+out:
-+	if(ret < 0) {
-+		clean_proc(xbus, xpd);
-+		ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
-+	} else {
-+		DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
-+	}
++	if(ret < 0)
++		goto err;
++	DBG("%s/%s: done\n", xbus->busname, xpd->xpdname);
+ 	return 0;
++err:
++	clean_proc(xbus, xpd);
++	ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
 +	return ret;
  }
  
  static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
-@@ -132,15 +369,200 @@
+@@ -132,15 +352,210 @@
  	BUG_ON(!xpd);
  	priv = xpd->priv;
  	DBG("%s/%s\n", xbus->busname, xpd->xpdname);
@@ -1368,42 +1400,62 @@
 +	return 0;
 +}
 +
-+static int FXS_card_zaptel_registration(xpd_t *xpd, bool on)
++static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
 +{
 +	xbus_t			*xbus;
 +	struct FXS_priv_data	*priv;
++	int			i;
 +	unsigned long		flags;
-+	int	i;
++	const enum fxs_leds     color = (on) ? LED_GREEN : LED_RED;
 +
 +	BUG_ON(!xpd);
 +	xbus = xpd->xbus;
++	BUG_ON(!xbus);
 +	priv = xpd->priv;
++	BUG_ON(!priv);
++	DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
++	snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: FXS", xbus->num, xpd->id);
++	for_each_line(xpd, i) {
++		struct zt_chan	*cur_chan = &xpd->chans[i];
++
++		DBG("setting FXS channel %d\n", i);
++		if(IS_SET(xpd->digital_outputs, i)) {
++			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d/%d/%d", xbus->num, xpd->id, i);
++		} else if(IS_SET(xpd->digital_inputs, i)) {
++			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d/%d/%d", xbus->num, xpd->id, i);
++		} else {
++			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%d/%d/%d", xbus->num, xpd->id, i);
++		}
++		cur_chan->chanpos = i + 1;
++		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);
++		mdelay(50);
++	}
++	return 0;
++}
++
++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;
 +	BUG_ON(!xbus);
-+	DBG("%s/%s: %s\n", xbus->busname, xpd->xpdname, (on)?"on":"off");
-+	if(on) {
-+		spin_lock_irqsave(&xpd->lock, flags);
-+		do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
-+		spin_unlock_irqrestore(&xpd->lock, flags);
-+		for_each_enabled_line(xpd, i) {
-+			DO_LED(priv,i,LED_GREEN,LED_ON);
-+			mdelay(50);
-+		}
-+		for_each_enabled_line(xpd, i) {
-+			DO_LED(priv,i,LED_GREEN,LED_OFF);
-+			mdelay(50);
-+		}
-+	} else {
-+		spin_lock_irqsave(&xpd->lock, flags);
-+		do_led(xpd, ALL_LINES, LED_RED, LED_OFF);
-+		spin_unlock_irqrestore(&xpd->lock, flags);
-+		for_each_enabled_line(xpd, i) {
-+			DO_LED(priv,i,LED_RED,LED_ON);
-+			mdelay(50);
-+		}
-+		for_each_enabled_line(xpd, i) {
-+			DO_LED(priv,i,LED_RED,LED_OFF);
-+			mdelay(50);
-+		}
++	priv = xpd->priv;
++	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);
++		mdelay(50);
  	}
 -#endif
  	return 0;
@@ -1420,26 +1472,15 @@
 +		DBG("Ignoring signal sent to digital input line\n");
 +		return 0;
 +	}
-+	if (IS_SET(xpd->digital_outputs, pos)) {
-+		DBG("This is an output channel.");
-+		switch(txsig) {
-+			case ZT_TXSIG_ONHOOK:
-+				DBG("%s/%s/%d: digital output OFF\n", xbus->busname, xpd->xpdname, pos);
-+				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
-+				return ret;
-+			case ZT_TXSIG_START:
-+				DBG("%s/%s/%d: digital output ON\n", xbus->busname, xpd->xpdname, pos);
-+				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
-+				return ret;
-+			default: 
-+				DBG("Ignoring signal %s: unhandled for output channel.\n", 
-+						txsig2str(txsig));
-+		}
-+	}
 +	switch(txsig) {
 +		case ZT_TXSIG_ONHOOK:
 +			xpd->ringing[pos] = 0;
 +			BIT_CLR(xpd->cid_on, pos);
++			if(IS_SET(xpd->digital_outputs, pos)) {
++				DBG("%s/%s/%d: digital output OFF\n", xbus->busname, xpd->xpdname, pos);
++				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
++				return ret;
++			}
 +			ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0);			// RING off
 +#if 0
 +			switch(chan->sig) {
@@ -1475,9 +1516,10 @@
 +			xpd->lasttxhook[pos] = FXS_LINE_RING;
 +			xpd->ringing[pos] = 1;
 +			BIT_CLR(xpd->cid_on, pos);
-+			if(IS_SET(xpd->digital_inputs, pos)) {
-+				NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
-+				return -EINVAL;
++			if(IS_SET(xpd->digital_outputs, pos)) {
++				DBG("%s/%s/%d: %s digital output ON\n", xbus->busname, xpd->xpdname, pos, txsig2str(txsig));
++				ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
++				return ret;
 +			}
 +			ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1);			// RING on
 +			break;
@@ -1562,20 +1604,34 @@
  /*
   * INPUT polling is done via SLIC register 0x06 (same as LEDS):
   *         7     6     5     4     3     2     1     0
-@@ -164,22 +586,30 @@
+@@ -155,6 +570,7 @@
+ {
+ 	int	i;
  
++	BUG_ON(xpd->id != 0);	// Only unit #0 has digital inputs
+ 	for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
+ 		int	pos = input_channels[i];
+ 
+@@ -164,177 +580,129 @@
+ 
  static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
  {
 -	static	int	rate_limit = 0;
 +	static int		rate_limit = 0;
 +	struct FXS_priv_data	*priv;
  
+-	if((rate_limit++ % 1000) == 0) {
+-		poll_inputs(xbus, xpd);
 +	BUG_ON(!xpd);
 +	priv = xpd->priv;
 +	BUG_ON(!priv);
- 	if((rate_limit++ % 1000) == 0) {
- 		poll_inputs(xbus, xpd);
++#if POLL_DIGITAL_INPUTS
++	if(poll_digital_inputs && xpd->id == 0) {
++		if((rate_limit++ % 1000) == 0) {
++			poll_inputs(xbus, xpd);
++		}
  	}
++#endif
 +	handle_fxs_leds(xpd);
  	return 0;
  }
@@ -1595,7 +1651,8 @@
  
  	BUG_ON(!xbus);
  	BUG_ON(!xpd);
-@@ -188,49 +618,35 @@
+-	lines &= xpd->enabled_chans;	// Ignore disabled channels
+ 	if(!lines) {
  		return 0;
  	}
  	DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
@@ -1659,7 +1716,7 @@
  
  	BUG_ON(!xbus);
  	BUG_ON(!xpd);
-@@ -238,103 +654,60 @@
+-	lines &= xpd->enabled_chans;	// Ignore disabled channels
  	if(!lines) {
  		return 0;
  	}
@@ -1684,14 +1741,15 @@
 +	struct FXS_priv_data	*priv;
  	xpacket_t	*pack;
  	slic_cmd_t	*sc;
- 	xpp_line_t	mask = (1 << pos);
+-	xpp_line_t	mask = (1 << pos);
++	xpp_line_t	mask = BIT(pos);
  	int		len;
 +	enum fxs_state	value = (on) ? 0x04 : 0x01;
  
  	BUG_ON(!xbus);
  	BUG_ON(!xpd);
+-	mask &= xpd->enabled_chans;	// Ignore disabled channels
 +	priv = xpd->priv;
- 	mask &= xpd->enabled_chans;	// Ignore disabled channels
  	if(!mask) {
  		return 0;
  	}
@@ -1707,10 +1765,10 @@
  
  	packet_send(xbus, pack);
 +	if(on) {
-+		DO_BLINK(priv,pos,LED_GREEN,LED_BLINK);
++		MARK_BLINK(priv,pos,LED_GREEN,LED_BLINK);
 +	} else {
 +		if(IS_BLINKING(priv, pos, LED_GREEN))
-+			DO_BLINK(priv,pos,LED_GREEN,0);
++			MARK_BLINK(priv,pos,LED_GREEN,0);
 +	}
  	return ret;
  }
@@ -1785,7 +1843,7 @@
  {
  	int		ret = 0;
  	xpacket_t	*pack;
-@@ -351,9 +724,9 @@
+@@ -351,9 +719,9 @@
  	which = which % ARRAY_SIZE(relay_channels);
  	lines = BIT(relay_channels[which]);
  	value = BIT(2) | BIT(3);
@@ -1797,31 +1855,43 @@
  	XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
  	sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
  	len = slic_cmd_direct_write(sc, lines, 0x06, value);
-@@ -364,7 +737,7 @@
+@@ -364,34 +732,7 @@
  	return ret;
  }
  
 -/* 0x0F */ HOSTCMD(FXS, SLIC_INIT)
-+static /* 0x0F */ HOSTCMD(FXS, SLIC_INIT)
- {
- 	int	ret = 0;
- 	xpacket_t		*pack;
-@@ -386,12 +759,12 @@
- 		pack->datalen = sizeof(xpp_line_t) + slic->len + 1;
- //		dump_packet("SLIC", pack, print_dbg);
- 		packet_send(xbus, pack);
+-{
+-	int	ret = 0;
+-	xpacket_t		*pack;
+-	slic_data_t		*slic;
+-	struct slic_init_data	*source;
+-	int			i;
+-
+-	BUG_ON(!xbus);
+-	BUG_ON(!xpd);
+-	DBG("INITIALIZING SLIC\n");
+-	for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
+-		source = &slic_init_data[i];
+-		XPACKET_NEW(pack, xbus, FXS, SLIC_INIT, xpd->id);
+-		RPACKET_FIELD(pack, FXS, SLIC_INIT, lines) = source->lines;
+-
+-		slic = &RPACKET_FIELD(pack, FXS, SLIC_INIT, slic_data);
+-		slic->len = source->slic_data.len;
+-		memcpy(slic->data, source->slic_data.data, source->slic_data.len);
+-		pack->datalen = sizeof(xpp_line_t) + slic->len + 1;
+-//		dump_packet("SLIC", pack, print_dbg);
+-		packet_send(xbus, pack);
 -		mdelay(10);	// FIXME: check with Dima
-+		mdelay(1);	// FIXME: check with Dima
- 	}
- 	return ret;
- }
- 
+-	}
+-	return ret;
+-}
+-
 -/* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
 +static /* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
  {
  	int	ret = 0;
  	xpacket_t	*pack;
-@@ -400,7 +773,7 @@
+@@ -400,7 +741,7 @@
  
  	BUG_ON(!xbus);
  	BUG_ON(!xpd);
@@ -1830,7 +1900,7 @@
  	XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
  	sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
  	len = slic_cmd_direct_read(sc, BIT(pos), reg_num);
-@@ -416,31 +789,45 @@
+@@ -416,31 +757,45 @@
  HANDLER_DEF(FXS, SIG_CHANGED)
  {
  	xpp_line_t	sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
@@ -1852,7 +1922,7 @@
 +	}
 +#if 0
 +	Is this needed?
-+	for_each_enabled_line(xpd, i) {
++	for_each_line(xpd, i) {
 +		if(IS_SET(sig_toggles, i))
 +			do_chan_power(xpd->xbus, xpd, BIT(i), 0);		// Power down (prevent overheating!!!)
  	}
@@ -1862,30 +1932,31 @@
 -	} else {					/* TO_PSTN - line ring changes */
 -		unsigned long	flags;
 -		int		i;
+-
+-		DBG("%s (PSTN) sig_status=0x%04X\n", xpd->xpdname, sig_status);
+-		spin_lock_irqsave(&xpd->lock, flags);
+-		for(i = 0; i < xpd->channels; i++) {
 +#endif
 +	for_each_line(xpd, i) {
 +		if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
 +			continue;
 +		if(IS_SET(sig_toggles, i)) {
 +			struct zt_chan *chan = &xpd->span.chans[i];
- 
--		DBG("%s (PSTN) sig_status=0x%04X\n", xpd->xpdname, sig_status);
--		spin_lock_irqsave(&xpd->lock, flags);
--		for(i = 0; i < xpd->channels; i++) {
++
 +			xpd->ringing[i] = 0;		// No more ringing...
-+			DO_BLINK(priv,i,LED_GREEN,0);
++			MARK_BLINK(priv,i,LED_GREEN,0);
  			if(IS_SET(sig_status, i)) {
 -				xpd->ringing[i] = RINGS_NUM*2;
 -				zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK);
 +				DBG("OFFHOOK: channo=%d\n", chan->channo);
-+				DO_LED(priv,i,LED_GREEN,LED_ON);
++				MARK_LED(priv,i,LED_GREEN,LED_ON);
 +				BIT_SET(xpd->hookstate, i);
 +				zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
  			} else {
 -				zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
 -				xpd->ringing[i] = 0;
 +				DBG("ONHOOK channo=%d\n", chan->channo);
-+				DO_LED(priv,i,LED_GREEN,LED_OFF);
++				MARK_LED(priv,i,LED_GREEN,LED_OFF);
 +				BIT_CLR(xpd->hookstate, i);
 +				zt_hooksig(chan, ZT_RXSIG_ONHOOK);
  			}
@@ -1894,7 +1965,7 @@
  	}
  	return 0;
  }
-@@ -460,52 +847,75 @@
+@@ -460,52 +815,75 @@
  	spin_lock_irqsave(&xpd->lock, flags);
  	priv = xpd->priv;
  	BUG_ON(!priv);
@@ -1945,7 +2016,7 @@
  	return 0;
  }
  
- 
+-
  xproto_table_t PROTO_TABLE(FXS) = {
 +	.owner = THIS_MODULE,
  	.entries = {
@@ -1960,7 +2031,8 @@
  		.card_new	= FXS_card_new,
  		.card_init	= FXS_card_init,
  		.card_remove	= FXS_card_remove,
-+		.card_zaptel_registration	= FXS_card_zaptel_registration,
++		.card_zaptel_preregistration	= FXS_card_zaptel_preregistration,
++		.card_zaptel_postregistration	= FXS_card_zaptel_postregistration,
 +#ifdef WITH_RBS
 +		.card_hooksig	= FXS_card_hooksig,
 +#else
@@ -1977,7 +2049,7 @@
  		.CHAN_CID	= XPROTO_CALLER(FXS, CHAN_CID),
  
  		.SYNC_SOURCE	= XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
-@@ -519,7 +929,7 @@
+@@ -519,7 +897,7 @@
  {
  	const xproto_entry_t	*xe;
  
@@ -1986,7 +2058,7 @@
  	xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->content.opcode);
  	return xe != NULL;
  }
-@@ -531,6 +941,56 @@
+@@ -531,6 +909,57 @@
  
  /*------------------------- SLIC Handling --------------------------*/
  
@@ -1999,7 +2071,8 @@
 +	int			i;
 +	int			led;
 +
-+	BUG_ON(!xpd);
++	if(!xpd)
++		return -ENODEV;
 +	spin_lock_irqsave(&xpd->lock, flags);
 +	priv = xpd->priv;
 +	BUG_ON(!priv);
@@ -2043,7 +2116,7 @@
  static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
  {
  	int			len = 0;
-@@ -570,7 +1030,7 @@
+@@ -570,7 +999,7 @@
   *      |
   *    SLIC #
   */
@@ -2052,7 +2125,7 @@
  {
  	char		op;		/* [W]rite, [R]ead */
  	char		reg_type;	/* [D]irect, [I]ndirect */
-@@ -588,9 +1048,17 @@
+@@ -588,9 +1017,17 @@
  			if(reg_type == 'D' && ret == 7) {
  				// DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
  				ret = slic_cmd_direct_read(sc, lines, reg_num);
@@ -2070,7 +2143,7 @@
  			} else {
  				NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
  				goto err;
-@@ -619,14 +1087,16 @@
+@@ -619,14 +1056,16 @@
  
  static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
  {
@@ -2092,7 +2165,7 @@
  	if((p = strchr(cmdline, '#')) != NULL)	/* Truncate comments */
  		*p = '\0';
  	if((p = strchr(cmdline, ';')) != NULL)	/* Truncate comments */
-@@ -635,7 +1105,7 @@
+@@ -635,12 +1074,11 @@
  		;
  	if(*p == '\0')
  		return 0;
@@ -2100,8 +2173,24 @@
 +	len = parse_slic_cmd(p, &sc, &priv->requested_reply);
  	if(len < 0)
  		return len;
- 	sc.lines &= xpd->enabled_chans;	// Ignore disabled channels
-@@ -677,6 +1147,7 @@
+-	sc.lines &= xpd->enabled_chans;	// Ignore disabled channels
+ 	if(!sc.lines) {
+-		NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__);
++		NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__);
+ 		return 0;
+ 	}
+ 	dump_slic_cmd("WRITE_SLIC", &sc);
+@@ -660,7 +1098,8 @@
+ 	int		i;
+ 	int		ret;
+ 
+-	BUG_ON(!xpd);
++	if(!xpd)
++		return -ENODEV;
+ 	for(i = 0; i < count; /* noop */) {
+ 		for(p = buf; p < buf + LINE_LEN; p++) {	/* read a line */
+ 			if(i >= count)
+@@ -677,6 +1116,7 @@
  		ret = process_slic_cmdline(xpd, buf);
  		if(ret < 0)
  			return ret;
@@ -2109,16 +2198,22 @@
  	}
  	return count;
  }
-@@ -684,7 +1155,7 @@
+@@ -684,7 +1124,13 @@
  
  int __init card_fxs_startup(void)
  {
 -	INFO("%s revision %s\n", THIS_MODULE->name, revision);
 +	INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
++#ifdef	POLL_DIGITAL_INPUTS
++	INFO("FEATURE: %s with DIGITAL INPUTS support (%s activated)\n",
++			THIS_MODULE->name, (poll_digital_inputs) ? "is" : "is not");
++#else
++	INFO("FEATURE: %s without DIGITAL INPUTS support\n", THIS_MODULE->name);
++#endif
  	xproto_register(&PROTO_TABLE(FXS));
  	return 0;
  }
-@@ -697,7 +1168,8 @@
+@@ -697,7 +1143,8 @@
  MODULE_DESCRIPTION("XPP FXS Card Driver");
  MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
  MODULE_LICENSE("GPL");
@@ -2128,9 +2223,9 @@
  
  module_init(card_fxs_startup);
  module_exit(card_fxs_cleanup);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxs.h zaptel-xpp-8WuH7d_dist/xpp/card_fxs.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_fxs.h zaptel-xpp-oaIQ8i_dist/xpp/card_fxs.h
 --- zaptel-1.2.6/xpp/card_fxs.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/card_fxs.h	2006-03-30 12:42:46.619481000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/card_fxs.h	2006-07-02 17:17:18.812352000 +0300
 @@ -2,7 +2,7 @@
  #define	CARD_FXS_H
  /*
@@ -2165,9 +2260,20 @@
  DEF_RPACKET_DATA(FXS, SIG_CHANGED,
  	byte		type;		/* unused -- we have it from DEV_DESC */
  	xpp_line_t	sig_status;	/* channels: lsb=1, msb=8 */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_global.c zaptel-xpp-8WuH7d_dist/xpp/card_global.c
+@@ -34,10 +52,6 @@
+ 	xpp_line_t	lines;
+ 	slic_reply_t	info;
+ 	);
+-DEF_RPACKET_DATA(FXS, SLIC_INIT,
+-	xpp_line_t      lines;
+-	slic_data_t     slic_data;
+-	);
+ DEF_RPACKET_DATA(FXS, SLIC_WRITE,
+ 	slic_cmd_t	slic_cmd;
+ 	);
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_global.c zaptel-xpp-oaIQ8i_dist/xpp/card_global.c
 --- zaptel-1.2.6/xpp/card_global.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/card_global.c	2006-03-30 12:42:46.619481000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/card_global.c	2006-07-03 14:04:21.414889000 +0300
 @@ -1,6 +1,6 @@
  /*
   * Written by Oron Peled <oron at actcom.co.il>
@@ -2184,20 +2290,26 @@
  #include <linux/module.h>
  
 -static const char rcsid[] = "$Id: card_global.c 949 2006-02-15 02:24:18Z kpfleming $";
-+static const char rcsid[] = "$Id: card_global.c 733 2006-03-30 10:42:46Z oron $";
++static const char rcsid[] = "$Id: card_global.c 1549 2006-07-03 11:04:21Z oron $";
  
  extern	int print_dbg;
  static bool pcm_valid(xpd_t *xpd, xpacket_t *pack);
-@@ -65,7 +66,7 @@
+@@ -61,13 +62,10 @@
+ 	byte		*pcm;
+ 	byte		*start_pcm;
+ 	int i;
+-	extern ulong	pcm_gen;
  
  	BUG_ON(!xbus);
  	BUG_ON(!xpd);
 -	lines &= xpd->enabled_chans;
-+	lines &= (xpd->enabled_chans | ~xpd->no_pcm);
- 	if(pcm_gen != 0)
- 		return 0;
+-	if(pcm_gen != 0)
+-		return 0;
++	lines &= ~xpd->no_pcm;
  //	if(lines == 0)
-@@ -81,7 +82,7 @@
+ //		return 0;
+ 
+@@ -81,7 +79,7 @@
  	XPACKET_NEW(pack, xbus, GLOBAL, PCM_WRITE, xpd->id);
  	RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
  	start_pcm = pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
@@ -2206,22 +2318,86 @@
  		if(IS_SET(lines, i)) {
  			memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
  			pcm += ZT_CHUNKSIZE;
-@@ -177,7 +178,7 @@
+@@ -116,32 +114,44 @@
+ 
+ /*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
+ 
++HANDLER_DEF(GLOBAL, NULL_REPLY)
++{
++	DBG("got len=%d\n", pack->datalen);
++	return 0;
++}
++
+ HANDLER_DEF(GLOBAL, DEV_DESC)
+ {
+ 	byte			rev = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, rev);
+ 	byte			type = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, type);
+ 	xpp_line_t		line_status = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, line_status);
+-	int			xpd_num = XPD_NUM(pack->content.addr);
++	xpd_addr_t		xpd_addr = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, addr);
+ 	struct card_desc_struct	*card_desc;
++	unsigned long		flags;
+ 
+-	DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n",
+-			xpd_num, type, rev, line_status);
++	BUG_ON(!xbus);
+ 	if((card_desc = kmalloc(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) {
+ 		ERR("%s: Card description allocation failed.\n", __FUNCTION__);
+ 		return -ENOMEM;
  	}
+ 	memset(card_desc, 0, sizeof(struct card_desc_struct));
+ 	card_desc->magic = CARD_DESC_MAGIC;
++	INIT_LIST_HEAD(&card_desc->card_list);
+ 	card_desc->xbus = xbus;
+ 	card_desc->type = type;
+ 	card_desc->rev = rev;
+-	card_desc->xpd_num = xpd_num;
+-	INIT_WORK(&card_desc->work, card_detected, card_desc);
+-	DBG("Queueing xpp_worker for xpd %d\n", xpd_num);
+-	if(!queue_work(xpp_worker, &card_desc->work)) {
+-		ERR("Failed to queue card description work\n");
+-		return -EINVAL;
+-	}
++	card_desc->xpd_addr = xpd_addr;
++	spin_lock_irqsave(&xbus->lock, flags);
++	DBG("xpd=%d-%d type=%d rev=%d line_status=0x%04X\n",
++			xpd_addr.unit, xpd_addr.subunit, type, rev, line_status);
++	if(type == XPD_TYPE_NOMODULE)
++		XBUS_COUNTER(xbus, DEV_DESC_EMPTY)++;
++	else
++		XBUS_COUNTER(xbus, DEV_DESC_FULL)++;
++	atomic_inc(&xbus->count_poll_answers);
++	wake_up(&xbus->wait_for_polls);
++	list_add_tail(&card_desc->card_list, &xbus->poll_results);
++	spin_unlock_irqrestore(&xbus->lock, flags);
+ 	return 0;
+ }
  
+@@ -155,6 +165,7 @@
+ 	unsigned long	flags;
+ 	int		i;
+ 
++	BUG_ON(!xbus);
+ 	if(!xpd) {
+ #if 0
+ 		int xpd_num = XPD_NUM(pack->content.addr);
+@@ -177,7 +188,7 @@
+ 	}
+ 
  	/* Copy PCM and put each channel in its index */
 -	for (i = 0; i < CHANNELS_PERXPD; i++) {
 +	for_each_line(xpd, i) {
  		if(IS_SET(lines, i)) {
  			memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
  			//memset((u_char *)r, 0x5A, ZT_CHUNKSIZE);	// DEBUG
-@@ -195,12 +196,18 @@
+@@ -195,12 +206,19 @@
  
  HANDLER_DEF(GLOBAL, SYNC_REPLY)
  {
 +	byte	mask = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, mask);
 +	bool	setit = mask & 0x01;
 +
++	BUG_ON(!xbus);
  	if(!xpd) {
  		int xpd_num = XPD_NUM(pack->content.addr);
  		NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
@@ -2235,7 +2411,15 @@
  	return 0;
  }
  
-@@ -239,7 +246,7 @@
+@@ -208,6 +226,7 @@
+ xproto_table_t PROTO_TABLE(GLOBAL) = {
+ 	.entries = {
+ 		/*	Card	Opcode		*/
++		XENTRY(	GLOBAL, NULL_REPLY	),
+ 		XENTRY(	GLOBAL, DEV_DESC	),
+ 		XENTRY(	GLOBAL,	PCM_READ	),
+ 		XENTRY(	GLOBAL,	SYNC_REPLY	),
+@@ -239,7 +258,7 @@
  
  	BUG_ON(!pack);
  	BUG_ON(pack->content.opcode != XPROTO_NAME(GLOBAL, PCM_READ));
@@ -2244,9 +2428,9 @@
  		if(IS_SET(lines, i))
  			count++;
  	if(pack->datalen != (sizeof(xpp_line_t) + count * 8)) {
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_global.h zaptel-xpp-8WuH7d_dist/xpp/card_global.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/card_global.h zaptel-xpp-oaIQ8i_dist/xpp/card_global.h
 --- zaptel-1.2.6/xpp/card_global.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/card_global.h	2006-03-30 12:42:46.619481000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/card_global.h	2006-07-03 13:44:48.152691000 +0300
 @@ -2,7 +2,7 @@
  #define	CARD_GLOBAL_H
  /*
@@ -2256,7 +2440,15 @@
   *
   * All rights reserved.
   *
-@@ -31,11 +31,11 @@
+@@ -24,6 +24,7 @@
+ 
+ #include "xdefs.h"
+ 
++DEF_RPACKET_DATA(GLOBAL, NULL_REPLY);
+ DEF_RPACKET_DATA(GLOBAL, DESC_REQ);
+ DEF_RPACKET_DATA(GLOBAL, DEV_DESC,
+ 	byte		rev;		/* Revision number */
+@@ -31,11 +32,11 @@
  	xpp_line_t	line_status;	/* hook/ring status, depending on unit */
  	);
  DEF_RPACKET_DATA(GLOBAL, PCM_WRITE,
@@ -2270,9 +2462,9 @@
  	byte		pcm[PCM_CHUNKSIZE];
  	);
  DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE,
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/cards.c zaptel-xpp-8WuH7d_dist/xpp/cards.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/cards.c zaptel-xpp-oaIQ8i_dist/xpp/cards.c
 --- zaptel-1.2.6/xpp/cards.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/cards.c	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/cards.c	1970-01-01 02:00:00.000000000 +0200
 @@ -1,394 +0,0 @@
 -#include <linux/module.h>
 -#include "xpd.h"
@@ -2668,9 +2860,9 @@
 -		return NULL;
 -	return &xpd_card_ops[xpd_type];
 -}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/cards.h zaptel-xpp-8WuH7d_dist/xpp/cards.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/cards.h zaptel-xpp-oaIQ8i_dist/xpp/cards.h
 --- zaptel-1.2.6/xpp/cards.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/cards.h	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/cards.h	1970-01-01 02:00:00.000000000 +0200
 @@ -1,23 +0,0 @@
 -#ifndef	CARDS_H
 -#define	CARDS_H
@@ -2695,62 +2887,10 @@
 -xops_t *get_xops(xpd_type_t xpd_type);
 -
 -#endif	/* CARDS_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/cmd2inc zaptel-xpp-8WuH7d_dist/xpp/cmd2inc
---- zaptel-1.2.6/xpp/cmd2inc	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/cmd2inc	2006-03-01 14:30:36.514598000 +0200
-@@ -0,0 +1,48 @@
-+#! /usr/bin/perl -w
-+
-+use strict;
-+
-+my $input;
-+my $header;
-+my $comment;
-+my $len;
-+
-+ at ARGV == 1 or @ARGV == 2 or die "Usage: $0 <infile> <outfile>\n";
-+$input = $ARGV[0];
-+$header = $ARGV[1];
-+open(IF, "$input") or die "Failed to open '$input': $!\n";
-+
-+if($header) {
-+	open(HF, ">$header") or die "Failed to write '$header': $!\n";
-+	select HF;
-+}
-+
-+while(<IF>) {
-+	chomp;
-+	undef $comment;
-+	s/\r//;				# CRLF -> LF
-+	if(s/\s*[;#]\s*(.*?)$//) {	# Comments
-+		$comment = $1;
-+	}
-+	if(/^\s*$/) {		# Empty lines
-+		next;
-+	}
-+	my ($slic0, $slic1, $slic2, $slic3, $op, @data) = split;
-+	my $slic = "$slic3$slic2$slic1$slic0";
-+	die "Bad slic address '$slic'" if length($slic) != 8;
-+	die "Bad op (op=%op)\n" if $op !~ /^[WR][DI]$/;
-+	if($op =~ /D$/) {	# Direct
-+		die "Bad input at line $.: @data=(@data)\n" if @data != 2;
-+		#                   len      reg    data
-+		printf "S_(0x$slic,\t0x02,\t0x%02s, 0x%02s),\t", $data[0], $data[1];
-+	} else {		# Indirect
-+		die "Bad input at line $.: @data=(@data)\n" if @data != 3;
-+		#                   len          data1         data2          reg
-+		printf "S_(0x$slic,\t0x06,\t0x1C, 0x%02s, 0x1D, 0x%02s, 0x1E, 0x%2s),\t", $data[2], $data[1], $data[0];
-+	}
-+} continue {
-+	if(defined($comment)) {
-+		print "// $comment";
-+	}
-+	print "\n";
-+}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/FPGA_XPD.hex zaptel-xpp-8WuH7d_dist/xpp/FPGA_XPD.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/gen_slic_init zaptel-xpp-8WuH7d_dist/xpp/gen_slic_init
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/FPGA_XPD.hex zaptel-xpp-oaIQ8i_dist/xpp/FPGA_XPD.hex
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/gen_slic_init zaptel-xpp-oaIQ8i_dist/xpp/gen_slic_init
 --- zaptel-1.2.6/xpp/gen_slic_init	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/gen_slic_init	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/gen_slic_init	1970-01-01 02:00:00.000000000 +0200
 @@ -1,37 +0,0 @@
 -#! /usr/bin/perl -w
 -
@@ -2789,9 +2929,9 @@
 -	}
 -	print HF "\n";
 -}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_3_19.cmd zaptel-xpp-8WuH7d_dist/xpp/init_data_3_19.cmd
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_3_19.cmd zaptel-xpp-oaIQ8i_dist/xpp/init_data_3_19.cmd
 --- zaptel-1.2.6/xpp/init_data_3_19.cmd	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/init_data_3_19.cmd	2006-06-26 11:48:58.007317000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/init_data_3_19.cmd	2006-06-26 11:48:58.007317000 +0300
 @@ -0,0 +1,169 @@
 +#
 +# Written by Oron Peled <oron at actcom.co.il>
@@ -2962,9 +3102,9 @@
 +80 00 00 00	WD	03 00
 +80 00 00 00	WD	04 39
 +80 00 00 00	WD	05 00
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_3_20.cmd zaptel-xpp-8WuH7d_dist/xpp/init_data_3_20.cmd
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_3_20.cmd zaptel-xpp-oaIQ8i_dist/xpp/init_data_3_20.cmd
 --- zaptel-1.2.6/xpp/init_data_3_20.cmd	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/init_data_3_20.cmd	2006-06-26 11:48:58.007317000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/init_data_3_20.cmd	2006-06-26 11:48:58.007317000 +0300
 @@ -0,0 +1,170 @@
 +#
 +# Written by Oron Peled <oron at actcom.co.il>
@@ -3136,9 +3276,9 @@
 +80 00 00 00	WD	03 00
 +80 00 00 00	WD	04 38
 +80 00 00 00	WD	05 00
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_4_19.cmd zaptel-xpp-8WuH7d_dist/xpp/init_data_4_19.cmd
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_4_19.cmd zaptel-xpp-oaIQ8i_dist/xpp/init_data_4_19.cmd
 --- zaptel-1.2.6/xpp/init_data_4_19.cmd	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/init_data_4_19.cmd	2006-04-27 16:03:25.463235000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/init_data_4_19.cmd	2006-04-27 16:03:25.463235000 +0300
 @@ -0,0 +1,69 @@
 +#
 +# Written by Oron Peled <oron at actcom.co.il>
@@ -3209,10 +3349,10 @@
 +
 +; ----------- DAA ONHOOK --------------------
 +FF FF 00 00	WD	05	00
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_4_20.cmd zaptel-xpp-8WuH7d_dist/xpp/init_data_4_20.cmd
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/init_data_4_20.cmd zaptel-xpp-oaIQ8i_dist/xpp/init_data_4_20.cmd
 --- zaptel-1.2.6/xpp/init_data_4_20.cmd	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/init_data_4_20.cmd	2006-04-27 16:03:25.463235000 +0300
-@@ -0,0 +1,69 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/init_data_4_20.cmd	2006-07-05 16:28:42.355959000 +0300
+@@ -0,0 +1,60 @@
 +#
 +# Written by Oron Peled <oron at actcom.co.il>
 +# Copyright (C) 2006, Xorcom
@@ -3232,59 +3372,50 @@
 +;
 +; DAA's 	CMD	Reg	High	Low
 +
++; Start with a software reset:
++FF FF 00 00	WD	01	80
++
 +; ----------------------------------==== 8-channel FXO unit initialization ===-----------------------------------------
 +
 +FF FF 00 00	WD	21	28
-+FF FF 00 00	WD	18	99
++; 99 also sets ring validation
++;FF FF 00 00	WD	18	99
 +FF FF 00 00	WD	06	00
 +
 +; ----------- DAA PCM start offset ----------
 +
-+01 00 00 00	WD	22 00
-+01 00 00 00	WD	23 00
-+01 00 00 00	WD	24 00
-+01 00 00 00	WD	25 00
++FF FF 00 00	WD	23	00
++FF FF 00 00	WD	25	00
 +
-+02 00 00 00	WD	22 08
-+02 00 00 00	WD	23 00
-+02 00 00 00	WD	24 08
-+02 00 00 00	WD	25 00
++01 00 00 00	WD	22	00
++01 00 00 00	WD	24	00
 +
-+04 00 00 00	WD	22 10
-+04 00 00 00	WD	23 00
-+04 00 00 00	WD	24 10
-+04 00 00 00	WD	25 00
++02 00 00 00	WD	22	08
++02 00 00 00	WD	24	08
 +
-+08 00 00 00	WD	22 18
-+08 00 00 00	WD	23 00
-+08 00 00 00	WD	24 18
-+08 00 00 00	WD	25 00
++04 00 00 00	WD	22	10
++04 00 00 00	WD	24	10
 +
-+10 00 00 00	WD	22 20
-+10 00 00 00	WD	23 00
-+10 00 00 00	WD	24 20
-+10 00 00 00	WD	25 00
++08 00 00 00	WD	22	18
++08 00 00 00	WD	24	18
 +
-+20 00 00 00	WD	22 28
-+20 00 00 00	WD	23 00
-+20 00 00 00	WD	24 28
-+20 00 00 00	WD	25 00
++10 00 00 00	WD	22	20
++10 00 00 00	WD	24	20
 +
-+40 00 00 00	WD	22 30
-+40 00 00 00	WD	23 00
-+40 00 00 00	WD	24 30
-+40 00 00 00	WD	25 00
++20 00 00 00	WD	22	28
++20 00 00 00	WD	24	28
 +
-+80 00 00 00	WD	22 38
-+80 00 00 00	WD	23 00
-+80 00 00 00	WD	24 38
-+80 00 00 00	WD	25 00
++40 00 00 00	WD	22	30
++40 00 00 00	WD	24	30
 +
++80 00 00 00	WD	22	38
++80 00 00 00	WD	24	38
++
 +; ----------- DAA ONHOOK --------------------
-+FF FF 00 00	WD	05	00
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/initialize_registers zaptel-xpp-8WuH7d_dist/xpp/initialize_registers
++FF FF 00 00	WD	05	08
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/initialize_registers zaptel-xpp-oaIQ8i_dist/xpp/initialize_registers
 --- zaptel-1.2.6/xpp/initialize_registers	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/initialize_registers	2006-05-01 12:49:12.732258000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/initialize_registers	2006-05-01 12:49:12.732258000 +0300
 @@ -0,0 +1,39 @@
 +#! /bin/sh
 +# XPD_BUS	- bus name
@@ -3325,9 +3456,9 @@
 +$LOGGER "Wrote '$FILE' into '$SLICS'"
 +
 +exit 0
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/LICENSE.firmware zaptel-xpp-8WuH7d_dist/xpp/LICENSE.firmware
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/LICENSE.firmware zaptel-xpp-oaIQ8i_dist/xpp/LICENSE.firmware
 --- zaptel-1.2.6/xpp/LICENSE.firmware	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/LICENSE.firmware	2006-05-01 22:45:43.558912000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/LICENSE.firmware	2006-05-01 22:45:43.558912000 +0300
 @@ -0,0 +1,37 @@
 +The firmware files (*.hex) in this directory are software for the 
 +Astribank itself and not intended to run on the Linux system itself. 
@@ -3366,47 +3497,26 @@
 +/*  hardware or firmware either solely or in combination with the firmware. */
 +/****************************************************************************/
 +
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/Makefile zaptel-xpp-8WuH7d_dist/xpp/Makefile
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/Makefile zaptel-xpp-oaIQ8i_dist/xpp/Makefile
 --- zaptel-1.2.6/xpp/Makefile	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/Makefile	2006-06-22 11:31:28.427315000 +0300
-@@ -1,5 +1,30 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/Makefile	2006-07-02 17:17:18.812352000 +0300
+@@ -1,5 +1,9 @@
 -EXTRA_CFLAGS	= -I$(src)/.. -DSOFT_SIMULATOR=0
-+EXTRA_CFLAGS	= -I$(SUBDIRS) -DDEBUG -DWITH_ECHO_SUPPRESSION -DXPP_EC_CHUNK -DWITH_RBS # -DHARD_CODED_INIT # -DOLD_CARD
++EXTRA_CFLAGS	= -I$(SUBDIRS) -DDEBUG -DPOLL_DIGITAL_INPUTS -DWITH_ECHO_SUPPRESSION -DXPP_EC_CHUNK -DWITH_RBS
  
 -obj-m		= xpd_fxs.o xpp.o xpp_usb.o
 -xpp-y		+= xproto.o card_global.o xpp_zap.o zap_debug.o
 -xpd_fxs-y	+= card_fxs.o slic.o
-+obj-m			= xpp.o xpd_fxs.o xpd_fxo.o xpp_usb.o
++obj-m			= xpp.o xpp_usb.o xpd_fxs.o xpd_fxo.o
 +xpp-y			+= xbus-core.o xpp_zap.o xproto.o card_global.o
 +xpd_fxs-y		+= card_fxs.o slic.o
 +xpd_fxo-y		+= card_fxo.o slic.o
 +
-+GENERATE_INIT_DATA	:= 1
-+INIT_DATA		= init_data_3_19.inc init_data_3_20.inc init_data_4_19.inc init_data_4_20.inc
-+clean-files		:= $(INIT_DATA)
-+
-+cmd2inc=$(src)/cmd2inc
-+
-+define run_cmd2inc
-+if [ ! -x $(cmd2inc) ]; then chmod +x $(cmd2inc); fi
-+$(cmd2inc) $^ $@
-+endef
-+
-+ifeq	($(GENERATE_INIT_DATA),1)
-+
-+$(obj)/%.inc: $(src)/%.cmd
-+	@echo "Generating $@"
-+	@$(run_cmd2inc)
-+
-+init_data: $(INIT_DATA)
-+
-+$(obj)/card_fxs.o: $(obj)/init_data_3_19.inc $(obj)/init_data_3_20.inc
-+$(obj)/card_fxo.o: $(obj)/init_data_4_19.inc $(obj)/init_data_4_20.inc
-+
-+endif
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/README.Astribank zaptel-xpp-8WuH7d_dist/xpp/README.Astribank
++ctags:
++	ctags *.[ch]
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/README.Astribank zaptel-xpp-oaIQ8i_dist/xpp/README.Astribank
 --- zaptel-1.2.6/xpp/README.Astribank	2006-03-03 21:11:53.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/README.Astribank	2006-06-19 11:29:10.334411000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/README.Astribank	2006-06-19 11:29:10.334411000 +0300
 @@ -5,15 +5,63 @@
  Building and Installation:
  """""""""""""""""""""""""
@@ -3520,9 +3630,9 @@
  
  BTW: XPP here does not stand for X Printing Panel, XML Pull Parser, 
  X-Windows Phase Plane or XML Professional Publisher. It is simply the 
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic.c zaptel-xpp-8WuH7d_dist/xpp/slic.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic.c zaptel-xpp-oaIQ8i_dist/xpp/slic.c
 --- zaptel-1.2.6/xpp/slic.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/slic.c	2006-05-01 12:37:15.907543000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/slic.c	2006-05-01 12:37:15.907543000 +0300
 @@ -1,6 +1,6 @@
  /*
   * Written by Oron Peled <oron at actcom.co.il>
@@ -3600,9 +3710,9 @@
  EXPORT_SYMBOL(slic_cmd_direct_write);
  EXPORT_SYMBOL(slic_cmd_direct_read);
  EXPORT_SYMBOL(slic_cmd_indirect_write);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic.h zaptel-xpp-8WuH7d_dist/xpp/slic.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic.h zaptel-xpp-oaIQ8i_dist/xpp/slic.h
 --- zaptel-1.2.6/xpp/slic.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/slic.h	2006-04-02 18:33:25.346374000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/slic.h	2006-07-02 17:17:18.812352000 +0300
 @@ -1,5 +1,26 @@
  #ifndef	SLIC_H
  #define	SLIC_H
@@ -3630,7 +3740,20 @@
  
  #include "xdefs.h"
  
-@@ -60,6 +81,7 @@
+@@ -46,12 +67,6 @@
+ 					(slic_reg)->reg_data = data;	\
+ 				} while(0);
+ 
+-/* OLD SLIC_INIT data */
+-typedef	struct slic_data {
+-	byte	len;
+-	byte	data[40];
+-} __attribute__((packed)) slic_data_t;
+-
+ 
+ /*------------------------------ SLIC Initializers -------------------------*/
+ 
+@@ -60,6 +75,7 @@
  int slic_cmd_indirect_write(slic_cmd_t *sc, xpp_line_t lines, byte reg, byte data_low, byte data_high);
  int slic_cmd_indirect_read(slic_cmd_t *sc, xpp_line_t lines, byte reg);
  void dump_slic_cmd(const char msg[], slic_cmd_t *sc);
@@ -3638,9 +3761,9 @@
  
  
  #endif	/* SLIC_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic_init.inc zaptel-xpp-8WuH7d_dist/xpp/slic_init.inc
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/slic_init.inc zaptel-xpp-oaIQ8i_dist/xpp/slic_init.inc
 --- zaptel-1.2.6/xpp/slic_init.inc	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/slic_init.inc	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/slic_init.inc	1970-01-01 02:00:00.000000000 +0200
 @@ -1,65 +0,0 @@
 -// ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
 -
@@ -3707,9 +3830,9 @@
 -S_(0x000000FF,	0x02,	0x42, 0x06),	
 -// -------------------------------------------------------------
 -
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/ec_xpp.h zaptel-xpp-8WuH7d_dist/xpp/supress/ec_xpp.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/ec_xpp.h zaptel-xpp-oaIQ8i_dist/xpp/supress/ec_xpp.h
 --- zaptel-1.2.6/xpp/supress/ec_xpp.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/supress/ec_xpp.h	2006-06-25 14:42:21.798100000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/supress/ec_xpp.h	2006-06-25 14:42:21.798100000 +0300
 @@ -0,0 +1,100 @@
 +#ifndef __EC_XPP_H__
 +#define __EC_XPP_H__
@@ -3811,9 +3934,9 @@
 +
 +#endif
 +
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/suppressor.c zaptel-xpp-8WuH7d_dist/xpp/supress/suppressor.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/suppressor.c zaptel-xpp-oaIQ8i_dist/xpp/supress/suppressor.c
 --- zaptel-1.2.6/xpp/supress/suppressor.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/supress/suppressor.c	2006-06-25 14:42:21.798100000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/supress/suppressor.c	2006-06-25 14:42:21.798100000 +0300
 @@ -0,0 +1,321 @@
 + /***********************************************************************
 + * Written by Sergey Serik.
@@ -4136,9 +4259,9 @@
 +
 +    return nearSample;
 +}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/suppressor.h zaptel-xpp-8WuH7d_dist/xpp/supress/suppressor.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/supress/suppressor.h zaptel-xpp-oaIQ8i_dist/xpp/supress/suppressor.h
 --- zaptel-1.2.6/xpp/supress/suppressor.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/supress/suppressor.h	2006-06-25 14:42:21.798100000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/supress/suppressor.h	2006-06-25 14:42:21.798100000 +0300
 @@ -0,0 +1,160 @@
 +#if 0  /* File Header */
 +************************************************************************
@@ -4300,9 +4423,9 @@
 +#endif
 +
 +#endif /* __SUPPRESSOR_H__ */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/sync.sh zaptel-xpp-8WuH7d_dist/xpp/sync.sh
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/sync.sh zaptel-xpp-oaIQ8i_dist/xpp/sync.sh
 --- zaptel-1.2.6/xpp/sync.sh	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/sync.sh	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/sync.sh	1970-01-01 02:00:00.000000000 +0200
 @@ -1,31 +0,0 @@
 -#!/bin/sh
 -
@@ -4335,10 +4458,10 @@
 -cp -a $XORTEL_DIR/gen_slic_init ${TARGET_DIR}/
 -cp -a $XPP_DIR/Makefile ${TARGET_DIR}/
 -cp -a $XPP_DIR/slic_init.inc ${TARGET_DIR}/
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/FPGA_FXS.hex zaptel-xpp-8WuH7d_dist/xpp/utils/FPGA_FXS.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/fpga_load.8 zaptel-xpp-8WuH7d_dist/xpp/utils/fpga_load.8
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/FPGA_FXS.hex zaptel-xpp-oaIQ8i_dist/xpp/utils/FPGA_FXS.hex
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/fpga_load.8 zaptel-xpp-oaIQ8i_dist/xpp/utils/fpga_load.8
 --- zaptel-1.2.6/xpp/utils/fpga_load.8	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/fpga_load.8	2006-04-16 16:20:04.117881000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/fpga_load.8	2006-04-16 16:20:04.117881000 +0300
 @@ -0,0 +1,72 @@
 +.TH "FPGA_LOAD" "8" "16 April 2006" "" ""
 +
@@ -4412,9 +4535,9 @@
 +
 +On Debian systems, the complete text of the GNU General Public
 +License can be found in /usr/share/common-licenses/GPL.
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/fpga_load.c zaptel-xpp-8WuH7d_dist/xpp/utils/fpga_load.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/fpga_load.c zaptel-xpp-oaIQ8i_dist/xpp/utils/fpga_load.c
 --- zaptel-1.2.6/xpp/utils/fpga_load.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/fpga_load.c	2006-06-01 11:50:28.294045000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/fpga_load.c	2006-06-01 11:50:28.294045000 +0300
 @@ -0,0 +1,822 @@
 +#include <stdio.h>
 +#include <assert.h>
@@ -5238,10 +5361,10 @@
 +	usb_cleanup(handle);
 +	return ret;
 +}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/genzaptelconf zaptel-xpp-8WuH7d_dist/xpp/utils/genzaptelconf
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/genzaptelconf zaptel-xpp-oaIQ8i_dist/xpp/utils/genzaptelconf
 --- zaptel-1.2.6/xpp/utils/genzaptelconf	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/genzaptelconf	2006-06-27 10:06:55.011704000 +0300
-@@ -0,0 +1,953 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/genzaptelconf	2006-06-27 20:23:31.736538000 +0300
+@@ -0,0 +1,954 @@
 +#! /bin/bash
 +
 +# genzaptelconf: generate as smartly as you can:
@@ -5278,8 +5401,9 @@
 +# 0.5.3:
 +# * Experimental support for Sangoma analog cards (A20x)
 +# * Support OpenVox A1200P (A TDM400P clone refactored)
-+# * fixed timeout for Astribank load
++# * Fixed timeout for Astribank load
 +# * Delete unsuccessfully-probe modules
++# * Pass callerid from trunks
 +# 0.5.2:
 +# * Now it should detect most PRI cards and even wcusb
 +# 0.5.1:
@@ -5588,7 +5712,7 @@
 +			fi
 +		else # this is an FXO (trunk/phone: FXO signalling)
 +		  # we have may have set it. So reset it:
-+			echo "callerid=\"\" <0>"
++			echo "callerid=asrecieved"
 +			echo "mailbox="
 +			if [ "$group_manual" != "yes" ]
 +			then 
@@ -6025,7 +6149,7 @@
 +					# NT is the same as FXS for us and TE is the same as FXO
 +					if [ "$span_termtype" = 'nt' ]
 +					then
-+						#echo "callerid=\"Channel $chan\" <$exten>"
++						echo "callerid=\"Channels $span_begin - $span_end\" <$span_begin>"
 +						#echo "mailbox=$exten"
 +						if [ "$group_manual" != "yes" ]
 +						then 
@@ -6036,7 +6160,7 @@
 +							echo "context=$context_phones"
 +						fi
 +					else # we have may have set it. So reset it:
-+						#echo "callerid=\"\" <0>"
++						echo "callerid=asrecieved"
 +						#echo "mailbox="
 +						if [ "$group_manual" != "yes" ]
 +						then 
@@ -6195,9 +6319,9 @@
 +fi
 +
 +# vim:ts=2:
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/genzaptelconf.8 zaptel-xpp-8WuH7d_dist/xpp/utils/genzaptelconf.8
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/genzaptelconf.8 zaptel-xpp-oaIQ8i_dist/xpp/utils/genzaptelconf.8
 --- zaptel-1.2.6/xpp/utils/genzaptelconf.8	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/genzaptelconf.8	2006-06-17 09:56:07.169240000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/genzaptelconf.8	2006-06-17 09:56:07.169240000 +0300
 @@ -0,0 +1,258 @@
 +.TH GENZAPTELCONF 8 "July 18th, 2005" "Xorcom Rapid Asterisk" "Linux Programmer's Manual"
 +.SH "NAME" 
@@ -6457,9 +6581,9 @@
 +
 +On Debian systems, the complete text of the GNU General Public 
 +License can be found in /usr/share/common-licenses/GPL. 
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/hexfile.c zaptel-xpp-8WuH7d_dist/xpp/utils/hexfile.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/hexfile.c zaptel-xpp-oaIQ8i_dist/xpp/utils/hexfile.c
 --- zaptel-1.2.6/xpp/utils/hexfile.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/hexfile.c	2006-06-18 17:05:04.917972000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/hexfile.c	2006-06-18 17:05:04.917972000 +0300
 @@ -0,0 +1,360 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
@@ -6821,9 +6945,9 @@
 +	fclose(fp);
 +}
 +
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/hexfile.h zaptel-xpp-8WuH7d_dist/xpp/utils/hexfile.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/hexfile.h zaptel-xpp-oaIQ8i_dist/xpp/utils/hexfile.h
 --- zaptel-1.2.6/xpp/utils/hexfile.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/hexfile.h	2006-05-15 17:27:26.264723000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/hexfile.h	2006-05-15 17:27:26.264723000 +0300
 @@ -0,0 +1,120 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
@@ -6945,15 +7069,16 @@
 +__END_DECLS
 +
 +#endif
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/Makefile zaptel-xpp-8WuH7d_dist/xpp/utils/Makefile
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/Makefile zaptel-xpp-oaIQ8i_dist/xpp/utils/Makefile
 --- zaptel-1.2.6/xpp/utils/Makefile	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/Makefile	2006-06-27 02:07:26.558841000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/Makefile	2006-07-02 17:49:51.471281000 +0300
 @@ -0,0 +1,50 @@
 +PEDANTIC	= -ansi -pedantic -std=c99
 +
 +CC		= gcc
 +RANLIB		= ranlib
 +INSTALL		= install
++INSTALL_DATA	= install -m 644
 +
 +BINDIR    = /usr/sbin
 +DATADIR   = /usr/share/zaptel
@@ -6968,17 +7093,16 @@
 +
 +all: $(TARGETS)
 +
-+# install: sets the executable bit
 +install: all
 +	$(INSTALL) -d $(DESTDIR)$(BINDIR)
 +	$(INSTALL) genzaptelconf fpga_load $(DESTDIR)$(BINDIR)/
 +	$(INSTALL) -d $(DESTDIR)$(DATADIR)
-+	cp -a $(DATA_FILES) $(DESTDIR)$(DATADIR)/
++	$(INSTALL_DATA) $(DATA_FILES) $(DESTDIR)$(DATADIR)/
 +	$(INSTALL) ../initialize_registers  $(DESTDIR)$(DATADIR)/
 +	$(INSTALL) -d $(DESTDIR)$(MANDIR)
-+	cp -a fpga_load.8 genzaptelconf.8 $(DESTDIR)$(MANDIR)/
++	$(INSTALL_DATA) fpga_load.8 genzaptelconf.8 $(DESTDIR)$(MANDIR)/
 +	$(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
-+	cp -a xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
++	$(INSTALL_DATA) xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
 +	$(INSTALL) xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/
 +
 +libhexfile.a: hexfile.o
@@ -6999,9 +7123,9 @@
 +
 +clean:
 +	$(RM) *.o $(TARGETS)
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/test_parse.c zaptel-xpp-8WuH7d_dist/xpp/utils/test_parse.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/test_parse.c zaptel-xpp-oaIQ8i_dist/xpp/utils/test_parse.c
 --- zaptel-1.2.6/xpp/utils/test_parse.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/test_parse.c	2006-05-15 17:27:26.264723000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/test_parse.c	2006-05-15 17:27:26.264723000 +0300
 @@ -0,0 +1,34 @@
 +#include <stdio.h>
 +#include <stdarg.h>
@@ -7037,12 +7161,12 @@
 +	}
 +	return 0;
 +}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/USB_1130.hex zaptel-xpp-8WuH7d_dist/xpp/utils/USB_1130.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/USB_8613.hex zaptel-xpp-8WuH7d_dist/xpp/utils/USB_8613.hex
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_fxloader zaptel-xpp-8WuH7d_dist/xpp/utils/xpp_fxloader
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/USB_1130.hex zaptel-xpp-oaIQ8i_dist/xpp/utils/USB_1130.hex
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/USB_8613.hex zaptel-xpp-oaIQ8i_dist/xpp/utils/USB_8613.hex
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_fxloader zaptel-xpp-oaIQ8i_dist/xpp/utils/xpp_fxloader
 --- zaptel-1.2.6/xpp/utils/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/xpp_fxloader	2006-06-27 02:07:26.558841000 +0300
-@@ -0,0 +1,158 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/xpp_fxloader	2006-07-02 17:49:51.471281000 +0300
+@@ -0,0 +1,163 @@
 +#!/bin/sh
 +
 +# xpp_fxload: load XPP firmware
@@ -7129,6 +7253,7 @@
 +  devices=`find_dev $v_id $p_id`
 +  for dev in $devices
 +  do
++    $LOGGER "USB Firmware $FIRMWARE_DIR/$fw into $dev"
 +    do_fxload -D $dev -I $FIRMWARE_DIR/$fw || exit 1
 +  done
 +
@@ -7143,23 +7268,24 @@
 +}
 +
 +load_fpga() {
-+	dev=$1
-+
++  v_id=$1
++  p_id=$2
++  fw=$3
++  
++  devices=`find_dev $v_id $p_id`
++  for dev in $devices
++  do
 +	card_ver=`$FPGA_LOAD -d -D $dev`
-+	firm_ver=`hexfile_version $FIRM_FXS`
++	firm_ver=`hexfile_version $FIRMWARE_DIR/$fw`
 +
-+	$LOGGER "considering fpga firmware version '$firm_ver' for $dev with version $card_ver."
-+	case "$card_ver" in 
-+	1.001)
-+		$LOGGER "Loading firmware '$FIRM_FXS' (version $firm_ver) into '$dev'"
-+		$FPGA_LOAD -D "$dev" -I "$FIRM_FXS" 2>&1 >/dev/null | $LOGGER
-+		status=$PIPESTATUS
-+		if [ $status != 0 ]; then
-+			echo "fpga_load failed with status $status" | $LOGGER
-+			exit 77
-+		fi
-+		;;
-+	esac
++	$LOGGER "FPGA Firmware $FIRMWARE_DIR/$fw into $dev"
++	$FPGA_LOAD -D "$dev" -I "$FIRMWARE_DIR/$fw" 2>&1 >/dev/null | $LOGGER
++	status=$PIPESTATUS
++	if [ $status != 0 ]; then
++		echo "fpga_load failed with status $status" | $LOGGER
++		exit 77
++	fi
++  done
 +}
 +
 +#########################
@@ -7169,11 +7295,13 @@
 +
 +# to run manually, pass the parameter 'xppdetect'
 +if [ "$1" = 'xppdetect' ]; then
++	echo "--------- FIRMWARE LOADING"
 +	load_fw 04b4 8613 USB_8613.hex 
 +	load_fw e4e4 1130 USB_1130.hex
-+	for dev in `find_dev e4e4 1131`; do
-+		load_fpga $dev
-+	done
++	load_fpga e4e4 1131 FPGA_FXS.hex
++
++	sleep 3		# Let it stabilize
++	echo "--------- FIRMWARE IS LOADED"
 +	exit $?
 +fi
 +
@@ -7185,33 +7313,34 @@
 +if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ]
 +then
 +	$LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE"
++	prod_id=`echo "$PRODUCT" | cut -d/ -f2`
 +	case "$PRODUCT" in
-+	4b4/8613/*)
-+		FIRM_USB=$FIRMWARE_DIR/USB_8613.hex
++	4b4/8613/*|e4e4/1130/*|e4e4/1140/*)
++		FIRM_USB="$FIRMWARE_DIR/USB_$prod_id.hex"
 +		$LOGGER "Loading firmware '$FIRM_USB' into '$DEVICE'"
 +		do_fxload -D "$DEVICE" -I "$FIRM_USB"
 +		;;
-+	e4e4/1130/*)
-+		FIRM_USB=$FIRMWARE_DIR/USB_1130.hex
-+		$LOGGER "Loading firmware '$FIRM_USB' into '$DEVICE'"
-+		do_fxload -D "$DEVICE" -I "$FIRM_USB"
++	e4e4/1131/*|e4e4/1141/*)
++		if [ "$prod_id" = 1131 ]; then
++			FIRM_FPGA="$FIRMWARE_DIR/FPGA_FXS.hex"	# Legacy
++		else
++			FIRM_FPGA="$FIRMWARE_DIR/FPGA_$prod_id.hex"
++		fi
++		$FPGA_LOAD -D "$DEVICE" -I "$FIRM_FPGA" 2>&1 >/dev/null | $LOGGER
 +		;;
-+	e4e4/1131/*)
-+		load_fpga $DEVICE
-+		;;
 +	esac	
 +fi
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_fxloader.usermap zaptel-xpp-8WuH7d_dist/xpp/utils/xpp_fxloader.usermap
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_fxloader.usermap zaptel-xpp-oaIQ8i_dist/xpp/utils/xpp_fxloader.usermap
 --- zaptel-1.2.6/xpp/utils/xpp_fxloader.usermap	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/xpp_fxloader.usermap	2006-05-01 18:45:04.050100000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/xpp_fxloader.usermap	2006-05-01 18:45:04.050100000 +0300
 @@ -0,0 +1,4 @@
 +# module	match_flags	idVendor	idProduct	bcdDevice_lo	bcdDevice_hi	bDeviceClass	bDeviceSubClass	bDeviceProtocol	bInterfaceClass	bInterfaceSubClass	bInterfaceProtocol	driver_info
 +xpp_fxloader	0x0003		0x04b4		0x8613		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
 +xpp_fxloader	0x0003		0xe4e4		0x1130		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
 +xpp_fxloader	0x0003		0xe4e4		0x1131		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_modprobe zaptel-xpp-8WuH7d_dist/xpp/utils/xpp_modprobe
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/utils/xpp_modprobe zaptel-xpp-oaIQ8i_dist/xpp/utils/xpp_modprobe
 --- zaptel-1.2.6/xpp/utils/xpp_modprobe	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/utils/xpp_modprobe	2006-05-01 17:08:34.781705000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/utils/xpp_modprobe	2006-05-01 17:08:34.781705000 +0300
 @@ -0,0 +1,10 @@
 +# Some debugging options for the brave of heart:
 +#options zaptel debug=1
@@ -7223,10 +7352,10 @@
 +
 +# For pre-loading of card modules (e.g: xpp_fxs)
 +#install xpp_usb /sbin/modprobe xpd_fxs && /sbin/modprobe --ignore-install xpp_usb
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xbus-core.c zaptel-xpp-8WuH7d_dist/xpp/xbus-core.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xbus-core.c zaptel-xpp-oaIQ8i_dist/xpp/xbus-core.c
 --- zaptel-1.2.6/xpp/xbus-core.c	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xbus-core.c	2006-04-26 15:44:38.391672000 +0300
-@@ -0,0 +1,677 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/xbus-core.c	2006-07-03 12:11:26.109424000 +0300
+@@ -0,0 +1,874 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2006, Xorcom
@@ -7259,21 +7388,23 @@
 +#include <linux/errno.h>
 +#include <linux/proc_fs.h>
 +#include <linux/device.h>
++#include <linux/delay.h>	/* for mdelay() to debug */
 +#include "xpd.h"
 +#include "xpp_zap.h"
 +#include "xbus-core.h"
 +#include "zap_debug.h"
 +
-+static const char rcsid[] = "$Id: xbus-core.c 894 2006-04-26 12:44:38Z oron $";
++static const char rcsid[] = "$Id: xbus-core.c 1543 2006-07-03 09:11:26Z oron $";
 +
 +/* Defines */
++#define	POLL_TIMEOUT		(MAX_XPDS)	/* in jiffies */
 +#define	PROC_XBUSES		"xbuses"
 +#define	PROC_XBUS_SUMMARY	"summary"
++#define	PROC_XBUS_WAITFOR_XPDS	"waitfor_xpds"
 +
 +/* Command line parameters */
 +extern int print_dbg;
 +extern int max_queue_len;
-+extern int ignore_xpds;
 +
 +/* Forward declarations */
 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
@@ -7287,10 +7418,13 @@
 +static DEVICE_ATTR_FUNC(connector_show, dev, buf);
 +static DEVICE_ATTR_FUNC(status_show, dev, buf);
 +
++static int xbus_poll(void *data);
 +static void xbus_release(struct device *dev);
 +static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
++static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data);
 +
 +/* Data structures */
++struct workqueue_struct		*xpp_worker = NULL;
 +static spinlock_t		xbuses_lock = SPIN_LOCK_UNLOCKED;
 +static xbus_t			*xbuses_array[MAX_BUSES] = {};
 +static int			bus_count = 0;
@@ -7463,29 +7597,154 @@
 +	return xbus->xpds[xpd_num];
 +}
 +
-+static void xbus_poll(xbus_t *xbus)
++int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd)
 +{
-+	int id;
-+	int ret;
-+	xpd_t **xpds;
-+	xpd_t *xpd;
++	unsigned int	xpd_num = xpd->id;
++	unsigned long	flags;
++	int		ret = 0;
 +
++	spin_lock_irqsave(&xbus->lock, flags);
++	if(!VALID_XPD_NUM(xpd_num)) {
++		ERR("%s: Bad xpd_num = %d\n", xbus->busname, xpd_num);
++		ret = -EINVAL;
++		goto out;
++	}
++	if(xbus->xpds[xpd_num] != NULL) {
++		xpd_t	*other = xbus->xpds[xpd_num];
++
++		ERR("%s: xpd_num=%d is occupied by %p (%s)\n",
++				xbus->busname, xpd_num, other, other->xpdname);
++		ret = -EINVAL;
++		goto out;
++	}
++	xbus->xpds[xpd_num] = xpd;
++	xbus->num_xpds++;
++out:
++	spin_unlock_irqrestore(&xbus->lock, flags);
++	return ret;
++}
++
++int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd)
++{
++	unsigned int	xpd_num = xpd->id;
++	unsigned long	flags;
++	int		ret = 0;
++
++	spin_lock_irqsave(&xbus->lock, flags);
++	if(!VALID_XPD_NUM(xpd_num)) {
++		ERR("%s: Bad xpd_num = %d\n", xbus->busname, xpd_num);
++		ret = -EINVAL;
++		goto out;
++	}
++	if(xbus->xpds[xpd_num] != xpd) {
++		xpd_t	*other = xbus->xpds[xpd_num];
++
++		ERR("%s: xpd_num=%d is occupied by %p (%s)\n",
++				xbus->busname, xpd_num, other, other->xpdname);
++		ret = -EINVAL;
++		goto out;
++	}
++	xbus->xpds[xpd_num] = NULL;
++	xbus->num_xpds--;
++	xpd->xbus = NULL;
++out:
++	spin_unlock_irqrestore(&xbus->lock, flags);
++	return ret;
++}
++
++/*
++ * This must be called from synchronous (non-interrupt) context
++ * it returns only when all XPD's on the bus are detected and
++ * initialized.
++ */
++static int xbus_poll(void *data)
++{
++	int			id;
++	int			ret;
++	unsigned long		flags;
++	struct list_head	*card;
++	struct list_head	*next_card;
++	struct list_head	removal_list;
++	struct list_head	additions_list;
++	int			count_removed;
++	int			count_added;
++	int			xpd_num;
++	xbus_t			*xbus = data;
++
++	spin_lock_irqsave(&xbus->lock, flags);
 +	DBG("%s\n", xbus->busname);
-+	xpds = xbus->xpds;
++
++	/*
++	 * Send out the polls
++	 */
++	atomic_set(&xbus->count_poll_answers, 0);
 +	for(id = 0; id < MAX_XPDS; id++) {
 +		if(!xbus->hardware_exists)
 +			break;
-+		xpd = xpd_of(xbus, id);
-+		if(IS_SET(ignore_xpds, id)) {		/* skip xpds */
-+			DBG("  Ignoring XPD #%d\n", id);
-+			continue;
-+		}
-+		DBG("  Polling slot %d %s\n", id, xbus->busname);
++		// DBG("  Polling slot %d %s\n", id, xbus->busname);
++		spin_unlock_irqrestore(&xbus->lock, flags);
 +		ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
++		spin_lock_irqsave(&xbus->lock, flags);
 +		if(ret < 0) {
 +			NOTICE("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
++			break;
 +		}
++		mdelay(1);	/* FIXME: debugging for Dima */
 +	}
++	spin_unlock_irqrestore(&xbus->lock, flags);
++	DBG("%s: Polled %d XPD's. Waiting for replies\n", xbus->busname, MAX_XPDS);
++	ret = wait_event_timeout(xbus->wait_for_polls, atomic_read(&xbus->count_poll_answers) >= MAX_XPDS, POLL_TIMEOUT);
++	if(ret < 0) {
++		ERR("%s: Poll timeout %d\n", xbus->busname, ret);
++		return ret;
++	}
++	DBG("%s: Poll finished. Start processing.\n", xbus->busname);
++	spin_lock_irqsave(&xbus->lock, flags);
++	INIT_LIST_HEAD(&removal_list);
++	INIT_LIST_HEAD(&additions_list);
++	count_removed = 0;
++	count_added = 0;
++	list_for_each_safe(card, next_card, &xbus->poll_results) {
++		struct card_desc_struct	*card_desc = list_entry(card, struct card_desc_struct, card_list);
++		byte			type = card_desc->type;
++		xpd_t			*xpd;
++
++		BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
++		xpd_num = xpd_addr2num(&card_desc->xpd_addr);
++		xpd = xpd_of(xbus, xpd_num);
++
++		if(xpd && type == XPD_TYPE_NOMODULE) {		/* card removal */
++			list_move_tail(card, &removal_list);
++			count_removed++;
++		} else if(!xpd && type != XPD_TYPE_NOMODULE) {	/* card detection */
++			list_move_tail(card, &additions_list);
++			count_added++;
++		} else {					/* same same */
++			list_del(card);
++			kfree(card_desc);
++		}
++	}
++	spin_unlock_irqrestore(&xbus->lock, flags);
++	INFO("%s: Poll results: removals=%d additions=%d\n", xbus->busname, count_removed, count_added);
++	list_for_each_safe(card, next_card, &removal_list) {
++		struct card_desc_struct	*card_desc = list_entry(card, struct card_desc_struct, card_list);
++		xpd_t			*xpd;
++
++		list_del(card);
++		xpd_num = xpd_addr2num(&card_desc->xpd_addr);
++		xpd = xpd_of(xbus, xpd_num);
++		if(xpd)
++			xpd_disconnect(xpd);
++		kfree(card);
++	}
++	list_for_each_safe(card, next_card, &additions_list) {
++		struct card_desc_struct	*card_desc = list_entry(card, struct card_desc_struct, card_list);
++
++		list_del(card);
++		card_detected(card_desc);
++	}
++	complete_all(&xbus->xpds_initialized);
++	return 0;
 +}
 +
 +
@@ -7503,7 +7762,11 @@
 +	xbus->hardware_exists = 1;
 +	DBG("Activating: %s\n", xbus->busname);
 +	/* Poll it */
-+	xbus_poll(xbus);
++	INIT_WORK(&xbus->xpds_init_work, (void (*)(void *))xbus_poll, (void *)xbus);
++	if(!queue_work(xpp_worker, &xbus->xpds_init_work)) {
++		ERR("Failed to queue xpd initialization work\n");
++		/* FIXME: need to return error */
++	}
 +}
 +
 +void xbus_disconnect(xbus_t *xbus)
@@ -7577,6 +7840,11 @@
 +			remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
 +			xbus->proc_xbus_summary = NULL;
 +		}
++		if(xbus->proc_xbus_waitfor_xpds) {
++			DBG("Removing proc '%s' for %s\n", PROC_XBUS_WAITFOR_XPDS, xbus->busname);
++			remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir);
++			xbus->proc_xbus_waitfor_xpds = NULL;
++		}
 +		DBG("Removing proc directory %s\n", xbus->busname);
 +		remove_proc_entry(xbus->busname, xpp_proc_toplevel);
 +		xbus->proc_xbus_dir = NULL;
@@ -7614,7 +7882,11 @@
 +	INFO("New xbus: %s\n", xbus->busname);
 +	init_waitqueue_head(&xbus->packet_cache_empty);
 +	atomic_set(&xbus->packet_counter, 0);
++	atomic_set(&xbus->count_poll_answers, 0);
++	init_waitqueue_head(&xbus->wait_for_polls);
 +	init_rwsem(&xbus->in_use);
++	INIT_LIST_HEAD(&xbus->poll_results);
++	init_completion(&xbus->xpds_initialized);
 +	xbus->num_xpds = 0;
 +	xbus_reset_counters(xbus);
 +
@@ -7654,6 +7926,15 @@
 +		err = -EIO;
 +		goto nobus;
 +	}
++	xbus->proc_xbus_summary->owner = THIS_MODULE;
++	xbus->proc_xbus_waitfor_xpds = create_proc_read_entry(PROC_XBUS_WAITFOR_XPDS, 0444, xbus->proc_xbus_dir,
++			xbus_read_waitfor_xpds, xbus);
++	if (!xbus->proc_xbus_waitfor_xpds) {
++		ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_WAITFOR_XPDS, xbus->busname);
++		err = -EIO;
++		goto nobus;
++	}
++	xbus->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
 +#endif
 +	/* Sanity checks */
 +	if(!ops->packet_send) {
@@ -7736,7 +8017,9 @@
 +			(xbus->hardware_exists) ? "connected" : "missing",
 +			xbus->bus_type
 +		      );
-+	len += sprintf(page + len, "max_packet_size=%d open_counter=%d packet_count=%d\n",
++	len += sprintf(page + len, "POLLS: %d/%d\n", atomic_read(&xbus->count_poll_answers), MAX_XPDS);
++	len += sprintf(page + len, "XPDS_READY: %s\n", (xbus->xpds_initialized.done) ? "YES" : "NO");
++	len += sprintf(page + len, "\nmax_packet_size=%d open_counter=%d packet_count=%d\n",
 +			xbus->max_packet_size,
 +			xbus->open_counter,
 +			atomic_read(&xbus->packet_counter)
@@ -7761,6 +8044,36 @@
 +
 +}
 +
++static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++	int len = 0;
++	unsigned long flags;
++	xbus_t	*xbus = data;
++	int i;
++
++	if(!xbus)
++		goto out;
++	i = wait_for_completion_interruptible_timeout(&xbus->xpds_initialized, 40*HZ);
++	if(i < 0) {
++		NOTICE("PID=%d waiting for XPDS initialization failed: %d\n", current->pid, i);
++		return i;
++	}
++	spin_lock_irqsave(&xbus->lock, flags);
++	len += sprintf(page + len, "XPDS_READY: %s\n", (xbus->xpds_initialized.done) ? "YES" : "NO");
++	spin_unlock_irqrestore(&xbus->lock, flags);
++out:
++	if (len <= off+count)
++		*eof = 1;
++	*start = page + off;
++	len -= off;
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++	return len;
++
++}
++
 +static int read_proc_xbuses(char *page, char **start, off_t off, int count, int *eof, void *data)
 +{
 +	int len = 0;
@@ -7840,14 +8153,19 @@
 +struct bus_type	xbus_bus_type = {
 +	.name = "xbus",
 +	.match = xbus_match,
++/* FIXME: Hotplug replaced with uevent in 2.6.16 */
 +#if 0
-+/* Hotplug replaced with uevent in 2.6.16 */
 +	.hotplug = xbus_hotplug,
 +#endif
 +};
 +
 +static void xbus_core_cleanup(void)
 +{
++	if (xpp_worker) {
++		flush_workqueue(xpp_worker);
++		destroy_workqueue(xpp_worker);
++		xpp_worker = NULL;
++	}
 +#ifdef CONFIG_PROC_FS
 +	if(proc_xbuses)
 +		remove_proc_entry(PROC_XBUSES, xpp_proc_toplevel);
@@ -7867,12 +8185,20 @@
 +	if(!packet_cache) {
 +		return -ENOMEM;
 +	}
++	xpp_worker = create_singlethread_workqueue("xppworker");
++	if(!xpp_worker) {
++		ERR("Failed to create card detector workqueue.\n");
++		xbus_core_cleanup();
++		return -ENOMEM;
++	}
 +#ifdef CONFIG_PROC_FS
 +	proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, 0);
 +	if (!proc_xbuses) {
++		ERR("Failed to create proc file %s\n", PROC_XBUSES);
 +		xbus_core_cleanup();
 +		return -EFAULT;
 +	}
++	proc_xbuses->owner = THIS_MODULE;
 +#endif
 +	ret = bus_register(&xbus_bus_type);
 +	if(ret) {
@@ -7904,10 +8230,10 @@
 +EXPORT_SYMBOL(xbus_activate);
 +EXPORT_SYMBOL(xbus_disconnect);
 +EXPORT_SYMBOL(xbus_reset_counters);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xbus-core.h zaptel-xpp-8WuH7d_dist/xpp/xbus-core.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xbus-core.h zaptel-xpp-oaIQ8i_dist/xpp/xbus-core.h
 --- zaptel-1.2.6/xpp/xbus-core.h	1970-01-01 02:00:00.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xbus-core.h	2006-03-13 14:24:00.628259000 +0200
-@@ -0,0 +1,53 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/xbus-core.h	2006-07-02 19:47:41.666262000 +0300
+@@ -0,0 +1,56 @@
 +/*
 + * Written by Oron Peled <oron at actcom.co.il>
 + * Copyright (C) 2004-2006, Xorcom
@@ -7959,11 +8285,14 @@
 +
 +void xbus_reset_counters(xbus_t *xbus);
 +
++int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd);
++int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd);
++
 +#endif	/* XBUS_CORE_H */
 +
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xdefs.h zaptel-xpp-8WuH7d_dist/xpp/xdefs.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xdefs.h zaptel-xpp-oaIQ8i_dist/xpp/xdefs.h
 --- zaptel-1.2.6/xpp/xdefs.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xdefs.h	2006-03-30 12:42:46.619481000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/xdefs.h	2006-07-03 12:11:26.109424000 +0300
 @@ -2,7 +2,7 @@
  #define	XDEFS_H
  /*
@@ -7991,15 +8320,20 @@
  #include <stdint.h>
  typedef uint32_t __u32;
  
-@@ -57,26 +52,17 @@
- typedef	struct xpd		xpd_t;
- typedef	struct xpacket_raw	xpacket_raw_t;
- typedef	struct xpacket		xpacket_t;
+@@ -50,33 +45,58 @@
+ 
+ #endif
+ 
+-typedef char			*charp;
+-typedef unsigned char		byte;
+-typedef int			bool;
+-typedef struct xbus		xbus_t;
+-typedef	struct xpd		xpd_t;
+-typedef	struct xpacket_raw	xpacket_raw_t;
+-typedef	struct xpacket		xpacket_t;
 -typedef struct xops	xops_t;
 -typedef	__u32 xpp_line_t;	/* at most 31 lines for E1 */
-+typedef struct xops		xops_t;
-+typedef	__u32			xpp_line_t;	/* at most 31 lines for E1 */
-+typedef	int			lineno_t;
++#define	PACKED	__attribute__((packed))
  
 +#define	ALL_LINES		((lineno_t)-1)
  
@@ -8010,24 +8344,63 @@
 +#define	BIT_SET(x,i)	((x) |= BIT(i))
 +#define	BIT_CLR(x,i)	((x) &= ~BIT(i))
 +#define	IS_SET(x,i)	(((x) & BIT(i)) != 0)
++#define	BITMASK(i)	(BIT(i) - 1)
++
++#define	CHANNELS_PERXPD	30	/* Depends on xpp_line_t and protocol fields */
  
 -#undef	SUPPORT_USB1
--
++#define	MAX_SPANNAME	20	/* From zaptel.h */
++#define	MAX_SPANDESC	40	/* From zaptel.h */
++#define	MAX_CHANNAME	40	/* From zaptel.h */
++
++#define	XPD_NAMELEN	10	/* must be <= from maximal workqueue name */
++#define	XPD_DESCLEN	20
++#define	XBUS_NAMELEN	20	/* must be <= from maximal workqueue name */
++#define	XBUS_DESCLEN	40
++
++#define	UNIT_BITS	4	/* Bit for Astribank unit number */
++#define	SUBUNIT_BITS	4	/* Bit for Astribank subunit number */
++
++#define	MAX_UNIT	4	/* 1 FXS + 3 FXS/FXO */
++#define	MAX_SUBUNIT	1	/* Firmware does not support subunits yet */
+ 
 -#ifdef	SUPPORT_USB1
--/*
+ /*
 - * packet size <= 64 bytes:
 - * 	ZT_CHUNKSIZE * 7 channels + header size <= 64
-- */
++ * Compile time sanity checks
+  */
 -#define	CHANNELS_PERXPD	7	/* 7 * ZT_CHUNKSIZE + header <= 64 bytes */
 -#else
- #define	CHANNELS_PERXPD	30	/* Depends on xpp_line_t and protocol fields */
--#endif
--
+-#define	CHANNELS_PERXPD	30	/* Depends on xpp_line_t and protocol fields */
++#if MAX_UNIT > BIT(UNIT_BITS)
++#error "MAX_UNIT too large"
++#endif
++
++#if MAX_SUBUNIT > BIT(SUBUNIT_BITS)
++#error "MAX_SUBUNIT too large"
+ #endif
  
++#define	MAX_XPDS		(MAX_UNIT*MAX_SUBUNIT)
++
++#define	VALID_XPD_NUM(x)	((x) < MAX_XPDS && (x) >= 0)
++
++typedef char			*charp;
++typedef unsigned char		byte;
++typedef int			bool;
++typedef struct xbus		xbus_t;
++typedef	struct xpd		xpd_t;
++typedef	struct xpacket_raw	xpacket_raw_t;
++typedef	struct xpacket		xpacket_t;
++typedef struct xops		xops_t;
++typedef	__u32			xpp_line_t;	/* at most 31 lines for E1 */
++typedef	int			lineno_t;
++
+ 
  #endif	/* XDEFS_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpd.h zaptel-xpp-8WuH7d_dist/xpp/xpd.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpd.h zaptel-xpp-oaIQ8i_dist/xpp/xpd.h
 --- zaptel-1.2.6/xpp/xpd.h	2006-03-03 22:14:09.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpd.h	2006-06-22 11:31:28.427315000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpd.h	2006-07-03 12:11:26.109424000 +0300
 @@ -3,7 +3,7 @@
  
  /*
@@ -8045,20 +8418,28 @@
  #include <asm/atomic.h>
  #include <asm/semaphore.h>
  #include <linux/moduleparam.h>
-@@ -61,9 +62,9 @@
+@@ -61,20 +62,6 @@
  #endif	// __KERNEL__
  
  
 -#define	MAX_SPANNAME	20
 -#define	MAX_SPANDESC	40
 -#define	MAX_CHANNAME	20
-+#define	MAX_SPANNAME	20	/* From zaptel.h */
-+#define	MAX_SPANDESC	40	/* From zaptel.h */
-+#define	MAX_CHANNAME	40	/* From zaptel.h */
+-
+-#define	XPD_NAMELEN	10	/* must be <= from maximal workqueue name */
+-#define	XPD_DESCLEN	20
+-#define	XBUS_NAMELEN	20	/* must be <= from maximal workqueue name */
+-#define	XBUS_DESCLEN	40
+-
+-/* Hardware does not check bank_num yet. So only 4 cards can be used */
+-#define	MAX_XPDS	4	// 1 FXS + 2 E1/T1 + 1 (Quad * E1/T1)
+-
+-#define	VALID_XPD_NUM(x)	((x) < MAX_XPDS && (x) >= 0)
+-
+ typedef	struct xbus_ops		xbus_ops_t;
  
- #define	XPD_NAMELEN	10	/* must be <= from maximal workqueue name */
- #define	XPD_DESCLEN	20
-@@ -100,6 +101,9 @@
+ typedef enum xbus_type {
+@@ -100,15 +87,17 @@
  	void (*packet_free)(xbus_t *xbus, xpacket_t *p);
  };
  
@@ -8067,9 +8448,35 @@
 + */
  enum {
  	XBUS_N_DESC_REQ,
- 	XBUS_N_DEV_DESC,
-@@ -133,30 +137,22 @@
+-	XBUS_N_DEV_DESC,
++	XBUS_N_DEV_DESC_FULL,
++	XBUS_N_DEV_DESC_EMPTY,
+ 	XBUS_N_PCM_WRITE,
+ 	XBUS_N_PCM_READ,
+ 	XBUS_N_TX_BYTES,
+ 	XBUS_N_RX_BYTES,
+-	XBUS_N_SOFTSIM_PACKETS,
+-	XBUS_N_SIM_PACKETS,
+ };
  
+ #define	XBUS_COUNTER(xbus, counter)	((xbus)->counters[XBUS_N_ ## counter])
+@@ -120,68 +109,76 @@
+ 	char	*name;
+ } xbus_counters[] = {
+ 	C_(DESC_REQ),
+-	C_(DEV_DESC),
++	C_(DEV_DESC_FULL),
++	C_(DEV_DESC_EMPTY),
+ 	C_(PCM_WRITE),
+ 	C_(PCM_READ),
+ 	C_(TX_BYTES),
+ 	C_(RX_BYTES),
+-	C_(SOFTSIM_PACKETS),
+-	C_(SIM_PACKETS),
+ };
+ 
+ #undef C_
+ 
  #define	XBUS_COUNTER_MAX	ARRAY_SIZE(xbus_counters)
  
 -struct xpd_sim {
@@ -8078,46 +8485,87 @@
 -	int		loopto;
 -	xpd_type_t	xpd_type;
 -	xpp_line_t	hookstate;
--};
--
--
++#define	CARD_DESC_MAGIC	0xca9dde5c
++
++struct	card_desc_struct {
++	struct list_head	card_list;
++	u32			magic;
++	xbus_t			*xbus;
++	byte			rev;		/* Revision number */
++	byte			type;		/* LSB: 1 - to_phone, 0 - to_line */
++	xpd_addr_t		xpd_addr;
+ };
+ 
+ 
 +/*
 + * An xbus is a transport layer for Xorcom Protocol commands
 + */
  struct xbus {
- 	char		busname[XBUS_NAMELEN];	/* only xbus_new set this */
- 	char		busdesc[XBUS_DESCLEN];	/* lowlevel drivers set this */
- 	int		num;
- 	xbus_ops_t	*ops;
- 	struct xpd	*xpds[MAX_XPDS];
-+	int		max_packet_size;
-+
-+	/* Device-Model */
-+	struct device	the_bus;
+-	char		busname[XBUS_NAMELEN];	/* only xbus_new set this */
+-	char		busdesc[XBUS_DESCLEN];	/* lowlevel drivers set this */
+-	int		num;
+-	xbus_ops_t	*ops;
+-	struct xpd	*xpds[MAX_XPDS];
++	char			busname[XBUS_NAMELEN];	/* only xbus_new set this */
++	char			busdesc[XBUS_DESCLEN];	/* lowlevel drivers set this */
++	int			num;
++	xbus_ops_t		*ops;
++	struct xpd		*xpds[MAX_XPDS];
++	int			max_packet_size;
  
- 	/* Simulator data */
- 	xbus_type_t	bus_type;
+-	/* Simulator data */
+-	xbus_type_t	bus_type;
 -#if SOFT_SIMULATOR
 -	struct xpd_sim	sim[MAX_XPDS];
 -	struct workqueue_struct *sim_workqueue;
 -	struct work_struct sim_work;		// workqueue job for running simulator
 -	packet_queue_t	sim_packet_queue;
 -#endif
++	/* Device-Model */
++	struct device		the_bus;
  
- 	spinlock_t	lock;
+-	spinlock_t	lock;
++	/* Simulator data */
++	xbus_type_t		bus_type;
  
-@@ -170,10 +166,6 @@
- 	int	num_xpds;
- 	void	*priv;				/* Pointer to transport level data structures */
+-	bool		hardware_exists;	/* Hardware is functional */
+-	int		open_counter;		/* Number of open channels */
+-	atomic_t	packet_counter;		/* Allocated packets */
+-	wait_queue_head_t packet_cache_empty;
+-
+-	struct timer_list poll_timer;
+-	struct	rw_semaphore in_use;
+-	int	num_xpds;
+-	void	*priv;				/* Pointer to transport level data structures */
++	spinlock_t		lock;
  
 -#ifdef	XPP_PACKET_LOG
 -	struct cyclic_buff *packet_log;
 -#endif
--
++	bool			hardware_exists;	/* Hardware is functional */
++	int			open_counter;		/* Number of open channels */
++	atomic_t		packet_counter;		/* Allocated packets */
++	wait_queue_head_t	packet_cache_empty;
++
++	struct timer_list	poll_timer;
++	/*
++	 * Bus scanning
++	 */
++	atomic_t		count_poll_answers;
++	struct list_head	poll_results;
++	wait_queue_head_t	wait_for_polls;
++	struct work_struct	xpds_init_work;
++	struct completion	xpds_initialized;
++
++	struct	rw_semaphore	in_use;
++	int			num_xpds;
++	void			*priv;			/* Pointer to transport level data structures */
+ 
  #ifdef CONFIG_PROC_FS
  	struct proc_dir_entry	*proc_xbus_dir;
  	struct proc_dir_entry	*proc_xbus_summary;
-@@ -181,7 +173,6 @@
++	struct proc_dir_entry	*proc_xbus_waitfor_xpds;
+ #endif
  
  	/* statistics */
  	int		counters[XBUS_COUNTER_MAX];
@@ -8125,7 +8573,7 @@
  };
  #endif
  
-@@ -190,15 +181,11 @@
+@@ -190,15 +187,11 @@
  	TO_PSTN = 1,
  } xpd_direction_t;
  
@@ -8144,7 +8592,7 @@
  enum {
  	XPD_N_PCM_READ,
  	XPD_N_PCM_WRITE,
-@@ -222,55 +209,69 @@
+@@ -222,60 +215,74 @@
  
  #define	XPD_COUNTER_MAX	(sizeof(xpd_counters)/sizeof(xpd_counters[0]))
  
@@ -8181,7 +8629,7 @@
  	xpd_type_t	type;
 +	byte		revision;		/* Card revision */
  	xpd_direction_t	direction;		/* TO_PHONE, TO_PSTN */
- 	xpp_line_t	enabled_chans;		/* hardware activation: 0 - off, 1 - on */
+-	xpp_line_t	enabled_chans;		/* hardware activation: 0 - off, 1 - on */
 -	xpp_line_t	hookstate;		/* 0 - ONHOOK, 1 - OFHOOK */
 -	xpp_line_t	ledstate[NUM_LEDS];	/* 0 - OFF, 1 - ON */
 +	xpp_line_t	no_pcm;			/* Temporary: disable PCM (for USB-1) */
@@ -8199,13 +8647,13 @@
 +
 +	wait_queue_head_t	txstateq[CHANNELS_PERXPD];	/* waiting on the tx state to change */
 +	int		delay_until_dialtone[CHANNELS_PERXPD];
-+
+ 
+-	struct work_struct xpd_post_init;
+-	xbus_t *xbus;
 +	enum fxs_state	lasttxhook[CHANNELS_PERXPD];
 +	int		idletxhookstate[CHANNELS_PERXPD];	/* IDLE changing hook state */
 +	int		ohttimer[CHANNELS_PERXPD];
- 
--	struct work_struct xpd_post_init;
--	xbus_t *xbus;
++
 +	xbus_t *xbus;			/* The XBUS we are connected to */
  
  	spinlock_t	lock;
@@ -8236,23 +8684,25 @@
  
  	unsigned int	recv_errors;
  	unsigned int	seq_errors;
-@@ -285,6 +286,13 @@
+ 	unsigned long	last_response;	/* in jiffies */
+ 	unsigned	id;
++	xpd_addr_t	addr;
+ 	struct list_head xpd_list;
+ 	unsigned int	timer_count;
+ 	volatile u_char *writechunk;	/* Double-word aligned write memory */
+@@ -285,6 +292,9 @@
  	u_char ec_chunk2[CHANNELS_PERXPD][ZT_CHUNKSIZE];
  };
  
 +#define	for_each_line(xpd,i)	\
 +		for((i) = 0; (i) < (xpd)->channels; (i)++)
 +
-+#define	for_each_enabled_line(xpd,i)	\
-+		for((i) = 0; (i) < (xpd)->channels; (i)++)	\
-+			if(IS_SET((xpd)->enabled_chans,(i)))
-+
  #endif
  
  #endif	/* XPD_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_fxloader zaptel-xpp-8WuH7d_dist/xpp/xpp_fxloader
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_fxloader zaptel-xpp-oaIQ8i_dist/xpp/xpp_fxloader
 --- zaptel-1.2.6/xpp/xpp_fxloader	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_fxloader	1970-01-01 02:00:00.000000000 +0200
 @@ -1,24 +0,0 @@
 -#!/bin/sh
 -
@@ -8278,15 +8728,15 @@
 -	fxload -t fx2 -D "$DEVICE" -I "$FIRMWARE" || exit 1
 -fi
 -
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_fxloader.usermap zaptel-xpp-8WuH7d_dist/xpp/xpp_fxloader.usermap
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_fxloader.usermap zaptel-xpp-oaIQ8i_dist/xpp/xpp_fxloader.usermap
 --- zaptel-1.2.6/xpp/xpp_fxloader.usermap	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_fxloader.usermap	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_fxloader.usermap	1970-01-01 02:00:00.000000000 +0200
 @@ -1,2 +0,0 @@
 -# module	match_flags	idVendor	idProduct	bcdDevice_lo	bcdDevice_hi	bDeviceClass	bDeviceSubClass	bDeviceProtocol	bInterfaceClass	bInterfaceSubClass	bInterfaceProtocol	driver_info
 -xpp_fxloader	0x0003		0x04b4		0x8613		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_modprobe zaptel-xpp-8WuH7d_dist/xpp/xpp_modprobe
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_modprobe zaptel-xpp-oaIQ8i_dist/xpp/xpp_modprobe
 --- zaptel-1.2.6/xpp/xpp_modprobe	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_modprobe	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_modprobe	1970-01-01 02:00:00.000000000 +0200
 @@ -1,10 +0,0 @@
 -# Some debugging options for the brave of heart:
 -#options zaptel debug=1
@@ -8298,9 +8748,9 @@
 -
 -# For auto loading of card modules
 -alias	xpd-type-3	xpd_fxs
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_proto.c zaptel-xpp-8WuH7d_dist/xpp/xpp_proto.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_proto.c zaptel-xpp-oaIQ8i_dist/xpp/xpp_proto.c
 --- zaptel-1.2.6/xpp/xpp_proto.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_proto.c	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_proto.c	1970-01-01 02:00:00.000000000 +0200
 @@ -1,1044 +0,0 @@
 -#include <linux/module.h>
 -#include <linux/delay.h>	/* for udelay */
@@ -9346,9 +9796,9 @@
 -EXPORT_SYMBOL(packet_receive);
 -EXPORT_SYMBOL(proc_xpd_slic_read);
 -EXPORT_SYMBOL(proc_xpd_slic_write);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_proto.h zaptel-xpp-8WuH7d_dist/xpp/xpp_proto.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_proto.h zaptel-xpp-oaIQ8i_dist/xpp/xpp_proto.h
 --- zaptel-1.2.6/xpp/xpp_proto.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_proto.h	1970-01-01 02:00:00.000000000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_proto.h	1970-01-01 02:00:00.000000000 +0200
 @@ -1,188 +0,0 @@
 -#ifndef	XPP_PROTO_H
 -#define	XPP_PROTO_H
@@ -9538,9 +9988,9 @@
 -#endif
 -
 -#endif	/* XPP_PROTO_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_usb.c zaptel-xpp-8WuH7d_dist/xpp/xpp_usb.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_usb.c zaptel-xpp-oaIQ8i_dist/xpp/xpp_usb.c
 --- zaptel-1.2.6/xpp/xpp_usb.c	2006-04-03 10:08:13.000000000 +0300
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_usb.c	2006-05-01 18:45:04.050100000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_usb.c	2006-07-04 17:49:04.495340000 +0300
 @@ -1,6 +1,6 @@
  /*
   * Written by Oron Peled <oron at actcom.co.il>
@@ -9572,7 +10022,7 @@
 +#endif
  
 -static const char revision[] = "$Revision: 995 $";
-+static const char rcsid[] = "$Id: xpp_usb.c 1104 2006-05-01 15:45:04Z oron $";
++static const char rcsid[] = "$Id: xpp_usb.c 1576 2006-07-04 14:49:04Z oron $";
  
  DEF_PARM(int, print_dbg, 0, "Print DBG statements");	/* must be before zap_debug.h */
  
@@ -9602,10 +10052,12 @@
  };
  
  static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack);
-@@ -110,18 +115,22 @@
+@@ -110,18 +115,24 @@
  
  #define	XUSB_COUNTER_MAX	ARRAY_SIZE(xusb_counters)
  
++#define	MAX_PENDING_WRITES	100
++
 +enum xusb_dir {
 +	XUSB_RECV = 0,
 +	XUSB_SEND = 1,
@@ -9628,8 +10080,11 @@
  
  	struct urb		*read_urb;
  
-@@ -131,10 +140,10 @@
+@@ -129,12 +140,13 @@
+ 
+ 	int			present;		/* if the device is not disconnected */
  	int			reading;		/* is the read_urb reading (listening) */
++	atomic_t		pending_writes;		/* submited but not out yet */
  	struct semaphore	sem;			/* locks this structure */
  	int		counters[XUSB_COUNTER_MAX];
 -};
@@ -9641,7 +10096,7 @@
  static unsigned bus_count = 0;
  
  
-@@ -153,7 +162,7 @@
+@@ -153,7 +165,7 @@
  static void xusb_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
  #endif
  static void xpp_urb_delete(struct urb *urb);
@@ -9650,7 +10105,7 @@
  static void xpp_send_callback(struct urb *urb, struct pt_regs *regs);
  static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs);
  
-@@ -208,42 +217,34 @@
+@@ -208,42 +220,34 @@
  	//DBG("Decremented packet_counter of bus %s (freed packet) to %d\n", 
  	//		xbus->busname, atomic_read(&xbus->packet_counter));
  }
@@ -9693,11 +10148,11 @@
 -	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
 -		XUSB_COUNTER(xusb, PCM_WRITES)++;
 +#else
- 
++
 +static void packet_debug(const char msg[], xusb_t *xusb, xpacket_t *pack)
 +{
 +	char	title[XBUS_DESCLEN];
-+
+ 
 +	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
 +#ifdef	DEBUG_PCM_TIMING
 +		/*
@@ -9716,7 +10171,7 @@
  #ifdef	DEBUG_PCM_TIMING
  		/*
  		 * DEBUG: high-res timing of PCM_READ to PCM_WRITE
-@@ -253,50 +254,88 @@
+@@ -253,50 +257,96 @@
  #endif
  #if 0
  		static	int rate_limit;
@@ -9790,6 +10245,14 @@
  	}
 -	return 0;
 -error:
++	atomic_inc(&xusb->pending_writes);
++	if(atomic_read(&xusb->pending_writes) > MAX_PENDING_WRITES) {
++		static	int rate_limit;
++
++		if((rate_limit++ % 1000) < 10)
++			ERR("%s: %s: more than %d pending writes. Dropping.\n", __FUNCTION__, xbus->busname, MAX_PENDING_WRITES);
++		ret = -ENODEV;
++	}
 +	if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE))
 +		XUSB_COUNTER(xusb, PCM_WRITES)++;
 +out:
@@ -9822,7 +10285,7 @@
  	struct urb	*urb;
  	unsigned char	*buffer;	/* the buffer to send data */
  	unsigned int	epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-@@ -304,6 +343,8 @@
+@@ -304,6 +354,8 @@
  					? usb_rcvbulkpipe(udev, epnum)
  					: usb_sndbulkpipe(udev, epnum);
  		 
@@ -9831,7 +10294,7 @@
  	urb = usb_alloc_urb(0, GFP_ATOMIC);
  	if (!urb) {
  		err("No free urbs available");
-@@ -326,30 +367,40 @@
+@@ -326,32 +378,36 @@
  		usb_free_urb(urb);
  		return NULL;
  	}
@@ -9873,16 +10336,14 @@
 -//	{ USB_DEVICE(0x04B4, 0x1004), .driver_info=(int)&model_table[1] }, // FPGA_bulkloop.hex
 -//	{ USB_DEVICE(0x04B4, 0x1004), .driver_info=(int)&model_table[2] }, // FIXME: temporary test for Dima
 -	{ USB_DEVICE(0xE4E4, 0x2211), .driver_info=(int)&model_table[2] }, // FPGA_XPD.hex
-+	{ USB_DEVICE(0x0547, 0x1002), .driver_info=(kernel_ulong_t)&model_table[0] }, // bulkloop.hex
-+//	{ USB_DEVICE(0x04B4, 0x1004), .driver_info=(kernel_ulong_t)&model_table[1] }, // FPGA_bulkloop.hex
-+//	{ USB_DEVICE(0x04B4, 0x1004), .driver_info=(kernel_ulong_t)&model_table[2] }, // FIXME: temporary test for Dima
+-	//{ USB_DEVICE(0x0548, 0x1) },
+-	//{ USB_DEVICE(0x062a, 0x0) },
 +	{ USB_DEVICE(0xE4E4, 0x2211), .driver_info=(kernel_ulong_t)&model_table[2] }, // FPGA_XPD.hex
 +	{ USB_DEVICE(0xE4E4, 0x1132), .driver_info=(kernel_ulong_t)&model_table[2] }, // FPGA_XPD.hex
-+//	{ USB_DEVICE(0x04B4, 0x1004), .driver_info=(kernel_ulong_t)&model_table[2] }, // TEST ONLY
- 	//{ USB_DEVICE(0x0548, 0x1) },
- 	//{ USB_DEVICE(0x062a, 0x0) },
  	/* "Gadget Zero" firmware runs under Linux */
-@@ -363,7 +414,7 @@
+ 	//{ USB_DEVICE(0x0525, 0xa4a0) },
+ 	{ }					/* Terminating entry */
+@@ -363,7 +419,7 @@
  /* usb specific object needed to register this driver with the usb subsystem */
  static struct usb_driver xusb_driver = {
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
@@ -9891,7 +10352,7 @@
  #endif
  	.name =		"xpp_usb",
  	.probe =	xusb_probe,
-@@ -412,10 +463,12 @@
+@@ -412,10 +468,12 @@
   * check out the endpoints
   * FIXME: Should be simplified (above 2.6.10) to use usb_dev->ep_in[0..16] and usb_dev->ep_out[0..16]
   */
@@ -9905,7 +10366,7 @@
  	int i;
  
  	iface_desc = &interface->altsetting[0];
-@@ -425,37 +478,40 @@
+@@ -425,37 +483,40 @@
  
  	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
  		endpoint = &iface_desc->endpoint[i].desc;
@@ -9961,7 +10422,7 @@
  	return 1;
  }
  
-@@ -468,10 +524,11 @@
+@@ -468,10 +529,11 @@
  static int xusb_probe(struct usb_interface *interface, const struct usb_device_id *id)
  {
  	struct usb_device	*udev = interface_to_usbdev(interface);
@@ -9976,7 +10437,7 @@
  	unsigned long		flags;
  	int			retval = -ENOMEM;
  	int			i;
-@@ -490,13 +547,13 @@
+@@ -490,15 +552,16 @@
  	}
  
  	/* allocate memory for our device state and initialize it */
@@ -9991,8 +10452,11 @@
 +	memset(xusb, 0, sizeof(xusb_t));
  
  	init_MUTEX (&xusb->sem);
++	atomic_set(&xusb->pending_writes, 0);
  	xusb->udev = udev;
-@@ -507,12 +564,14 @@
+ 	xusb->interface = interface;
+ 	xusb->model_info = model_info;
+@@ -507,12 +570,14 @@
  		retval = -ENODEV;
  		goto probe_failed;
  	}
@@ -10008,7 +10472,7 @@
  	/* allow device read, write and ioctl */
  	xusb->present = 1;
  
-@@ -521,7 +580,7 @@
+@@ -521,7 +586,7 @@
  	retval = usb_register_dev (interface, &xusb_class);
  	if (retval) {
  		/* something prevented us from registering this driver */
@@ -10017,7 +10481,7 @@
  		goto probe_failed;
  	}
  
-@@ -531,33 +590,31 @@
+@@ -531,33 +596,31 @@
  	INFO ("USB XPP device now attached to minor %d\n", xusb->minor);
  
  	/* Allocate high level structures */
@@ -10054,7 +10518,7 @@
  
  	DBG("GOT XPP USB BUS #%d: %s (type=%d)\n", i, xbus->busdesc, xbus->bus_type);
  
-@@ -568,7 +625,6 @@
+@@ -568,20 +631,22 @@
  	DBG("Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
  	procsummary = create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444, xbus->proc_xbus_dir,
  			xusb_read_proc, xusb);
@@ -10062,9 +10526,10 @@
  	if (!procsummary) {
  		ERR("Failed to create proc read entry for xbus %s\n", xbus->busname);
  		// FIXME: better error handling
-@@ -576,12 +632,14 @@
+ 		retval = -EIO;
  		goto probe_failed;
  	}
++	procsummary->owner = THIS_MODULE;
  #endif
 +	bus_count++;
  	retval = usb_submit_urb(xusb->read_urb, GFP_ATOMIC);
@@ -10079,7 +10544,7 @@
  	return retval;
  probe_failed:
  	ERR("Failed to initialize xpp usb bus: %d\n", retval);
-@@ -593,6 +651,13 @@
+@@ -593,6 +658,13 @@
  			usb_deregister_dev(interface, &xusb_class);
  		kfree(xusb);
  	}
@@ -10093,7 +10558,7 @@
  	return retval;
  }
  
-@@ -609,7 +674,7 @@
+@@ -609,7 +681,7 @@
   */
  static void xusb_disconnect(struct usb_interface *interface)
  {
@@ -10102,7 +10567,7 @@
  	xbus_t			*xbus;
  	int			minor;
  	int			i;
-@@ -636,7 +701,7 @@
+@@ -636,7 +708,7 @@
  	}
  #endif
  	xusb->present = 0;
@@ -10111,7 +10576,7 @@
  
  	down (&xusb->sem);
  
-@@ -645,6 +710,7 @@
+@@ -645,6 +717,7 @@
  	/* give back our minor */
  	usb_deregister_dev (interface, &xusb_class);
  
@@ -10119,7 +10584,7 @@
  	/* terminate an ongoing write */
  	// FIXME: Does it really kill pending URB's?
  
-@@ -657,12 +723,12 @@
+@@ -657,59 +730,71 @@
  	kfree(xusb);
  
  	up (&disconnect_sem);
@@ -10134,7 +10599,8 @@
  	xbus_t			*xbus = xusb->xbus;
  
  	BUG_ON(!xbus);
-@@ -670,7 +736,7 @@
++	atomic_dec(&xusb->pending_writes);
+ 	/* sync/async unlink faults aren't errors */
  	if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) {
  		static	int rate_limit;
  		if((rate_limit++ % 1000) < 10)
@@ -10142,8 +10608,15 @@
 +			DBG("nonzero read bulk status received: %d\n", urb->status);
  		XUSB_COUNTER(xusb, TX_ERRORS)++;
  	}
++	xpp_urb_delete(urb);
  	if(!xusb->present) {
-@@ -684,32 +750,43 @@
+ 		ERR("A packet from non-connected device?\n");
+ 		return;
+ 	}
+-	xpp_urb_delete(urb);
+ 	/* allow device read, write and ioctl */
+ 	XUSB_COUNTER(xusb, TX_PACKETS)++;
+ }
  
  static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
  {
@@ -10204,7 +10677,7 @@
  	}
  	pack = xbus->ops->packet_new(xbus, GFP_ATOMIC);
  	if(!pack) {
-@@ -723,42 +800,21 @@
+@@ -723,42 +808,21 @@
  	pack->datalen = size - sizeof(xpd_addr_t) - 1; 	// opcode size
  	// DBG("datalen of new packet: %d\n", pack->datalen);
  
@@ -10259,7 +10732,7 @@
  	}
  }
  
-@@ -768,14 +824,14 @@
+@@ -768,14 +832,14 @@
  int __init xpp_usb_init(void)
  {
  	int result;
@@ -10277,7 +10750,7 @@
  		return result;
  	}
  	return 0;
-@@ -784,34 +840,7 @@
+@@ -784,34 +848,7 @@
  
  void __exit xpp_usb_cleanup(void)
  {
@@ -10312,7 +10785,7 @@
  	/* deregister this driver with the USB subsystem */
  	usb_deregister(&xusb_driver);
  }
-@@ -822,30 +851,29 @@
+@@ -822,31 +859,31 @@
  
  static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
  {
@@ -10352,9 +10825,11 @@
 +		xusb->endpoints[XUSB_SEND].ep_addr,
 +		xusb->endpoints[XUSB_SEND].max_size
  	);
++	len += sprintf(page + len, "\npending_writes=%d\n", atomic_read(&xusb->pending_writes));
  #ifdef	DEBUG_PCM_TIMING
  	len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff);
-@@ -878,7 +906,7 @@
+ #endif
+@@ -878,7 +915,7 @@
  MODULE_DESCRIPTION("XPP USB Driver");
  MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
  MODULE_LICENSE("GPL");
@@ -10363,10 +10838,10 @@
  
  module_init(xpp_usb_init);
  module_exit(xpp_usb_cleanup);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_zap.c zaptel-xpp-8WuH7d_dist/xpp/xpp_zap.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_zap.c zaptel-xpp-oaIQ8i_dist/xpp/xpp_zap.c
 --- zaptel-1.2.6/xpp/xpp_zap.c	2006-04-03 10:08:13.000000000 +0300
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_zap.c	2006-06-27 19:12:43.273949228 +0300
-@@ -33,40 +33,34 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_zap.c	2006-07-08 03:48:48.529239179 +0300
+@@ -33,245 +33,64 @@
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/module.h>
@@ -10382,7 +10857,7 @@
  #include "xpp_zap.h"
  
 -static char revision[] = "$Revision: 995 $";
-+static const char rcsid[] = "$Id: xpp_zap.c 1435 2006-06-22 10:07:06Z oron $";
++static const char rcsid[] = "$Id: xpp_zap.c 1588 2006-07-06 11:10:00Z tzafrir $";
  
  #ifdef CONFIG_PROC_FS
 -struct proc_dir_entry *xpp_procdir = NULL;
@@ -10413,33 +10888,35 @@
 +static xpd_t			*sync_master = NULL;	// Start with host based sync
  static unsigned int		xpp_timer_count = 0;
  static unsigned int		xpp_last_jiffies = 0;
- struct workqueue_struct		*xpp_worker = NULL;
-@@ -75,203 +69,35 @@
+-struct workqueue_struct		*xpp_worker = NULL;
+-
+-static	LIST_HEAD(xpd_list);
  
  DEF_PARM(int, print_dbg, 0, "Print DBG statements");
  DEF_PARM(int, max_queue_len, MAX_QUEUE_LEN, "Maximum Queue Length.");
 -DEF_PARM(int, xbus_err_disable_bus, 1000, "Number of errors needed to disable bus");
- DEF_PARM(int, ignore_xpds, 0, "a bitmask of xpd numbers to ignore");
+-DEF_PARM(int, ignore_xpds, 0, "a bitmask of xpd numbers to ignore");
 -#ifdef SOFT_SIMULATOR
 -DEF_PARM(ulong, softloop_xpds, 0, "a bitmask of software xpd numbers");
 -#endif
-+DEF_PARM(int, xbus_err_disable_bus, 1000, "Number of errors needed to disable bus");	// FIXME: unused now.
- DEF_PARM(ulong, pcm_gen, 0, "a bitmask of line numbers for hardware tone generator");
+-DEF_PARM(ulong, pcm_gen, 0, "a bitmask of line numbers for hardware tone generator");
+-
+-DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd");
 +DEF_PARM(bool, have_sync_bus, 0, "True if all Astribank(TM) devices are connected via a sync-cable");
 +DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)");
  
- DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd");
- 
  #include "zap_debug.h"
--
 +#ifdef	XPP_EC_CHUNK
 +#include "supress/ec_xpp.h"
 +#endif
  
- static int xpd_zaptel_register(xpd_t *xpd);
- static int xpd_zaptel_unregister(xpd_t *xpd);
+ 
+-static int xpd_zaptel_register(xpd_t *xpd);
+-static int xpd_zaptel_unregister(xpd_t *xpd);
 -static void xbus_remove(xbus_t *xbus);
 -static void xpd_blink_leds(xpd_t *xpd);
++static int zaptel_register_xpd(xpd_t *xpd);
++static int zaptel_unregister_xpd(xpd_t *xpd);
  static void xpp_ring_generate(xpd_t *xpd);
  static void xpp_transmitprep(xpd_t *xpd);
  static void xpp_receiveprep(xpd_t *xpd);
@@ -10627,7 +11104,7 @@
  	for(i = 0; i < MAX_BUSES; i++) {
  		xbus_t	*xbus = xbus_of(i);
  		if(!xbus)
-@@ -279,21 +105,26 @@
+@@ -279,21 +98,26 @@
  		if (!xbus->hardware_exists)
  			continue;
  		for(j = 0; j < MAX_XPDS; j++) {
@@ -10662,7 +11139,7 @@
  		external_sync(NULL);
  		if(!timer_pending(&xpp_timer)) {
  			xpp_timer.function = xpp_tick;
-@@ -301,10 +132,6 @@
+@@ -301,10 +125,6 @@
  			xpp_timer.expires = jiffies + 1;	/* Must be 1KHz rate */
  			add_timer(&xpp_timer);
  		}
@@ -10673,7 +11150,7 @@
  	}
  }
  
-@@ -337,42 +164,45 @@
+@@ -337,43 +157,49 @@
  			continue;
  		if (!xbus->hardware_exists)
  			continue;
@@ -10722,17 +11199,23 @@
  		return;
  	xbus = xpd->xbus;
 -	xpd_card_disable(xpd);
++	if(!xbus)
++		return;
  	DBG("%s/%s\n", xbus->busname, xpd->xpdname);
++	xbus_unregister_xpd(xbus, xpd);
  #ifdef CONFIG_PROC_FS
  	if(xpd->proc_xpd_dir) {
-@@ -391,109 +221,145 @@
+ 		if(xpd->proc_xpd_summary) {
+@@ -391,109 +217,149 @@
  		xpd->proc_xpd_dir = NULL;
  	}
  #endif
 +	if(xpd->writechunk)
 +		kfree((void *)xpd->writechunk);
++	xpd->writechunk = NULL;
 +	if(xpd->xproto)
 +		xproto_put(xpd->xproto);
++	xpd->xproto = NULL;
 +	kfree(xpd);
  }
  
@@ -10797,14 +11280,13 @@
 -void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack)
 +/*
 + * Synchronous part of XPD detection.
-+ * Called from xpp_worker workqueue.
++ * Called from xbus_poll()
 + */
-+void card_detected(void *data)
++void card_detected(struct card_desc_struct *card_desc)
  {
 -	unsigned long	flags;
 -
 -	spin_lock_irqsave(&q->lock, flags);
-+	struct card_desc_struct	*card_desc = (struct card_desc_struct *)data;
 +	xbus_t			*xbus;
 +	xpd_t			*xpd = NULL;
 +	int			xpd_num;
@@ -10823,22 +11305,24 @@
 +	BUG_ON(!card_desc);
 +	BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
 +	xbus = card_desc->xbus;
-+	xpd_num = card_desc->xpd_num;
++	xpd_num = xpd_addr2num(&card_desc->xpd_addr);
 +	type = card_desc->type;
 +	rev = card_desc->rev;
 +	BUG_ON(!xbus);
 +	if(!good_rev(rev)) {
-+		NOTICE("%s: New XPD #%d type=%d has bad firmware revision %d.%d\n", xbus->busname,
-+			xpd_num, type, rev / 10, rev % 10);
++		NOTICE("%s: New XPD #%d (%d-%d) type=%d has bad firmware revision %d.%d\n", xbus->busname,
++			xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
++			type, rev / 10, rev % 10);
 +		goto err;
 +	}
-+	INFO("%s: New XPD #%d type=%d Revision %d.%d\n", xbus->busname,
-+			xpd_num, type, rev / 10, rev % 10);
++	INFO("%s: New XPD #%d (%d-%d) type=%d Revision %d.%d\n", xbus->busname,
++			xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
++			type, rev / 10, rev % 10);
 +	xpd = xpd_of(xbus, xpd_num);
 +	if(xpd) {
 +		if(type == XPD_TYPE_NOMODULE) {
 +			NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
-+			xpd_disconnect(xpd);
++			BUG();
 +			goto out;
  		}
 -		q->overflows++;
@@ -10891,13 +11375,14 @@
 +		NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
 +		goto err;
 +	}
++	xpd->addr = card_desc->xpd_addr;
 +
 +	/* For USB-1 disable some channels */
 +	if(xbus->max_packet_size < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
 +		xpp_line_t	no_pcm;
 +
 +		no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
-+		xpd->no_pcm = no_pcm & xpd->enabled_chans;
++		xpd->no_pcm = no_pcm;
 +		NOTICE("%s: max packet size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
 +				xbus->busname, xbus->max_packet_size, xpd->no_pcm);
 +	}
@@ -10914,28 +11399,28 @@
 +		ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
 +		goto err;
 +	}
++	xpd->proc_xpd_summary->owner = THIS_MODULE;
 +	xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
 +	if (!xpd->proc_xpd_ztregister) {
 +		ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
 +		goto err;
 +	}
++	xpd->proc_xpd_ztregister->owner = THIS_MODULE;
 +	xpd->proc_xpd_ztregister->data = xpd;
 +	xpd->proc_xpd_ztregister->read_proc = proc_xpd_ztregister_read;
 +	xpd->proc_xpd_ztregister->write_proc = proc_xpd_ztregister_write;
 +#endif
++	xbus_register_xpd(xbus, xpd);
 +	if(CALL_XMETHOD(card_init, xbus, xpd) < 0)
 +		goto err;
-+	list_add(&xpd->xpd_list, &xpd_list);
-+	xbus->xpds[xpd->id] = xpd;
-+	xbus->num_xpds++;
 +	// Turn off all channels
 +	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ~0, 0);
 +	xpd->card_present = 1;
-+	// Turn on enabled channels
-+	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
++	// Turn on all channels
++	CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ALL_LINES, 1);
 +
 +	if(zap_autoreg)
-+		xpd_zaptel_register(xpd);
++		zaptel_register_xpd(xpd);
  out:
 -	spin_unlock_irqrestore(&q->lock, flags);
 -	return pack;
@@ -10953,7 +11438,7 @@
  #ifdef CONFIG_PROC_FS
  
  /**
-@@ -510,83 +376,82 @@
+@@ -510,83 +376,78 @@
  	int		len = 0;
  	xpd_t		*xpd = data;
  	xbus_t		*xbus;
@@ -10985,11 +11470,10 @@
  			xpd->timer_count, xpd->span.mainttimer
  			);
  	len += sprintf(page + len, "STATES:");
- 	len += sprintf(page + len, "\n\t%-17s: ", "enabled");
+-	len += sprintf(page + len, "\n\t%-17s: ", "enabled");
 -	for(i = 0; i < channels; i++) {
-+	for_each_line(xpd, i) {
- 		len += sprintf(page + len, "%d ", IS_SET(xpd->enabled_chans, i));
- 	}
+-		len += sprintf(page + len, "%d ", IS_SET(xpd->enabled_chans, i));
+-	}
  	len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
 -	for(i = 0; i < channels; i++) {
 +	for_each_line(xpd, i) {
@@ -11073,7 +11557,7 @@
  			struct zt_chan *chan = &xpd->span.chans[i];
  			len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig);
  		}
-@@ -620,7 +485,9 @@
+@@ -620,10 +481,11 @@
  xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision)
  {
  	xpd_t		*xpd = NULL;
@@ -11081,9 +11565,13 @@
  	size_t		alloc_size = sizeof(xpd_t) + privsize;
 +	int		i;
  
- 	INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
- 			xpd_num, revision / 10, revision % 10, xbus->busname);
-@@ -645,14 +512,20 @@
+-	INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
+-			xpd_num, revision / 10, revision % 10, xbus->busname);
++	DBG("%s: xpd #%d\n", xbus->busname, xpd_num);
+ 	if(!VALID_XPD_NUM(xpd_num)) {
+ 		ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num);
+ 		goto err;
+@@ -645,14 +507,19 @@
  	xpd->id = xpd_num;
  	xpd->channels = channels;
  	xpd->chans = NULL;
@@ -11094,7 +11582,7 @@
  	xpd->type = proto_table->type;
 +	xpd->xproto = proto_table;
  	xpd->xops = &proto_table->xops;
- 	xpd->enabled_chans = enabled_channels[xpd_num];
+-	xpd->enabled_chans = enabled_channels[xpd_num];
  	xpd->digital_outputs = 0;
  	xpd->digital_inputs = 0;
 +
@@ -11105,7 +11593,7 @@
  	atomic_set(&xpd->open_counter, 0);
  
  	xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL);
-@@ -660,33 +533,47 @@
+@@ -660,33 +527,61 @@
  		ERR("%s: Unable to allocate channels\n", __FUNCTION__);
  		goto err;
  	}
@@ -11142,12 +11630,20 @@
  }
  
 -static void xpd_card_disable(xpd_t *xpd)
++/* FIXME: this should be removed once digium patch their zaptel.h
++ * I simply wish to avoid changing zaptel.h in the xpp patches.
++ */
++#ifndef ZT_EVENT_REMOVED
++#define ZT_EVENT_REMOVED (20)
++#endif
++
 +void xpd_disconnect(xpd_t *xpd)
  {
 +	unsigned long	flags;
 +
  	BUG_ON(!xpd);
 -	atomic_set(&xpd->card_present, 0);
+-	if(SPAN_REGISTERED(xpd))
 +
 +	// TODO: elect a new sync master
 +	if(sync_master == xpd)
@@ -11158,27 +11654,37 @@
 +	if(!xpd->card_present)	/* Multiple reports */
 +		goto out;
 +	xpd->card_present = 0;
- 	if(SPAN_REGISTERED(xpd))
++	if(SPAN_REGISTERED(xpd)) {
++		int i;
++
  		update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
++		/* TODO: Should this be done before releasing the spinlock? */
++		DBG("Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n");
++		for (i=0; i<xpd->span.channels; i++)
++			zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED);
++	}
 +out:
 +	spin_unlock_irqrestore(&xpd->lock, flags);
  }
  
  void xpd_remove(xpd_t *xpd)
-@@ -696,22 +583,16 @@
+@@ -695,23 +590,14 @@
+ 
  	BUG_ON(!xpd);
  	xbus = xpd->xbus;
- 	INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
+-	INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
 -#if 0
 -	// TODO: elect a new sync master
 -	if(sync_master == xpd)
 -		set_sync_master(NULL);
 -#endif
+-	xpd_zaptel_unregister(xpd);
+-	xbus->xpds[xpd->id] = NULL;
+-	list_del(&xpd->xpd_list);
+-	xbus->num_xpds--;
++	INFO("%s: Remove XPD #%d from\n", xbus->busname, xpd->id);
 +
- 	xpd_zaptel_unregister(xpd);
- 	xbus->xpds[xpd->id] = NULL;
- 	list_del(&xpd->xpd_list);
- 	xbus->num_xpds--;
++	zaptel_unregister_xpd(xpd);
  	CALL_XMETHOD(card_remove, xbus, xpd);
 -	xpd_cleanup(xpd);
 -	kfree((void *)xpd->writechunk);
@@ -11191,19 +11697,24 @@
  {
  	struct zt_span *span = &xpd->span;
  
-@@ -734,80 +615,6 @@
+@@ -734,78 +620,16 @@
  	DBG("Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
  }
  
 -void phone_hook(xpd_t *xpd, int channo, bool offhook)
--{
++void update_line_status(xpd_t *xpd, int pos, bool good)
+ {
 -	struct zt_chan *chan = &xpd->span.chans[channo];
--
++	struct zt_chan	*chan;
+ 
 -	if(offhook && !IS_SET(xpd->hookstate, channo)) {		// OFFHOOK
 -		DBG("OFFHOOK: channo=%d\n", chan->channo);
 -		xpd->ringing[channo] = 0;
 -		BIT_SET(xpd->hookstate, channo);
--		zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
++	BUG_ON(!xpd);
++	chan = &xpd->chans[pos];
++	if(good)
+ 		zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
 -		if(!IS_SET(xpd->digital_outputs, channo) && !IS_SET(xpd->digital_inputs, channo)) {
 -			CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(channo), 0);		// Power down (prevent overheating!!!)
 -			CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(channo), LED_GREEN, 1);
@@ -11212,7 +11723,8 @@
 -		DBG("ONHOOK channo=%d\n", chan->channo);
 -		xpd->ringing[channo] = 0;
 -		BIT_CLR(xpd->hookstate, channo);
--		zt_hooksig(chan, ZT_RXSIG_ONHOOK);
++	else
+ 		zt_hooksig(chan, ZT_RXSIG_ONHOOK);
 -		if(!IS_SET(xpd->digital_outputs, channo) && !IS_SET(xpd->digital_inputs, channo)) {
 -			CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(channo), 0);		// Power down (prevent overheating!!!)
 -			CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(channo), LED_GREEN, 0);
@@ -11267,21 +11779,19 @@
 -		}
 -	}
 -	spin_unlock_irqrestore(&xpd->lock, flags);
--}
--
+ }
+ 
  static void xpp_ring_generate(xpd_t *xpd)
- {
- 	int		i;
-@@ -829,7 +636,7 @@
+@@ -829,7 +653,7 @@
  	 * Ring detect logic:
  	 * 	fxo_power is toggled
  	 */
 -	for(i = 0; i < xpd->channels; i++) {
-+	for_each_enabled_line(xpd, i) {
++	for_each_line(xpd, i) {
  		if(xpd->ringing[i] || xpd->ringer_on[i]) {
  			// ring state is only changed once per second:
  			if((xpd->timer_count % 1000) == 0) {
-@@ -839,10 +646,7 @@
+@@ -839,10 +663,7 @@
  				} else {
  					zt_hooksig(&xpd->chans[i], ZT_RXSIG_RING);
  				}
@@ -11292,7 +11802,7 @@
  			}
  		}
  	}
-@@ -850,98 +654,13 @@
+@@ -850,98 +671,13 @@
  	spin_unlock_irqrestore(&xpd->lock, flags);
  }
  
@@ -11394,7 +11904,7 @@
  
  	len += sprintf(page + len, "# To modify sync source write into this file:\n");
  	len += sprintf(page + len, "#     HOST        - For host based sync\n");
-@@ -952,8 +671,8 @@
+@@ -952,8 +688,8 @@
  	else
  		len += sprintf(page + len, "%s/%s\n", sync_master->xbus->busname, sync_master->xpdname);
  	len += sprintf(page + len, "tick: #%d\n", xpp_timer_count);
@@ -11405,7 +11915,7 @@
  	if(now - xpp_last_jiffies > 0) {
  		xpp_timer_rate = ((xpp_timer_count % SAMPLE_TICKS) * 1000) / (now - xpp_last_jiffies);
  		len += sprintf(page + len, "tick rate: %4d/second (average over %d seconds)\n", xpp_timer_rate, SAMPLE_TICKS/HZ);
-@@ -971,7 +690,6 @@
+@@ -971,7 +707,6 @@
  
  static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
  {
@@ -11413,7 +11923,7 @@
  	const int	NUM_SIZE = 100;
  	char		buf[NUM_SIZE];
  	int		xbus_num;
-@@ -979,31 +697,47 @@
+@@ -979,31 +714,47 @@
  	xbus_t		*xbus;
  	xpd_t		*xpd;
  	int		ret;
@@ -11468,12 +11978,10 @@
  out:
  	return count;
  }
-@@ -1048,348 +782,75 @@
- 	if(ret != 1)
- 		return -EINVAL;
+@@ -1050,346 +801,73 @@
  	DBG("%s: %s/%s %s\n", __FUNCTION__,
--			xpd->xbus->busname, xpd->xpdname, (zt_reg) ? "register" : "unregister");
--	if(zt_reg)
+ 			xpd->xbus->busname, xpd->xpdname, (zt_reg) ? "register" : "unregister");
+ 	if(zt_reg)
 -		ret = xpd_zaptel_register(xpd);
 -	else
 -		ret = xpd_zaptel_unregister(xpd);
@@ -11690,8 +12198,12 @@
 -	}
 -#endif
 -	kfree(xbus);
--}
--
++		ret = zaptel_register_xpd(xpd);
++	else
++		ret = zaptel_unregister_xpd(xpd);
++	return (ret < 0) ? ret : count;
+ }
+ 
 -xbus_t *xbus_new(ulong loopback_xpds)
 -{
 -	unsigned long	flags;
@@ -11717,14 +12229,7 @@
 -	xbuses_array[xbus_num] = xbus;
 -	bus_count++;
 -	spin_unlock_irqrestore(&xbuses_lock, flags);
-+			xpd->xbus->busname, xpd->xpdname, (zt_reg) ? "register" : "unregister");
-+	if(zt_reg)
-+		ret = xpd_zaptel_register(xpd);
-+	else
-+		ret = xpd_zaptel_unregister(xpd);
-+	return (ret < 0) ? ret : count;
-+}
- 
+-
 -	/* Init data structures */
 -	spin_lock_init(&xbus->lock);
 -	snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus_num);
@@ -11875,7 +12380,7 @@
  }
  
  
-@@ -1407,12 +868,12 @@
+@@ -1407,12 +885,12 @@
  	int	i;
  	int	channels = xpd->channels;
  	struct zt_chan	*chans = xpd->span.chans;
@@ -11890,7 +12395,7 @@
  	if (xpd->timer_count & 1) {
  		/* First part */
  		w = writechunk = xpd->writechunk /* + 1 */;
-@@ -1422,18 +883,26 @@
+@@ -1422,18 +900,26 @@
  	zt_transmit(&xpd->span);
  
  	for (i = 0; i < channels; i++) {
@@ -11921,7 +12426,7 @@
  }
  
  void fill_beep(u_char *buf, int duration)
-@@ -1446,20 +915,46 @@
+@@ -1446,20 +932,46 @@
  	static u_char beep[] = {
  //		0x7F, 0xBE, 0xD8, 0xBE, 0x80, 0x41, 0x24, 0x41,	/* Dima */
  //		0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67,	/* silence */
@@ -11970,7 +12475,7 @@
  //	if((xpd->timer_count % PREP_REPORT_RATE) == 0)
  //		DBG("%d\n", xpd->timer_count);
  
-@@ -1472,20 +967,29 @@
+@@ -1472,20 +984,29 @@
  
  	for (i = 0; i < channels; i++) {
  		if(IS_SET(xpd->hookstate, i)) {
@@ -12001,7 +12506,7 @@
  }
  
  static int xpp_startup(struct zt_span *span)
-@@ -1540,13 +1044,18 @@
+@@ -1540,13 +1061,18 @@
  	spin_lock_irqsave(&xbus->lock, flags);
  	xbus->open_counter--;
  	atomic_dec(&xpd->open_counter);
@@ -12021,7 +12526,7 @@
  	return 0;
  }
  
-@@ -1560,10 +1069,11 @@
+@@ -1560,10 +1086,11 @@
  		case ZT_ONHOOKTRANSFER:
  			if (get_user(x, (int *)arg))
  				return -EFAULT;
@@ -12036,7 +12541,21 @@
  			}
  			DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos);
  			return -ENOTTY;
-@@ -1590,109 +1100,15 @@
+@@ -1574,6 +1101,13 @@
+ 				xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE));
+ 			return -ENOTTY;
+ 		default:
++			/* Some span-specific commands before we give up: */
++			if (xpd->xops->card_ioctl != NULL) {
++				x = xpd->xops->card_ioctl(xpd, pos, cmd, arg);
++				if (x != -ENOTTY)
++					return x;
++			}
++				
+ 			DBG("ENOTTY: chan=%d cmd=0x%x\n", pos, cmd);
+ 			DBG("        IOC_TYPE=0x%02X\n", _IOC_TYPE(cmd));
+ 			DBG("        IOC_DIR=0x%02X\n", _IOC_DIR(cmd));
+@@ -1590,109 +1124,15 @@
  	xpd_t	*xpd = chan->pvt;
  	xbus_t	*xbus;
  	int pos = chan->chanpos - 1;
@@ -12153,7 +12672,7 @@
  
  static int xpp_sethook(struct zt_chan *chan, int hookstate)
  {
-@@ -1701,102 +1117,15 @@
+@@ -1701,102 +1141,15 @@
  	xbus_t	*xbus;
  	int ret = 0;
  
@@ -12260,7 +12779,7 @@
  /* Req: Set the requested chunk size.  This is the unit in which you must
     report results for conferencing, etc */
  int xpp_setchunksize(struct zt_span *span, int chunksize);
-@@ -1815,7 +1144,6 @@
+@@ -1815,7 +1168,6 @@
  	switch(cmd) {
  		case ZT_MAINT_NONE:
  			printk("XXX Turn off local and remote loops XXX\n");
@@ -12268,7 +12787,7 @@
  			break;
  		case ZT_MAINT_LOCALLOOP:
  			printk("XXX Turn on local loopback XXX\n");
-@@ -1825,12 +1153,10 @@
+@@ -1825,12 +1177,10 @@
  			break;
  		case ZT_MAINT_LOOPUP:
  			printk("XXX Send loopup code XXX\n");
@@ -12281,7 +12800,7 @@
  			break;
  		case ZT_MAINT_LOOPSTOP:
  			printk("XXX Stop sending loop codes XXX\n");
-@@ -1848,8 +1174,7 @@
+@@ -1848,8 +1198,7 @@
  /* Set signalling type (if appropriate) */
  static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
  {
@@ -12291,7 +12810,7 @@
  	// FIXME: sanity checks:
  	// - should be supported (within the sigcap)
  	// - should not replace fxs <->fxo ??? (covered by previous?)
-@@ -1878,6 +1203,29 @@
+@@ -1878,6 +1227,29 @@
  int (*sethook)(struct zt_chan *chan, int hookstate);
  #endif
  
@@ -12321,23 +12840,12 @@
  #ifdef	CONFIG_ZAPTEL_WATCHDOG
  /*
   * If the watchdog detects no received data, it will call the
-@@ -1893,6 +1241,13 @@
- }
- #endif
- 
-+/* FIXME: this should be removed once digium patch their zaptel.h
-+ * I simply wish to avoid changing zaptel.h in the xpp patches.
-+ */
-+#ifndef ZT_EVENT_REMOVED
-+#define ZT_EVENT_REMOVED (20)
-+#endif
-+
- /**
-  * Unregister an xpd from zaptel and release related resources
-  * @xpd The xpd to be unregistered
-@@ -1906,20 +1261,33 @@
+@@ -1904,33 +1276,40 @@
+  * 	- User action through /proc
+  * 	- During xpd_remove()
   */
- static int xpd_zaptel_unregister(xpd_t *xpd)
+-static int xpd_zaptel_unregister(xpd_t *xpd)
++static int zaptel_unregister_xpd(xpd_t *xpd)
  {
 +	unsigned long	flags;
 +
@@ -12354,26 +12862,45 @@
 +		sync_master_is(NULL);			// FIXME: it's better to elect a new prince
  	update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
  	if(atomic_read(&xpd->open_counter)) {
-+		int i;
  		NOTICE("%s: %s is busy (open_counter=%d). Skipping.\n", __FUNCTION__, xpd->xpdname, atomic_read(&xpd->open_counter));
 +		spin_unlock_irqrestore(&xpd->lock, flags);
-+		/* TODO: Should this be done before releasing the spinlock? */
-+		DBG("Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n");
-+		for (i=0; i<xpd->span.channels; i++)
-+			zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED);
  		return -EBUSY;
  	}
  	mdelay(2);	// FIXME: This is to give chance for transmit/receiveprep to finish.
 +	spin_unlock_irqrestore(&xpd->lock, flags);
 +	if(xpd->card_present)
-+		xpd->xops->card_zaptel_registration(xpd, 0);
++		xpd->xops->card_zaptel_preregistration(xpd, 0);
  	zt_unregister(&xpd->span);
++	if(xpd->card_present)
++		xpd->xops->card_zaptel_postregistration(xpd, 0);
  	return 0;
  }
-@@ -1952,33 +1320,20 @@
+ 
+-static int xpd_zaptel_register(xpd_t *xpd)
++static int zaptel_register_xpd(xpd_t *xpd)
+ {
+-	struct zt_chan	*cur_chan;
+ 	struct zt_span	*span;
+ 	xbus_t		*xbus;
+-	int		sigfxs;
+-	int		i;
+ 	int		cn;
+ 	const xops_t	*xops;
+ 
+@@ -1941,7 +1320,6 @@
+ 		ERR("xpd %s already registered\n", xpd->xpdname);
+ 		return -EEXIST;
+ 	}
+-	sigfxs = ! (xpd->direction == TO_PHONE);	/* signaling is opposite */
+ 	cn = xpd->channels;
+ 	DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
+ 
+@@ -1950,59 +1328,7 @@
+ 
+ 	span = &xpd->span;
  	xbus = xpd->xbus;
- 	snprintf(span->name, MAX_SPANNAME, "%s/%s",
- 			xbus->busname, xpd->xpdname);
+-	snprintf(span->name, MAX_SPANNAME, "%s/%s",
+-			xbus->busname, xpd->xpdname);
 -	{
 -		char tmp[MAX_SPANNAME];
 -#if SOFT_SIMULATOR
@@ -12386,30 +12913,50 @@
 -			tmp[0] = '\0';
 -
 -		snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
-+		snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s",
- 				xbus->num, xpd->id,
+-				xbus->num, xpd->id,
 -				(xpd->direction == TO_PHONE) ? "FXS" : "FXO",
 -				tmp
-+				(xpd->direction == TO_PHONE) ? "FXS" : "FXO"
- 				);
+-				);
 -	}
- 	for(i = 0; i < cn; i++) {
- 		
- 		cur_chan = &xpd->chans[i];
- 		DBG("setting channel %d (sigfxs=%d)\n", i, sigfxs);
- 		if(IS_SET(xpd->digital_outputs, i)) {
+-	for(i = 0; i < cn; i++) {
+-		
+-		cur_chan = &xpd->chans[i];
+-		DBG("setting channel %d (sigfxs=%d)\n", i, sigfxs);
+-		if(IS_SET(xpd->digital_outputs, i)) {
 -			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d-%d", xpd->id, i);
-+			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d/%d/%d", xbus->num, xpd->id, i);
- 		} else if(IS_SET(xpd->digital_inputs, i)) {
+-		} else if(IS_SET(xpd->digital_inputs, i)) {
 -			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d-%d", xpd->id, i);
-+			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d/%d/%d", xbus->num, xpd->id, i);
- 		} else {
+-		} else {
 -			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d-%d", (sigfxs) ? "FXO" : "FXS", xpd->id, i);
-+			snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d/%d/%d", (sigfxs) ? "FXO" : "FXS", xbus->num, xpd->id, i);
- 		}
- 		cur_chan->chanpos = i + 1;
- 		cur_chan->pvt = xpd;
-@@ -2023,6 +1378,9 @@
+-		}
+-		cur_chan->chanpos = i + 1;
+-		cur_chan->pvt = xpd;
+-		if (sigfxs)
+-			cur_chan->sigcap =
+-#if 1
+-				ZT_SIG_FXSKS	|
+-				ZT_SIG_FXSLS	|
+-#else
+-				ZT_SIG_SF	|
+-#endif
+-				0;
+-		else
+-			cur_chan->sigcap =
+-#if 1
+-				ZT_SIG_FXOKS	|
+-				ZT_SIG_FXOLS	|
+-				ZT_SIG_FXOGS	|
+-#else
+-				ZT_SIG_SF	|
+-				ZT_SIG_EM	|
+-#endif
+-				0;
+-	}
++	snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname);
+ 	span->deflaw = ZT_LAW_MULAW;
+ 	init_waitqueue_head(&span->maintq);
+ 	span->pvt = xpd;
+@@ -2023,67 +1349,28 @@
  #endif
  	span->ioctl = xpp_ioctl;
  	span->maint = xpp_maint;
@@ -12419,14 +12966,24 @@
  #ifdef	CONFIG_ZAPTEL_WATCHDOG
  	span->watchdog = xpp_watchdog;
  #endif
-@@ -2038,52 +1396,14 @@
- 		xbus->num_xpds--;
+ 
+-	DBG("Finished span_load: ZT_FLAG_RUNNING=%d\n", span->flags & ZT_FLAG_RUNNING);
+-
+ 	DBG("Registering span of %s.\n", xpd->xpdname);
++	xpd->xops->card_zaptel_preregistration(xpd, 1);
+ 	if(zt_register(&xpd->span, 1)) {
+ 		xbus_t	*xbus = xpd->xbus;
+-		ERR("Failed to zt_register of span of xpd %s.\n", xpd->xpdname);
+-		xbus->xpds[xpd->id] = NULL;
+-		list_del(&xpd->xpd_list);
+-		xbus->num_xpds--;
++		ERR("%s/%s: Failed to zt_register span\n", xbus->busname, xpd->xpdname);
  		return -ENODEV;
  	}
 -//	if(xpd->id == 0)
 -//		set_sync_master(xpd);
 -
-+	xpd->xops->card_zaptel_registration(xpd, 1);
++	xpd->xops->card_zaptel_postregistration(xpd, 1);
  	return 0;
  }
  
@@ -12473,7 +13030,7 @@
  #if 0
  static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
  {
-@@ -2097,6 +1417,7 @@
+@@ -2097,6 +1384,7 @@
  #define	MINOR_XBUS_NUM(m)	((m) >> 4)
  #define	MINOR_XPD_NUM(m)	((m) & 0xF);
  
@@ -12481,7 +13038,16 @@
  static int xpp_sys_open (struct inode * inode, struct file * file)
  {
  	xbus_t *xbus;
-@@ -2186,6 +1507,7 @@
+@@ -2164,7 +1452,7 @@
+ 	if (copy_from_user (pack_tx->content.raw, buf, count)) {
+ 		return -EFAULT;
+ 	}
+-	XPD_ADDR_SET(pack_tx->content.addr, xpdnum);
++	xpd_set_addr(&pack_tx->content.addr, xpdnum);
+ 	pack_tx->datalen = count;
+ 	// pack_tx->flags |= XPP_PACKET_FIREANDFORGET;
+ 	DBG("sending op=%d to %d\n", pack_tx->content.opcode, xpdnum);
+@@ -2186,6 +1474,7 @@
  	.release	= xpp_sys_release,
  };
  
@@ -12489,33 +13055,28 @@
  
  /*------------------------- Initialization -------------------------*/
  
-@@ -2193,42 +1515,52 @@
+@@ -2193,42 +1482,47 @@
  {
  	if(timer_pending(&xpp_timer))
  		del_timer_sync(&xpp_timer);
--	unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
--#ifdef CONFIG_PROC_FS
++#if 0
+ 	unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
++#endif
+ #ifdef CONFIG_PROC_FS
 -	remove_proc_entry(PROC_SYNC, xpp_procdir);
 -	remove_proc_entry(PROC_XBUSES, xpp_procdir);
 -	if(xpp_procdir) {
--		remove_proc_entry(PROC_DIR, NULL);
++	remove_proc_entry(PROC_SYNC, xpp_proc_toplevel);
++	if(xpp_proc_toplevel) {
+ 		remove_proc_entry(PROC_DIR, NULL);
+ 	}
+ #endif
+-	if (xpp_worker) {
+-		flush_workqueue(xpp_worker);
+-		destroy_workqueue(xpp_worker);
+-		xpp_worker = NULL;
 -	}
--#endif
- 	if (xpp_worker) {
- 		flush_workqueue(xpp_worker);
- 		destroy_workqueue(xpp_worker);
- 		xpp_worker = NULL;
- 	}
 -	kmem_cache_destroy(packet_cache);
-+#if 0
-+	unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
-+#endif
-+#ifdef CONFIG_PROC_FS
-+	remove_proc_entry(PROC_SYNC, xpp_proc_toplevel);
-+	if(xpp_proc_toplevel) {
-+		remove_proc_entry(PROC_DIR, NULL);
-+	}
-+#endif
  }
  
  int __init xpp_zap_init(void)
@@ -12563,7 +13124,7 @@
  	if(!ent) {
  		do_cleanup();
  		return -EFAULT;
-@@ -2236,11 +1568,6 @@
+@@ -2236,67 +1530,42 @@
  	ent->read_proc = proc_sync_read;
  	ent->write_proc = proc_sync_write;
  	ent->data = NULL;
@@ -12573,18 +13134,16 @@
 -		return -EFAULT;
 -	}
  #endif
- 	xpp_worker = create_singlethread_workqueue("xppworker");
- 	if(!xpp_worker) {
-@@ -2248,55 +1575,40 @@
- 		do_cleanup();
- 		return -ENOMEM;
- 	}
+-	xpp_worker = create_singlethread_workqueue("xppworker");
+-	if(!xpp_worker) {
+-		ERR("Failed to create card detector workqueue.\n");
 +	ret = xbus_core_init();
 +	if(ret) {
 +		ERR("xbus_core_init failed (%d)\n", ret);
-+		do_cleanup();
+ 		do_cleanup();
+-		return -ENOMEM;
 +		return ret;
-+	}
+ 	}
  	
 +#if 0
  	if (register_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name, &xpp_fops)) {
@@ -12633,6 +13192,7 @@
 +EXPORT_SYMBOL(xpd_disconnect);
  EXPORT_SYMBOL(packet_send);
 +EXPORT_SYMBOL(update_xpd_status);
++EXPORT_SYMBOL(update_line_status);
  EXPORT_SYMBOL(fill_beep);
 -EXPORT_SYMBOL(xbus_enqueue_packet);
 -EXPORT_SYMBOL(xbus_dequeue_packet);
@@ -12643,7 +13203,7 @@
  EXPORT_SYMBOL(xpp_tick);
  EXPORT_SYMBOL(xpp_open);
  EXPORT_SYMBOL(xpp_close);
-@@ -2306,7 +1618,7 @@
+@@ -2306,7 +1575,7 @@
  MODULE_DESCRIPTION("XPP Zaptel Driver");
  MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
  MODULE_LICENSE("GPL");
@@ -12652,10 +13212,10 @@
  
  module_init(xpp_zap_init);
  module_exit(xpp_zap_cleanup);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_zap.h zaptel-xpp-8WuH7d_dist/xpp/xpp_zap.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xpp_zap.h zaptel-xpp-oaIQ8i_dist/xpp/xpp_zap.h
 --- zaptel-1.2.6/xpp/xpp_zap.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xpp_zap.h	2006-03-30 12:42:46.619481000 +0200
-@@ -1,37 +1,44 @@
++++ zaptel-xpp-oaIQ8i_dist/xpp/xpp_zap.h	2006-07-02 19:47:41.666262000 +0300
+@@ -1,58 +1,54 @@
  #ifndef	XPP_ZAP_H
  #define	XPP_ZAP_H
 +/*
@@ -12703,10 +13263,12 @@
 -void phone_hook(xpd_t *xpd, int channo, bool offhook);
 -void xpp_check_hookstate(xpd_t *xpd, xpp_line_t fxs_off_hook);
 -xpd_t *xpd_of(xbus_t *xbus, int xpd_num);
- void card_detected(void *data);
+-void card_detected(void *data);
++void card_detected(struct card_desc_struct *card_desc);
  xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision);
  void xpd_remove(xpd_t *xpd);
 +void update_xpd_status(xpd_t *xpd, int alarm_flag);
++void update_line_status(xpd_t *xpd, int pos, bool good);
  void fill_beep(u_char *buf, int duration);
  void xpp_tick(unsigned long param);
  int xpp_open(struct zt_chan *chan);
@@ -12715,9 +13277,18 @@
  int xpp_maint(struct zt_span *span, int cmd);
 +void sync_master_is(xpd_t *xpd);
  
- #define	CARD_DESC_MAGIC	0xca9dde5c
+-#define	CARD_DESC_MAGIC	0xca9dde5c
+-
+-struct	card_desc_struct {
+-	struct work_struct	work;
+-	u32			magic;
+-	xbus_t			*xbus;
+-	byte			rev;		/* Revision number */
+-	byte			type;		/* LSB: 1 - to_phone, 0 - to_line */
+-	byte			xpd_num;
+-};
+ extern struct workqueue_struct		*xpp_worker;
  
-@@ -48,11 +55,9 @@
  #ifdef CONFIG_PROC_FS
  #include <linux/proc_fs.h>
  
@@ -12731,9 +13302,9 @@
 +#define	SPAN_REGISTERED(xpd)	((xpd)->span.flags & ZT_FLAG_REGISTERED)
  
  #endif	/* XPP_ZAP_H */
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xproto.c zaptel-xpp-8WuH7d_dist/xpp/xproto.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xproto.c zaptel-xpp-oaIQ8i_dist/xpp/xproto.c
 --- zaptel-1.2.6/xpp/xproto.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xproto.c	2006-06-22 11:31:28.427315000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/xproto.c	2006-07-03 12:11:26.109424000 +0300
 @@ -1,6 +1,6 @@
  /*
   * Written by Oron Peled <oron at actcom.co.il>
@@ -12742,7 +13313,7 @@
   *
   * All rights reserved.
   *
-@@ -23,9 +23,11 @@
+@@ -23,35 +23,36 @@
  #include "xpd.h"
  #include "xproto.h"
  #include "xpp_zap.h"
@@ -12751,11 +13322,45 @@
  #include <linux/module.h>
  
 -static const char rcsid[] = "$Id: xproto.c 949 2006-02-15 02:24:18Z kpfleming $";
-+static const char rcsid[] = "$Id: xproto.c 1431 2006-06-22 08:31:28Z oron $";
++static const char rcsid[] = "$Id: xproto.c 1543 2006-07-03 09:11:26Z oron $";
  
  extern	int print_dbg;
  static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack);
-@@ -75,7 +77,7 @@
+ 
+ static const xproto_table_t *xprotocol_tables[XPD_TYPE_NOMODULE];
+ 
++#if MAX_UNIT*MAX_SUBUNIT > MAX_XPDS
++#error MAX_XPDS is too small
++#endif
++
+ bool valid_xpd_addr(const xpd_addr_t *addr)
+ {
+-	return ((addr->bank_num & ~0x1) == 0) && ((addr->card_id & ~0x3) == 0);
++	return ((addr->subunit & ~0x1) == 0) && ((addr->unit & ~0x3) == 0);
+ }
+ 
+ int xpd_addr2num(const xpd_addr_t *addr)
+ {
+ 	BUG_ON(!valid_xpd_addr(addr));
+-	return addr->bank_num * 4 + addr->card_id;
++	return addr->unit + addr->subunit * MAX_UNIT;
+ }
+ 
+ void xpd_set_addr(xpd_addr_t *addr, int xpd_num)
+ {
+-	if(xpd_num < 4) {
+-		addr->card_id = xpd_num;
+-		addr->bank_num = 0;
+-	} else {
+-		addr->card_id = xpd_num % 4;
+-		addr->bank_num = xpd_num / 4;
+-	}
++	addr->unit = xpd_num % MAX_UNIT;
++	addr->subunit = xpd_num / MAX_UNIT;
+ }
+ 
+ 
+@@ -75,7 +76,7 @@
  	return xe;
  }
  
@@ -12764,7 +13369,7 @@
  {
  	return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode);
  }
-@@ -87,7 +89,7 @@
+@@ -87,7 +88,7 @@
  	return xprotocol_tables[cardtype];
  }
  
@@ -12773,7 +13378,7 @@
  {
  	const xproto_table_t *xtable;
  
-@@ -95,18 +97,34 @@
+@@ -95,18 +96,34 @@
  		return NULL;
  	xtable = xprotocol_tables[cardtype];
  	if(!xtable) {	/* Try to load the relevant module */
@@ -12811,7 +13416,7 @@
  {
  	const xproto_entry_t *xe;
  
-@@ -115,7 +133,7 @@
+@@ -115,7 +132,7 @@
  	return xe->handler;
  }
  
@@ -12820,7 +13425,7 @@
  {
  	const xproto_entry_t *xe;
  	
-@@ -136,18 +154,6 @@
+@@ -136,18 +153,6 @@
  	return xe;
  }
  
@@ -12839,7 +13444,7 @@
  int packet_receive(xbus_t *xbus, xpacket_t *pack)
  {
  	int	xpd_num;
-@@ -161,7 +167,7 @@
+@@ -161,7 +166,7 @@
  		return -EPROTO;
  	}
  	xpd_num = XPD_NUM(pack->content.addr);
@@ -12848,6 +13453,30 @@
  	if(xbus->sim[xpd_num].simulated) {
  		//dump_packet("packet_receive -> simulate", pack, print_dbg);
  		return simulate_xpd(xbus, xpd_num, pack);
+@@ -189,7 +194,8 @@
+ 	xe = find_xproto_entry(xpd, op);
+ 	/*-------- Validations -----------*/
+ 	if(!xe) {
+-		ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
++		ERR("xpp: %s: %s unit #%d: bad command op=0x%02X\n",
++				__FUNCTION__, xbus->busname, xpd_num, op);
+ 		dump_packet("packet_process -- bad command", pack, print_dbg);
+ 		ret = -EPROTO;
+ 		goto out;
+@@ -221,10 +227,10 @@
+ 
+ 	if(!print_dbg)
+ 		return;
+-	DBG("%s: @0x%1X%1X OP=0x%02X LEN=%d\n",
++	DBG("%s: U=0x%1X S=0x%1X OP=0x%02X LEN=%d\n",
+ 			msg,
+-			packet->content.addr.bank_num,
+-			packet->content.addr.card_id,
++			packet->content.addr.unit,
++			packet->content.addr.subunit,
+ 			op,
+ 			(byte)packet->datalen);
+ #if VERBOSE_DEBUG
 @@ -256,7 +262,7 @@
  {
  	const xproto_table_t	*proto_table;
@@ -12866,16 +13495,18 @@
  		NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type);
  		return -EINVAL;
  	}
-@@ -290,14 +296,18 @@
+@@ -290,14 +296,20 @@
  	CHECK_XOP(card_init);
  	CHECK_XOP(card_remove);
  	CHECK_XOP(card_tick);
-+	CHECK_XOP(card_zaptel_registration);
++	CHECK_XOP(card_zaptel_preregistration);
++	CHECK_XOP(card_zaptel_postregistration);
 +#ifdef WITH_RBS
 +	CHECK_XOP(card_hooksig);
 +#else
 +	CHECK_XOP(card_sethook);
 +#endif
++	// CHECK_XOP(card_ioctl);	// optional method -- call after testing
  	CHECK_XOP(SYNC_SOURCE);
  	CHECK_XOP(PCM_WRITE);
  	CHECK_XOP(CHAN_ENABLE);
@@ -12887,7 +13518,7 @@
  	CHECK_XOP(RELAY_OUT);
  
  	xprotocol_tables[type] = proto_table;
-@@ -313,7 +323,7 @@
+@@ -313,7 +325,7 @@
  	type = proto_table->type;
  	name = proto_table->name;
  	DBG("%s (%d)\n", name, type);
@@ -12896,9 +13527,9 @@
  		NOTICE("%s: Bad xproto type %s (%d)\n", __FUNCTION__, name, type);
  		return;
  	}
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xproto.h zaptel-xpp-8WuH7d_dist/xpp/xproto.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/xproto.h zaptel-xpp-oaIQ8i_dist/xpp/xproto.h
 --- zaptel-1.2.6/xpp/xproto.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/xproto.h	2006-06-22 11:31:28.427315000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/xproto.h	2006-07-03 13:44:48.152691000 +0300
 @@ -2,7 +2,7 @@
  #define	XPROTO_H
  /*
@@ -12908,7 +13539,7 @@
   *
   * All rights reserved.
   *
-@@ -26,18 +26,22 @@
+@@ -26,31 +26,39 @@
  
  #ifdef	__KERNEL__
  #include <linux/list.h>
@@ -12923,8 +13554,13 @@
 -	XPD_TYPE(FXS)		= 0x03,
 -	XPD_TYPE(NOMODULE)	= 0x0F,
 -} xpd_type_t;
-+#define	XPD_TYPE_FXS		3
-+#define	XPD_TYPE_FXO		4
++/*
++ * The LSB of the type number signifies:
++ * 	0 - TO_PSTN
++ * 	1 - TO_PHONE
++ */
++#define	XPD_TYPE_FXS		3	// TO_PHONE
++#define	XPD_TYPE_FXO		4	// TO_PSTN
 +#define	XPD_TYPE_NOMODULE	15
 +
 +typedef	byte	xpd_type_t;
@@ -12938,7 +13574,64 @@
  #define	PCM_CHUNKSIZE	(CHANNELS_PERXPD * 8)	/* samples of 8 bytes */
  
  typedef struct xpd_addr {
-@@ -124,14 +128,13 @@
+-	byte	card_id:4;
+-	byte	bank_num:4;
+-} __attribute__((packed)) xpd_addr_t;
++	byte	unit:UNIT_BITS;
++	byte	subunit:SUBUNIT_BITS;
++} PACKED xpd_addr_t;
+ 
+ bool valid_xpd_addr(const xpd_addr_t *addr);
+ int xpd_addr2num(const xpd_addr_t *addr);
+ void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
+ 
+ #define	XPD_NUM(x)		xpd_addr2num(&x)
+-#define	XPD_ADDR_SET(x,val)	xpd_set_addr(&x, val)
+ #define	MAX_XPACKET_DATALEN	100
+ 
+ #define	XPROTO_NAME(card,op)	card ## _ ## op
+@@ -82,11 +90,12 @@
+ 		byte		opcode;	\
+ 		xpd_addr_t	addr;	\
+ 		__VA_ARGS__		\
+-	} __attribute__((packed))
++	} PACKED
+ 
+ #define	RPACKET_CAST(p,card,op)		((RPACKET_TYPE(card,op) *)p)
+ #define	RPACKET_FIELD(p,card,op,field)	(RPACKET_CAST(p,card,op)->field)
+ #define	RPACKET_SIZE(card,op)		sizeof(RPACKET_TYPE(card,op))
++#define	RPACKET_DATALEN(card,op)	(RPACKET_SIZE(card,op) - sizeof(xpd_addr_t) - 1)
+ 
+ #define	PACKET_LEN(p) \
+ 	((p)->datalen + sizeof(xpd_addr_t) + 1)
+@@ -94,7 +103,7 @@
+ #define	XENTRY(card,op)					\
+ 	[ XPROTO_NAME(card,op) ] {			\
+ 		.handler = XPROTO_HANDLER(card,op),	\
+-		.datalen = RPACKET_SIZE(card,op),	\
++		.datalen = RPACKET_DATALEN(card,op),	\
+ 		.name = #op,				\
+ 		.table = &PROTO_TABLE(card)		\
+ 	}
+@@ -103,7 +112,7 @@
+ #define	XPACKET_INIT(p, card, op)					\
+ 		do {							\
+ 			p->content.opcode = XPROTO_NAME(card,op);	\
+-			p->datalen = RPACKET_SIZE(card,op);		\
++			p->datalen = RPACKET_DATALEN(card,op);		\
+ 		} while(0)
+ 
+ #define	XPACKET_NEW(p, xbus, card, op, to)			\
+@@ -112,7 +121,7 @@
+ 		if(!p)						\
+ 			return -ENOMEM;				\
+ 		XPACKET_INIT(p, card, op);			\
+-		XPD_ADDR_SET(p->content.addr, to);		\
++		xpd_set_addr(&p->content.addr, to);		\
+ 	} while(0);
+ 
+ typedef struct xproto_entry	xproto_entry_t;
+@@ -124,14 +133,13 @@
  		const xproto_entry_t *cmd,
  		xpacket_t *pack);
  
@@ -12957,16 +13650,18 @@
  
  #define	CALL_XMETHOD(name, xbus, xpd, ...)				\
  			(xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )
-@@ -141,23 +144,23 @@
+@@ -141,23 +149,25 @@
  	int (*card_init)(xbus_t *xbus, xpd_t *xpd);
  	int (*card_remove)(xbus_t *xbus, xpd_t *xpd);
  	int (*card_tick)(xbus_t *xbus, xpd_t *xpd);
-+	int (*card_zaptel_registration)(xpd_t *xpd, bool on);
++	int (*card_zaptel_preregistration)(xpd_t *xpd, bool on);
++	int (*card_zaptel_postregistration)(xpd_t *xpd, bool on);
 +#ifdef	WITH_RBS
 +	int (*card_hooksig)(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig);
 +#else
 +	int (*card_sethook)(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate);
 +#endif
++	int (*card_ioctl)(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg);
  
  	int (*SYNC_SOURCE)(xbus_t *xbus, xpd_t *xpd, bool setit, bool is_master);
  	int (*PCM_WRITE)(xbus_t *xbus, xpd_t *xpd, xpp_line_t hookstate,  volatile byte *buf);
@@ -12989,7 +13684,7 @@
  struct xproto_entry {
  	xproto_handler_t	handler;
  	int			datalen;
-@@ -166,6 +169,7 @@
+@@ -166,6 +176,7 @@
  };
  
  struct xproto_table {
@@ -12997,16 +13692,19 @@
  	xproto_entry_t	entries[255];	/* Indexed by opcode */
  	xops_t		xops;
  	xpd_type_t	type;
-@@ -176,6 +180,7 @@
+@@ -176,8 +187,10 @@
  
  #include "card_global.h"
  #include "card_fxs.h"
 +#include "card_fxo.h"
  
  enum opcodes {
++	XPROTO_NAME(GLOBAL, NULL_REPLY)		= 0xFE,
  	XPROTO_NAME(GLOBAL, DESC_REQ)		= 0x04,
-@@ -186,21 +191,6 @@
+ 	XPROTO_NAME(GLOBAL, DEV_DESC)		= 0x05,
  /**/
+@@ -186,21 +199,6 @@
+ /**/
  	XPROTO_NAME(GLOBAL, SYNC_SOURCE)	= 0x19,
  	XPROTO_NAME(GLOBAL, SYNC_REPLY)		= 0x1A,
 -
@@ -13027,21 +13725,28 @@
  };
  
  
-@@ -218,6 +208,13 @@
+@@ -210,6 +208,7 @@
+ 	byte		opcode;
+ 	xpd_addr_t	addr;
+ 	union {
++		MEMBER(GLOBAL, NULL_REPLY);
+ 		MEMBER(GLOBAL, DESC_REQ);
+ 		MEMBER(GLOBAL, DEV_DESC);
+ 		MEMBER(GLOBAL, PCM_WRITE);
+@@ -218,15 +217,21 @@
  
  		MEMBER(FXS, SIG_CHANGED);
  		MEMBER(FXS, SLIC_REPLY);
-+		MEMBER(FXS, SLIC_INIT);
 +		MEMBER(FXS, SLIC_WRITE);
 +
 +		MEMBER(FXO, SIG_CHANGED);
 +		MEMBER(FXO, DAA_REPLY);
-+		MEMBER(FXO, DAA_INIT);
 +		MEMBER(FXO, DAA_WRITE);
  
  		byte	data[0];
  	};
-@@ -225,8 +222,9 @@
+-} __attribute__((packed));
++} PACKED;
  
  struct xpacket {
  	xpacket_raw_t		content;
@@ -13052,9 +13757,9 @@
  };
  
  void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/zap_debug.c zaptel-xpp-8WuH7d_dist/xpp/zap_debug.c
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/zap_debug.c zaptel-xpp-oaIQ8i_dist/xpp/zap_debug.c
 --- zaptel-1.2.6/xpp/zap_debug.c	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/zap_debug.c	2006-03-30 12:42:46.619481000 +0200
++++ zaptel-xpp-oaIQ8i_dist/xpp/zap_debug.c	2006-03-30 12:42:46.619481000 +0200
 @@ -1,6 +1,6 @@
  /*
   * Written by Oron Peled <oron at actcom.co.il>
@@ -13147,9 +13852,9 @@
  EXPORT_SYMBOL(dump_poll);
 -EXPORT_SYMBOL(event2str);
 -EXPORT_SYMBOL(dump_sigtype);
-diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/zap_debug.h zaptel-xpp-8WuH7d_dist/xpp/zap_debug.h
+diff -uNr -x .svn -x debian zaptel-1.2.6/xpp/zap_debug.h zaptel-xpp-oaIQ8i_dist/xpp/zap_debug.h
 --- zaptel-1.2.6/xpp/zap_debug.h	2006-02-15 04:24:18.000000000 +0200
-+++ zaptel-xpp-8WuH7d_dist/xpp/zap_debug.h	2006-06-19 10:36:29.741020000 +0300
++++ zaptel-xpp-oaIQ8i_dist/xpp/zap_debug.h	2006-06-19 10:36:29.741020000 +0300
 @@ -1,16 +1,125 @@
  #ifndef	ZAP_DEBUG_H
  #define	ZAP_DEBUG_H




More information about the Pkg-voip-commits mailing list